From 7b87561c4f4d2ecd014d243b90e6973be964ff6d Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Thu, 28 Feb 2013 13:17:21 -0500 Subject: [PATCH] Bug 844290 - Refactor GeckoInputConnection key handling code; r=cpeterson --- mobile/android/base/GeckoInputConnection.java | 131 +++++++++--------- 1 file changed, 66 insertions(+), 65 deletions(-) diff --git a/mobile/android/base/GeckoInputConnection.java b/mobile/android/base/GeckoInputConnection.java index 6505f14b233..ebbd6fe3788 100644 --- a/mobile/android/base/GeckoInputConnection.java +++ b/mobile/android/base/GeckoInputConnection.java @@ -661,15 +661,7 @@ class GeckoInputConnection return false; } - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - return processKeyDown(keyCode, event); - } - - private boolean processKeyDown(int keyCode, KeyEvent event) { - if (keyCode > KeyEvent.getMaxKeyCode()) - return false; - + private boolean shouldProcessKey(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_MENU: case KeyEvent.KEYCODE_BACK: @@ -677,87 +669,96 @@ class GeckoInputConnection case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_SEARCH: return false; + } + return true; + } + + private boolean shouldSkipKeyListener(int keyCode, KeyEvent event) { + if (mIMEState == IME_STATE_DISABLED || + mIMEState == IME_STATE_PLUGIN) { + return true; + } + // Preserve enter and tab keys for the browser + if (keyCode == KeyEvent.KEYCODE_ENTER || + keyCode == KeyEvent.KEYCODE_TAB) { + return true; + } + // BaseKeyListener returns false even if it handled these keys for us, + // so we skip the key listener entirely and handle these ourselves + if (keyCode == KeyEvent.KEYCODE_DEL || + keyCode == KeyEvent.KEYCODE_FORWARD_DEL) { + return true; + } + return false; + } + + private KeyEvent translateKey(int keyCode, KeyEvent event) { + switch (keyCode) { case KeyEvent.KEYCODE_ENTER: if ((event.getFlags() & KeyEvent.FLAG_EDITOR_ACTION) != 0 && - mIMEActionHint.equalsIgnoreCase("next")) - event = new KeyEvent(event.getAction(), KeyEvent.KEYCODE_TAB); - break; - default: + mIMEActionHint.equalsIgnoreCase("next")) { + return new KeyEvent(event.getAction(), KeyEvent.KEYCODE_TAB); + } break; } + return event; + } + + private boolean processKey(int keyCode, KeyEvent event, boolean down) { + if (keyCode > KeyEvent.getMaxKeyCode() || + !shouldProcessKey(keyCode, event)) { + return false; + } + event = translateKey(keyCode, event); + keyCode = event.getKeyCode(); View view = getView(); - KeyListener keyListener = TextKeyListener.getInstance(); - - // KeyListener returns true if it handled the event for us. KeyListener is only - // safe to use on the UI thread; therefore we need to pass a proxy Editable to it - if (mIMEState == IME_STATE_DISABLED || - mIMEState == IME_STATE_PLUGIN || - keyCode == KeyEvent.KEYCODE_ENTER || - keyCode == KeyEvent.KEYCODE_DEL || - keyCode == KeyEvent.KEYCODE_TAB || - (event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 || - view == null) { + if (view == null) { mEditableClient.sendEvent(GeckoEvent.createKeyEvent(event)); return true; } + // KeyListener returns true if it handled the event for us. KeyListener is only + // safe to use on the UI thread; therefore we need to pass a proxy Editable to it + KeyListener keyListener = TextKeyListener.getInstance(); Handler uiHandler = view.getRootView().getHandler(); Handler icHandler = mEditableClient.getInputConnectionHandler(); Editable uiEditable = mThreadUtils.getEditableForUiThread(uiHandler, icHandler); - if (!keyListener.onKeyDown(view, uiEditable, keyCode, event)) { + boolean skip = shouldSkipKeyListener(keyCode, event); + + if (skip || + (down && !keyListener.onKeyDown(view, uiEditable, keyCode, event)) || + (!down && !keyListener.onKeyUp(view, uiEditable, keyCode, event))) { mEditableClient.sendEvent(GeckoEvent.createKeyEvent(event)); + if (skip && down) { + // Usually, the down key listener call above adjusts meta states for us. + // However, if we skip that call above, we have to manually adjust meta + // states so the meta states remain consistent + TextKeyListener.adjustMetaAfterKeypress(uiEditable); + } } return true; } + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + return processKey(keyCode, event, true); + } + @Override public boolean onKeyUp(int keyCode, KeyEvent event) { - return processKeyUp(keyCode, event); - } - - private boolean processKeyUp(int keyCode, KeyEvent event) { - if (keyCode > KeyEvent.getMaxKeyCode()) - return false; - - switch (keyCode) { - case KeyEvent.KEYCODE_BACK: - case KeyEvent.KEYCODE_SEARCH: - case KeyEvent.KEYCODE_MENU: - return false; - default: - break; - } - - View view = getView(); - KeyListener keyListener = TextKeyListener.getInstance(); - - // KeyListener returns true if it handled the event for us. KeyListener is only - // safe to use on the UI thread; therefore we need to pass a proxy Editable to it - if (mIMEState == IME_STATE_DISABLED || - mIMEState == IME_STATE_PLUGIN || - keyCode == KeyEvent.KEYCODE_ENTER || - keyCode == KeyEvent.KEYCODE_DEL || - (event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 || - view == null) { - mEditableClient.sendEvent(GeckoEvent.createKeyEvent(event)); - return true; - } - - Handler uiHandler = view.getRootView().getHandler(); - Handler icHandler = mEditableClient.getInputConnectionHandler(); - Editable uiEditable = mThreadUtils.getEditableForUiThread(uiHandler, icHandler); - if (!keyListener.onKeyUp(view, uiEditable, keyCode, event)) { - mEditableClient.sendEvent(GeckoEvent.createKeyEvent(event)); - } - return true; + return processKey(keyCode, event, false); } @Override public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_UNKNOWN) { + // KEYCODE_UNKNOWN means the characters are in KeyEvent.getCharacters() + return commitText(event.getCharacters(), 1); + } while ((repeatCount--) != 0) { - if (!processKeyDown(keyCode, event) || - !processKeyUp(keyCode, event)) { + if (!processKey(keyCode, event, true) || + !processKey(keyCode, event, false)) { return false; } }