@Override public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) { if (keyCode != KeyEvent.KEYCODE_UNKNOWN || event.getAction() != KeyEvent.ACTION_MULTIPLE) return super.onKeyMultiple(keyCode, count, event); if (event.getCharacters() != null) { int utf8Char = event.getCharacters().codePointAt(0); handleKeyDown(host, utf8Char, utf8Char); return true; } return false; }
@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 onKeyMultiple(final int inKeyCode, int repeatCount, KeyEvent event) { String s = event.getCharacters(); if (s == null || s.length() == 0) return super.onKeyMultiple(inKeyCode, repeatCount, event); final char[] cc = s.toCharArray(); int cnt = 0; for (int i = cc.length; --i >= 0; cnt += cc[i] != 0 ? 1 : 0) ; if (cnt == 0) return super.onKeyMultiple(inKeyCode, repeatCount, event); final Activity me = this; queueEvent( new Runnable() { // This method will be called on the rendering thread: public void run() { for (int i = 0, n = cc.length; i < n; i++) { int keyCode; if ((keyCode = cc[i]) != 0) { // Simulate key down and up... GodotLib.key(0, keyCode, true); GodotLib.key(0, keyCode, false); } } } }); return true; }
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; }
@Override public boolean onKey(View v, int keyCode, android.view.KeyEvent e) { for (int i = 0, n = keyListeners.size(); i < n; i++) if (keyListeners.get(i).onKey(v, keyCode, e)) return true; synchronized (this) { KeyEvent event = null; if (e.getKeyCode() == android.view.KeyEvent.KEYCODE_UNKNOWN && e.getAction() == android.view.KeyEvent.ACTION_MULTIPLE) { String chars = e.getCharacters(); for (int i = 0; i < chars.length(); i++) { event = usedKeyEvents.obtain(); event.keyCode = 0; event.keyChar = chars.charAt(i); event.type = KeyEvent.KEY_TYPED; keyEvents.add(event); } return false; } char character = (char) e.getUnicodeChar(); // Android doesn't report a unicode char for back space. hrm... if (keyCode == 67) character = '\b'; switch (e.getAction()) { case android.view.KeyEvent.ACTION_DOWN: event = usedKeyEvents.obtain(); event.keyChar = 0; event.keyCode = e.getKeyCode(); event.type = KeyEvent.KEY_DOWN; // Xperia hack for circle key. gah... if (keyCode == android.view.KeyEvent.KEYCODE_BACK && e.isAltPressed()) { keyCode = Keys.BUTTON_CIRCLE; event.keyCode = keyCode; } keyEvents.add(event); keys.put(event.keyCode, null); break; case android.view.KeyEvent.ACTION_UP: event = usedKeyEvents.obtain(); event.keyChar = 0; event.keyCode = e.getKeyCode(); event.type = KeyEvent.KEY_UP; // Xperia hack for circle key. gah... if (keyCode == android.view.KeyEvent.KEYCODE_BACK && e.isAltPressed()) { keyCode = Keys.BUTTON_CIRCLE; event.keyCode = keyCode; } keyEvents.add(event); event = usedKeyEvents.obtain(); event.keyChar = character; event.keyCode = 0; event.type = KeyEvent.KEY_TYPED; keyEvents.add(event); if (keyCode == Keys.BUTTON_CIRCLE) keys.remove(Keys.BUTTON_CIRCLE); else keys.remove(e.getKeyCode()); } app.getGraphics().requestRendering(); } // circle button on Xperia Play shouldn't need catchBack == true if (keyCode == Keys.BUTTON_CIRCLE) return true; if (catchBack && keyCode == android.view.KeyEvent.KEYCODE_BACK) return true; if (catchMenu && keyCode == android.view.KeyEvent.KEYCODE_MENU) return true; return false; }
/** * Converts the {@link KeyEvent} into low-level events and sends them to the host as either * key-events or text-events. This contains some logic for handling some special keys, and avoids * sending a key-up event for a key that was previously injected as a text-event. */ public boolean sendKeyEvent(KeyEvent event) { int keyCode = event.getKeyCode(); boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN; // Events received from software keyboards generate TextEvent in two // cases: // 1. This is an ACTION_MULTIPLE event. // 2. Ctrl, Alt and Meta are not pressed. // This ensures that on-screen keyboard always injects input that // correspond to what user sees on the screen, while physical keyboard // acts as if it is connected to the remote host. if (event.getAction() == KeyEvent.ACTION_MULTIPLE) { mInjector.sendTextEvent(event.getCharacters()); return true; } // For Enter getUnicodeChar() returns 10 (line feed), but we still // want to send it as KeyEvent. int unicode = keyCode != KeyEvent.KEYCODE_ENTER ? event.getUnicodeChar() : 0; boolean no_modifiers = !event.isAltPressed() && !event.isCtrlPressed() && !event.isMetaPressed(); if (pressed && unicode != 0 && no_modifiers) { mPressedTextKeys.add(keyCode); int[] codePoints = {unicode}; mInjector.sendTextEvent(new String(codePoints, 0, 1)); return true; } if (!pressed && mPressedTextKeys.contains(keyCode)) { mPressedTextKeys.remove(keyCode); return true; } switch (keyCode) { // KEYCODE_AT, KEYCODE_POUND, KEYCODE_STAR and KEYCODE_PLUS are // deprecated, but they still need to be here for older devices and // third-party keyboards that may still generate these events. See // https://source.android.com/devices/input/keyboard-devices.html#legacy-unsupported-keys case KeyEvent.KEYCODE_AT: mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed); mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_2, pressed); return true; case KeyEvent.KEYCODE_POUND: mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed); mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_3, pressed); return true; case KeyEvent.KEYCODE_STAR: mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed); mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_8, pressed); return true; case KeyEvent.KEYCODE_PLUS: mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed); mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_EQUALS, pressed); return true; default: // We try to send all other key codes to the host directly. return mInjector.sendKeyEvent(0, keyCode, pressed); } }
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; }
/** * Called once when a keyboard key is pressed, then again when that same key is released. This is * not guaranteed to be notified of all soft keyboard events: certian keyboards might not call it * at all, while others might skip it in certain situations (e.g. swipe input). */ @Override public boolean dispatchKeyEvent(KeyEvent event) { int keyCode = event.getKeyCode(); // Dispatch the back button to the system to handle navigation if (keyCode == KeyEvent.KEYCODE_BACK) { JniInterface.disconnectFromHost(); return super.dispatchKeyEvent(event); } boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN; // Physical keyboard must work as if it is connected to the remote host // and so events coming from physical keyboard never generate text // events. Also scan codes must be used instead of key code, so that // the keyboard layout selected on the client doesn't affect the key // codes sent to the host. if (event.getDeviceId() != KeyCharacterMap.VIRTUAL_KEYBOARD) { return JniInterface.sendKeyEvent(event.getScanCode(), 0, pressed); } // Events received from software keyboards generate TextEvent in two // cases: // 1. This is an ACTION_MULTIPLE event. // 2. Ctrl, Alt and Meta are not pressed. // This ensures that on-screen keyboard always injects input that // correspond to what user sees on the screen, while physical keyboard // acts as if it is connected to the remote host. if (event.getAction() == KeyEvent.ACTION_MULTIPLE) { JniInterface.sendTextEvent(event.getCharacters()); return true; } // For Enter getUnicodeChar() returns 10 (line feed), but we still // want to send it as KeyEvent. int unicode = keyCode != KeyEvent.KEYCODE_ENTER ? event.getUnicodeChar() : 0; boolean no_modifiers = !event.isAltPressed() && !event.isCtrlPressed() && !event.isMetaPressed(); if (pressed && unicode != 0 && no_modifiers) { mPressedTextKeys.add(keyCode); int[] codePoints = {unicode}; JniInterface.sendTextEvent(new String(codePoints, 0, 1)); return true; } if (!pressed && mPressedTextKeys.contains(keyCode)) { mPressedTextKeys.remove(keyCode); return true; } switch (keyCode) { // KEYCODE_AT, KEYCODE_POUND, KEYCODE_STAR and KEYCODE_PLUS are // deprecated, but they still need to be here for older devices and // third-party keyboards that may still generate these events. See // https://source.android.com/devices/input/keyboard-devices.html#legacy-unsupported-keys case KeyEvent.KEYCODE_AT: JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed); JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_2, pressed); return true; case KeyEvent.KEYCODE_POUND: JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed); JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_3, pressed); return true; case KeyEvent.KEYCODE_STAR: JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed); JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_8, pressed); return true; case KeyEvent.KEYCODE_PLUS: JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed); JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_EQUALS, pressed); return true; default: // We try to send all other key codes to the host directly. return JniInterface.sendKeyEvent(0, keyCode, pressed); } }
/** * 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; }