OLD | NEW |
---|---|
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.content.browser.input; | 5 package org.chromium.content.browser.input; |
6 | 6 |
7 import android.os.Handler; | 7 import android.os.Handler; |
8 import android.os.ResultReceiver; | 8 import android.os.ResultReceiver; |
9 import android.os.SystemClock; | 9 import android.os.SystemClock; |
10 import android.text.Editable; | 10 import android.text.Editable; |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
109 static int sTextInputTypeUrl; | 109 static int sTextInputTypeUrl; |
110 static int sTextInputTypeEmail; | 110 static int sTextInputTypeEmail; |
111 static int sTextInputTypeTel; | 111 static int sTextInputTypeTel; |
112 static int sTextInputTypeNumber; | 112 static int sTextInputTypeNumber; |
113 static int sTextInputTypeContentEditable; | 113 static int sTextInputTypeContentEditable; |
114 static int sModifierShift; | 114 static int sModifierShift; |
115 static int sModifierAlt; | 115 static int sModifierAlt; |
116 static int sModifierCtrl; | 116 static int sModifierCtrl; |
117 static int sModifierCapsLockOn; | 117 static int sModifierCapsLockOn; |
118 static int sModifierNumLockOn; | 118 static int sModifierNumLockOn; |
119 static KeyCharacterMap sKeyCharacterMap; | |
119 | 120 |
120 private long mNativeImeAdapterAndroid; | 121 private long mNativeImeAdapterAndroid; |
121 private InputMethodManagerWrapper mInputMethodManagerWrapper; | 122 private InputMethodManagerWrapper mInputMethodManagerWrapper; |
122 private AdapterInputConnection mInputConnection; | 123 private AdapterInputConnection mInputConnection; |
123 private final ImeAdapterDelegate mViewEmbedder; | 124 private final ImeAdapterDelegate mViewEmbedder; |
124 private final Handler mHandler; | 125 private final Handler mHandler; |
125 private DelayedDismissInput mDismissInput = null; | 126 private DelayedDismissInput mDismissInput = null; |
126 private int mTextInputType; | 127 private int mTextInputType; |
128 private String mLastComposeText; | |
129 | |
130 @VisibleForTesting | |
131 int mLastComposeKeyCode; | |
127 | 132 |
128 @VisibleForTesting | 133 @VisibleForTesting |
129 boolean mIsShowWithoutHideOutstanding = false; | 134 boolean mIsShowWithoutHideOutstanding = false; |
130 | 135 |
131 /** | 136 /** |
132 * @param wrapper InputMethodManagerWrapper that should receive all the call directed to | 137 * @param wrapper InputMethodManagerWrapper that should receive all the call directed to |
133 * InputMethodManager. | 138 * InputMethodManager. |
134 * @param embedder The view that is used for callbacks from ImeAdapter. | 139 * @param embedder The view that is used for callbacks from ImeAdapter. |
135 */ | 140 */ |
136 public ImeAdapter(InputMethodManagerWrapper wrapper, ImeAdapterDelegate embe dder) { | 141 public ImeAdapter(InputMethodManagerWrapper wrapper, ImeAdapterDelegate embe dder) { |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
310 } | 315 } |
311 | 316 |
312 private int shouldSendKeyEventWithKeyCode(String text) { | 317 private int shouldSendKeyEventWithKeyCode(String text) { |
313 if (text.length() != 1) return COMPOSITION_KEY_CODE; | 318 if (text.length() != 1) return COMPOSITION_KEY_CODE; |
314 | 319 |
315 if (text.equals("\n")) return KeyEvent.KEYCODE_ENTER; | 320 if (text.equals("\n")) return KeyEvent.KEYCODE_ENTER; |
316 else if (text.equals("\t")) return KeyEvent.KEYCODE_TAB; | 321 else if (text.equals("\t")) return KeyEvent.KEYCODE_TAB; |
317 else return COMPOSITION_KEY_CODE; | 322 else return COMPOSITION_KEY_CODE; |
318 } | 323 } |
319 | 324 |
325 private static int androidKeyCodeForCharacter(char chr) { | |
326 if (sKeyCharacterMap == null) { | |
327 sKeyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYB OARD); | |
328 } | |
329 char[] chars = new char[1]; | |
jdduke (slow)
2014/07/08 19:26:23
This will create garbage every time we fetch the k
| |
330 chars[0] = chr; | |
331 KeyEvent[] events = sKeyCharacterMap.getEvents(chars); | |
332 return events[0].getKeyCode(); | |
333 } | |
334 | |
335 @VisibleForTesting | |
336 public static int getTypedKeycodeGuess(String oldtext, String newtext) { | |
337 // Starting typing a new composition should add only a single character. Any composition | |
338 // beginning with text longer than that must come from something other t han typing so | |
339 // return 0. | |
340 if (oldtext == null) { | |
341 if (newtext.length() == 1) { | |
342 return androidKeyCodeForCharacter(newtext.charAt(0)); | |
343 } else { | |
344 return 0; | |
345 } | |
346 } | |
347 | |
348 // The content has grown in length: assume the last character is the key that caused it. | |
349 if (newtext.length() > oldtext.length() && newtext.startsWith(oldtext)) | |
350 return androidKeyCodeForCharacter(newtext.charAt(newtext.length() - 1)); | |
351 | |
352 // The content has shrunk in length: assume that backspace was pressed. | |
353 if (oldtext.length() > newtext.length() && oldtext.startsWith(newtext)) | |
354 return KeyEvent.KEYCODE_DEL; | |
355 | |
356 // The content is unchanged or has undergone a complex change (i.e. not a simple tail | |
357 // modification) so return an unknown key-code. | |
358 return 0; | |
359 } | |
360 | |
320 void sendKeyEventWithKeyCode(int keyCode, int flags) { | 361 void sendKeyEventWithKeyCode(int keyCode, int flags) { |
321 long eventTime = SystemClock.uptimeMillis(); | 362 long eventTime = SystemClock.uptimeMillis(); |
322 translateAndSendNativeEvents(new KeyEvent(eventTime, eventTime, | 363 translateAndSendNativeEvents(new KeyEvent(eventTime, eventTime, |
323 KeyEvent.ACTION_DOWN, keyCode, 0, 0, | 364 KeyEvent.ACTION_DOWN, keyCode, 0, 0, |
324 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, | 365 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, |
325 flags)); | 366 flags)); |
326 translateAndSendNativeEvents(new KeyEvent(SystemClock.uptimeMillis(), ev entTime, | 367 translateAndSendNativeEvents(new KeyEvent(SystemClock.uptimeMillis(), ev entTime, |
327 KeyEvent.ACTION_UP, keyCode, 0, 0, | 368 KeyEvent.ACTION_UP, keyCode, 0, 0, |
328 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, | 369 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, |
329 flags)); | 370 flags)); |
330 } | 371 } |
331 | 372 |
332 // Calls from Java to C++ | 373 // Calls from Java to C++ |
333 | 374 |
334 boolean checkCompositionQueueAndCallNative(CharSequence text, int newCursorP osition, | 375 boolean checkCompositionQueueAndCallNative(CharSequence text, int newCursorP osition, |
335 boolean isCommit) { | 376 boolean isCommit) { |
336 if (mNativeImeAdapterAndroid == 0) return false; | 377 if (mNativeImeAdapterAndroid == 0) return false; |
337 String textStr = text.toString(); | 378 String textStr = text.toString(); |
338 | 379 |
339 // Committing an empty string finishes the current composition. | 380 // Committing an empty string finishes the current composition. |
340 boolean isFinish = textStr.isEmpty(); | 381 boolean isFinish = textStr.isEmpty(); |
341 mViewEmbedder.onImeEvent(isFinish); | 382 mViewEmbedder.onImeEvent(isFinish); |
342 int keyCode = shouldSendKeyEventWithKeyCode(textStr); | 383 int keyCode = shouldSendKeyEventWithKeyCode(textStr); |
343 long timeStampMs = SystemClock.uptimeMillis(); | 384 long timeStampMs = SystemClock.uptimeMillis(); |
344 | 385 |
345 if (keyCode != COMPOSITION_KEY_CODE) { | 386 if (keyCode != COMPOSITION_KEY_CODE) { |
346 sendKeyEventWithKeyCode(keyCode, | 387 sendKeyEventWithKeyCode(keyCode, |
347 KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE) ; | 388 KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE) ; |
348 } else { | 389 } else { |
349 nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeRawK eyDown, | 390 keyCode = getTypedKeycodeGuess(mLastComposeText, textStr); |
350 timeStampMs, keyCode, 0); | 391 mLastComposeText = textStr; |
392 mLastComposeKeyCode = keyCode; | |
393 | |
394 if (keyCode != 0) | |
395 nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventType RawKeyDown, | |
396 timeStampMs, keyCode, 0); | |
351 if (isCommit) { | 397 if (isCommit) { |
352 nativeCommitText(mNativeImeAdapterAndroid, textStr); | 398 nativeCommitText(mNativeImeAdapterAndroid, textStr); |
399 mLastComposeText = null; | |
353 } else { | 400 } else { |
354 nativeSetComposingText(mNativeImeAdapterAndroid, text, textStr, newCursorPosition); | 401 nativeSetComposingText(mNativeImeAdapterAndroid, text, textStr, newCursorPosition); |
355 } | 402 } |
356 nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeKeyU p, | 403 if (keyCode != 0) |
357 timeStampMs, keyCode, 0); | 404 nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventType KeyUp, |
405 timeStampMs, keyCode, 0); | |
358 } | 406 } |
359 | 407 |
360 return true; | 408 return true; |
361 } | 409 } |
362 | 410 |
363 void finishComposingText() { | 411 void finishComposingText() { |
364 if (mNativeImeAdapterAndroid == 0) return; | 412 if (mNativeImeAdapterAndroid == 0) return; |
413 mLastComposeText = null; | |
365 nativeFinishComposingText(mNativeImeAdapterAndroid); | 414 nativeFinishComposingText(mNativeImeAdapterAndroid); |
366 } | 415 } |
367 | 416 |
368 boolean translateAndSendNativeEvents(KeyEvent event) { | 417 boolean translateAndSendNativeEvents(KeyEvent event) { |
369 if (mNativeImeAdapterAndroid == 0) return false; | 418 if (mNativeImeAdapterAndroid == 0) return false; |
370 | 419 |
371 int action = event.getAction(); | 420 int action = event.getAction(); |
372 if (action != KeyEvent.ACTION_DOWN && | 421 if (action != KeyEvent.ACTION_DOWN && |
373 action != KeyEvent.ACTION_UP) { | 422 action != KeyEvent.ACTION_UP) { |
374 // action == KeyEvent.ACTION_MULTIPLE | 423 // action == KeyEvent.ACTION_MULTIPLE |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
546 } else if (span instanceof UnderlineSpan) { | 595 } else if (span instanceof UnderlineSpan) { |
547 nativeAppendUnderlineSpan(underlines, spannableString.getSpanSta rt(span), | 596 nativeAppendUnderlineSpan(underlines, spannableString.getSpanSta rt(span), |
548 spannableString.getSpanEnd(span)); | 597 spannableString.getSpanEnd(span)); |
549 } | 598 } |
550 } | 599 } |
551 } | 600 } |
552 | 601 |
553 @CalledByNative | 602 @CalledByNative |
554 private void cancelComposition() { | 603 private void cancelComposition() { |
555 if (mInputConnection != null) mInputConnection.restartInput(); | 604 if (mInputConnection != null) mInputConnection.restartInput(); |
605 mLastComposeText = null; | |
556 } | 606 } |
557 | 607 |
558 @CalledByNative | 608 @CalledByNative |
559 void detach() { | 609 void detach() { |
560 if (mDismissInput != null) mHandler.removeCallbacks(mDismissInput); | 610 if (mDismissInput != null) mHandler.removeCallbacks(mDismissInput); |
561 mNativeImeAdapterAndroid = 0; | 611 mNativeImeAdapterAndroid = 0; |
562 mTextInputType = 0; | 612 mTextInputType = 0; |
563 } | 613 } |
564 | 614 |
565 private native boolean nativeSendSyntheticKeyEvent(long nativeImeAdapterAndr oid, | 615 private native boolean nativeSendSyntheticKeyEvent(long nativeImeAdapterAndr oid, |
(...skipping 25 matching lines...) Expand all Loading... | |
591 private native void nativeDeleteSurroundingText(long nativeImeAdapterAndroid , | 641 private native void nativeDeleteSurroundingText(long nativeImeAdapterAndroid , |
592 int before, int after); | 642 int before, int after); |
593 | 643 |
594 private native void nativeUnselect(long nativeImeAdapterAndroid); | 644 private native void nativeUnselect(long nativeImeAdapterAndroid); |
595 private native void nativeSelectAll(long nativeImeAdapterAndroid); | 645 private native void nativeSelectAll(long nativeImeAdapterAndroid); |
596 private native void nativeCut(long nativeImeAdapterAndroid); | 646 private native void nativeCut(long nativeImeAdapterAndroid); |
597 private native void nativeCopy(long nativeImeAdapterAndroid); | 647 private native void nativeCopy(long nativeImeAdapterAndroid); |
598 private native void nativePaste(long nativeImeAdapterAndroid); | 648 private native void nativePaste(long nativeImeAdapterAndroid); |
599 private native void nativeResetImeAdapter(long nativeImeAdapterAndroid); | 649 private native void nativeResetImeAdapter(long nativeImeAdapterAndroid); |
600 } | 650 } |
OLD | NEW |