OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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.SystemClock; | 7 import android.os.SystemClock; |
8 import android.text.Editable; | 8 import android.text.Editable; |
9 import android.text.InputType; | 9 import android.text.InputType; |
10 import android.text.Selection; | 10 import android.text.Selection; |
11 import android.text.TextUtils; | 11 import android.text.TextUtils; |
12 import android.util.Log; | 12 import android.util.Log; |
13 import android.view.KeyCharacterMap; | |
13 import android.view.KeyEvent; | 14 import android.view.KeyEvent; |
14 import android.view.View; | 15 import android.view.View; |
15 import android.view.inputmethod.BaseInputConnection; | 16 import android.view.inputmethod.BaseInputConnection; |
16 import android.view.inputmethod.EditorInfo; | 17 import android.view.inputmethod.EditorInfo; |
17 import android.view.inputmethod.ExtractedText; | 18 import android.view.inputmethod.ExtractedText; |
18 import android.view.inputmethod.ExtractedTextRequest; | 19 import android.view.inputmethod.ExtractedTextRequest; |
19 | 20 |
20 import org.chromium.base.VisibleForTesting; | 21 import org.chromium.base.VisibleForTesting; |
21 import org.chromium.blink_public.web.WebInputEventType; | 22 import org.chromium.blink_public.web.WebInputEventType; |
22 import org.chromium.blink_public.web.WebTextInputFlags; | 23 import org.chromium.blink_public.web.WebTextInputFlags; |
(...skipping 12 matching lines...) Expand all Loading... | |
35 */ | 36 */ |
36 public static final int INVALID_SELECTION = -1; | 37 public static final int INVALID_SELECTION = -1; |
37 public static final int INVALID_COMPOSITION = -1; | 38 public static final int INVALID_COMPOSITION = -1; |
38 | 39 |
39 private final View mInternalView; | 40 private final View mInternalView; |
40 private final ImeAdapter mImeAdapter; | 41 private final ImeAdapter mImeAdapter; |
41 private final Editable mEditable; | 42 private final Editable mEditable; |
42 | 43 |
43 private boolean mSingleLine; | 44 private boolean mSingleLine; |
44 private int mNumNestedBatchEdits = 0; | 45 private int mNumNestedBatchEdits = 0; |
46 private int mPendingAccent; | |
45 | 47 |
46 private int mLastUpdateSelectionStart = INVALID_SELECTION; | 48 private int mLastUpdateSelectionStart = INVALID_SELECTION; |
47 private int mLastUpdateSelectionEnd = INVALID_SELECTION; | 49 private int mLastUpdateSelectionEnd = INVALID_SELECTION; |
48 private int mLastUpdateCompositionStart = INVALID_COMPOSITION; | 50 private int mLastUpdateCompositionStart = INVALID_COMPOSITION; |
49 private int mLastUpdateCompositionEnd = INVALID_COMPOSITION; | 51 private int mLastUpdateCompositionEnd = INVALID_COMPOSITION; |
50 | 52 |
51 @VisibleForTesting | 53 @VisibleForTesting |
52 AdapterInputConnection(View view, ImeAdapter imeAdapter, Editable editable, | 54 AdapterInputConnection(View view, ImeAdapter imeAdapter, Editable editable, |
53 EditorInfo outAttrs) { | 55 EditorInfo outAttrs) { |
54 super(view, true); | 56 super(view, true); |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
235 mLastUpdateCompositionEnd = compositionEnd; | 237 mLastUpdateCompositionEnd = compositionEnd; |
236 } | 238 } |
237 | 239 |
238 /** | 240 /** |
239 * @see BaseInputConnection#setComposingText(java.lang.CharSequence, int) | 241 * @see BaseInputConnection#setComposingText(java.lang.CharSequence, int) |
240 */ | 242 */ |
241 @Override | 243 @Override |
242 public boolean setComposingText(CharSequence text, int newCursorPosition) { | 244 public boolean setComposingText(CharSequence text, int newCursorPosition) { |
243 if (DEBUG) Log.w(TAG, "setComposingText [" + text + "] [" + newCursorPos ition + "]"); | 245 if (DEBUG) Log.w(TAG, "setComposingText [" + text + "] [" + newCursorPos ition + "]"); |
244 if (maybePerformEmptyCompositionWorkaround(text)) return true; | 246 if (maybePerformEmptyCompositionWorkaround(text)) return true; |
247 mPendingAccent = 0; | |
245 super.setComposingText(text, newCursorPosition); | 248 super.setComposingText(text, newCursorPosition); |
246 updateSelectionIfRequired(); | 249 updateSelectionIfRequired(); |
247 return mImeAdapter.checkCompositionQueueAndCallNative(text, newCursorPos ition, false); | 250 return mImeAdapter.checkCompositionQueueAndCallNative(text, newCursorPos ition, false); |
248 } | 251 } |
249 | 252 |
250 /** | 253 /** |
251 * @see BaseInputConnection#commitText(java.lang.CharSequence, int) | 254 * @see BaseInputConnection#commitText(java.lang.CharSequence, int) |
252 */ | 255 */ |
253 @Override | 256 @Override |
254 public boolean commitText(CharSequence text, int newCursorPosition) { | 257 public boolean commitText(CharSequence text, int newCursorPosition) { |
255 if (DEBUG) Log.w(TAG, "commitText [" + text + "] [" + newCursorPosition + "]"); | 258 if (DEBUG) Log.w(TAG, "commitText [" + text + "] [" + newCursorPosition + "]"); |
256 if (maybePerformEmptyCompositionWorkaround(text)) return true; | 259 if (maybePerformEmptyCompositionWorkaround(text)) return true; |
260 mPendingAccent = 0; | |
257 super.commitText(text, newCursorPosition); | 261 super.commitText(text, newCursorPosition); |
258 updateSelectionIfRequired(); | 262 updateSelectionIfRequired(); |
259 return mImeAdapter.checkCompositionQueueAndCallNative(text, newCursorPos ition, | 263 return mImeAdapter.checkCompositionQueueAndCallNative(text, newCursorPos ition, |
260 text.length() > 0); | 264 text.length() > 0); |
261 } | 265 } |
262 | 266 |
263 /** | 267 /** |
264 * @see BaseInputConnection#performEditorAction(int) | 268 * @see BaseInputConnection#performEditorAction(int) |
265 */ | 269 */ |
266 @Override | 270 @Override |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
344 @Override | 348 @Override |
345 public boolean deleteSurroundingText(int beforeLength, int afterLength) { | 349 public boolean deleteSurroundingText(int beforeLength, int afterLength) { |
346 return deleteSurroundingTextImpl(beforeLength, afterLength, false); | 350 return deleteSurroundingTextImpl(beforeLength, afterLength, false); |
347 } | 351 } |
348 | 352 |
349 private boolean deleteSurroundingTextImpl( | 353 private boolean deleteSurroundingTextImpl( |
350 int beforeLength, int afterLength, boolean fromPhysicalKey) { | 354 int beforeLength, int afterLength, boolean fromPhysicalKey) { |
351 if (DEBUG) { | 355 if (DEBUG) { |
352 Log.w(TAG, "deleteSurroundingText [" + beforeLength + " " + afterLen gth + "]"); | 356 Log.w(TAG, "deleteSurroundingText [" + beforeLength + " " + afterLen gth + "]"); |
353 } | 357 } |
358 | |
359 if (mPendingAccent != 0) { | |
360 mPendingAccent = 0; | |
361 finishComposingText(); | |
362 } | |
363 | |
354 int originalBeforeLength = beforeLength; | 364 int originalBeforeLength = beforeLength; |
355 int originalAfterLength = afterLength; | 365 int originalAfterLength = afterLength; |
356 int availableBefore = Selection.getSelectionStart(mEditable); | 366 int availableBefore = Selection.getSelectionStart(mEditable); |
357 int availableAfter = mEditable.length() - Selection.getSelectionEnd(mEdi table); | 367 int availableAfter = mEditable.length() - Selection.getSelectionEnd(mEdi table); |
358 beforeLength = Math.min(beforeLength, availableBefore); | 368 beforeLength = Math.min(beforeLength, availableBefore); |
359 afterLength = Math.min(afterLength, availableAfter); | 369 afterLength = Math.min(afterLength, availableAfter); |
360 super.deleteSurroundingText(beforeLength, afterLength); | 370 super.deleteSurroundingText(beforeLength, afterLength); |
361 updateSelectionIfRequired(); | 371 updateSelectionIfRequired(); |
362 | 372 |
363 // If this was called due to a physical key, no need to generate a key e vent here as | 373 // If this was called due to a physical key, no need to generate a key e vent here as |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
396 @Override | 406 @Override |
397 public boolean sendKeyEvent(KeyEvent event) { | 407 public boolean sendKeyEvent(KeyEvent event) { |
398 if (DEBUG) { | 408 if (DEBUG) { |
399 Log.w(TAG, "sendKeyEvent [" + event.getAction() + "] [" + event.getK eyCode() + "]"); | 409 Log.w(TAG, "sendKeyEvent [" + event.getAction() + "] [" + event.getK eyCode() + "]"); |
400 } | 410 } |
401 | 411 |
402 int action = event.getAction(); | 412 int action = event.getAction(); |
403 int keycode = event.getKeyCode(); | 413 int keycode = event.getKeyCode(); |
404 int unicodeChar = event.getUnicodeChar(); | 414 int unicodeChar = event.getUnicodeChar(); |
405 | 415 |
416 // If we're not focused in a textbox or if this isn't a KeyDown event, n o need to update | |
417 // composition state; just pass the key event through and return. | |
418 if (mImeAdapter.getTextInputType() == TextInputType.NONE | |
419 || action != KeyEvent.ACTION_DOWN) { | |
aurimas (slooooooooow)
2015/06/03 00:44:20
Would this result in us sending KeyUp events witho
aelias_OOO_until_Jul13
2015/06/03 01:15:01
Yes, it does and I spent some time looking into if
bcwhite
2015/06/03 15:28:58
I've been trying this patch with a physical keyboa
aelias_OOO_until_Jul13
2015/06/03 21:10:29
Good catch, thanks. It looks like this is a side
| |
420 mImeAdapter.translateAndSendNativeEvents(event); | |
421 return true; | |
422 } | |
423 | |
406 // If this is backspace/del or if the key has a character representation , | 424 // If this is backspace/del or if the key has a character representation , |
407 // need to update the underlying Editable (i.e. the local representation of the text | 425 // need to update the underlying Editable (i.e. the local representation of the text |
408 // being edited). Some IMEs like Jellybean stock IME and Samsung IME mi x in delete | 426 // being edited). Some IMEs like Jellybean stock IME and Samsung IME mi x in delete |
409 // KeyPress events instead of calling deleteSurroundingText. | 427 // KeyPress events instead of calling deleteSurroundingText. |
410 if (action == KeyEvent.ACTION_DOWN && keycode == KeyEvent.KEYCODE_DEL) { | 428 if (keycode == KeyEvent.KEYCODE_DEL) { |
411 deleteSurroundingTextImpl(1, 0, true); | 429 deleteSurroundingTextImpl(1, 0, true); |
412 } else if (action == KeyEvent.ACTION_DOWN && keycode == KeyEvent.KEYCODE _FORWARD_DEL) { | 430 } else if (keycode == KeyEvent.KEYCODE_FORWARD_DEL) { |
aurimas (slooooooooow)
2015/06/03 00:44:20
What would happen if we have DEL, FORWARD_DEL or E
aelias_OOO_until_Jul13
2015/06/03 01:15:01
I did try out those scenarios earlier today and ha
| |
413 deleteSurroundingTextImpl(0, 1, true); | 431 deleteSurroundingTextImpl(0, 1, true); |
414 } else if (action == KeyEvent.ACTION_DOWN && keycode == KeyEvent.KEYCODE _ENTER) { | 432 } else if (keycode == KeyEvent.KEYCODE_ENTER) { |
415 // Finish text composition when pressing enter, as that may submit a form field. | 433 // Finish text composition when pressing enter, as that may submit a form field. |
416 // TODO(aurimas): remove this workaround when crbug.com/278584 is fi xed. | 434 // TODO(aurimas): remove this workaround when crbug.com/278584 is fi xed. |
417 beginBatchEdit(); | 435 beginBatchEdit(); |
418 finishComposingText(); | 436 finishComposingText(); |
419 mImeAdapter.translateAndSendNativeEvents(event); | 437 mImeAdapter.translateAndSendNativeEvents(event); |
420 endBatchEdit(); | 438 endBatchEdit(); |
421 return true; | 439 return true; |
422 } else if (action == KeyEvent.ACTION_UP && unicodeChar != 0) { | 440 } else if ((unicodeChar & KeyCharacterMap.COMBINING_ACCENT) != 0) { |
441 // Store a pending accent character and make it the current composit ion. | |
442 int pendingAccent = unicodeChar & KeyCharacterMap.COMBINING_ACCENT_M ASK; | |
443 StringBuilder builder = new StringBuilder(); | |
444 builder.appendCodePoint(pendingAccent); | |
445 setComposingText(builder.toString(), 1); | |
446 mPendingAccent = pendingAccent; | |
447 return true; | |
448 } | |
449 | |
450 if (unicodeChar != 0) { | |
451 if (mPendingAccent != 0) { | |
452 int combined = KeyEvent.getDeadChar(mPendingAccent, unicodeChar) ; | |
453 if (combined != 0) { | |
454 StringBuilder builder = new StringBuilder(); | |
455 builder.appendCodePoint(combined); | |
456 commitText(builder.toString(), 1); | |
457 return true; | |
458 } | |
459 // Noncombinable character; commit the accent character and fall through to sending | |
460 // the key event for the character afterwards. | |
461 finishComposingText(); | |
462 } | |
463 | |
464 // Update the mEditable state to reflect what Blink will do in respo nse to the KeyDown | |
465 // for a unicode-mapped key event. | |
423 int selectionStart = Selection.getSelectionStart(mEditable); | 466 int selectionStart = Selection.getSelectionStart(mEditable); |
424 int selectionEnd = Selection.getSelectionEnd(mEditable); | 467 int selectionEnd = Selection.getSelectionEnd(mEditable); |
425 if (selectionStart > selectionEnd) { | 468 if (selectionStart > selectionEnd) { |
426 int temp = selectionStart; | 469 int temp = selectionStart; |
427 selectionStart = selectionEnd; | 470 selectionStart = selectionEnd; |
428 selectionEnd = temp; | 471 selectionEnd = temp; |
429 } | 472 } |
430 mEditable.replace(selectionStart, selectionEnd, | 473 mEditable.replace(selectionStart, selectionEnd, |
431 Character.toString((char) unicodeChar)); | 474 Character.toString((char) unicodeChar)); |
432 } | 475 } |
476 | |
433 mImeAdapter.translateAndSendNativeEvents(event); | 477 mImeAdapter.translateAndSendNativeEvents(event); |
434 return true; | 478 return true; |
435 } | 479 } |
436 | 480 |
437 /** | 481 /** |
438 * @see BaseInputConnection#finishComposingText() | 482 * @see BaseInputConnection#finishComposingText() |
439 */ | 483 */ |
440 @Override | 484 @Override |
441 public boolean finishComposingText() { | 485 public boolean finishComposingText() { |
442 if (DEBUG) Log.w(TAG, "finishComposingText"); | 486 if (DEBUG) Log.w(TAG, "finishComposingText"); |
443 if (getComposingSpanStart(mEditable) == getComposingSpanEnd(mEditable)) { | 487 if (getComposingSpanStart(mEditable) == getComposingSpanEnd(mEditable)) { |
444 return true; | 488 return true; |
445 } | 489 } |
446 | 490 |
491 mPendingAccent = 0; | |
447 super.finishComposingText(); | 492 super.finishComposingText(); |
448 updateSelectionIfRequired(); | 493 updateSelectionIfRequired(); |
449 mImeAdapter.finishComposingText(); | 494 mImeAdapter.finishComposingText(); |
450 | 495 |
451 return true; | 496 return true; |
452 } | 497 } |
453 | 498 |
454 /** | 499 /** |
455 * @see BaseInputConnection#setSelection(int, int) | 500 * @see BaseInputConnection#setSelection(int, int) |
456 */ | 501 */ |
457 @Override | 502 @Override |
458 public boolean setSelection(int start, int end) { | 503 public boolean setSelection(int start, int end) { |
459 if (DEBUG) Log.w(TAG, "setSelection [" + start + " " + end + "]"); | 504 if (DEBUG) Log.w(TAG, "setSelection [" + start + " " + end + "]"); |
460 int textLength = mEditable.length(); | 505 int textLength = mEditable.length(); |
461 if (start < 0 || end < 0 || start > textLength || end > textLength) retu rn true; | 506 if (start < 0 || end < 0 || start > textLength || end > textLength) retu rn true; |
462 super.setSelection(start, end); | 507 super.setSelection(start, end); |
463 updateSelectionIfRequired(); | 508 updateSelectionIfRequired(); |
464 return mImeAdapter.setEditableSelectionOffsets(start, end); | 509 return mImeAdapter.setEditableSelectionOffsets(start, end); |
465 } | 510 } |
466 | 511 |
467 /** | 512 /** |
468 * Informs the InputMethodManager and InputMethodSession (i.e. the IME) that the text | 513 * Informs the InputMethodManager and InputMethodSession (i.e. the IME) that the text |
469 * state is no longer what the IME has and that it needs to be updated. | 514 * state is no longer what the IME has and that it needs to be updated. |
470 */ | 515 */ |
471 void restartInput() { | 516 void restartInput() { |
472 if (DEBUG) Log.w(TAG, "restartInput"); | 517 if (DEBUG) Log.w(TAG, "restartInput"); |
473 getInputMethodManagerWrapper().restartInput(mInternalView); | 518 getInputMethodManagerWrapper().restartInput(mInternalView); |
474 mNumNestedBatchEdits = 0; | 519 mNumNestedBatchEdits = 0; |
520 mPendingAccent = 0; | |
475 } | 521 } |
476 | 522 |
477 /** | 523 /** |
478 * @see BaseInputConnection#setComposingRegion(int, int) | 524 * @see BaseInputConnection#setComposingRegion(int, int) |
479 */ | 525 */ |
480 @Override | 526 @Override |
481 public boolean setComposingRegion(int start, int end) { | 527 public boolean setComposingRegion(int start, int end) { |
482 if (DEBUG) Log.w(TAG, "setComposingRegion [" + start + " " + end + "]"); | 528 if (DEBUG) Log.w(TAG, "setComposingRegion [" + start + " " + end + "]"); |
483 int textLength = mEditable.length(); | 529 int textLength = mEditable.length(); |
484 int a = Math.min(start, end); | 530 int a = Math.min(start, end); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
558 @VisibleForTesting | 604 @VisibleForTesting |
559 ImeState getImeStateForTesting() { | 605 ImeState getImeStateForTesting() { |
560 String text = mEditable.toString(); | 606 String text = mEditable.toString(); |
561 int selectionStart = Selection.getSelectionStart(mEditable); | 607 int selectionStart = Selection.getSelectionStart(mEditable); |
562 int selectionEnd = Selection.getSelectionEnd(mEditable); | 608 int selectionEnd = Selection.getSelectionEnd(mEditable); |
563 int compositionStart = getComposingSpanStart(mEditable); | 609 int compositionStart = getComposingSpanStart(mEditable); |
564 int compositionEnd = getComposingSpanEnd(mEditable); | 610 int compositionEnd = getComposingSpanEnd(mEditable); |
565 return new ImeState(text, selectionStart, selectionEnd, compositionStart , compositionEnd); | 611 return new ImeState(text, selectionStart, selectionEnd, compositionStart , compositionEnd); |
566 } | 612 } |
567 } | 613 } |
OLD | NEW |