Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(247)

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java

Issue 373523002: Send correct key-codes when doing composition events instead of always 0. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: simplified guessing heuristic and fixed test; replaced key-code function with call to Android code Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698