OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.chrome.browser; |
| 6 |
| 7 import android.view.KeyEvent; |
| 8 |
| 9 import com.google.android.apps.chrome.R; |
| 10 |
| 11 import org.chromium.base.annotations.SuppressFBWarnings; |
| 12 import org.chromium.chrome.browser.tabmodel.ChromeTabCreator; |
| 13 import org.chromium.chrome.browser.tabmodel.TabModel; |
| 14 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType; |
| 15 import org.chromium.chrome.browser.tabmodel.TabModelUtils; |
| 16 import org.chromium.content.browser.ContentViewCore; |
| 17 import org.chromium.content_public.browser.LoadUrlParams; |
| 18 import org.chromium.ui.base.PageTransition; |
| 19 |
| 20 /** |
| 21 * Implements app-level keyboard shortcuts for ChromeTabbedActivity and Document
Activity. |
| 22 */ |
| 23 public class KeyboardShortcuts { |
| 24 |
| 25 private static final int CTRL = 1 << 31; |
| 26 private static final int ALT = 1 << 30; |
| 27 private static final int SHIFT = 1 << 29; |
| 28 |
| 29 private KeyboardShortcuts() {} |
| 30 |
| 31 private static int getMetaState(KeyEvent event) { |
| 32 return (event.isCtrlPressed() ? CTRL : 0) |
| 33 | (event.isAltPressed() ? ALT : 0) |
| 34 | (event.isShiftPressed() ? SHIFT : 0); |
| 35 } |
| 36 |
| 37 /** |
| 38 * This should be called from the Activity's dispatchKeyEvent() to handle ke
yboard shortcuts. |
| 39 * |
| 40 * Note: dispatchKeyEvent() is called before the active view or web page get
s a chance to handle |
| 41 * the key event. So the keys handled here cannot be overridden by any view
or web page. |
| 42 * |
| 43 * @param event The KeyEvent to handle. |
| 44 * @param activity The ChromeActivity in which the key was pressed. |
| 45 * @param uiInitialized Whether the UI has been initialized. If this is fals
e, most keys will |
| 46 * not be handled. |
| 47 * @return True if the event was handled. False if the event was ignored. Nu
ll if the event |
| 48 * should be handled by the activity's parent class. |
| 49 */ |
| 50 @SuppressFBWarnings("NP_BOOLEAN_RETURN_NULL") |
| 51 public static Boolean dispatchKeyEvent(KeyEvent event, ChromeActivity activi
ty, |
| 52 boolean uiInitialized) { |
| 53 int keyCode = event.getKeyCode(); |
| 54 if (!uiInitialized) { |
| 55 if (keyCode == KeyEvent.KEYCODE_SEARCH || keyCode == KeyEvent.KEYCOD
E_MENU) return true; |
| 56 return null; |
| 57 } |
| 58 |
| 59 switch (keyCode) { |
| 60 case KeyEvent.KEYCODE_SEARCH: |
| 61 if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeat
Count() == 0) { |
| 62 activity.onMenuOrKeyboardAction(R.id.focus_url_bar, false); |
| 63 } |
| 64 // Always consume the SEARCH key events to prevent android from
showing |
| 65 // the default app search UI, which locks up Chrome. |
| 66 return true; |
| 67 case KeyEvent.KEYCODE_MENU: |
| 68 if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeat
Count() == 0) { |
| 69 activity.onMenuOrKeyboardAction(R.id.show_menu, false); |
| 70 } |
| 71 return true; |
| 72 case KeyEvent.KEYCODE_TV: |
| 73 case KeyEvent.KEYCODE_GUIDE: |
| 74 case KeyEvent.KEYCODE_DVR: |
| 75 case KeyEvent.KEYCODE_AVR_INPUT: |
| 76 case KeyEvent.KEYCODE_AVR_POWER: |
| 77 case KeyEvent.KEYCODE_STB_INPUT: |
| 78 case KeyEvent.KEYCODE_STB_POWER: |
| 79 case KeyEvent.KEYCODE_TV_INPUT: |
| 80 case KeyEvent.KEYCODE_TV_POWER: |
| 81 case KeyEvent.KEYCODE_WINDOW: |
| 82 // Do not consume the AV device-related keys so that the system
will take |
| 83 // an appropriate action, such as switching to TV mode. |
| 84 return false; |
| 85 } |
| 86 |
| 87 return null; |
| 88 } |
| 89 |
| 90 /** |
| 91 * This should be called from the Activity's onKeyDown() to handle keyboard
shortcuts. |
| 92 * |
| 93 * Note: onKeyDown() is called after the active view or web page has had a c
hance to handle |
| 94 * the key event. So the keys handled here *can* be overridden by any view o
r web page. |
| 95 * |
| 96 * @param event The KeyEvent to handle. |
| 97 * @param activity The ChromeActivity in which the key was pressed. |
| 98 * @param isCurrentTabVisible Whether page-related actions are valid, e.g. r
eload, zoom in. |
| 99 * This should be false when in the tab switcher. |
| 100 * @param tabSwitchingEnabled Whether shortcuts that switch between tabs are
enabled (e.g. |
| 101 * Ctrl+Tab, Ctrl+3). |
| 102 * @return Whether the key event was handled. |
| 103 */ |
| 104 public static boolean onKeyDown(KeyEvent event, ChromeActivity activity, |
| 105 boolean isCurrentTabVisible, boolean tabSwitchingEnabled) { |
| 106 int keyCode = event.getKeyCode(); |
| 107 if (event.getRepeatCount() != 0 || KeyEvent.isModifierKey(keyCode)) retu
rn false; |
| 108 if (!event.isCtrlPressed() && !event.isAltPressed() |
| 109 && keyCode != KeyEvent.KEYCODE_F3 |
| 110 && keyCode != KeyEvent.KEYCODE_F5) { |
| 111 return false; |
| 112 } |
| 113 |
| 114 TabModel curModel = activity.getCurrentTabModel(); |
| 115 int count = curModel.getCount(); |
| 116 |
| 117 int metaState = getMetaState(event); |
| 118 int keyCodeAndMeta = keyCode | metaState; |
| 119 |
| 120 switch (keyCodeAndMeta) { |
| 121 case CTRL | KeyEvent.KEYCODE_T: |
| 122 activity.onMenuOrKeyboardAction(curModel.isIncognito() |
| 123 ? R.id.new_incognito_tab_menu_id |
| 124 : R.id.new_tab_menu_id, false); |
| 125 return true; |
| 126 case CTRL | KeyEvent.KEYCODE_N: |
| 127 activity.onMenuOrKeyboardAction(R.id.new_tab_menu_id, false); |
| 128 return true; |
| 129 case CTRL | SHIFT | KeyEvent.KEYCODE_N: |
| 130 activity.onMenuOrKeyboardAction(R.id.new_incognito_tab_menu_id,
false); |
| 131 return true; |
| 132 case CTRL | SHIFT | KeyEvent.KEYCODE_B: |
| 133 case CTRL | KeyEvent.KEYCODE_H: |
| 134 String url = keyCode == KeyEvent.KEYCODE_B |
| 135 ? UrlConstants.BOOKMARKS_URL |
| 136 : UrlConstants.HISTORY_URL; |
| 137 Tab currentTab = TabModelUtils.getCurrentTab(curModel); |
| 138 if (currentTab != null && isCurrentTabVisible) { |
| 139 currentTab.loadUrl(new LoadUrlParams(url, PageTransition.AUT
O_BOOKMARK)); |
| 140 } else { |
| 141 ChromeTabCreator tabCreator = activity.getCurrentTabCreator(
); |
| 142 if (tabCreator != null) { |
| 143 tabCreator.launchUrl(url, TabLaunchType.FROM_KEYBOARD); |
| 144 } |
| 145 } |
| 146 return true; |
| 147 case ALT | KeyEvent.KEYCODE_F: |
| 148 activity.onMenuOrKeyboardAction(R.id.show_menu, false); |
| 149 return true; |
| 150 } |
| 151 |
| 152 if (isCurrentTabVisible) { |
| 153 if (tabSwitchingEnabled && (metaState == CTRL || metaState == ALT))
{ |
| 154 int numCode = keyCode - KeyEvent.KEYCODE_0; |
| 155 if (numCode > 0 && numCode <= Math.min(count, 8)) { |
| 156 // Ctrl+1 to Ctrl+8: select tab by index |
| 157 TabModelUtils.setIndex(curModel, numCode - 1); |
| 158 return true; |
| 159 } else if (numCode == 9 && count != 0) { |
| 160 // Ctrl+9: select last tab |
| 161 TabModelUtils.setIndex(curModel, count - 1); |
| 162 return true; |
| 163 } |
| 164 } |
| 165 |
| 166 switch (keyCodeAndMeta) { |
| 167 case CTRL | KeyEvent.KEYCODE_TAB: |
| 168 case CTRL | KeyEvent.KEYCODE_PAGE_DOWN: |
| 169 if (tabSwitchingEnabled && count > 1) { |
| 170 TabModelUtils.setIndex(curModel, (curModel.index() + 1)
% count); |
| 171 } |
| 172 return true; |
| 173 case CTRL | SHIFT | KeyEvent.KEYCODE_TAB: |
| 174 case CTRL | KeyEvent.KEYCODE_PAGE_UP: |
| 175 if (tabSwitchingEnabled && count > 1) { |
| 176 TabModelUtils.setIndex(curModel, (curModel.index() + cou
nt - 1) % count); |
| 177 } |
| 178 return true; |
| 179 case CTRL | KeyEvent.KEYCODE_W: |
| 180 case CTRL | KeyEvent.KEYCODE_F4: |
| 181 TabModelUtils.closeCurrentTab(curModel); |
| 182 return true; |
| 183 case CTRL | KeyEvent.KEYCODE_F: |
| 184 case CTRL | KeyEvent.KEYCODE_G: |
| 185 case CTRL | SHIFT | KeyEvent.KEYCODE_G: |
| 186 case KeyEvent.KEYCODE_F3: |
| 187 case SHIFT | KeyEvent.KEYCODE_F3: |
| 188 activity.onMenuOrKeyboardAction(R.id.find_in_page_id, false)
; |
| 189 return true; |
| 190 case CTRL | KeyEvent.KEYCODE_L: |
| 191 case ALT | KeyEvent.KEYCODE_D: |
| 192 activity.onMenuOrKeyboardAction(R.id.focus_url_bar, false); |
| 193 return true; |
| 194 case KeyEvent.KEYCODE_BOOKMARK: |
| 195 case CTRL | KeyEvent.KEYCODE_D: |
| 196 activity.onMenuOrKeyboardAction(R.id.bookmark_this_page_id,
false); |
| 197 return true; |
| 198 case CTRL | KeyEvent.KEYCODE_P: |
| 199 activity.onMenuOrKeyboardAction(R.id.print_id, false); |
| 200 return true; |
| 201 case CTRL | KeyEvent.KEYCODE_PLUS: |
| 202 case CTRL | KeyEvent.KEYCODE_EQUALS: |
| 203 case CTRL | SHIFT | KeyEvent.KEYCODE_PLUS: |
| 204 case CTRL | SHIFT | KeyEvent.KEYCODE_EQUALS: |
| 205 case KeyEvent.KEYCODE_ZOOM_IN: |
| 206 ContentViewCore cvc = activity.getCurrentContentViewCore(); |
| 207 if (cvc != null) cvc.zoomIn(); |
| 208 return true; |
| 209 case CTRL | KeyEvent.KEYCODE_MINUS: |
| 210 case KeyEvent.KEYCODE_ZOOM_OUT: |
| 211 cvc = activity.getCurrentContentViewCore(); |
| 212 if (cvc != null) cvc.zoomOut(); |
| 213 return true; |
| 214 case CTRL | KeyEvent.KEYCODE_0: |
| 215 cvc = activity.getCurrentContentViewCore(); |
| 216 if (cvc != null) cvc.zoomReset(); |
| 217 return true; |
| 218 case CTRL | KeyEvent.KEYCODE_R: |
| 219 case KeyEvent.KEYCODE_F5: |
| 220 Tab tab = activity.getActivityTab(); |
| 221 if (tab != null) tab.reload(); |
| 222 return true; |
| 223 case ALT | KeyEvent.KEYCODE_DPAD_LEFT: |
| 224 tab = activity.getActivityTab(); |
| 225 if (tab != null && tab.canGoBack()) tab.goBack(); |
| 226 return true; |
| 227 case ALT | KeyEvent.KEYCODE_DPAD_RIGHT: |
| 228 tab = activity.getActivityTab(); |
| 229 if (tab != null && tab.canGoForward()) tab.goForward(); |
| 230 return true; |
| 231 case CTRL | SHIFT | KeyEvent.KEYCODE_SLASH: // i.e. Ctrl+? |
| 232 activity.onMenuOrKeyboardAction(R.id.help_id, false); |
| 233 return true; |
| 234 } |
| 235 } |
| 236 |
| 237 return false; |
| 238 } |
| 239 } |
OLD | NEW |