summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandre Elias <aelias@chromium.org>2015-03-04 13:49:30 -0800
committerAlexandre Elias <aelias@chromium.org>2015-03-04 21:50:39 +0000
commit373a6eea7fb583fe839ed9e7c427bec99107edf8 (patch)
tree3f269380cde032f0ee8a793d2ab3098c8b7ccdfd
parenta1f79207c7a6aab957ecb3a11789f8afdfd06877 (diff)
downloadchromium_src-373a6eea7fb583fe839ed9e7c427bec99107edf8.zip
chromium_src-373a6eea7fb583fe839ed9e7c427bec99107edf8.tar.gz
chromium_src-373a6eea7fb583fe839ed9e7c427bec99107edf8.tar.bz2
Revert "Revert "Fix problem with accents caused by race condition.""
This reverts commit 694ea4e297e4faf085c61e097122da8bc5ae94fa. This revert turned out to not address the bug it was intended to (addressed with https://codereview.chromium.org/979683002 instead) so return the 41 branch to its previous state here. BUG=453499 Review URL: https://codereview.chromium.org/984453002 Cr-Commit-Position: refs/branch-heads/2272@{#405} Cr-Branched-From: 827a380cfdb31aa54c8d56e63ce2c3fd8c3ba4d4-refs/heads/master@{#310958}
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java97
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java21
-rw-r--r--content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java47
3 files changed, 144 insertions, 21 deletions
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java b/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java
index 1935025..600af68 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java
@@ -10,6 +10,7 @@ import android.text.InputType;
import android.text.Selection;
import android.text.TextUtils;
import android.util.Log;
+import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.BaseInputConnection;
@@ -28,6 +29,7 @@ import org.chromium.ui.base.ime.TextInputType;
public class AdapterInputConnection extends BaseInputConnection {
private static final String TAG = "AdapterInputConnection";
private static final boolean DEBUG = false;
+ private static final int NO_ACCENT = 0;
/**
* Selection value should be -1 if not known. See EditorInfo.java for details.
*/
@@ -40,6 +42,7 @@ public class AdapterInputConnection extends BaseInputConnection {
private boolean mSingleLine;
private int mNumNestedBatchEdits = 0;
+ private int mPendingAccent;
private int mLastUpdateSelectionStart = INVALID_SELECTION;
private int mLastUpdateSelectionEnd = INVALID_SELECTION;
@@ -126,6 +129,16 @@ public class AdapterInputConnection extends BaseInputConnection {
updateSelectionIfRequired();
}
+ public static int maybeAddAccentToCharacter(int accentChar, int unicodeChar) {
+ if (accentChar != NO_ACCENT) {
+ int combinedChar = KeyEvent.getDeadChar(accentChar, unicodeChar);
+ if (combinedChar != 0) {
+ return combinedChar;
+ }
+ }
+ return unicodeChar;
+ }
+
/**
* Updates the AdapterInputConnection's internal representation of the text being edited and
* its selection and composition properties. The resulting Editable is accessible through the
@@ -216,6 +229,8 @@ public class AdapterInputConnection extends BaseInputConnection {
mLastUpdateSelectionEnd = selectionEnd;
mLastUpdateCompositionStart = compositionStart;
mLastUpdateCompositionEnd = compositionEnd;
+ // Change in selection or cursor position invalidates any pending accent.
+ mPendingAccent = NO_ACCENT;
}
/**
@@ -370,6 +385,22 @@ public class AdapterInputConnection extends BaseInputConnection {
if (DEBUG) {
Log.w(TAG, "sendKeyEvent [" + event.getAction() + "] [" + event.getKeyCode() + "]");
}
+
+ // Short-cut modifier keys so they're not affected by accents.
+ if (KeyEvent.isModifierKey(event.getKeyCode())) {
+ return mImeAdapter.translateAndSendNativeEvents(event, NO_ACCENT);
+ }
+
+ // Some keys we just want to pass events straight through. This allows
+ // proper "repeating key" behavior with physical keyboards.
+ int eventKeyCode = event.getKeyCode();
+ if (eventKeyCode == KeyEvent.KEYCODE_DEL || eventKeyCode == KeyEvent.KEYCODE_FORWARD_DEL) {
+ mPendingAccent = 0;
+ return mImeAdapter.translateAndSendNativeEvents(event, NO_ACCENT);
+ }
+
+ int unicodeChar = event.getUnicodeChar();
+
// If this is a key-up, and backspace/del or if the key has a character representation,
// need to update the underlying Editable (i.e. the local representation of the text
// being edited).
@@ -380,26 +411,24 @@ public class AdapterInputConnection extends BaseInputConnection {
} else if (event.getKeyCode() == KeyEvent.KEYCODE_FORWARD_DEL) {
deleteSurroundingText(0, 1);
return true;
- } else {
- int unicodeChar = event.getUnicodeChar();
- if (unicodeChar != 0) {
- int selectionStart = Selection.getSelectionStart(mEditable);
- int selectionEnd = Selection.getSelectionEnd(mEditable);
- if (selectionStart > selectionEnd) {
- int temp = selectionStart;
- selectionStart = selectionEnd;
- selectionEnd = temp;
- }
- mEditable.replace(selectionStart, selectionEnd,
- Character.toString((char) unicodeChar));
+ } else if (unicodeChar != 0) {
+ int selectionStart = Selection.getSelectionStart(mEditable);
+ int selectionEnd = Selection.getSelectionEnd(mEditable);
+ if (selectionStart > selectionEnd) {
+ int temp = selectionStart;
+ selectionStart = selectionEnd;
+ selectionEnd = temp;
}
+ int combinedChar = maybeAddAccentToCharacter(mPendingAccent, unicodeChar);
+ mEditable.replace(selectionStart, selectionEnd,
+ Character.toString((char) combinedChar));
}
} else if (event.getAction() == KeyEvent.ACTION_DOWN) {
// TODO(aurimas): remove this workaround when crbug.com/278584 is fixed.
if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
beginBatchEdit();
finishComposingText();
- mImeAdapter.translateAndSendNativeEvents(event);
+ mImeAdapter.translateAndSendNativeEvents(event, 0);
endBatchEdit();
return true;
} else if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
@@ -408,7 +437,46 @@ public class AdapterInputConnection extends BaseInputConnection {
return true;
}
}
- mImeAdapter.translateAndSendNativeEvents(event);
+
+ // Physical keyboards also have their events come through here though not
+ // by BaseInputConnection. In order to support "accent" key sequences
+ // such as "~n" or "^o" we have to record that one has been pressed
+ // and, if an accentable letter follows, delete the accent glyph and
+ // insert the composed character.
+
+ // Copy class variable to local because class version may get indirectly
+ // cleared by the deleteSurroundingText() call below.
+ int pendingAccent = mPendingAccent;
+ int nextAccent = mPendingAccent;
+
+ if ((unicodeChar & KeyCharacterMap.COMBINING_ACCENT) != 0) {
+ pendingAccent = NO_ACCENT;
+ nextAccent = unicodeChar & KeyCharacterMap.COMBINING_ACCENT_MASK;
+ } else if (pendingAccent != NO_ACCENT) {
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ int combined = KeyEvent.getDeadChar(pendingAccent, unicodeChar);
+ if (combined != 0) {
+ // Previous accent combines with new character to create
+ // a new accented character. First delete the displayed
+ // accent so it appears overwritten by the composition.
+ super.deleteSurroundingText(1, 0);
+ mImeAdapter.deleteSurroundingText(1, 0);
+ } else {
+ // Previous accent doesn't combine with this character
+ // so assume both are completely independent.
+ pendingAccent = NO_ACCENT;
+ nextAccent = NO_ACCENT;
+ }
+ }
+
+ if (event.getAction() == KeyEvent.ACTION_UP) {
+ // Forget accent after release of key being accented.
+ nextAccent = NO_ACCENT;
+ }
+ }
+
+ mImeAdapter.translateAndSendNativeEvents(event, pendingAccent);
+ mPendingAccent = nextAccent;
return true;
}
@@ -450,6 +518,7 @@ public class AdapterInputConnection extends BaseInputConnection {
if (DEBUG) Log.w(TAG, "restartInput");
getInputMethodManagerWrapper().restartInput(mInternalView);
mNumNestedBatchEdits = 0;
+ mPendingAccent = NO_ACCENT;
}
/**
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 d7dba0e..f8890a6 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
@@ -322,7 +322,12 @@ public class ImeAdapter {
}
public boolean dispatchKeyEvent(KeyEvent event) {
- return translateAndSendNativeEvents(event);
+ // Physical keyboards have their events come through here instead of
+ // AdapterInputConnection.
+ if (mInputConnection != null) {
+ return mInputConnection.sendKeyEvent(event);
+ }
+ return translateAndSendNativeEvents(event, 0);
}
private int shouldSendKeyEventWithKeyCode(String text) {
@@ -391,11 +396,11 @@ public class ImeAdapter {
translateAndSendNativeEvents(new KeyEvent(eventTime, eventTime,
KeyEvent.ACTION_DOWN, keyCode, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
- flags));
+ flags), 0);
translateAndSendNativeEvents(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
KeyEvent.ACTION_UP, keyCode, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
- flags));
+ flags), 0);
}
// Calls from Java to C++
@@ -430,9 +435,9 @@ public class ImeAdapter {
// composition below.
if (keyCode > 0 && isCommit && mLastComposeText == null && textStr.length() == 1) {
mLastSyntheticKeyCode = keyCode;
- return translateAndSendNativeEvents(keyEvent)
+ return translateAndSendNativeEvents(keyEvent, 0)
&& translateAndSendNativeEvents(
- KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_UP));
+ KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_UP), 0);
}
// FIXME: Use WebTextInputFlags.AutocompleteOff. We need this hack to enable merge into
@@ -494,7 +499,7 @@ public class ImeAdapter {
nativeFinishComposingText(mNativeImeAdapterAndroid);
}
- boolean translateAndSendNativeEvents(KeyEvent event) {
+ boolean translateAndSendNativeEvents(KeyEvent event, int accentChar) {
if (mNativeImeAdapterAndroid == 0) return false;
int action = event.getAction();
@@ -512,9 +517,11 @@ public class ImeAdapter {
return false;
}
mViewEmbedder.onImeEvent();
+ int unicodeChar = AdapterInputConnection.maybeAddAccentToCharacter(
+ accentChar, event.getUnicodeChar());
return nativeSendKeyEvent(mNativeImeAdapterAndroid, event, event.getAction(),
getModifiers(event.getMetaState()), event.getEventTime(), event.getKeyCode(),
- /*isSystemKey=*/false, event.getUnicodeChar());
+ /*isSystemKey=*/false, unicodeChar);
}
boolean sendSyntheticKeyEvent(int eventType, long timestampMs, int keyCode, int modifiers,
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
index c5c3e04..50828fd 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
@@ -600,6 +600,44 @@ public class ImeTest extends ContentShellTestBase {
@SmallTest
@Feature({"TextInput", "Main"})
+ public void testAccentKeyCodesFromPhysicalKeyboard() throws Throwable {
+ DOMUtils.focusNode(mWebContents, "textarea");
+ assertWaitForKeyboardStatus(true);
+
+ // The calls below are a reflection of what a physical keyboard sends when the noted
+ // key is pressed on the device. Exercise care when altering to make sure that the test
+ // reflects reality.
+ mConnection = (TestAdapterInputConnection) getAdapterInputConnection();
+ waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 0, "", 0, 0, -1, -1);
+
+ // H
+ dispatchKeyEvent(mConnection, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_H));
+ dispatchKeyEvent(mConnection, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_H));
+ assertEquals("h", mConnection.getTextBeforeCursor(9, 0));
+
+ // I
+ dispatchKeyEvent(mConnection, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I));
+ dispatchKeyEvent(mConnection, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I));
+ assertEquals("hi", mConnection.getTextBeforeCursor(9, 0));
+
+ // ALT-I (circomflex accent key on virtual keyboard)
+ dispatchKeyEvent(
+ mConnection, new KeyEvent(
+ 0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I, 0, KeyEvent.META_ALT_ON));
+ dispatchKeyEvent(
+ mConnection, new KeyEvent(
+ 0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I, 0, KeyEvent.META_ALT_ON));
+ assertEquals("hiˆ", mConnection.getTextBeforeCursor(9, 0));
+
+ // O (accented key)
+ dispatchKeyEvent(mConnection, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_O));
+ assertEquals("hi", mConnection.getTextBeforeCursor(9, 0));
+ dispatchKeyEvent(mConnection, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_O));
+ assertEquals("hiô", mConnection.getTextBeforeCursor(9, 0));
+ }
+
+ @SmallTest
+ @Feature({"TextInput", "Main"})
public void testSetComposingRegionOutOfBounds() throws Throwable {
DOMUtils.focusNode(mWebContents, "textarea");
assertWaitForKeyboardStatus(true);
@@ -918,6 +956,15 @@ public class ImeTest extends ContentShellTestBase {
});
}
+ private void dispatchKeyEvent(final AdapterInputConnection connection, final KeyEvent event) {
+ ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+ @Override
+ public void run() {
+ mImeAdapter.dispatchKeyEvent(event);
+ }
+ });
+ }
+
private static class TestAdapterInputConnectionFactory extends
ImeAdapter.AdapterInputConnectionFactory {
@Override