private void sendCharKeyEvents(Action action) { if (action.mSequence.length() == 0 || (action.mSequence instanceof Spannable && ((Spannable) action.mSequence).nextSpanTransition(-1, Integer.MAX_VALUE, null) < Integer.MAX_VALUE)) { // Spans are not preserved when we use key events, // so we need the sequence to not have any spans return; } KeyEvent[] keyEvents = synthesizeKeyEvents(action.mSequence); if (keyEvents == null) { return; } for (KeyEvent event : keyEvents) { if (KeyEvent.isModifierKey(event.getKeyCode())) { continue; } if (event.getAction() == KeyEvent.ACTION_UP && mSuppressKeyUp) { continue; } if (DEBUG) { Log.d(LOGTAG, "sending: " + event); } onKeyEvent(event, event.getAction(), /* metaState */ 0, /* isSynthesizedImeKey */ true); } }
/** * @param keyCode * @param event * @return true to say we handled this, false to tell Android to handle it */ public static boolean keyUp(int keyCode, KeyEvent event) { if (KeyEvent.isModifierKey(keyCode)) { /* Android sends a shift keycode (for instance), then the key that goes with the shift. We don't need the first keycode, that info is in event.getMetaState() anyway */ return false; } else { int unicodeChar = event.getUnicodeChar(); onKeyUp(unicodeChar); // return false to let Android handle certain keys // like the back and menu keys return false; } }
private boolean synthesizeKeyEvents(char inputChar) { if (mKeyCharacterMap == null) { mKeyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); } // Synthesize VKB key events that could plausibly generate the input character. char[] inputChars = {inputChar}; KeyEvent[] events = mKeyCharacterMap.getEvents(inputChars); if (events == null) { if (DEBUG) { Log.d(LOGTAG, "synthesizeKeyEvents: char '" + inputChar + "' has no virtual key mapping"); } return false; } boolean sentKeyEvents = false; for (KeyEvent event : events) { if (!KeyEvent.isModifierKey(event.getKeyCode())) { if (DEBUG) { Log.d( LOGTAG, "synthesizeKeyEvents: char '" + inputChar + "' -> action=" + event.getAction() + ", keyCode=" + event.getKeyCode() + ", UnicodeChar='" + (char) event.getUnicodeChar() + "'"); } GeckoAppShell.sendEventToGecko(GeckoEvent.createKeyEvent(event)); sentKeyEvents = true; } } return sentKeyEvents; }
/** * @param keyCode * @param event * @return true to say we handled this, false to tell Android to handle it */ public static boolean keyDown(int keyCode, KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0)) { if (onBackPressed()) { return true; } else { // let the Android system handle the back button return false; } } if (KeyEvent.isModifierKey(keyCode)) { /* Android sends a shift keycode (for instance), then the key that goes with the shift. We don't need the first keycode, that info is in event.getMetaState() anyway */ return false; } else { int unicodeChar = event.getUnicodeChar(); onKeyDown(unicodeChar); // return false to let Android handle certain keys // like the back and menu keys return false; } }
@Override public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { /* If we're ignoring this key, don't handle it */ if (isKeyCodeToIgnore(keyCode)) { return false; } /* If this is a modifier key, ignore it */ if (KeyEvent.isModifierKey(keyCode)) { return true; } if (event.getAction() == KeyEvent.ACTION_DOWN) { Long keyCombo = keyEventToExtendedKeyCode(event); if (mKeyCombos.contains(keyCombo)) { /* Don't check other keys - if it's a duplicate, it's being removed */ mKeyCombos.remove(keyCombo); updateKeyListAdapter(); } else { CharSequence titleOfOtherPrefForKey = getTitleOfOtherActionAssociatedWith(keyCombo); if (titleOfOtherPrefForKey != null) { CharSequence toastText = String.format( getContext().getString(R.string.toast_msg_key_already_assigned), describeExtendedKeyCode(keyCombo), titleOfOtherPrefForKey); Toast.makeText(getContext(), toastText, Toast.LENGTH_SHORT).show(); } else { mKeyCombos.add(keyCombo); updateKeyListAdapter(); } } } return true; }
/** * This should be called from the Activity's onKeyDown() to handle keyboard shortcuts. * * <p>Note: onKeyDown() is called after the active view or web page has had a chance to handle the * key event. So the keys handled here *can* be overridden by any view or web page. * * @param event The KeyEvent to handle. * @param activity The ChromeActivity in which the key was pressed. * @param isCurrentTabVisible Whether page-related actions are valid, e.g. reload, zoom in. This * should be false when in the tab switcher. * @param tabSwitchingEnabled Whether shortcuts that switch between tabs are enabled (e.g. * Ctrl+Tab, Ctrl+3). * @return Whether the key event was handled. */ public static boolean onKeyDown( KeyEvent event, ChromeActivity activity, boolean isCurrentTabVisible, boolean tabSwitchingEnabled) { int keyCode = event.getKeyCode(); if (event.getRepeatCount() != 0 || KeyEvent.isModifierKey(keyCode)) return false; if (KeyEvent.isGamepadButton(keyCode)) { if (isGamepadAPIActive(activity)) return false; } else if (!event.isCtrlPressed() && !event.isAltPressed() && keyCode != KeyEvent.KEYCODE_F3 && keyCode != KeyEvent.KEYCODE_F5 && keyCode != KeyEvent.KEYCODE_F10 && keyCode != KeyEvent.KEYCODE_FORWARD) { return false; } TabModel curModel = activity.getCurrentTabModel(); int count = curModel.getCount(); int metaState = getMetaState(event); int keyCodeAndMeta = keyCode | metaState; switch (keyCodeAndMeta) { case CTRL | SHIFT | KeyEvent.KEYCODE_T: activity.onMenuOrKeyboardAction(R.id.open_recently_closed_tab, false); return true; case CTRL | KeyEvent.KEYCODE_T: activity.onMenuOrKeyboardAction( curModel.isIncognito() ? R.id.new_incognito_tab_menu_id : R.id.new_tab_menu_id, false); return true; case CTRL | KeyEvent.KEYCODE_N: activity.onMenuOrKeyboardAction(R.id.new_tab_menu_id, false); return true; case CTRL | SHIFT | KeyEvent.KEYCODE_N: activity.onMenuOrKeyboardAction(R.id.new_incognito_tab_menu_id, false); return true; // Alt+E represents a special character ´ (latin code: ´) in Android. // If an EditText or ContentView has focus, Alt+E will be swallowed by // the default dispatchKeyEvent and cannot open the menu. case ALT | KeyEvent.KEYCODE_E: case ALT | KeyEvent.KEYCODE_F: case KeyEvent.KEYCODE_F10: case KeyEvent.KEYCODE_BUTTON_Y: activity.onMenuOrKeyboardAction(R.id.show_menu, false); return true; } if (isCurrentTabVisible) { if (tabSwitchingEnabled && (metaState == CTRL || metaState == ALT)) { int numCode = keyCode - KeyEvent.KEYCODE_0; if (numCode > 0 && numCode <= Math.min(count, 8)) { // Ctrl+1 to Ctrl+8: select tab by index TabModelUtils.setIndex(curModel, numCode - 1); return true; } else if (numCode == 9 && count != 0) { // Ctrl+9: select last tab TabModelUtils.setIndex(curModel, count - 1); return true; } } switch (keyCodeAndMeta) { case CTRL | KeyEvent.KEYCODE_TAB: case CTRL | KeyEvent.KEYCODE_PAGE_DOWN: case KeyEvent.KEYCODE_BUTTON_R1: if (tabSwitchingEnabled && count > 1) { TabModelUtils.setIndex(curModel, (curModel.index() + 1) % count); } return true; case CTRL | SHIFT | KeyEvent.KEYCODE_TAB: case CTRL | KeyEvent.KEYCODE_PAGE_UP: case KeyEvent.KEYCODE_BUTTON_L1: if (tabSwitchingEnabled && count > 1) { TabModelUtils.setIndex(curModel, (curModel.index() + count - 1) % count); } return true; case CTRL | KeyEvent.KEYCODE_W: case CTRL | KeyEvent.KEYCODE_F4: case KeyEvent.KEYCODE_BUTTON_B: TabModelUtils.closeCurrentTab(curModel); return true; case CTRL | KeyEvent.KEYCODE_F: case CTRL | KeyEvent.KEYCODE_G: case CTRL | SHIFT | KeyEvent.KEYCODE_G: case KeyEvent.KEYCODE_F3: case SHIFT | KeyEvent.KEYCODE_F3: activity.onMenuOrKeyboardAction(R.id.find_in_page_id, false); return true; case CTRL | KeyEvent.KEYCODE_L: case ALT | KeyEvent.KEYCODE_D: case KeyEvent.KEYCODE_BUTTON_X: activity.onMenuOrKeyboardAction(R.id.focus_url_bar, false); return true; case CTRL | SHIFT | KeyEvent.KEYCODE_B: activity.onMenuOrKeyboardAction(R.id.all_bookmarks_menu_id, false); return true; case KeyEvent.KEYCODE_BOOKMARK: case CTRL | KeyEvent.KEYCODE_D: activity.onMenuOrKeyboardAction(R.id.bookmark_this_page_id, false); return true; case CTRL | KeyEvent.KEYCODE_H: activity.onMenuOrKeyboardAction(R.id.open_history_menu_id, false); return true; case CTRL | KeyEvent.KEYCODE_P: activity.onMenuOrKeyboardAction(R.id.print_id, false); return true; case CTRL | KeyEvent.KEYCODE_PLUS: case CTRL | KeyEvent.KEYCODE_EQUALS: case CTRL | SHIFT | KeyEvent.KEYCODE_PLUS: case CTRL | SHIFT | KeyEvent.KEYCODE_EQUALS: case KeyEvent.KEYCODE_ZOOM_IN: ContentViewCore cvc = activity.getCurrentContentViewCore(); if (cvc != null) cvc.zoomIn(); return true; case CTRL | KeyEvent.KEYCODE_MINUS: case KeyEvent.KEYCODE_ZOOM_OUT: cvc = activity.getCurrentContentViewCore(); if (cvc != null) cvc.zoomOut(); return true; case CTRL | KeyEvent.KEYCODE_0: cvc = activity.getCurrentContentViewCore(); if (cvc != null) cvc.zoomReset(); return true; case SHIFT | CTRL | KeyEvent.KEYCODE_R: case CTRL | KeyEvent.KEYCODE_R: case SHIFT | KeyEvent.KEYCODE_F5: case KeyEvent.KEYCODE_F5: Tab tab = activity.getActivityTab(); if (tab != null) { if ((keyCodeAndMeta & SHIFT) == SHIFT) { tab.reloadIgnoringCache(); } else { tab.reload(); } if (activity.getToolbarManager() != null && tab.getWebContents() != null && tab.getWebContents().focusLocationBarByDefault()) { activity.getToolbarManager().revertLocationBarChanges(); } else { tab.requestFocus(); } } return true; case ALT | KeyEvent.KEYCODE_DPAD_LEFT: tab = activity.getActivityTab(); if (tab != null && tab.canGoBack()) tab.goBack(); return true; case ALT | KeyEvent.KEYCODE_DPAD_RIGHT: case KeyEvent.KEYCODE_FORWARD: case KeyEvent.KEYCODE_BUTTON_START: tab = activity.getActivityTab(); if (tab != null && tab.canGoForward()) tab.goForward(); return true; case CTRL | SHIFT | KeyEvent.KEYCODE_SLASH: // i.e. Ctrl+? activity.onMenuOrKeyboardAction(R.id.help_id, false); return true; } } return false; }