| Index: content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
|
| diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
|
| index 109c8b8021d70a2f401804e823d5cc5c92c5242e..7eb72e77ed7608c310548c813f369e7dae9f34ea 100644
|
| --- a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
|
| +++ b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
|
| @@ -109,10 +109,6 @@ public class ImeAdapter {
|
| private final Handler mHandler;
|
| private int mTextInputType;
|
| private int mTextInputFlags;
|
| - private String mLastComposeText;
|
| -
|
| - @VisibleForTesting
|
| - int mLastSyntheticKeyCode;
|
|
|
| @VisibleForTesting
|
| boolean mIsShowWithoutHideOutstanding = false;
|
| @@ -163,7 +159,6 @@ public class ImeAdapter {
|
| */
|
| void setInputConnection(AdapterInputConnection inputConnection) {
|
| mInputConnection = inputConnection;
|
| - mLastComposeText = null;
|
| }
|
|
|
| /**
|
| @@ -246,7 +241,6 @@ public class ImeAdapter {
|
| nativeAttachImeAdapter(nativeImeAdapter);
|
| }
|
| mNativeImeAdapterAndroid = nativeImeAdapter;
|
| - mLastComposeText = null;
|
| mTextInputFlags = textInputFlags;
|
| if (textInputType == mTextInputType) return;
|
| mTextInputType = textInputType;
|
| @@ -315,186 +309,71 @@ public class ImeAdapter {
|
| if (mInputConnection != null) {
|
| return mInputConnection.sendKeyEvent(event);
|
| }
|
| - return translateAndSendNativeEvents(event);
|
| - }
|
| -
|
| - private int shouldSendKeyEventWithKeyCode(String text) {
|
| - if (text.length() != 1) return COMPOSITION_KEY_CODE;
|
| -
|
| - if (text.equals("\n")) {
|
| - return KeyEvent.KEYCODE_ENTER;
|
| - } else if (text.equals("\t")) {
|
| - return KeyEvent.KEYCODE_TAB;
|
| - } else {
|
| - return COMPOSITION_KEY_CODE;
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * @return Android KeyEvent for a single unicode character. Only one KeyEvent is returned
|
| - * even if the system determined that various modifier keys (like Shift) would also have
|
| - * been pressed.
|
| - */
|
| - private static KeyEvent androidKeyEventForCharacter(char chr) {
|
| - if (sKeyCharacterMap == null) {
|
| - sKeyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
|
| - }
|
| - sSingleCharArray[0] = chr;
|
| - // TODO: Evaluate cost of this system call.
|
| - KeyEvent[] events = sKeyCharacterMap.getEvents(sSingleCharArray);
|
| - if (events == null) { // No known key sequence will create that character.
|
| - return null;
|
| - }
|
| -
|
| - for (int i = 0; i < events.length; ++i) {
|
| - if (events[i].getAction() == KeyEvent.ACTION_DOWN
|
| - && !KeyEvent.isModifierKey(events[i].getKeyCode())) {
|
| - return events[i];
|
| - }
|
| - }
|
| -
|
| - return null; // No printing characters were found.
|
| + return sendKeyEvent(event);
|
| }
|
|
|
| /**
|
| * @see BaseInputConnection#performContextMenuAction(int)
|
| */
|
| - public boolean performContextMenuAction(int id) {
|
| + boolean performContextMenuAction(int id) {
|
| Log.d(TAG, "performContextMenuAction: id [%d]", id);
|
| return mViewEmbedder.performContextMenuAction(id);
|
| }
|
|
|
| - @VisibleForTesting
|
| - public static KeyEvent getTypedKeyEventGuess(String oldtext, String newtext) {
|
| - // Starting typing a new composition should add only a single character. Any composition
|
| - // beginning with text longer than that must come from something other than typing so
|
| - // return 0.
|
| - if (oldtext == null) {
|
| - if (newtext.length() == 1) {
|
| - return androidKeyEventForCharacter(newtext.charAt(0));
|
| - } else {
|
| - return null;
|
| - }
|
| - }
|
| -
|
| - // The content has grown in length: assume the last character is the key that caused it.
|
| - if (newtext.length() > oldtext.length() && newtext.startsWith(oldtext)) {
|
| - return androidKeyEventForCharacter(newtext.charAt(newtext.length() - 1));
|
| - }
|
| -
|
| - // The content has shrunk in length: assume that backspace was pressed.
|
| - if (oldtext.length() > newtext.length() && oldtext.startsWith(newtext)) {
|
| - return new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL);
|
| + boolean performEditorAction(int actionCode) {
|
| + if (mNativeImeAdapterAndroid == 0) return false;
|
| + if (actionCode == EditorInfo.IME_ACTION_NEXT) {
|
| + sendSyntheticKeyPress(KeyEvent.KEYCODE_TAB,
|
| + KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
|
| + | KeyEvent.FLAG_EDITOR_ACTION);
|
| + } else {
|
| + sendSyntheticKeyPress(KeyEvent.KEYCODE_ENTER,
|
| + KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
|
| + | KeyEvent.FLAG_EDITOR_ACTION);
|
| }
|
| -
|
| - // The content is unchanged or has undergone a complex change (i.e. not a simple tail
|
| - // modification) so return an unknown key-code.
|
| - return null;
|
| + return true;
|
| }
|
|
|
| - void sendKeyEventWithKeyCode(int keyCode, int flags) {
|
| + @VisibleForTesting
|
| + protected void sendSyntheticKeyPress(int keyCode, int flags) {
|
| long eventTime = SystemClock.uptimeMillis();
|
| - mLastSyntheticKeyCode = keyCode;
|
| - translateAndSendNativeEvents(new KeyEvent(eventTime, eventTime,
|
| + sendKeyEvent(new KeyEvent(eventTime, eventTime,
|
| KeyEvent.ACTION_DOWN, keyCode, 0, 0,
|
| KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
|
| flags));
|
| - translateAndSendNativeEvents(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
|
| + sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
|
| KeyEvent.ACTION_UP, keyCode, 0, 0,
|
| KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
|
| flags));
|
| }
|
|
|
| - // Calls from Java to C++
|
| - // TODO: Add performance tracing to more complicated functions.
|
| - boolean checkCompositionQueueAndCallNative(CharSequence text, int newCursorPosition,
|
| - boolean isCommit) {
|
| + boolean sendCompositionToNative(CharSequence text, int newCursorPosition, boolean isCommit) {
|
| if (mNativeImeAdapterAndroid == 0) return false;
|
| mViewEmbedder.onImeEvent();
|
|
|
| - String textStr = text.toString();
|
| - int keyCode = shouldSendKeyEventWithKeyCode(textStr);
|
| - long timeStampMs = SystemClock.uptimeMillis();
|
| + long timestampMs = SystemClock.uptimeMillis();
|
| + nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, WebInputEventType.RawKeyDown,
|
| + timestampMs, COMPOSITION_KEY_CODE, 0, 0);
|
|
|
| - if (keyCode != COMPOSITION_KEY_CODE) {
|
| - sendKeyEventWithKeyCode(keyCode,
|
| - KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE);
|
| + if (isCommit) {
|
| + nativeCommitText(mNativeImeAdapterAndroid, text.toString());
|
| } else {
|
| - KeyEvent keyEvent = getTypedKeyEventGuess(mLastComposeText, textStr);
|
| - int modifiers = 0;
|
| - if (keyEvent != null) {
|
| - keyCode = keyEvent.getKeyCode();
|
| - modifiers = getModifiers(keyEvent.getMetaState());
|
| - } else if (!textStr.equals(mLastComposeText)) {
|
| - keyCode = KeyEvent.KEYCODE_UNKNOWN;
|
| - } else {
|
| - keyCode = -1;
|
| - }
|
| -
|
| - // If this is a single-character commit with no previous composition, then treat it as
|
| - // a native KeyDown/KeyUp pair with no composition rather than a synthetic pair with
|
| - // composition below.
|
| - if (keyCode > 0 && isCommit && mLastComposeText == null && textStr.length() == 1) {
|
| - mLastSyntheticKeyCode = keyCode;
|
| - return translateAndSendNativeEvents(keyEvent)
|
| - && translateAndSendNativeEvents(
|
| - KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_UP));
|
| - }
|
| -
|
| - // Always send compose events. This is a quick fix for http://crbug.com/476497.
|
| - keyCode = COMPOSITION_KEY_CODE;
|
| - modifiers = 0;
|
| -
|
| - // When typing, there is no issue sending KeyDown and KeyUp events around the
|
| - // composition event because those key events do nothing (other than call JS
|
| - // handlers). Typing does not cause changes outside of a KeyPress event which
|
| - // we don't call here. However, if the key-code is a control key such as
|
| - // KEYCODE_DEL then there never is an associated KeyPress event and the KeyDown
|
| - // event itself causes the action. The net result below is that the Renderer calls
|
| - // cancelComposition() and then Android starts anew with setComposingRegion().
|
| - // This stopping and restarting of composition could be a source of problems
|
| - // with 3rd party keyboards.
|
| - //
|
| - // An alternative is to *not* call nativeSetComposingText() in the non-commit case
|
| - // below. This avoids the restart of composition described above but fails to send
|
| - // an update to the composition while in composition which, strictly speaking,
|
| - // does not match the spec.
|
| - //
|
| - // For now, the solution is to endure the restarting of composition and only dive
|
| - // into the alternate solution should there be problems in the field. --bcwhite
|
| -
|
| - if (keyCode >= 0) {
|
| - nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, WebInputEventType.RawKeyDown,
|
| - timeStampMs, keyCode, modifiers, 0);
|
| - }
|
| -
|
| - if (isCommit) {
|
| - nativeCommitText(mNativeImeAdapterAndroid, textStr);
|
| - textStr = null;
|
| - } else {
|
| - nativeSetComposingText(mNativeImeAdapterAndroid, text, textStr, newCursorPosition);
|
| - }
|
| -
|
| - if (keyCode >= 0) {
|
| - nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, WebInputEventType.KeyUp,
|
| - timeStampMs, keyCode, modifiers, 0);
|
| - }
|
| -
|
| - mLastSyntheticKeyCode = keyCode;
|
| + nativeSetComposingText(
|
| + mNativeImeAdapterAndroid, text, text.toString(), newCursorPosition);
|
| }
|
|
|
| - mLastComposeText = textStr;
|
| + nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, WebInputEventType.KeyUp,
|
| + timestampMs, COMPOSITION_KEY_CODE, 0, 0);
|
| return true;
|
| }
|
|
|
| @VisibleForTesting
|
| protected void finishComposingText() {
|
| - mLastComposeText = null;
|
| if (mNativeImeAdapterAndroid == 0) return;
|
| nativeFinishComposingText(mNativeImeAdapterAndroid);
|
| }
|
|
|
| - boolean translateAndSendNativeEvents(KeyEvent event) {
|
| + boolean sendKeyEvent(KeyEvent event) {
|
| if (mNativeImeAdapterAndroid == 0) return false;
|
|
|
| int action = event.getAction();
|
| @@ -517,15 +396,6 @@ public class ImeAdapter {
|
| event.getScanCode(), /*isSystemKey=*/false, event.getUnicodeChar());
|
| }
|
|
|
| - boolean sendSyntheticKeyEvent(int eventType, long timestampMs, int keyCode, int modifiers,
|
| - int unicodeChar) {
|
| - if (mNativeImeAdapterAndroid == 0) return false;
|
| -
|
| - nativeSendSyntheticKeyEvent(
|
| - mNativeImeAdapterAndroid, eventType, timestampMs, keyCode, modifiers, unicodeChar);
|
| - return true;
|
| - }
|
| -
|
| /**
|
| * Send a request to the native counterpart to delete a given range of characters.
|
| * @param beforeLength Number of characters to extend the selection by before the existing
|
| @@ -537,7 +407,11 @@ public class ImeAdapter {
|
| boolean deleteSurroundingText(int beforeLength, int afterLength) {
|
| mViewEmbedder.onImeEvent();
|
| if (mNativeImeAdapterAndroid == 0) return false;
|
| + nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, WebInputEventType.RawKeyDown,
|
| + SystemClock.uptimeMillis(), COMPOSITION_KEY_CODE, 0, 0);
|
| nativeDeleteSurroundingText(mNativeImeAdapterAndroid, beforeLength, afterLength);
|
| + nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid,
|
| + WebInputEventType.KeyUp, SystemClock.uptimeMillis(), COMPOSITION_KEY_CODE, 0, 0);
|
| return true;
|
| }
|
|
|
| @@ -562,7 +436,6 @@ public class ImeAdapter {
|
| boolean setComposingRegion(CharSequence text, int start, int end) {
|
| if (mNativeImeAdapterAndroid == 0) return false;
|
| nativeSetComposingRegion(mNativeImeAdapterAndroid, start, end);
|
| - mLastComposeText = text != null ? text.toString() : null;
|
| return true;
|
| }
|
|
|
| @@ -596,7 +469,6 @@ public class ImeAdapter {
|
| private void cancelComposition() {
|
| Log.d(TAG, "cancelComposition");
|
| if (mInputConnection != null) mInputConnection.restartInput();
|
| - mLastComposeText = null;
|
| }
|
|
|
| @CalledByNative
|
|
|