зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1593683 - Part 2. Handle arrow left/right key when having composition. r=geckoview-reviewers,esawin
Most IMEs handle arrow key, then set caret position by IME. But GBoard doesn't handle it. GBoard will dispatch key event to application for arrow left/right even if having IME composition. Since Gecko doesn't dispatch key press during IME composition due to DOM UI events spec, we have to emulate arrow key's behaviour. And, `GeckoEditable` has a hack that composition text is committed when dispatching key event. This hack is unnecessary after landing bug 1613804 that `InputConnection.finishComposingText` is implemented. Differential Revision: https://phabricator.services.mozilla.com/D76658
This commit is contained in:
Родитель
83fbd04e63
Коммит
0917864e45
|
@ -791,4 +791,24 @@ class TextInputDelegateTest : BaseSessionTest() {
|
|||
|
||||
assertText("commit abc", ic, "abc")
|
||||
}
|
||||
|
||||
// Bug 1593683 - Cursor is jumping when using the arrow keys in input field on GBoard
|
||||
@WithDisplay(width = 512, height = 512) // Child process updates require having a display.
|
||||
@Test fun inputConnection_bug1593683() {
|
||||
setupContent("")
|
||||
|
||||
val ic = mainSession.textInput.onCreateInputConnection(EditorInfo())!!
|
||||
|
||||
setComposingText(ic, "foo", 1)
|
||||
assertTextAndSelectionAt("Can set the composing text", ic, "foo", 3)
|
||||
// Arrow key should keep composition then move caret
|
||||
pressKey(ic, KeyEvent.KEYCODE_DPAD_LEFT)
|
||||
pressKey(ic, KeyEvent.KEYCODE_DPAD_LEFT)
|
||||
pressKey(ic, KeyEvent.KEYCODE_DPAD_LEFT)
|
||||
assertSelection("IME caret is moved to top", ic, 0, 0, /* checkGecko */ false)
|
||||
|
||||
setComposingText(ic, "bar", 1)
|
||||
finishComposingText(ic)
|
||||
assertText("commit abc", ic, "bar")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1014,10 +1014,52 @@ import android.view.inputmethod.EditorInfo;
|
|||
return;
|
||||
}
|
||||
|
||||
// Most IMEs handle arrow key, then set caret position. But GBoard
|
||||
// doesn't handle it. GBoard will dispatch KeyEvent for arrow left/right
|
||||
// even if having IME composition.
|
||||
// Since Gecko doesn't dispatch keypress during IME composition due to
|
||||
// DOM UI events spec, we have to emulate arrow key's behaviour.
|
||||
boolean commitCompositionBeforeKeyEvent = action == KeyEvent.ACTION_DOWN;
|
||||
if (isComposing(mText.getShadowText()) &&
|
||||
action == KeyEvent.ACTION_DOWN && event.hasNoModifiers()) {
|
||||
final int selStart = Selection.getSelectionStart(mText.getShadowText());
|
||||
final int selEnd = Selection.getSelectionEnd(mText.getShadowText());
|
||||
if (selStart == selEnd) {
|
||||
// If dispatching arrow left/right key into composition,
|
||||
// we update IME caret.
|
||||
switch (event.getKeyCode()) {
|
||||
case KeyEvent.KEYCODE_DPAD_LEFT:
|
||||
if (getComposingStart(mText.getShadowText()) < selStart) {
|
||||
Selection.setSelection(getEditable(), selStart - 1, selStart - 1);
|
||||
mNeedUpdateComposition = true;
|
||||
commitCompositionBeforeKeyEvent = false;
|
||||
} else if (selStart == 0) {
|
||||
// Keep current composition
|
||||
commitCompositionBeforeKeyEvent = false;
|
||||
}
|
||||
break;
|
||||
case KeyEvent.KEYCODE_DPAD_RIGHT:
|
||||
if (getComposingEnd(mText.getShadowText()) > selEnd) {
|
||||
Selection.setSelection(getEditable(), selStart + 1, selStart + 1);
|
||||
mNeedUpdateComposition = true;
|
||||
commitCompositionBeforeKeyEvent = false;
|
||||
} else if (selEnd == mText.getShadowText().length()) {
|
||||
// Keep current composition
|
||||
commitCompositionBeforeKeyEvent = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Focused; key event may go to chrome window or to content window.
|
||||
if (mNeedUpdateComposition) {
|
||||
icMaybeSendComposition(mText.getShadowText(), SEND_COMPOSITION_NOTIFY_GECKO);
|
||||
}
|
||||
|
||||
if (commitCompositionBeforeKeyEvent) {
|
||||
mFocusedChild.onImeRequestCommit();
|
||||
}
|
||||
onKeyEvent(mFocusedChild, event, action, metaState,
|
||||
/* isSynthesizedImeKey */ false);
|
||||
icOfferAction(new Action(Action.TYPE_EVENT));
|
||||
|
@ -2251,5 +2293,29 @@ import android.view.inputmethod.EditorInfo;
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int getComposingStart(final Spanned text) {
|
||||
int composingStart = Integer.MAX_VALUE;
|
||||
final Object[] spans = text.getSpans(0, text.length(), Object.class);
|
||||
for (final Object span : spans) {
|
||||
if ((text.getSpanFlags(span) & Spanned.SPAN_COMPOSING) != 0) {
|
||||
composingStart = Math.min(composingStart, text.getSpanStart(span));
|
||||
}
|
||||
}
|
||||
|
||||
return composingStart;
|
||||
}
|
||||
|
||||
private static int getComposingEnd(final Spanned text) {
|
||||
int composingEnd = -1;
|
||||
final Object[] spans = text.getSpans(0, text.length(), Object.class);
|
||||
for (final Object span : spans) {
|
||||
if ((text.getSpanFlags(span) & Spanned.SPAN_COMPOSING) != 0) {
|
||||
composingEnd = Math.max(composingEnd, text.getSpanEnd(span));
|
||||
}
|
||||
}
|
||||
|
||||
return composingEnd;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -502,7 +502,6 @@ void GeckoEditableSupport::OnKeyEvent(int32_t aAction, int32_t aKeyCode,
|
|||
// these keys are dispatched in sequence.
|
||||
mIMEKeyEvents.AppendElement(UniquePtr<WidgetEvent>(event.Duplicate()));
|
||||
} else {
|
||||
RemoveComposition();
|
||||
NS_ENSURE_SUCCESS_VOID(BeginInputTransaction(dispatcher));
|
||||
dispatcher->DispatchKeyboardEvent(msg, event, status);
|
||||
if (widget->Destroyed() || status == nsEventStatus_eConsumeNoDefault) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче