/** 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;
          }
        }
示例#2
0
  /*
   * 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;
  }
示例#4
0
 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);
 }
示例#5
0
  @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);
  }
示例#6
0
 @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());
  }
示例#8
0
  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;
  }
示例#9
0
  /*
   * 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;
  }
示例#12
0
 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;
    }
  }
示例#14
0
  @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;
  }
示例#15
0
  /**
   * 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());
  }
示例#16
0
  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);
    }
  }
示例#22
0
  /**
   * 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;
  }
示例#25
0
  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;
  }