Index: content/public/android/java/src/org/chromium/content/browser/ImeAdapter.java |
=================================================================== |
--- content/public/android/java/src/org/chromium/content/browser/ImeAdapter.java (revision 178087) |
+++ content/public/android/java/src/org/chromium/content/browser/ImeAdapter.java (working copy) |
@@ -10,6 +10,7 @@ |
import android.text.Editable; |
import android.text.InputType; |
import android.text.Selection; |
+import android.view.KeyCharacterMap; |
import android.view.KeyEvent; |
import android.view.View; |
import android.view.inputmethod.BaseInputConnection; |
@@ -21,29 +22,22 @@ |
import org.chromium.base.CalledByNative; |
import org.chromium.base.JNINamespace; |
-// We have to adapt and plumb android IME service and chrome text input API. |
-// ImeAdapter provides an interface in both ways native <-> java: |
-// 1. InputConnectionAdapter notifies native code of text composition state and |
-// dispatch key events from java -> WebKit. |
-// 2. Native ImeAdapter notifies java side to clear composition text. |
-// |
-// The basic flow is: |
-// 1. Intercept dispatchKeyEventPreIme() to record the current key event, but do |
-// nothing else. |
-// 2. When InputConnectionAdapter gets called with composition or result text: |
-// a) If a key event has been recorded in dispatchKeyEventPreIme() and we |
-// receive a result text with single character, then we probably need to |
-// send the result text as a Char event rather than a ConfirmComposition |
-// event. So we need to dispatch the recorded key event followed by a |
-// synthetic Char event. |
-// b) If we receive a composition text or a result text with more than one |
-// characters, then no matter if we recorded a key event or not in |
-// dispatchKeyEventPreIme(), we just need to dispatch a synthetic key |
-// event with special keycode 229, and then dispatch the composition or |
-// result text. |
-// 3. Intercept dispatchKeyEvent() method for key events not handled by IME, we |
-// need to dispatch them to webkit and check webkit's reply. Then inject a |
-// new key event for further processing if webkit didn't handle it. |
+/** |
+ We have to adapt and plumb android IME service and chrome text input API. |
+ ImeAdapter provides an interface in both ways native <-> java: |
+ 1. InputConnectionAdapter notifies native code of text composition state and |
+ dispatch key events from java -> WebKit. |
+ 2. Native ImeAdapter notifies java side to clear composition text. |
+ |
+ The basic flow is: |
+ 1. When InputConnectionAdapter gets called with composition or result text: |
+ If we receive a composition text or a result text, then we just need to |
+ dispatch a synthetic key event with special keycode 229, and then dispatch |
+ the composition or result text. |
+ 2. Intercept dispatchKeyEvent() method for key events not handled by IME, we |
+ need to dispatch them to webkit and check webkit's reply. Then inject a |
+ new key event for further processing if webkit didn't handle it. |
+*/ |
@JNINamespace("content") |
class ImeAdapter { |
interface ViewEmbedder { |
@@ -117,7 +111,6 @@ |
private int mNativeImeAdapterAndroid; |
private int mTextInputType; |
- private int mPreImeEventCount; |
private Context mContext; |
private SelectionHandleController mSelectionHandleController; |
@@ -152,7 +145,6 @@ |
ImeAdapter(Context context, SelectionHandleController selectionHandleController, |
InsertionHandleController insertionHandleController, ViewEmbedder embedder) { |
- mPreImeEventCount = 0; |
mContext = context; |
mSelectionHandleController = selectionHandleController; |
mInsertionHandleController = insertionHandleController; |
@@ -302,14 +294,7 @@ |
return InputDialogContainer.isDialogInputType(mTextInputType); |
} |
- void dispatchKeyEventPreIme(KeyEvent event) { |
- // We only register that a key was pressed, but we don't actually intercept |
- // it. |
- ++mPreImeEventCount; |
- } |
- |
boolean dispatchKeyEvent(KeyEvent event) { |
- mPreImeEventCount = 0; |
return translateAndSendNativeEvents(event); |
} |
@@ -341,28 +326,47 @@ |
mInsertionHandleController.hideAndDisallowAutomaticShowing(); |
} |
mViewEmbedder.onImeEvent(isFinish); |
- boolean hasSingleChar = mPreImeEventCount == 1 && text.length() == 1; |
- int keyCode = hasSingleChar ? text.codePointAt(0) : COMPOSITION_KEY_CODE; |
- int keyChar = hasSingleChar ? text.codePointAt(0) : 0; |
+ int keyCode = shouldSendKeyEventWithKeyCode(text); |
long timeStampMs = System.currentTimeMillis(); |
- nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeRawKeyDown, |
- timeStampMs, keyCode, keyChar); |
- if (hasSingleChar) { |
- nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeChar, |
- timeStampMs, text.codePointAt(0), text.codePointAt(0)); |
+ |
+ if (keyCode != COMPOSITION_KEY_CODE) { |
+ sendKeyEventWithKeyCode(keyCode, |
+ KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE); |
} else { |
+ nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeRawKeyDown, |
+ timeStampMs, keyCode, 0); |
if (isCommit) { |
nativeCommitText(mNativeImeAdapterAndroid, text); |
} else { |
nativeSetComposingText(mNativeImeAdapterAndroid, text, newCursorPosition); |
} |
+ nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeKeyUp, |
+ timeStampMs, keyCode, 0); |
} |
- nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeKeyUp, |
- timeStampMs, keyCode, keyChar); |
- mPreImeEventCount = 0; |
+ |
return true; |
} |
+ 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; |
+ } |
+ |
+ private void sendKeyEventWithKeyCode(int keyCode, int flags) { |
+ long eventTime = System.currentTimeMillis(); |
+ translateAndSendNativeEvents(new KeyEvent(eventTime, eventTime, |
+ KeyEvent.ACTION_DOWN, keyCode, 0, 0, |
+ KeyCharacterMap.VIRTUAL_KEYBOARD, 0, |
+ flags)); |
+ translateAndSendNativeEvents(new KeyEvent(System.currentTimeMillis(), eventTime, |
+ KeyEvent.ACTION_UP, keyCode, 0, 0, |
+ KeyCharacterMap.VIRTUAL_KEYBOARD, 0, |
+ flags)); |
+ } |
+ |
private boolean translateAndSendNativeEvents(KeyEvent event) { |
if (mNativeImeAdapterAndroid == 0) { |
return false; |
@@ -609,8 +613,10 @@ |
mImeAdapter.dismissInput(true); |
break; |
} |
- |
- return super.performEditorAction(actionCode); |
+ mImeAdapter.sendKeyEventWithKeyCode(KeyEvent.KEYCODE_ENTER, |
+ KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE |
+ | KeyEvent.FLAG_EDITOR_ACTION); |
+ return true; |
} |
@Override |
@@ -681,7 +687,8 @@ |
} |
} |
} |
- return super.sendKeyEvent(event); |
+ mImeAdapter.translateAndSendNativeEvents(event); |
+ return true; |
} |
@Override |