/** Keyboard shortcuts (tab management, paste) */ private boolean keyboardShortcuts(int keyCode, KeyEvent event) { if (event.getAction() != KeyEvent.ACTION_DOWN) { return false; } if (!mUseKeyboardShortcuts) { return false; } boolean isCtrlPressed = (event.getMetaState() & KeycodeConstants.META_CTRL_ON) != 0; boolean isShiftPressed = (event.getMetaState() & KeycodeConstants.META_SHIFT_ON) != 0; if (keyCode == KeycodeConstants.KEYCODE_TAB && isCtrlPressed) { if (isShiftPressed) { mViewFlipper.showPrevious(); } else { mViewFlipper.showNext(); } return true; } else if (keyCode == KeycodeConstants.KEYCODE_N && isCtrlPressed && isShiftPressed) { doCreateNewWindow(); return true; } else if (keyCode == KeycodeConstants.KEYCODE_V && isCtrlPressed && isShiftPressed) { doPaste(); return true; } else { return false; } }
/* * We want to return the menu item associated with the key, but if there is no * ambiguity (i.e. there is only one menu item corresponding to the key) we want * to return it even if it's not an exact match; this allow the user to * _not_ use the ALT key for example, making the use of shortcuts slightly more * user-friendly. An example is on the G1, '!' and '1' are on the same key, and * in Gmail, Menu+1 will trigger Menu+! (the actual shortcut). * * On the other hand, if two (or more) shortcuts corresponds to the same key, * we have to only return the exact match. */ MenuItemImpl findItemWithShortcutForKey(int keyCode, KeyEvent event) { // Get all items that can be associated directly or indirectly with the keyCode ArrayList<MenuItemImpl> items = mTempShortcutItemList; items.clear(); findItemsWithShortcutForKey(items, keyCode, event); if (items.isEmpty()) { return null; } final int metaState = event.getMetaState(); final KeyCharacterMap.KeyData possibleChars = new KeyCharacterMap.KeyData(); // Get the chars associated with the keyCode (i.e using any chording combo) event.getKeyData(possibleChars); // If we have only one element, we can safely returns it final int size = items.size(); if (size == 1) { return items.get(0); } final boolean qwerty = isQwertyMode(); // If we found more than one item associated with the key, // we have to return the exact match for (int i = 0; i < size; i++) { final MenuItemImpl item = items.get(i); final char shortcutChar = qwerty ? item.getAlphabeticShortcut() : item.getNumericShortcut(); if ((shortcutChar == possibleChars.meta[0] && (metaState & KeyEvent.META_ALT_ON) == 0) || (shortcutChar == possibleChars.meta[2] && (metaState & KeyEvent.META_ALT_ON) != 0) || (qwerty && shortcutChar == '\b' && keyCode == KeyEvent.KEYCODE_DEL)) { return item; } } return null; }
private boolean processKeyUp(int keyCode, KeyEvent event, boolean isPreIme) { if (DEBUG) { Log.d( LOGTAG, "IME: processKeyUp(keyCode=" + keyCode + ", event=" + event + ", " + isPreIme + ")"); } switch (keyCode) { case KeyEvent.KEYCODE_BACK: case KeyEvent.KEYCODE_SEARCH: case KeyEvent.KEYCODE_MENU: return false; default: break; } if (isPreIme && mIMEState != IME_STATE_DISABLED && (event.getMetaState() & KeyEvent.META_ALT_ON) != 0) // Let active IME process pre-IME key events return false; View view = GeckoApp.mAppContext.getLayerController().getView(); KeyListener keyListener = TextKeyListener.getInstance(); if (mIMEState == IME_STATE_DISABLED || keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_DEL || (event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 || !keyListener.onKeyUp(view, mEditable, keyCode, event)) { GeckoAppShell.sendEventToGecko(GeckoEvent.createKeyEvent(event)); } return true; }
private void onKeyEvent( KeyEvent event, int action, int savedMetaState, boolean isSynthesizedImeKey) { // Use a separate action argument so we can override the key's original action, // e.g. change ACTION_MULTIPLE to ACTION_DOWN. That way we don't have to allocate // a new key event just to change its action field. // // Normally we expect event.getMetaState() to reflect the current meta-state; however, // some software-generated key events may not have event.getMetaState() set, e.g. key // events from Swype. Therefore, it's necessary to combine the key's meta-states // with the meta-states that we keep separately in KeyListener final int metaState = event.getMetaState() | savedMetaState; final int unmodifiedMetaState = metaState & ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK | KeyEvent.META_META_MASK); final int unicodeChar = event.getUnicodeChar(metaState); final int domPrintableKeyValue = unicodeChar >= ' ' ? unicodeChar : unmodifiedMetaState != metaState ? event.getUnicodeChar(unmodifiedMetaState) : 0; onKeyEvent( action, event.getKeyCode(), event.getScanCode(), metaState, event.getEventTime(), unicodeChar, // e.g. for Ctrl+A, Android returns 0 for unicodeChar, // but Gecko expects 'a', so we return that in baseUnicodeChar. event.getUnicodeChar(0), domPrintableKeyValue, event.getRepeatCount(), event.getFlags(), isSynthesizedImeKey); }
@Override public boolean dispatchKeyEvent(KeyEvent event) { if (m_started && event.getAction() == KeyEvent.ACTION_MULTIPLE && event.getCharacters() != null && event.getCharacters().length() == 1 && event.getKeyCode() == 0) { Log.i( QtApplication.QtTAG, "dispatchKeyEvent at MULTIPLE with one character: " + event.getCharacters()); QtApplication.keyDown(0, event.getCharacters().charAt(0), event.getMetaState()); QtApplication.keyUp(0, event.getCharacters().charAt(0), event.getMetaState()); } return super.dispatchKeyEvent(event); }
@Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (!m_started) return false; m_metaState = MetaKeyKeyListener.handleKeyUp(m_metaState, keyCode, event); QtApplication.keyUp(keyCode, event.getUnicodeChar(), event.getMetaState()); return true; }
boolean sendKeyEvent(KeyEvent event) { if (mNativeImeAdapterAndroid == 0) return false; int action = event.getAction(); if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_UP) { // action == KeyEvent.ACTION_MULTIPLE // TODO(bulach): confirm the actual behavior. Apparently: // If event.getKeyCode() == KEYCODE_UNKNOWN, we can send a // composition key down (229) followed by a commit text with the // string from event.getUnicodeChars(). // Otherwise, we'd need to send an event with a // WebInputEvent::IsAutoRepeat modifier. We also need to verify when // we receive ACTION_MULTIPLE: we may receive it after an ACTION_DOWN, // and if that's the case, we'll need to review when to send the Char // event. return false; } mViewEmbedder.onImeEvent(); return nativeSendKeyEvent( mNativeImeAdapterAndroid, event, event.getAction(), getModifiers(event.getMetaState()), event.getEventTime(), event.getKeyCode(), event.getScanCode(), /*isSystemKey=*/ false, event.getUnicodeChar()); }
public int translateKey(int inCode, KeyEvent event) { switch (inCode) { case KeyEvent.KEYCODE_DPAD_CENTER: return 13; /* Fake ENTER */ case KeyEvent.KEYCODE_DPAD_LEFT: return 37; case KeyEvent.KEYCODE_DPAD_RIGHT: return 39; case KeyEvent.KEYCODE_DPAD_UP: return 38; case KeyEvent.KEYCODE_DPAD_DOWN: return 40; case KeyEvent.KEYCODE_BACK: return 27; /* Fake Escape */ case KeyEvent.KEYCODE_MENU: return 0x01000012; /* Fake MENU */ case KeyEvent.KEYCODE_DEL: return 8; } int result = event.getUnicodeChar(event.getMetaState()); if (result == android.view.KeyCharacterMap.COMBINING_ACCENT) { // TODO: return 0; } return result; }
/* * This function will return all the menu and sub-menu items that can * be directly (the shortcut directly corresponds) and indirectly * (the ALT-enabled char corresponds to the shortcut) associated * with the keyCode. */ @SuppressWarnings("deprecation") void findItemsWithShortcutForKey(List<MenuItemImpl> items, int keyCode, KeyEvent event) { final boolean qwerty = isQwertyMode(); final int metaState = event.getMetaState(); final KeyCharacterMap.KeyData possibleChars = new KeyCharacterMap.KeyData(); // Get the chars associated with the keyCode (i.e using any chording combo) final boolean isKeyCodeMapped = event.getKeyData(possibleChars); // The delete key is not mapped to '\b' so we treat it specially if (!isKeyCodeMapped && (keyCode != KeyEvent.KEYCODE_DEL)) { return; } // Look for an item whose shortcut is this key. final int N = mItems.size(); for (int i = 0; i < N; i++) { MenuItemImpl item = mItems.get(i); if (item.hasSubMenu()) { ((MenuBuilder) item.getSubMenu()).findItemsWithShortcutForKey(items, keyCode, event); } final char shortcutChar = qwerty ? item.getAlphabeticShortcut() : item.getNumericShortcut(); if (((metaState & (KeyEvent.META_SHIFT_ON | KeyEvent.META_SYM_ON)) == 0) && (shortcutChar != 0) && (shortcutChar == possibleChars.meta[0] || shortcutChar == possibleChars.meta[2] || (qwerty && shortcutChar == '\b' && keyCode == KeyEvent.KEYCODE_DEL)) && item.isEnabled()) { items.add(item); } } }
private boolean processKeyDown(int keyCode, KeyEvent event, boolean isPreIme) { if (DEBUG) { Log.d( LOGTAG, "IME: processKeyDown(keyCode=" + keyCode + ", event=" + event + ", " + isPreIme + ")"); } clampSelection(); switch (keyCode) { case KeyEvent.KEYCODE_MENU: case KeyEvent.KEYCODE_BACK: case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_SEARCH: return false; case KeyEvent.KEYCODE_DEL: // See comments in GeckoInputConnection.onKeyDel if (onKeyDel()) { return true; } break; 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: break; } if (isPreIme && mIMEState != IME_STATE_DISABLED && (event.getMetaState() & KeyEvent.META_ALT_ON) != 0) // Let active IME process pre-IME key events return false; View view = GeckoApp.mAppContext.getLayerController().getView(); KeyListener keyListener = TextKeyListener.getInstance(); // KeyListener returns true if it handled the event for us. if (mIMEState == IME_STATE_DISABLED || keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_TAB || (event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 || !keyListener.onKeyDown(view, mEditable, keyCode, event)) { // Make sure selection in Gecko is up-to-date final Editable content = getEditable(); int a = Selection.getSelectionStart(content); int b = Selection.getSelectionEnd(content); GeckoAppShell.sendEventToGecko( GeckoEvent.createIMEEvent(GeckoEvent.IME_SET_SELECTION, a, b - a)); GeckoAppShell.sendEventToGecko(GeckoEvent.createKeyEvent(event)); } return true; }
public boolean handleKeyCode(int keyCode, KeyEvent event, boolean appMode) throws IOException { String code = null; if (event != null) { int keyMod = 0; // META_CTRL_ON was added only in API 11, so don't use it, // use our own tracking of Ctrl key instead. // (event.getMetaState() & META_CTRL_ON) != 0 if (mHardwareControlKey || mControlKey.isActive()) { keyMod |= KEYMOD_CTRL; } if ((event.getMetaState() & META_ALT_ON) != 0) { keyMod |= KEYMOD_ALT; } if ((event.getMetaState() & META_SHIFT_ON) != 0) { keyMod |= KEYMOD_SHIFT; } // First try to map scancode code = mKeyMap.get(event.getScanCode() | KEYMOD_SCAN | keyMod); if (code == null) { code = mKeyMap.get(keyCode | keyMod); } } if (code == null && keyCode >= 0 && keyCode < mKeyCodes.length) { if (appMode) { code = mAppKeyCodes[keyCode]; } if (code == null) { code = mKeyCodes[keyCode]; } } if (code != null) { if (EmulatorDebug.LOG_CHARACTERS_FLAG) { byte[] bytes = code.getBytes(); Log.d( EmulatorDebug.LOG_TAG, "Out: '" + EmulatorDebug.bytesToString(bytes, 0, bytes.length) + "'"); } mTermSession.write(code); return true; } return false; }
private void initKeyEvent(KeyEvent k) { mAction = k.getAction(); mTime = k.getEventTime(); mMetaState = k.getMetaState(); mFlags = k.getFlags(); mKeyCode = k.getKeyCode(); mUnicodeChar = k.getUnicodeChar(); mRepeatCount = k.getRepeatCount(); mCharacters = k.getCharacters(); mDomKeyLocation = isJoystickButton(mKeyCode) ? DOM_KEY_LOCATION_JOYSTICK : DOM_KEY_LOCATION_MOBILE; }
/** Overrides the superclass's lookup method to prefer the number field from the KeyEvent. */ protected int lookup(KeyEvent event, Spannable content) { int meta = event.getMetaState() | getMetaState(content); int number = event.getNumber(); /* * Prefer number if no meta key is active, or if it produces something * valid and the meta lookup does not. */ if ((meta & (MetaKeyKeyListener.META_ALT_ON | MetaKeyKeyListener.META_SHIFT_ON)) == 0) { if (number != 0) { return number; } } int match = super.lookup(event, content); if (match != 0) { return match; } else { /* * If a meta key is active but the lookup with the meta key * did not produce anything, try some other meta keys, because * the user might have pressed SHIFT when they meant ALT, * or vice versa. */ if (meta != 0) { KeyData kd = new KeyData(); char[] accepted = getAcceptedChars(); if (event.getKeyData(kd)) { for (int i = 1; i < kd.meta.length; i++) { if (ok(accepted, kd.meta[i])) { return kd.meta[i]; } } } } /* * Otherwise, use the number associated with the key, since * whatever they wanted to do with the meta key does not * seem to be valid here. */ return number; } }
@Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (!m_started) return false; m_metaState = MetaKeyKeyListener.handleKeyDown(m_metaState, keyCode, event); int c = event.getUnicodeChar(MetaKeyKeyListener.getMetaState(m_metaState)); int lc = c; m_metaState = MetaKeyKeyListener.adjustMetaAfterKeypress(m_metaState); if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) { c = c & KeyCharacterMap.COMBINING_ACCENT_MASK; int composed = KeyEvent.getDeadChar(m_lastChar, c); c = composed; } m_lastChar = lc; if (keyCode != KeyEvent.KEYCODE_BACK) QtApplication.keyDown(keyCode, c, event.getMetaState()); return true; }
/** * Map Android key codes to MoSync key codes. * * @param keyCode * @param keyEvent * @return */ private final int convertToMoSyncKeyCode(int keyCode, KeyEvent keyEvent) { if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) return MAK_LEFT; if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) return MAK_RIGHT; if (keyCode == KeyEvent.KEYCODE_DPAD_UP) return MAK_UP; if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) return MAK_DOWN; if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) return MAK_FIRE; if (keyCode == KeyEvent.KEYCODE_SOFT_LEFT) return MAK_SOFTLEFT; if (keyCode == KeyEvent.KEYCODE_SOFT_RIGHT) return MAK_SOFTRIGHT; if (keyCode == KeyEvent.KEYCODE_BACK) return MAK_BACK; if (keyCode == KeyEvent.KEYCODE_MENU) return MAK_MENU; if (keyCode == KeyEvent.KEYCODE_SEARCH) return MAK_SEARCH; // Support for native virtual keyboard. if (keyCode == KeyEvent.KEYCODE_DEL) { return MAK_CLEAR; } KeyCharacterMap keyCharacterMap = KeyCharacterMap.load(keyEvent.getDeviceId()); return keyCharacterMap.get(keyCode, keyEvent.getMetaState()); }
boolean translateAndSendNativeEvents(KeyEvent event) { if (mNativeImeAdapterAndroid == 0) return false; int action = event.getAction(); if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_UP) { // action == KeyEvent.ACTION_MULTIPLE // TODO(bulach): confirm the actual behavior. Apparently: // If event.getKeyCode() == KEYCODE_UNKNOWN, we can send a // composition key down (229) followed by a commit text with the // string from event.getUnicodeChars(). // Otherwise, we'd need to send an event with a // WebInputEvent::IsAutoRepeat modifier. We also need to verify when // we receive ACTION_MULTIPLE: we may receive it after an ACTION_DOWN, // and if that's the case, we'll need to review when to send the Char // event. return false; } // Begin add by TCL zhanghangzhi, mail: [email protected] if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER && (event.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) != 0) { android.os.SystemProperties.set( "webviewchromium.tv_enterKeyFlag", String.valueOf(event.getFlags())); android.util.Log.e("ImeAdapter", "[ESTALENT] sys.tv_enterKeyFlag: " + event.getFlags()); } else { android.os.SystemProperties.set("webviewchromium.tv_enterKeyFlag", ""); android.util.Log.e("ImeAdapter", "[ESTALENT] clean sys.tv_enterKeyFlag"); } // End of TCL mViewEmbedder.onImeEvent(false); return nativeSendKeyEvent( mNativeImeAdapterAndroid, event, event.getAction(), getModifiers(event.getMetaState()), event.getEventTime(), event.getKeyCode(), event.isSystem(), event.getUnicodeChar()); }
private void logKeyEvent(int keyCode, KeyEvent event, boolean down) { String s = down ? "KeyDown event:" : "KeyUp event:"; s += " action " + event.getAction() + " keycode " + keyCode + " " + KeyEvent.keyCodeToString(keyCode); s += " unicode " + event.getUnicodeChar() + " " + event.getDisplayLabel(); s += " ScanCode " + event.getScanCode(); s += " MetaState " + event.getMetaState() + " Flags " + event.getFlags() + " modifiers " + event.getModifiers(); s += " source " + printSource(event.getSource()) + " device " + printDevice(event.getDeviceId()); pushText(s); }
/** * Handle onKey() events coming down from a {@link TerminalView} above us. Modify the keys to make * more sense to a host then pass it to the transport. */ public boolean onKey(View v, int keyCode, KeyEvent event) { try { final boolean hardKeyboardHidden = manager.hardKeyboardHidden; // Ignore all key-up events except for the special keys if (event.getAction() == KeyEvent.ACTION_UP) { // There's nothing here for virtual keyboard users. if (!hardKeyboard || (hardKeyboard && hardKeyboardHidden)) return false; // skip keys if we aren't connected yet or have been disconnected if (bridge.isDisconnected() || bridge.transport == null) return false; if (PreferenceConstants.KEYMODE_RIGHT.equals(keymode)) { if (keyCode == KeyEvent.KEYCODE_ALT_RIGHT && (metaState & META_SLASH) != 0) { metaState &= ~(META_SLASH | META_TRANSIENT); bridge.transport.write('/'); return true; } else if (keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT && (metaState & META_TAB) != 0) { metaState &= ~(META_TAB | META_TRANSIENT); bridge.transport.write(0x09); return true; } } else if (PreferenceConstants.KEYMODE_LEFT.equals(keymode)) { if (keyCode == KeyEvent.KEYCODE_ALT_LEFT && (metaState & META_SLASH) != 0) { metaState &= ~(META_SLASH | META_TRANSIENT); bridge.transport.write('/'); return true; } else if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT && (metaState & META_TAB) != 0) { metaState &= ~(META_TAB | META_TRANSIENT); bridge.transport.write(0x09); return true; } } return false; } // check for terminal resizing keys if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { bridge.increaseFontSize(); return true; } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { bridge.decreaseFontSize(); return true; } // skip keys if we aren't connected yet or have been disconnected if (bridge.isDisconnected() || bridge.transport == null) return false; bridge.resetScrollPosition(); if (keyCode == KeyEvent.KEYCODE_UNKNOWN && event.getAction() == KeyEvent.ACTION_MULTIPLE) { byte[] input = event.getCharacters().getBytes(encoding); bridge.transport.write(input); return true; } int curMetaState = event.getMetaState(); final int orgMetaState = curMetaState; if ((metaState & META_SHIFT_MASK) != 0) { curMetaState |= KeyEvent.META_SHIFT_ON; } if ((metaState & META_ALT_MASK) != 0) { curMetaState |= KeyEvent.META_ALT_ON; } int key = event.getUnicodeChar(curMetaState); // no hard keyboard? ALT-k should pass through to below if ((orgMetaState & KeyEvent.META_ALT_ON) != 0 && (!hardKeyboard || hardKeyboardHidden)) { key = 0; } if ((key & KeyCharacterMap.COMBINING_ACCENT) != 0) { mDeadKey = key & KeyCharacterMap.COMBINING_ACCENT_MASK; return true; } if (mDeadKey != 0) { key = KeyCharacterMap.getDeadChar(mDeadKey, keyCode); mDeadKey = 0; } final boolean printing = (key != 0 && keyCode != KeyEvent.KEYCODE_ENTER); // otherwise pass through to existing session // print normal keys if (printing) { metaState &= ~(META_SLASH | META_TAB); // Remove shift and alt modifiers final int lastMetaState = metaState; metaState &= ~(META_SHIFT_ON | META_ALT_ON); if (metaState != lastMetaState) { bridge.redraw(); } if ((metaState & META_CTRL_MASK) != 0) { metaState &= ~META_CTRL_ON; bridge.redraw(); // If there is no hard keyboard or there is a hard keyboard currently hidden, // CTRL-1 through CTRL-9 will send F1 through F9 if ((!hardKeyboard || (hardKeyboard && hardKeyboardHidden)) && sendFunctionKey(keyCode)) return true; key = keyAsControl(key); } // handle pressing f-keys if ((hardKeyboard && !hardKeyboardHidden) && (curMetaState & KeyEvent.META_SHIFT_ON) != 0 && sendFunctionKey(keyCode)) return true; if (key < 0x80) bridge.transport.write(key); else // TODO write encoding routine that doesn't allocate each time bridge.transport.write(new String(Character.toChars(key)).getBytes(encoding)); return true; } // send ctrl and meta-keys as appropriate if (!hardKeyboard || hardKeyboardHidden) { int k = event.getUnicodeChar(0); int k0 = k; boolean sendCtrl = false; boolean sendMeta = false; if (k != 0) { if ((orgMetaState & HC_META_CTRL_ON) != 0) { k = keyAsControl(k); if (k != k0) sendCtrl = true; // send F1-F10 via CTRL-1 through CTRL-0 if (!sendCtrl && sendFunctionKey(keyCode)) return true; } else if ((orgMetaState & KeyEvent.META_ALT_ON) != 0) { sendMeta = true; sendEscape(); } if (sendMeta || sendCtrl) { bridge.transport.write(k); return true; } } } // try handling keymode shortcuts if (hardKeyboard && !hardKeyboardHidden && event.getRepeatCount() == 0) { if (PreferenceConstants.KEYMODE_RIGHT.equals(keymode)) { switch (keyCode) { case KeyEvent.KEYCODE_ALT_RIGHT: metaState |= META_SLASH; return true; case KeyEvent.KEYCODE_SHIFT_RIGHT: metaState |= META_TAB; return true; case KeyEvent.KEYCODE_SHIFT_LEFT: metaPress(META_SHIFT_ON); return true; case KeyEvent.KEYCODE_ALT_LEFT: metaPress(META_ALT_ON); return true; } } else if (PreferenceConstants.KEYMODE_LEFT.equals(keymode)) { switch (keyCode) { case KeyEvent.KEYCODE_ALT_LEFT: metaState |= META_SLASH; return true; case KeyEvent.KEYCODE_SHIFT_LEFT: metaState |= META_TAB; return true; case KeyEvent.KEYCODE_SHIFT_RIGHT: metaPress(META_SHIFT_ON); return true; case KeyEvent.KEYCODE_ALT_RIGHT: metaPress(META_ALT_ON); return true; } } else { switch (keyCode) { case KeyEvent.KEYCODE_ALT_LEFT: case KeyEvent.KEYCODE_ALT_RIGHT: metaPress(META_ALT_ON); return true; case KeyEvent.KEYCODE_SHIFT_LEFT: case KeyEvent.KEYCODE_SHIFT_RIGHT: metaPress(META_SHIFT_ON); return true; } } } // look for special chars switch (keyCode) { case KEYCODE_ESCAPE: sendEscape(); return true; case KeyEvent.KEYCODE_TAB: bridge.transport.write(0x09); return true; case KeyEvent.KEYCODE_SEARCH: // check to see which shortcut the search button triggers String search = manager.prefs.getString(PreferenceConstants.SEARCH, PreferenceConstants.SEARCH_ESC); if (PreferenceConstants.SEARCH_BACKBTN.equals(search)) { // TODO: figure out what to do here! } else if (PreferenceConstants.SEARCH_ESC.equals(search)) { sendEscape(); } return true; case KeyEvent.KEYCODE_CAMERA: // check to see which shortcut the camera button triggers String camera = manager.prefs.getString( PreferenceConstants.CAMERA, PreferenceConstants.CAMERA_CTRLA_SPACE); if (PreferenceConstants.CAMERA_CTRLA_SPACE.equals(camera)) { bridge.transport.write(0x01); bridge.transport.write(' '); } else if (PreferenceConstants.CAMERA_CTRLA.equals(camera)) { bridge.transport.write(0x01); } else if (PreferenceConstants.CAMERA_ESC.equals(camera)) { ((vt320) buffer).keyTyped(vt320.KEY_ESCAPE, ' ', 0); } else if (PreferenceConstants.CAMERA_ESC_A.equals(camera)) { ((vt320) buffer).keyTyped(vt320.KEY_ESCAPE, ' ', 0); bridge.transport.write('a'); } break; case KeyEvent.KEYCODE_DEL: ((vt320) buffer).keyPressed(vt320.KEY_BACK_SPACE, ' ', getStateForBuffer()); metaState &= ~META_TRANSIENT; return true; case KeyEvent.KEYCODE_ENTER: ((vt320) buffer).keyTyped(vt320.KEY_ENTER, ' ', 0); metaState &= ~META_TRANSIENT; return true; case KeyEvent.KEYCODE_DPAD_LEFT: if (selectingForCopy) { selectionArea.decrementColumn(); bridge.redraw(); } else { ((vt320) buffer).keyPressed(vt320.KEY_LEFT, ' ', getStateForBuffer()); metaState &= ~META_TRANSIENT; bridge.tryKeyVibrate(); } return true; case KeyEvent.KEYCODE_DPAD_UP: if (selectingForCopy) { selectionArea.decrementRow(); bridge.redraw(); } else { ((vt320) buffer).keyPressed(vt320.KEY_UP, ' ', getStateForBuffer()); metaState &= ~META_TRANSIENT; bridge.tryKeyVibrate(); } return true; case KeyEvent.KEYCODE_DPAD_DOWN: if (selectingForCopy) { selectionArea.incrementRow(); bridge.redraw(); } else { ((vt320) buffer).keyPressed(vt320.KEY_DOWN, ' ', getStateForBuffer()); metaState &= ~META_TRANSIENT; bridge.tryKeyVibrate(); } return true; case KeyEvent.KEYCODE_DPAD_RIGHT: if (selectingForCopy) { selectionArea.incrementColumn(); bridge.redraw(); } else { ((vt320) buffer).keyPressed(vt320.KEY_RIGHT, ' ', getStateForBuffer()); metaState &= ~META_TRANSIENT; bridge.tryKeyVibrate(); } return true; case KeyEvent.KEYCODE_DPAD_CENTER: if (selectingForCopy) { if (selectionArea.isSelectingOrigin()) selectionArea.finishSelectingOrigin(); else { if (clipboard != null) { // copy selected area to clipboard String copiedText = selectionArea.copyFrom(buffer); clipboard.setText(copiedText); // XXX STOPSHIP // manager.notifyUser(manager.getString( // R.string.console_copy_done, // copiedText.length())); selectingForCopy = false; selectionArea.reset(); } } } else { if ((metaState & META_CTRL_ON) != 0) { sendEscape(); metaState &= ~META_CTRL_ON; } else metaPress(META_CTRL_ON); } bridge.redraw(); return true; case KeyEvent.KEYCODE_PAGE_UP: ((vt320) buffer).keyPressed(vt320.KEY_PAGE_UP, ' ', getStateForBuffer()); metaState &= ~META_TRANSIENT; bridge.tryKeyVibrate(); return true; case KeyEvent.KEYCODE_PAGE_DOWN: ((vt320) buffer).keyPressed(vt320.KEY_PAGE_DOWN, ' ', getStateForBuffer()); metaState &= ~META_TRANSIENT; bridge.tryKeyVibrate(); return true; case KeyEvent.KEYCODE_MOVE_HOME: // ((vt320) buffer).keyPressed(vt320.KEY_HOME, ' ',getStateForBuffer()); ((vt320) buffer).keyTyped(vt320.KEY_ESCAPE, ' ', 0); bridge.transport.write("[1~".getBytes()); metaState &= ~META_TRANSIENT; bridge.tryKeyVibrate(); return true; case KeyEvent.KEYCODE_MOVE_END: // ((vt320) buffer).keyPressed(vt320.KEY_END, ' ',getStateForBuffer()); ((vt320) buffer).keyTyped(vt320.KEY_ESCAPE, ' ', 0); bridge.transport.write("[4~".getBytes()); metaState &= ~META_TRANSIENT; bridge.tryKeyVibrate(); return true; } } catch (IOException e) { Log.e(TAG, "Problem while trying to handle an onKey() event", e); try { bridge.transport.flush(); } catch (IOException ioe) { Log.d(TAG, "Our transport was closed, dispatching disconnect event"); bridge.dispatchDisconnect(false); } } catch (NullPointerException npe) { Log.d(TAG, "Input before connection established ignored."); return true; } return false; }
private static CompactKeyEvent getCompactKeyEvent(android.view.KeyEvent keyEvent) { return new CompactKeyEvent( keyEvent.getScanCode(), getCompactMetaState(keyEvent.getMetaState())); }
@Override public ProtoCommands.KeyEvent getMozcKeyEvent(android.view.KeyEvent keyEvent) { int metaState = keyEvent.getMetaState(); int unicodeChar = keyEvent.getUnicodeChar(); int keyCode = keyEvent.getKeyCode(); ProtoCommands.KeyEvent.Builder builder = ProtoCommands.KeyEvent.newBuilder(); switch (keyCode) { case android.view.KeyEvent.KEYCODE_SPACE: builder.setSpecialKey(SpecialKey.SPACE); break; case android.view.KeyEvent.KEYCODE_DEL: builder.setSpecialKey(SpecialKey.BACKSPACE); break; case android.view.KeyEvent.KEYCODE_TAB: builder.setSpecialKey(SpecialKey.TAB); break; case android.view.KeyEvent.KEYCODE_ENTER: builder.setSpecialKey(SpecialKey.ENTER); break; case android.view.KeyEvent.KEYCODE_HOME: builder.setSpecialKey(SpecialKey.HOME); break; case android.view.KeyEvent.KEYCODE_PAGE_UP: builder.setSpecialKey(SpecialKey.PAGE_UP); break; case android.view.KeyEvent.KEYCODE_PAGE_DOWN: builder.setSpecialKey(SpecialKey.PAGE_DOWN); break; case android.view.KeyEvent.KEYCODE_NUMPAD_DIVIDE: builder.setSpecialKey(SpecialKey.DIVIDE); break; case android.view.KeyEvent.KEYCODE_NUMPAD_MULTIPLY: builder.setSpecialKey(SpecialKey.MULTIPLY); break; case android.view.KeyEvent.KEYCODE_NUMPAD_SUBTRACT: builder.setSpecialKey(SpecialKey.SUBTRACT); break; case android.view.KeyEvent.KEYCODE_NUMPAD_ADD: builder.setSpecialKey(SpecialKey.ADD); break; case android.view.KeyEvent.KEYCODE_NUMPAD_ENTER: builder.setSpecialKey(SpecialKey.SEPARATOR); break; case android.view.KeyEvent.KEYCODE_NUMPAD_DOT: builder.setSpecialKey(SpecialKey.DECIMAL); break; case android.view.KeyEvent.KEYCODE_NUMPAD_0: builder.setSpecialKey(SpecialKey.NUMPAD0); break; case android.view.KeyEvent.KEYCODE_NUMPAD_1: builder.setSpecialKey(SpecialKey.NUMPAD1); break; case android.view.KeyEvent.KEYCODE_NUMPAD_2: builder.setSpecialKey(SpecialKey.NUMPAD2); break; case android.view.KeyEvent.KEYCODE_NUMPAD_3: builder.setSpecialKey(SpecialKey.NUMPAD3); break; case android.view.KeyEvent.KEYCODE_NUMPAD_4: builder.setSpecialKey(SpecialKey.NUMPAD4); break; case android.view.KeyEvent.KEYCODE_NUMPAD_5: builder.setSpecialKey(SpecialKey.NUMPAD5); break; case android.view.KeyEvent.KEYCODE_NUMPAD_6: builder.setSpecialKey(SpecialKey.NUMPAD6); break; case android.view.KeyEvent.KEYCODE_NUMPAD_7: builder.setSpecialKey(SpecialKey.NUMPAD7); break; case android.view.KeyEvent.KEYCODE_NUMPAD_8: builder.setSpecialKey(SpecialKey.NUMPAD8); break; case android.view.KeyEvent.KEYCODE_NUMPAD_9: builder.setSpecialKey(SpecialKey.NUMPAD9); break; default: if (unicodeChar != 0) { builder.setKeyCode(unicodeChar); } break; } if (!isPrintable(unicodeChar)) { // Mozc server accepts modifiers only if non-printable key event is sent. if ((metaState & android.view.KeyEvent.META_SHIFT_MASK) != 0) { builder.addModifierKeys(ModifierKey.SHIFT); } if ((metaState & android.view.KeyEvent.META_ALT_MASK) != 0) { builder.addModifierKeys(ModifierKey.ALT); } if ((metaState & android.view.KeyEvent.META_CTRL_MASK) != 0) { builder.addModifierKeys(ModifierKey.CTRL); } } return builder.build(); }
/** * Handle a keyDown event. * * @param keyCode the keycode of the keyDown event */ public void keyDown(int keyCode, KeyEvent event, boolean appMode, boolean allowToggle) throws IOException { if (LOG_KEYS) { Log.i(TAG, "keyDown(" + keyCode + "," + event + "," + appMode + "," + allowToggle + ")"); } if (handleKeyCode(keyCode, event, appMode)) { return; } int result = -1; boolean chordedCtrl = false; boolean setHighBit = false; switch (keyCode) { case KeyEvent.KEYCODE_ALT_RIGHT: case KeyEvent.KEYCODE_ALT_LEFT: if (allowToggle) { mAltKey.onPress(); updateCursorMode(); } break; case KeyEvent.KEYCODE_SHIFT_LEFT: case KeyEvent.KEYCODE_SHIFT_RIGHT: if (allowToggle) { mCapKey.onPress(); updateCursorMode(); } break; case KEYCODE_CTRL_LEFT: case KEYCODE_CTRL_RIGHT: // Ignore the control key. return; case KEYCODE_CAPS_LOCK: // Ignore the capslock key. return; case KEYCODE_FUNCTION: // Ignore the function key. return; case KeyEvent.KEYCODE_BACK: result = mBackKeyCode; break; default: { int metaState = event.getMetaState(); chordedCtrl = ((META_CTRL_ON & metaState) != 0); boolean effectiveCaps = allowToggle && (mCapKey.isActive()); boolean effectiveAlt = allowToggle && mAltKey.isActive(); int effectiveMetaState = metaState & (~META_CTRL_MASK); if (effectiveCaps) { effectiveMetaState |= KeyEvent.META_SHIFT_ON; } if (!allowToggle && (effectiveMetaState & META_ALT_ON) != 0) { effectiveAlt = true; } if (effectiveAlt) { if (mAltSendsEsc) { mTermSession.write(new byte[] {0x1b}, 0, 1); effectiveMetaState &= ~KeyEvent.META_ALT_MASK; } else if (SUPPORT_8_BIT_META) { setHighBit = true; effectiveMetaState &= ~KeyEvent.META_ALT_MASK; } else { // Legacy behavior: Pass Alt through to allow composing characters. effectiveMetaState |= KeyEvent.META_ALT_ON; } } // Note: The Hacker keyboard IME key labeled Alt actually sends Meta. if ((metaState & KeyEvent.META_META_ON) != 0) { if (mAltSendsEsc) { mTermSession.write(new byte[] {0x1b}, 0, 1); effectiveMetaState &= ~KeyEvent.META_META_MASK; } else { if (SUPPORT_8_BIT_META) { setHighBit = true; effectiveMetaState &= ~KeyEvent.META_META_MASK; } } } result = event.getUnicodeChar(effectiveMetaState); if ((result & KeyCharacterMap.COMBINING_ACCENT) != 0) { if (LOG_COMBINING_ACCENT) { Log.i(TAG, "Got combining accent " + result); } mCombiningAccent = result & KeyCharacterMap.COMBINING_ACCENT_MASK; return; } if (mCombiningAccent != 0) { int unaccentedChar = result; result = KeyCharacterMap.getDeadChar(mCombiningAccent, unaccentedChar); if (LOG_COMBINING_ACCENT) { Log.i( TAG, "getDeadChar(" + mCombiningAccent + ", " + unaccentedChar + ") -> " + result); } mCombiningAccent = 0; } break; } } boolean effectiveControl = chordedCtrl || mHardwareControlKey || (allowToggle && mControlKey.isActive()); boolean effectiveFn = allowToggle && mFnKey.isActive(); result = mapControlChar(effectiveControl, effectiveFn, result); if (result >= KEYCODE_OFFSET) { handleKeyCode(result - KEYCODE_OFFSET, null, appMode); } else if (result >= 0) { if (setHighBit) { result |= 0x80; } mTermSession.write(result); } }
/** * Use this to monitor key events being delivered to the application. We get first crack at them, * and can either resume them or let them continue to the app. */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: // The InputMethodService already takes care of the back // key for us, to dismiss the input method if it is shown. // However, our keyboard could be showing a pop-up window // that back should dismiss, so we first allow it to do that. if (event.getRepeatCount() == 0 && mInputView != null) { if (mInputView.handleBack()) { return true; } } break; case KeyEvent.KEYCODE_DEL: // Special handling of the delete key: if we currently are // composing text for the user, we want to modify that instead // of let the application to the delete itself. if (mComposing.length() > 0) { onKey(Keyboard.KEYCODE_DELETE, null); return true; } break; case KeyEvent.KEYCODE_ENTER: // Let the underlying text editor always handle these. return false; default: // For all other keys, if we want to do transformations on // text being entered with a hard keyboard, we need to process // it and do the appropriate action. if (PROCESS_HARD_KEYS) { if (keyCode == KeyEvent.KEYCODE_SPACE && (event.getMetaState() & KeyEvent.META_ALT_ON) != 0) { // A silly example: in our input method, Alt+Space // is a shortcut for 'android' in lower case. InputConnection ic = getCurrentInputConnection(); if (ic != null) { // First, tell the editor that it is no longer in the // shift state, since we are consuming this. ic.clearMetaKeyStates(KeyEvent.META_ALT_ON); keyDownUp(KeyEvent.KEYCODE_A); keyDownUp(KeyEvent.KEYCODE_N); keyDownUp(KeyEvent.KEYCODE_D); keyDownUp(KeyEvent.KEYCODE_R); keyDownUp(KeyEvent.KEYCODE_O); keyDownUp(KeyEvent.KEYCODE_I); keyDownUp(KeyEvent.KEYCODE_D); // And we consume this event. return true; } } if (mPredictionOn && translateKeyDown(keyCode, event)) { return true; } } } return super.onKeyDown(keyCode, event); }
private void capsLock(KeyEvent event) { int status = event.getMetaState() == KeyEvent.META_CAPS_LOCK_ON ? ASUSDEC_STATUS_ON : ASUSDEC_STATUS_OFF; notifyKey(ASUSDEC_CAPS_LOCK, status); }
@Override public boolean handleKeyEvent(KeyEvent event) { if (DEBUG_KEYEVENT) { Log.d( TAG, "KeyEvent: action=" + event.getAction() + ", flags=" + event.getFlags() + ", canceled=" + event.isCanceled() + ", keyCode=" + event.getKeyCode() + ", scanCode=" + event.getScanCode() + ", metaState=" + event.getMetaState() + ", repeatCount=" + event.getRepeatCount()); } if (event.getAction() != KeyEvent.ACTION_UP || event.getRepeatCount() != 0) { return false; } switch (event.getScanCode()) { case SCANCODE_TOGGLE_WIFI: toggleWifi(); break; case SCANCODE_TOGGLE_BT: toggleBluetooth(); break; case SCANCODE_TOGGLE_TOUCHPAD: toggleTouchpad(); break; case SCANCODE_BRIGHTNESS_DOWN: brightnessDown(); break; case SCANCODE_BRIGHTNESS_UP: brightnessUp(); break; case SCANCODE_BRIGHTNESS_AUTO: toggleAutoBrightness(); break; case SCANCODE_SCREENSHOT: takeScreenshot(); break; case SCANCODE_EXPLORER: launchExplorer(); return false; case SCANCODE_SETTINGS: launchSettings(); break; case SCANCODE_VOLUME_MUTE: // KEYCODE_VOLUME_MUTE is part of the aosp keyevent intercept handling, but // aosp uses it stop ringing in phone devices (no system volume mute toggle). // Since transformer devices doesn't have a telephony subsystem, we handle and // treat this event as a volume mute toggle action. the asusdec KeyHandler // mustn't mark the key event as consumed. toggleAudioMute(); return false; case SCANCODE_VOLUME_DOWN: volumeDown(); return false; case SCANCODE_VOLUME_UP: volumeUp(); return false; case SCANCODE_MEDIA_PLAY_PAUSE: mediaPlayPause(); return false; case SCANCODE_MEDIA_PREVIOUS: mediaPrevious(); return false; case SCANCODE_MEDIA_NEXT: mediaNext(); return false; case SCANCODE_CAPS_LOCK: capsLock(event); return false; default: return false; } return true; }
public boolean processLocalKeyEvent(int keyCode, KeyEvent evt) { android.util.Log.e(TAG, evt.toString() + " " + keyCode); if (rfb != null && rfb.isInNormalProtocol()) { RemotePointer pointer = vncCanvas.getPointer(); boolean down = (evt.getAction() == KeyEvent.ACTION_DOWN) || (evt.getAction() == KeyEvent.ACTION_MULTIPLE); boolean unicode = false; int metaState = 0, numchars = 1; int keyboardMetaState = evt.getMetaState(); // Add shift to metaState if necessary. if ((keyboardMetaState & 0x000000c1) != 0) metaState |= SHIFT_MASK; // If the keyboardMetaState contains any hint of CTRL, add CTRL_MASK to metaState if ((keyboardMetaState & 0x00007000) != 0) metaState |= CTRL_MASK; // If the keyboardMetaState contains left ALT, add ALT_MASK to metaState. // Leaving KeyEvent.KEYCODE_ALT_LEFT for symbol input on hardware keyboards. if ((keyboardMetaState & KeyEvent.META_ALT_RIGHT_ON) != 0) metaState |= ALT_MASK; if ((keyboardMetaState & (RemoteKeyboard.SUPER_MASK | 0x00010000)) != 0) metaState |= SUPER_MASK; if (keyCode == KeyEvent.KEYCODE_MENU) return true; // Ignore menu key if (pointer.handleHardwareButtons( keyCode, evt, metaState | onScreenMetaState | hardwareMetaState)) return true; int key = 0, keysym = 0; if (!down) { switch (evt.getScanCode()) { case SCAN_ESC: key = 0xff1b; break; case SCAN_LEFTCTRL: case SCAN_RIGHTCTRL: hardwareMetaState &= ~CTRL_MASK; break; case SCAN_F1: keysym = 0xffbe; break; case SCAN_F2: keysym = 0xffbf; break; case SCAN_F3: keysym = 0xffc0; break; case SCAN_F4: keysym = 0xffc1; break; case SCAN_F5: keysym = 0xffc2; break; case SCAN_F6: keysym = 0xffc3; break; case SCAN_F7: keysym = 0xffc4; break; case SCAN_F8: keysym = 0xffc5; break; case SCAN_F9: keysym = 0xffc6; break; case SCAN_F10: keysym = 0xffc7; break; } switch (keyCode) { case KeyEvent.KEYCODE_DPAD_CENTER: hardwareMetaState &= ~CTRL_MASK; break; // Leaving KeyEvent.KEYCODE_ALT_LEFT for symbol input on hardware keyboards. case KeyEvent.KEYCODE_ALT_RIGHT: hardwareMetaState &= ~ALT_MASK; break; } } switch (keyCode) { // case KeyEvent.KEYCODE_BACK: keysym = 0xff1b; break; case KeyEvent.KEYCODE_DPAD_LEFT: keysym = 0xff51; break; case KeyEvent.KEYCODE_DPAD_UP: keysym = 0xff52; break; case KeyEvent.KEYCODE_DPAD_RIGHT: keysym = 0xff53; break; case KeyEvent.KEYCODE_DPAD_DOWN: keysym = 0xff54; break; case KeyEvent.KEYCODE_DEL: keysym = 0xff08; break; case KeyEvent.KEYCODE_ENTER: keysym = 0xff0d; break; case KeyEvent.KEYCODE_TAB: keysym = 0xff09; break; case 92 /* KEYCODE_PAGE_UP */: keysym = 0xff55; break; case 93 /* KEYCODE_PAGE_DOWN */: keysym = 0xff56; break; case 111 /* KEYCODE_ESCAPE */: keysym = 0xff1b; break; case 112 /* KEYCODE_FORWARD_DEL */: keysym = 0xffff; break; case 113 /* KEYCODE_CTRL_LEFT */: keysym = 0xffe3; break; case 114 /* KEYCODE_CTRL_RIGHT */: keysym = 0xffe4; break; case 115 /* KEYCODE_CAPS_LOCK */: keysym = 0xffe5; break; case 116 /* KEYCODE_SCROLL_LOCK */: keysym = 0xff14; break; case 117 /* KEYCODE_META_LEFT */: keysym = 0xffeb; break; case 118 /* KEYCODE_META_RIGHT */: keysym = 0xffec; break; case 120 /* KEYCODE_SYSRQ */: keysym = 0xff61; break; case 121 /* KEYCODE_BREAK */: keysym = 0xff6b; break; case 122 /* KEYCODE_MOVE_HOME */: keysym = 0xff50; break; case 123 /* KEYCODE_MOVE_END */: keysym = 0xff57; break; case 124 /* KEYCODE_INSERT */: keysym = 0xff63; break; case 131 /* KEYCODE_F1 */: keysym = 0xffbe; break; case 132 /* KEYCODE_F2 */: keysym = 0xffbf; break; case 133 /* KEYCODE_F3 */: keysym = 0xffc0; break; case 134 /* KEYCODE_F4 */: keysym = 0xffc1; break; case 135 /* KEYCODE_F5 */: keysym = 0xffc2; break; case 136 /* KEYCODE_F6 */: keysym = 0xffc3; break; case 137 /* KEYCODE_F7 */: keysym = 0xffc4; break; case 138 /* KEYCODE_F8 */: keysym = 0xffc5; break; case 139 /* KEYCODE_F9 */: keysym = 0xffc6; break; case 140 /* KEYCODE_F10 */: keysym = 0xffc7; break; case 141 /* KEYCODE_F11 */: keysym = 0xffc8; break; case 142 /* KEYCODE_F12 */: keysym = 0xffc9; break; case 143 /* KEYCODE_NUM_LOCK */: keysym = 0xff7f; break; case 0 /* KEYCODE_UNKNOWN */: if (evt.getCharacters() != null) { key = evt.getCharacters().charAt(0); keysym = UnicodeToKeysym.translate(key); numchars = evt.getCharacters().length(); unicode = true; } break; default: // Modifier handling is a bit tricky. Alt, Ctrl, and Super should be passed // through to the VNC server so that they get handled there, but strip // them from the character before retrieving the Unicode char from it. // Don't clear Shift, we still want uppercase characters. int metaMask = (0x00007000 | 0x00070000); // KeyEvent.META_CTRL_MASK | KeyEvent.META_META_MASK // We still want alt-key combinations to give us symbols, so we only strip out // KeyEvent.META_ALT_MASK // if we've decided to send out ALT as a separate key modifier over. if ((metaState & ALT_MASK) != 0) metaMask |= 0x00000032; KeyEvent copy = new KeyEvent( evt.getDownTime(), evt.getEventTime(), evt.getAction(), evt.getKeyCode(), evt.getRepeatCount(), keyboardMetaState & ~metaMask, evt.getDeviceId(), evt.getScanCode()); key = copy.getUnicodeChar(); keysym = UnicodeToKeysym.translate(key); break; } if (down) { // Look for standard scan-codes from external keyboards switch (evt.getScanCode()) { case SCAN_ESC: keysym = 0xff1b; break; case SCAN_LEFTCTRL: case SCAN_RIGHTCTRL: hardwareMetaState |= CTRL_MASK; break; case SCAN_F1: keysym = 0xffbe; break; case SCAN_F2: keysym = 0xffbf; break; case SCAN_F3: keysym = 0xffc0; break; case SCAN_F4: keysym = 0xffc1; break; case SCAN_F5: keysym = 0xffc2; break; case SCAN_F6: keysym = 0xffc3; break; case SCAN_F7: keysym = 0xffc4; break; case SCAN_F8: keysym = 0xffc5; break; case SCAN_F9: keysym = 0xffc6; break; case SCAN_F10: keysym = 0xffc7; break; } switch (keyCode) { case KeyEvent.KEYCODE_DPAD_CENTER: hardwareMetaState |= CTRL_MASK; break; // Leaving KeyEvent.KEYCODE_ALT_LEFT for symbol input on hardware keyboards. case KeyEvent.KEYCODE_ALT_RIGHT: hardwareMetaState |= ALT_MASK; break; } } try { if (afterMenu) { afterMenu = false; if (!down && keysym != lastKeyDown) return true; } if (down) lastKeyDown = keysym; if (numchars == 1) { android.util.Log.e( TAG, "action down? = " + down + " key = " + key + " keysym = " + keysym + " onscreen metastate = " + onScreenMetaState + " keyboard metastate = " + keyboardMetaState + " RFB metastate = " + metaState + " keycode = " + keyCode + " unicode = " + evt.getUnicodeChar()); // TODO: UGLY HACK for Z10 devices running 10.1 which never send the down-event // for backspace... so we send it instead. Remove as soon as possible! if (backspaceWorkaround && keyCode == KeyEvent.KEYCODE_DEL) rfb.writeKeyEvent(keysym, (onScreenMetaState | hardwareMetaState | metaState), true); rfb.writeKeyEvent(keysym, (onScreenMetaState | hardwareMetaState | metaState), down); // If this is a unicode key, the up event will never come, so we artificially insert it. if (unicode) rfb.writeKeyEvent(keysym, (onScreenMetaState | hardwareMetaState | metaState), false); // TODO: UGLY HACK for BB10 devices which never send the up-event // for space, backspace and enter... so we send it instead. Remove as soon as possible! if (bb10 && (keyCode == KeyEvent.KEYCODE_SPACE || keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_ENTER)) rfb.writeKeyEvent(keysym, (onScreenMetaState | hardwareMetaState | metaState), false); } else if (numchars > 1) { for (int i = 0; i < numchars; i++) { key = evt.getCharacters().charAt(i); // Log.e(TAG,"action down? = " + down + " key = " + key + " keysym = " + keysym + " // onscreen metastate = " + onScreenMetaState + " keyboard metastate = " + // keyboardMetaState + " RFB metastate = " + metaState + " keycode = " + keyCode + " // unicode = " + evt.getUnicodeChar()); keysym = UnicodeToKeysym.translate(key); rfb.writeKeyEvent(keysym, (onScreenMetaState | hardwareMetaState | metaState), true); rfb.writeKeyEvent(keysym, (onScreenMetaState | hardwareMetaState | metaState), false); } } } catch (Exception e) { e.printStackTrace(); } return true; } return false; }