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 73735e0cdd4183676469dc4f4eb327f4af1d42d0..470a0dae53340ec06af5910bf620485c122fcad6 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 |
@@ -116,6 +116,7 @@ public class ImeAdapter { |
static int sModifierCtrl; |
static int sModifierCapsLockOn; |
static int sModifierNumLockOn; |
+ static KeyCharacterMap sKeyCharacterMap; |
private long mNativeImeAdapterAndroid; |
private InputMethodManagerWrapper mInputMethodManagerWrapper; |
@@ -124,6 +125,10 @@ public class ImeAdapter { |
private final Handler mHandler; |
private DelayedDismissInput mDismissInput = null; |
private int mTextInputType; |
+ private String mLastComposeText; |
+ |
+ @VisibleForTesting |
+ int mLastSyntheticKeyCode; |
@VisibleForTesting |
boolean mIsShowWithoutHideOutstanding = false; |
@@ -317,6 +322,42 @@ public class ImeAdapter { |
else return COMPOSITION_KEY_CODE; |
} |
+ private static int androidKeyCodeForCharacter(char chr) { |
+ if (sKeyCharacterMap == null) { |
+ sKeyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); |
+ } |
+ char[] chars = new char[1]; |
+ chars[0] = chr; |
+ KeyEvent[] events = sKeyCharacterMap.getEvents(chars); |
+ return events[0].getKeyCode(); |
+ } |
+ |
+ @VisibleForTesting |
+ public static int getTypedKeycodeGuess(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 androidKeyCodeForCharacter(newtext.charAt(0)); |
+ } else { |
+ return 0; |
+ } |
+ } |
+ |
+ // 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 androidKeyCodeForCharacter(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 KeyEvent.KEYCODE_DEL; |
+ |
+ // The content is unchanged or has undergone a complex change (i.e. not a simple tail |
+ // modification) so return an unknown key-code. |
+ return 0; |
+ } |
+ |
void sendKeyEventWithKeyCode(int keyCode, int flags) { |
long eventTime = SystemClock.uptimeMillis(); |
translateAndSendNativeEvents(new KeyEvent(eventTime, eventTime, |
@@ -346,15 +387,22 @@ public class ImeAdapter { |
sendKeyEventWithKeyCode(keyCode, |
KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE); |
} else { |
- nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeRawKeyDown, |
- timeStampMs, keyCode, 0); |
+ keyCode = getTypedKeycodeGuess(mLastComposeText, textStr); |
+ mLastComposeText = textStr; |
+ mLastSyntheticKeyCode = keyCode; |
+ |
+ if (keyCode != 0) |
+ nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeRawKeyDown, |
+ timeStampMs, keyCode, 0); |
if (isCommit) { |
nativeCommitText(mNativeImeAdapterAndroid, textStr); |
+ mLastComposeText = null; |
} else { |
nativeSetComposingText(mNativeImeAdapterAndroid, text, textStr, newCursorPosition); |
} |
- nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeKeyUp, |
- timeStampMs, keyCode, 0); |
+ if (keyCode != 0) |
+ nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeKeyUp, |
+ timeStampMs, keyCode, 0); |
} |
return true; |
@@ -362,7 +410,18 @@ public class ImeAdapter { |
void finishComposingText() { |
if (mNativeImeAdapterAndroid == 0) return; |
+ /*int keyCode = mLastComposeText != null && mLastComposeText.length() == 1 ? |
+ KeyEvent.KEYCODE_DEL : 0; |
+ long timeStampMs = SystemClock.uptimeMillis(); |
+ mLastComposeText = null; |
+ |
+ if (keyCode != 0) |
+ nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeRawKeyDown, |
+ timeStampMs, keyCode, 0);*/ |
nativeFinishComposingText(mNativeImeAdapterAndroid); |
+ /*if (keyCode != 0) |
+ nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeKeyUp, |
+ timeStampMs, keyCode, 0);*/ |
} |
boolean translateAndSendNativeEvents(KeyEvent event) { |
@@ -408,15 +467,21 @@ public class ImeAdapter { |
boolean deleteSurroundingText(int beforeLength, int afterLength) { |
mViewEmbedder.onImeEvent(false); |
if (mNativeImeAdapterAndroid == 0) return false; |
- // Can't send the deletion key code yet because it will delete an extra char at the end. |
- // Also the deleteSurroundingText message is not always ordered properly with key event |
- // messages yet. |
- // TODO(guohui): fix the ordering and send the deletion key code for single-char deletion. |
- sendSyntheticKeyEvent( |
- sEventTypeRawKeyDown, SystemClock.uptimeMillis(), KeyEvent.KEYCODE_UNKNOWN, 0); |
+ int keyCode = beforeLength > 0 && afterLength == 0 ? |
+ KeyEvent.KEYCODE_DEL : 0; |
+ long timeStampMs = SystemClock.uptimeMillis(); |
+ mLastSyntheticKeyCode = keyCode; |
+ |
+ // TODO(guohui): The ordering of the following three events is not maintained with the |
+ // "delete" message typically arriving before the other two (which do arrive in order). |
+ // It is possibly due to the processing of Key messages to begin/end other operations. |
+ if (keyCode != 0) |
+ nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeRawKeyDown, |
guohui
2014/07/11 15:20:09
please see review comments in https://codereview.c
guohui
2014/07/11 19:00:37
just tried your patch locally, it suffered the sam
|
+ timeStampMs, keyCode, 0); |
nativeDeleteSurroundingText(mNativeImeAdapterAndroid, beforeLength, afterLength); |
- sendSyntheticKeyEvent( |
- sEventTypeKeyUp, SystemClock.uptimeMillis(), KeyEvent.KEYCODE_UNKNOWN, 0); |
+ if (keyCode != 0) |
+ nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeKeyUp, |
+ timeStampMs, keyCode, 0); |
return true; |
} |
@@ -433,14 +498,15 @@ public class ImeAdapter { |
} |
/** |
- * Send a request to the native counterpart to set compositing region to given indices. |
+ * Send a request to the native counterpart to set composing region to given indices. |
* @param start The start of the composition. |
* @param end The end of the composition. |
* @return Whether the native counterpart of ImeAdapter received the call. |
*/ |
- boolean setComposingRegion(int start, int end) { |
+ 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; |
} |
@@ -554,6 +620,7 @@ public class ImeAdapter { |
@CalledByNative |
private void cancelComposition() { |
if (mInputConnection != null) mInputConnection.restartInput(); |
+ mLastComposeText = null; |
} |
@CalledByNative |