accelerator_controller.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Use of this source code is governed by a BSD-style license that can be 3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// found in the LICENSE file. 4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/accelerators/accelerator_controller.h" 6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <algorithm> 8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <cmath> 9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <iostream> 10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <string> 11b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 12b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/accelerators/accelerator_table.h" 13b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/ash_switches.h" 14471ae72f18e7b23a96b245dbd508386fe139449cpbos@webrtc.org#include "ash/caps_lock_delegate.h" 15471ae72f18e7b23a96b245dbd508386fe139449cpbos@webrtc.org#include "ash/debug.h" 16b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/desktop_background/desktop_background_controller.h" 17b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/desktop_background/user_wallpaper_delegate.h" 18b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/display/display_controller.h" 19b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/display/display_manager.h" 20b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/focus_cycler.h" 21b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/ime_control_delegate.h" 22b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/launcher/launcher.h" 23b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/launcher/launcher_delegate.h" 24b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/launcher/launcher_model.h" 25b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/magnifier/magnification_controller.h" 26b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/magnifier/partial_magnification_controller.h" 27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/root_window_controller.h" 28b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/rotator/screen_rotation.h" 29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/screenshot_delegate.h" 30b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/session_state_delegate.h" 3154f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.org#include "ash/shelf/shelf_widget.h" 32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/shell.h" 33ca7a9a2696d2f73f543241093c4faeb4c608678cpbos@webrtc.org#include "ash/shell_delegate.h" 34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/shell_window_ids.h" 3554f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.org#include "ash/system/brightness/brightness_control_delegate.h" 36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/system/keyboard_brightness/keyboard_brightness_control_delegate.h" 3754f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.org#include "ash/system/status_area_widget.h" 38b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/system/tray/system_tray.h" 3954f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.org#include "ash/system/tray/system_tray_delegate.h" 4054f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.org#include "ash/system/tray/system_tray_notifier.h" 41b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/system/web_notification/web_notification_tray.h" 42ca7a9a2696d2f73f543241093c4faeb4c608678cpbos@webrtc.org#include "ash/touch/touch_hud_debug.h" 43b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/volume_control_delegate.h" 44b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/wm/partial_screenshot_view.h" 45b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/wm/power_button_controller.h" 46b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/wm/property_util.h" 47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/wm/window_cycle_controller.h" 48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/wm/window_util.h" 49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ash/wm/workspace/snap_sizer.h" 50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "base/bind.h" 51ca7a9a2696d2f73f543241093c4faeb4c608678cpbos@webrtc.org#include "base/command_line.h" 52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "content/public/browser/gpu_data_manager.h" 53b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ui/aura/env.h" 54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ui/aura/root_window.h" 55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ui/base/accelerators/accelerator.h" 56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ui/base/accelerators/accelerator_manager.h" 5754f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.org#include "ui/base/events/event.h" 58b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ui/base/keycodes/keyboard_codes.h" 59b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ui/compositor/debug_utils.h" 60b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ui/compositor/layer.h" 6154f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.org#include "ui/compositor/layer_animation_sequence.h" 62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ui/compositor/layer_animator.h" 63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ui/gfx/screen.h" 64b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ui/oak/oak.h" 65b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ui/views/controls/webview/webview.h" 66b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ui/views/debug_utils.h" 67b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "ui/views/widget/widget.h" 68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 69b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#if defined(OS_CHROMEOS) 7054f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.org#include "ash/system/chromeos/keyboard_brightness_controller.h" 71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include "base/chromeos/chromeos_version.h" 72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#endif // defined(OS_CHROMEOS) 73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace ash { 75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace { 76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgusing internal::DisplayInfo; 78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 79b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool DebugShortcutsEnabled() { 80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#if defined(NDEBUG) 81b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return CommandLine::ForCurrentProcess()->HasSwitch( 82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org switches::kAshDebugShortcuts); 83b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#else 84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return true; 853b89e10f31160da35b408fd00cb8f89d2b08862dpbos@webrtc.org#endif 86b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 873b89e10f31160da35b408fd00cb8f89d2b08862dpbos@webrtc.org 88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool HandleCycleWindowMRU(WindowCycleController::Direction direction, 89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool is_alt_down) { 90 Shell::GetInstance()-> 91 window_cycle_controller()->HandleCycleWindow(direction, is_alt_down); 92 // Always report we handled the key, even if the window didn't change. 93 return true; 94} 95 96void HandleCycleWindowLinear(CycleDirection direction) { 97 Shell::GetInstance()-> 98 window_cycle_controller()->HandleLinearCycleWindow(); 99} 100 101bool HandleAccessibleFocusCycle(bool reverse) { 102 if (!Shell::GetInstance()->delegate()->IsSpokenFeedbackEnabled()) 103 return false; 104 aura::Window* active_window = ash::wm::GetActiveWindow(); 105 if (!active_window) 106 return false; 107 views::Widget* widget = 108 views::Widget::GetWidgetForNativeWindow(active_window); 109 if (!widget) 110 return false; 111 views::FocusManager* focus_manager = widget->GetFocusManager(); 112 if (!focus_manager) 113 return false; 114 views::View* view = focus_manager->GetFocusedView(); 115 if (!view) 116 return false; 117 if (!strcmp(view->GetClassName(), views::WebView::kViewClassName)) 118 return false; 119 120 focus_manager->AdvanceFocus(reverse); 121 return true; 122} 123 124void HandleSilenceSpokenFeedback() { 125 if (!Shell::GetInstance()->delegate()->IsSpokenFeedbackEnabled()) 126 return; 127 128 Shell::GetInstance()->delegate()->SilenceSpokenFeedback(); 129} 130 131#if defined(OS_CHROMEOS) 132bool HandleLock() { 133 Shell::GetInstance()->session_state_delegate()->LockScreen(); 134 return true; 135} 136 137bool HandleFileManager(bool as_dialog) { 138 Shell::GetInstance()->delegate()->OpenFileManager(as_dialog); 139 return true; 140} 141 142bool HandleCrosh() { 143 Shell::GetInstance()->delegate()->OpenCrosh(); 144 return true; 145} 146 147bool HandleToggleSpokenFeedback() { 148 Shell::GetInstance()->delegate()-> 149 ToggleSpokenFeedback(A11Y_NOTIFICATION_SHOW); 150 return true; 151} 152 153#endif // defined(OS_CHROMEOS) 154 155bool HandleRotatePaneFocus(Shell::Direction direction) { 156 Shell* shell = Shell::GetInstance(); 157 switch (direction) { 158 case Shell::FORWARD: 159 shell->focus_cycler()->RotateFocus(internal::FocusCycler::FORWARD); 160 break; 161 case Shell::BACKWARD: 162 shell->focus_cycler()->RotateFocus(internal::FocusCycler::BACKWARD); 163 break; 164 } 165 return true; 166} 167 168// Rotate the active window. 169bool HandleRotateActiveWindow() { 170 aura::Window* active_window = wm::GetActiveWindow(); 171 if (active_window) { 172 // The rotation animation bases its target transform on the current 173 // rotation and position. Since there could be an animation in progress 174 // right now, queue this animation so when it starts it picks up a neutral 175 // rotation and position. Use replace so we only enqueue one at a time. 176 active_window->layer()->GetAnimator()-> 177 set_preemption_strategy(ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS); 178 active_window->layer()->GetAnimator()->StartAnimation( 179 new ui::LayerAnimationSequence( 180 new ash::ScreenRotation(360, active_window->layer()))); 181 } 182 return true; 183} 184 185gfx::Display::Rotation GetNextRotation(gfx::Display::Rotation current) { 186 switch (current) { 187 case gfx::Display::ROTATE_0: 188 return gfx::Display::ROTATE_90; 189 case gfx::Display::ROTATE_90: 190 return gfx::Display::ROTATE_180; 191 case gfx::Display::ROTATE_180: 192 return gfx::Display::ROTATE_270; 193 case gfx::Display::ROTATE_270: 194 return gfx::Display::ROTATE_0; 195 } 196 NOTREACHED() << "Unknown rotation:" << current; 197 return gfx::Display::ROTATE_0; 198} 199 200bool HandleScaleUI(bool up) { 201 internal::DisplayManager* display_manager = 202 Shell::GetInstance()->display_manager(); 203 int64 display_id = display_manager->GetDisplayIdForUIScaling(); 204 if (display_id == gfx::Display::kInvalidDisplayID) 205 return false; 206 const DisplayInfo& display_info = display_manager->GetDisplayInfo(display_id); 207 float next_scale = 208 internal::DisplayManager::GetNextUIScale(display_info, up); 209 display_manager->SetDisplayUIScale(display_id, next_scale); 210 return true; 211} 212 213bool HandleScaleReset() { 214 internal::DisplayManager* display_manager = 215 Shell::GetInstance()->display_manager(); 216 int64 display_id = display_manager->GetDisplayIdForUIScaling(); 217 if (display_id == gfx::Display::kInvalidDisplayID) 218 return false; 219 display_manager->SetDisplayUIScale(display_id, 1.0f); 220 return true; 221} 222 223// Rotates the screen. 224bool HandleRotateScreen() { 225 gfx::Point point = Shell::GetScreen()->GetCursorScreenPoint(); 226 gfx::Display display = Shell::GetScreen()->GetDisplayNearestPoint(point); 227 const DisplayInfo& display_info = 228 Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id()); 229 Shell::GetInstance()->display_manager()->SetDisplayRotation( 230 display.id(), GetNextRotation(display_info.rotation())); 231 return true; 232} 233 234bool HandleToggleDesktopBackgroundMode() { 235 DesktopBackgroundController* desktop_background_controller = 236 Shell::GetInstance()->desktop_background_controller(); 237 if (desktop_background_controller->desktop_background_mode() == 238 DesktopBackgroundController::BACKGROUND_IMAGE) { 239 desktop_background_controller->SetDesktopBackgroundSolidColorMode( 240 SK_ColorBLACK); 241 } else { 242 ash::Shell::GetInstance()->user_wallpaper_delegate()-> 243 InitializeWallpaper(); 244 } 245 return true; 246} 247 248bool HandleToggleRootWindowFullScreen() { 249 Shell::GetPrimaryRootWindow()->ToggleFullScreen(); 250 return true; 251} 252 253// Magnify the screen 254bool HandleMagnifyScreen(int delta_index) { 255 if (ash::Shell::GetInstance()->magnification_controller()->IsEnabled()) { 256 // TODO(yoshiki): Move the following logic to MagnificationController. 257 float scale = 258 ash::Shell::GetInstance()->magnification_controller()->GetScale(); 259 // Calculate rounded logarithm (base kMagnificationScaleFactor) of scale. 260 int scale_index = 261 std::floor(std::log(scale) / std::log(kMagnificationScaleFactor) + 0.5); 262 263 int new_scale_index = std::max(0, std::min(8, scale_index + delta_index)); 264 265 ash::Shell::GetInstance()->magnification_controller()-> 266 SetScale(std::pow(kMagnificationScaleFactor, new_scale_index), true); 267 } else if (ash::Shell::GetInstance()-> 268 partial_magnification_controller()->is_enabled()) { 269 float scale = delta_index > 0 ? kDefaultPartialMagnifiedScale : 1; 270 ash::Shell::GetInstance()->partial_magnification_controller()-> 271 SetScale(scale); 272 } 273 274 return true; 275} 276 277bool HandleMediaNextTrack() { 278 Shell::GetInstance()->delegate()->HandleMediaNextTrack(); 279 return true; 280} 281 282bool HandleMediaPlayPause() { 283 Shell::GetInstance()->delegate()->HandleMediaPlayPause(); 284 return true; 285} 286 287bool HandleMediaPrevTrack() { 288 Shell::GetInstance()->delegate()->HandleMediaPrevTrack(); 289 return true; 290} 291 292bool HandlePrintLayerHierarchy() { 293 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); 294 for (size_t i = 0; i < root_windows.size(); ++i) { 295 ui::PrintLayerHierarchy(root_windows[i]->layer(), 296 root_windows[i]->GetLastMouseLocationInRoot()); 297 } 298 return true; 299} 300 301bool HandlePrintViewHierarchy() { 302 aura::Window* active_window = ash::wm::GetActiveWindow(); 303 if (!active_window) 304 return true; 305 views::Widget* browser_widget = 306 views::Widget::GetWidgetForNativeWindow(active_window); 307 if (!browser_widget) 308 return true; 309 views::PrintViewHierarchy(browser_widget->GetRootView()); 310 return true; 311} 312 313void PrintWindowHierarchy(aura::Window* window, 314 int indent, 315 std::ostringstream* out) { 316 std::string indent_str(indent, ' '); 317 std::string name(window->name()); 318 if (name.empty()) 319 name = "\"\""; 320 *out << indent_str << name << " (" << window << ")" 321 << " type=" << window->type() 322 << (wm::IsActiveWindow(window) ? " [active] " : " ") 323 << (window->IsVisible() ? " visible " : " ") 324 << window->bounds().ToString() 325 << '\n'; 326 327 for (size_t i = 0; i < window->children().size(); ++i) 328 PrintWindowHierarchy(window->children()[i], indent + 3, out); 329} 330 331bool HandlePrintWindowHierarchy() { 332 Shell::RootWindowControllerList controllers = 333 Shell::GetAllRootWindowControllers(); 334 for (size_t i = 0; i < controllers.size(); ++i) { 335 std::ostringstream out; 336 out << "RootWindow " << i << ":\n"; 337 PrintWindowHierarchy(controllers[i]->root_window(), 0, &out); 338 // Error so logs can be collected from end-users. 339 LOG(ERROR) << out.str(); 340 } 341 return true; 342} 343 344bool HandlePrintUIHierarchies() { 345 // This is a separate command so the user only has to hit one key to generate 346 // all the logs. Developers use the individual dumps repeatedly, so keep 347 // those as separate commands to avoid spamming their logs. 348 HandlePrintLayerHierarchy(); 349 HandlePrintWindowHierarchy(); 350 HandlePrintViewHierarchy(); 351 return true; 352} 353 354} // namespace 355 356//////////////////////////////////////////////////////////////////////////////// 357// AcceleratorControllerContext, public: 358 359AcceleratorControllerContext::AcceleratorControllerContext() { 360 current_accelerator_.set_type(ui::ET_UNKNOWN); 361 previous_accelerator_.set_type(ui::ET_UNKNOWN); 362} 363 364void AcceleratorControllerContext::UpdateContext( 365 const ui::Accelerator& accelerator) { 366 previous_accelerator_ = current_accelerator_; 367 current_accelerator_ = accelerator; 368} 369 370//////////////////////////////////////////////////////////////////////////////// 371// AcceleratorController, public: 372 373AcceleratorController::AcceleratorController() 374 : accelerator_manager_(new ui::AcceleratorManager) { 375 Init(); 376} 377 378AcceleratorController::~AcceleratorController() { 379} 380 381void AcceleratorController::Init() { 382 for (size_t i = 0; i < kActionsAllowedAtLoginOrLockScreenLength; ++i) { 383 actions_allowed_at_login_screen_.insert( 384 kActionsAllowedAtLoginOrLockScreen[i]); 385 actions_allowed_at_lock_screen_.insert( 386 kActionsAllowedAtLoginOrLockScreen[i]); 387 } 388 for (size_t i = 0; i < kActionsAllowedAtLockScreenLength; ++i) 389 actions_allowed_at_lock_screen_.insert(kActionsAllowedAtLockScreen[i]); 390 for (size_t i = 0; i < kActionsAllowedAtModalWindowLength; ++i) 391 actions_allowed_at_modal_window_.insert(kActionsAllowedAtModalWindow[i]); 392 for (size_t i = 0; i < kReservedActionsLength; ++i) 393 reserved_actions_.insert(kReservedActions[i]); 394 for (size_t i = 0; i < kNonrepeatableActionsLength; ++i) 395 nonrepeatable_actions_.insert(kNonrepeatableActions[i]); 396 for (size_t i = 0; i < kActionsAllowedInAppModeLength; ++i) 397 actions_allowed_in_app_mode_.insert(kActionsAllowedInAppMode[i]); 398 399 RegisterAccelerators(kAcceleratorData, kAcceleratorDataLength); 400 401#if !defined(NDEBUG) 402 RegisterAccelerators(kDesktopAcceleratorData, kDesktopAcceleratorDataLength); 403#endif 404 405 if (DebugShortcutsEnabled()) { 406 RegisterAccelerators(kDebugAcceleratorData, kDebugAcceleratorDataLength); 407 for (size_t i = 0; i < kReservedDebugActionsLength; ++i) 408 reserved_actions_.insert(kReservedDebugActions[i]); 409 } 410 411#if defined(OS_CHROMEOS) 412 keyboard_brightness_control_delegate_.reset( 413 new KeyboardBrightnessController()); 414#endif 415} 416 417void AcceleratorController::Register(const ui::Accelerator& accelerator, 418 ui::AcceleratorTarget* target) { 419 accelerator_manager_->Register(accelerator, 420 ui::AcceleratorManager::kNormalPriority, 421 target); 422} 423 424void AcceleratorController::Unregister(const ui::Accelerator& accelerator, 425 ui::AcceleratorTarget* target) { 426 accelerator_manager_->Unregister(accelerator, target); 427} 428 429void AcceleratorController::UnregisterAll(ui::AcceleratorTarget* target) { 430 accelerator_manager_->UnregisterAll(target); 431} 432 433bool AcceleratorController::Process(const ui::Accelerator& accelerator) { 434 if (ime_control_delegate_) { 435 return accelerator_manager_->Process( 436 ime_control_delegate_->RemapAccelerator(accelerator)); 437 } 438 return accelerator_manager_->Process(accelerator); 439} 440 441bool AcceleratorController::IsRegistered( 442 const ui::Accelerator& accelerator) const { 443 return accelerator_manager_->GetCurrentTarget(accelerator) != NULL; 444} 445 446bool AcceleratorController::IsReservedAccelerator( 447 const ui::Accelerator& accelerator) const { 448 const ui::Accelerator remapped_accelerator = ime_control_delegate_.get() ? 449 ime_control_delegate_->RemapAccelerator(accelerator) : accelerator; 450 451 std::map<ui::Accelerator, int>::const_iterator iter = 452 accelerators_.find(remapped_accelerator); 453 if (iter == accelerators_.end()) 454 return false; // not an accelerator. 455 456 return reserved_actions_.find(iter->second) != reserved_actions_.end(); 457} 458 459bool AcceleratorController::PerformAction(int action, 460 const ui::Accelerator& accelerator) { 461 ash::Shell* shell = ash::Shell::GetInstance(); 462 if (!shell->session_state_delegate()->IsActiveUserSessionStarted() && 463 actions_allowed_at_login_screen_.find(action) == 464 actions_allowed_at_login_screen_.end()) { 465 return false; 466 } 467 if (shell->session_state_delegate()->IsScreenLocked() && 468 actions_allowed_at_lock_screen_.find(action) == 469 actions_allowed_at_lock_screen_.end()) { 470 return false; 471 } 472 if (shell->IsSystemModalWindowOpen() && 473 actions_allowed_at_modal_window_.find(action) == 474 actions_allowed_at_modal_window_.end()) { 475 // Note: we return true. This indicates the shortcut is handled 476 // and will not be passed to the modal window. This is important 477 // for things like Alt+Tab that would cause an undesired effect 478 // in the modal window by cycling through its window elements. 479 return true; 480 } 481 if (shell->delegate()->IsRunningInForcedAppMode() && 482 actions_allowed_in_app_mode_.find(action) == 483 actions_allowed_in_app_mode_.end()) { 484 return false; 485 } 486 487 const ui::KeyboardCode key_code = accelerator.key_code(); 488 // PerformAction() is performed from gesture controllers and passes 489 // empty Accelerator() instance as the second argument. Such events 490 // should never be suspended. 491 const bool gesture_event = key_code == ui::VKEY_UNKNOWN; 492 493 // Ignore accelerators invoked as repeated (while holding a key for a long 494 // time, if their handling is nonrepeatable. 495 if (nonrepeatable_actions_.find(action) != nonrepeatable_actions_.end() && 496 context_.repeated() && !gesture_event) { 497 return true; 498 } 499 // Type of the previous accelerator. Used by NEXT_IME and DISABLE_CAPS_LOCK. 500 const ui::EventType previous_event_type = 501 context_.previous_accelerator().type(); 502 const ui::KeyboardCode previous_key_code = 503 context_.previous_accelerator().key_code(); 504 505 // You *MUST* return true when some action is performed. Otherwise, this 506 // function might be called *twice*, via BrowserView::PreHandleKeyboardEvent 507 // and BrowserView::HandleKeyboardEvent, for a single accelerator press. 508 switch (action) { 509 case ACCESSIBLE_FOCUS_NEXT: 510 return HandleAccessibleFocusCycle(false); 511 case ACCESSIBLE_FOCUS_PREVIOUS: 512 return HandleAccessibleFocusCycle(true); 513 case CYCLE_BACKWARD_MRU: 514 if (key_code == ui::VKEY_TAB) 515 shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_PREVWINDOW_TAB); 516 return HandleCycleWindowMRU(WindowCycleController::BACKWARD, 517 accelerator.IsAltDown()); 518 case CYCLE_FORWARD_MRU: 519 if (key_code == ui::VKEY_TAB) 520 shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_NEXTWINDOW_TAB); 521 return HandleCycleWindowMRU(WindowCycleController::FORWARD, 522 accelerator.IsAltDown()); 523 case CYCLE_BACKWARD_LINEAR: 524 if (key_code == ui::VKEY_MEDIA_LAUNCH_APP1) 525 shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_PREVWINDOW_F5); 526 HandleCycleWindowLinear(CYCLE_BACKWARD); 527 return true; 528 case CYCLE_FORWARD_LINEAR: 529 if (key_code == ui::VKEY_MEDIA_LAUNCH_APP1) 530 shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_NEXTWINDOW_F5); 531 HandleCycleWindowLinear(CYCLE_FORWARD); 532 return true; 533#if defined(OS_CHROMEOS) 534 case ADD_REMOVE_DISPLAY: 535 Shell::GetInstance()->display_manager()->AddRemoveDisplay(); 536 return true; 537 case TOGGLE_MIRROR_MODE: 538 Shell::GetInstance()->display_controller()->ToggleMirrorMode(); 539 return true; 540 case LOCK_SCREEN: 541 if (key_code == ui::VKEY_L) 542 shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_LOCK_SCREEN_L); 543 return HandleLock(); 544 case OPEN_FILE_DIALOG: 545 return HandleFileManager(true /* as_dialog */); 546 case OPEN_FILE_MANAGER: 547 return HandleFileManager(false /* as_dialog */); 548 case OPEN_CROSH: 549 return HandleCrosh(); 550 case SILENCE_SPOKEN_FEEDBACK: 551 HandleSilenceSpokenFeedback(); 552 break; 553 case SWAP_PRIMARY_DISPLAY: 554 Shell::GetInstance()->display_controller()->SwapPrimaryDisplay(); 555 return true; 556 case TOGGLE_SPOKEN_FEEDBACK: 557 return HandleToggleSpokenFeedback(); 558 case TOGGLE_WIFI: 559 Shell::GetInstance()->system_tray_notifier()->NotifyRequestToggleWifi(); 560 return true; 561 case TOUCH_HUD_CLEAR: { 562 internal::RootWindowController* controller = 563 internal::RootWindowController::ForActiveRootWindow(); 564 if (controller->touch_hud_debug()) { 565 controller->touch_hud_debug()->Clear(); 566 return true; 567 } 568 return false; 569 } 570 case TOUCH_HUD_MODE_CHANGE: { 571 internal::RootWindowController* controller = 572 internal::RootWindowController::ForActiveRootWindow(); 573 if (controller->touch_hud_debug()) { 574 controller->touch_hud_debug()->ChangeToNextMode(); 575 return true; 576 } 577 return false; 578 } 579 case TOUCH_HUD_PROJECTION_TOGGLE: { 580 bool enabled = Shell::GetInstance()->is_touch_hud_projection_enabled(); 581 Shell::GetInstance()->SetTouchHudProjectionEnabled(!enabled); 582 return true; 583 } 584 case DISABLE_GPU_WATCHDOG: 585 content::GpuDataManager::GetInstance()->DisableGpuWatchdog(); 586 return true; 587#endif 588 case OPEN_FEEDBACK_PAGE: 589 ash::Shell::GetInstance()->delegate()->OpenFeedbackPage(); 590 return true; 591 case EXIT: 592 // UMA metrics are recorded in the handler. 593 exit_warning_handler_.HandleAccelerator(); 594 return true; 595 case NEW_INCOGNITO_WINDOW: 596 Shell::GetInstance()->delegate()->NewWindow(true /* is_incognito */); 597 return true; 598 case NEW_TAB: 599 if (key_code == ui::VKEY_T) 600 shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_NEWTAB_T); 601 Shell::GetInstance()->delegate()->NewTab(); 602 return true; 603 case NEW_WINDOW: 604 Shell::GetInstance()->delegate()->NewWindow(false /* is_incognito */); 605 return true; 606 case RESTORE_TAB: 607 Shell::GetInstance()->delegate()->RestoreTab(); 608 return true; 609 case TAKE_SCREENSHOT: 610 if (screenshot_delegate_.get() && 611 screenshot_delegate_->CanTakeScreenshot()) { 612 screenshot_delegate_->HandleTakeScreenshotForAllRootWindows(); 613 } 614 // Return true to prevent propagation of the key event. 615 return true; 616 case TAKE_PARTIAL_SCREENSHOT: 617 if (screenshot_delegate_) { 618 ash::PartialScreenshotView::StartPartialScreenshot( 619 screenshot_delegate_.get()); 620 } 621 // Return true to prevent propagation of the key event because 622 // this key combination is reserved for partial screenshot. 623 return true; 624 case TOGGLE_APP_LIST: 625 // If something else was pressed between the Search key (LWIN) 626 // being pressed and released, then ignore the release of the 627 // Search key. 628 if (key_code == ui::VKEY_LWIN && 629 (previous_event_type == ui::ET_KEY_RELEASED || 630 previous_key_code != ui::VKEY_LWIN)) 631 return false; 632 if (key_code == ui::VKEY_LWIN) 633 shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_SEARCH_LWIN); 634 // When spoken feedback is enabled, we should neither toggle the list nor 635 // consume the key since Search+Shift is one of the shortcuts the a11y 636 // feature uses. crbug.com/132296 637 DCHECK_EQ(ui::VKEY_LWIN, accelerator.key_code()); 638 if (Shell::GetInstance()->delegate()->IsSpokenFeedbackEnabled()) 639 return false; 640 ash::Shell::GetInstance()->ToggleAppList(NULL); 641 return true; 642 case DISABLE_CAPS_LOCK: 643 if (previous_event_type == ui::ET_KEY_RELEASED || 644 (previous_key_code != ui::VKEY_LSHIFT && 645 previous_key_code != ui::VKEY_SHIFT && 646 previous_key_code != ui::VKEY_RSHIFT)) { 647 // If something else was pressed between the Shift key being pressed 648 // and released, then ignore the release of the Shift key. 649 return false; 650 } 651 if (shell->caps_lock_delegate()->IsCapsLockEnabled()) { 652 shell->caps_lock_delegate()->SetCapsLockEnabled(false); 653 return true; 654 } 655 return false; 656 case TOGGLE_CAPS_LOCK: 657 if (key_code == ui::VKEY_LWIN) { 658 // If something else was pressed between the Search key (LWIN) 659 // being pressed and released, then ignore the release of the 660 // Search key. 661 // TODO(danakj): Releasing Alt first breaks this: crbug.com/166495 662 if (previous_event_type == ui::ET_KEY_RELEASED || 663 previous_key_code != ui::VKEY_LWIN) 664 return false; 665 } 666 shell->caps_lock_delegate()->ToggleCapsLock(); 667 return true; 668 case BRIGHTNESS_DOWN: 669 if (brightness_control_delegate_) 670 return brightness_control_delegate_->HandleBrightnessDown(accelerator); 671 break; 672 case BRIGHTNESS_UP: 673 if (brightness_control_delegate_) 674 return brightness_control_delegate_->HandleBrightnessUp(accelerator); 675 break; 676 case KEYBOARD_BRIGHTNESS_DOWN: 677 if (keyboard_brightness_control_delegate_) 678 return keyboard_brightness_control_delegate_-> 679 HandleKeyboardBrightnessDown(accelerator); 680 break; 681 case KEYBOARD_BRIGHTNESS_UP: 682 if (keyboard_brightness_control_delegate_) 683 return keyboard_brightness_control_delegate_-> 684 HandleKeyboardBrightnessUp(accelerator); 685 break; 686 case VOLUME_MUTE: 687 return shell->system_tray_delegate()->GetVolumeControlDelegate()-> 688 HandleVolumeMute(accelerator); 689 break; 690 case VOLUME_DOWN: 691 return shell->system_tray_delegate()->GetVolumeControlDelegate()-> 692 HandleVolumeDown(accelerator); 693 break; 694 case VOLUME_UP: 695 return shell->system_tray_delegate()->GetVolumeControlDelegate()-> 696 HandleVolumeUp(accelerator); 697 break; 698 case FOCUS_LAUNCHER: 699 return shell->focus_cycler()->FocusWidget( 700 Launcher::ForPrimaryDisplay()->shelf_widget()); 701 break; 702 case FOCUS_NEXT_PANE: 703 return HandleRotatePaneFocus(Shell::FORWARD); 704 case FOCUS_PREVIOUS_PANE: 705 return HandleRotatePaneFocus(Shell::BACKWARD); 706 case SHOW_KEYBOARD_OVERLAY: 707 ash::Shell::GetInstance()->delegate()->ShowKeyboardOverlay(); 708 return true; 709 case SHOW_OAK: 710 if (CommandLine::ForCurrentProcess()->HasSwitch( 711 switches::kAshEnableOak)) { 712 oak::ShowOakWindowWithContext(Shell::GetPrimaryRootWindow()); 713 return true; 714 } 715 break; 716 case SHOW_SYSTEM_TRAY_BUBBLE: { 717 internal::RootWindowController* controller = 718 internal::RootWindowController::ForActiveRootWindow(); 719 if (!controller->GetSystemTray()->HasSystemBubble()) 720 controller->GetSystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW); 721 break; 722 } 723 case SHOW_MESSAGE_CENTER_BUBBLE: { 724 internal::RootWindowController* controller = 725 internal::RootWindowController::ForActiveRootWindow(); 726 internal::StatusAreaWidget* status_area_widget = 727 controller->shelf()->status_area_widget(); 728 if (status_area_widget) { 729 WebNotificationTray* notification_tray = 730 status_area_widget->web_notification_tray(); 731 if (notification_tray->visible()) 732 notification_tray->ShowMessageCenterBubble(); 733 } 734 break; 735 } 736 case SHOW_TASK_MANAGER: 737 Shell::GetInstance()->delegate()->ShowTaskManager(); 738 return true; 739 case NEXT_IME: 740 // This check is necessary e.g. not to process the Shift+Alt+ 741 // ET_KEY_RELEASED accelerator for Chrome OS (see ash/accelerators/ 742 // accelerator_controller.cc) when Shift+Alt+Tab is pressed and then Tab 743 // is released. 744 if (previous_event_type == ui::ET_KEY_RELEASED && 745 // Workaround for crbug.com/139556. CJK IME users tend to press 746 // Enter (or Space) and Shift+Alt almost at the same time to commit 747 // an IME string and then switch from the IME to the English layout. 748 // This workaround allows the user to trigger NEXT_IME even if the 749 // user presses Shift+Alt before releasing Enter. 750 // TODO(nona|mazda): Fix crbug.com/139556 in a cleaner way. 751 previous_key_code != ui::VKEY_RETURN && 752 previous_key_code != ui::VKEY_SPACE) { 753 // We totally ignore this accelerator. 754 // TODO(mazda): Fix crbug.com/158217 755 return false; 756 } 757 if (ime_control_delegate_) 758 return ime_control_delegate_->HandleNextIme(); 759 break; 760 case PREVIOUS_IME: 761 if (ime_control_delegate_) 762 return ime_control_delegate_->HandlePreviousIme(); 763 break; 764 case PRINT_UI_HIERARCHIES: 765 return HandlePrintUIHierarchies(); 766 case SWITCH_IME: 767 if (ime_control_delegate_) 768 return ime_control_delegate_->HandleSwitchIme(accelerator); 769 break; 770 case LAUNCH_APP_0: 771 Launcher::ForPrimaryDisplay()->LaunchAppIndexAt(0); 772 return true; 773 case LAUNCH_APP_1: 774 Launcher::ForPrimaryDisplay()->LaunchAppIndexAt(1); 775 return true; 776 case LAUNCH_APP_2: 777 Launcher::ForPrimaryDisplay()->LaunchAppIndexAt(2); 778 return true; 779 case LAUNCH_APP_3: 780 Launcher::ForPrimaryDisplay()->LaunchAppIndexAt(3); 781 return true; 782 case LAUNCH_APP_4: 783 Launcher::ForPrimaryDisplay()->LaunchAppIndexAt(4); 784 return true; 785 case LAUNCH_APP_5: 786 Launcher::ForPrimaryDisplay()->LaunchAppIndexAt(5); 787 return true; 788 case LAUNCH_APP_6: 789 Launcher::ForPrimaryDisplay()->LaunchAppIndexAt(6); 790 return true; 791 case LAUNCH_APP_7: 792 Launcher::ForPrimaryDisplay()->LaunchAppIndexAt(7); 793 return true; 794 case LAUNCH_LAST_APP: 795 Launcher::ForPrimaryDisplay()->LaunchAppIndexAt(-1); 796 return true; 797 case WINDOW_SNAP_LEFT: 798 case WINDOW_SNAP_RIGHT: { 799 aura::Window* window = wm::GetActiveWindow(); 800 // Disable window docking shortcut key for full screen window due to 801 // http://crbug.com/135487. 802 if (!window || 803 window->type() != aura::client::WINDOW_TYPE_NORMAL || 804 wm::IsWindowFullscreen(window)) { 805 break; 806 } 807 808 internal::SnapSizer::SnapWindow(window, 809 action == WINDOW_SNAP_LEFT ? internal::SnapSizer::LEFT_EDGE : 810 internal::SnapSizer::RIGHT_EDGE); 811 return true; 812 } 813 case WINDOW_MINIMIZE: { 814 aura::Window* window = wm::GetActiveWindow(); 815 // Attempt to restore the window that would be cycled through next from 816 // the launcher when there is no active window. 817 if (!window) 818 return HandleCycleWindowMRU(WindowCycleController::FORWARD, false); 819 // Disable the shortcut for minimizing full screen window due to 820 // crbug.com/131709, which is a crashing issue related to minimizing 821 // full screen pepper window. 822 if (!wm::IsWindowFullscreen(window) && wm::CanMinimizeWindow(window)) { 823 ash::Shell::GetInstance()->delegate()->RecordUserMetricsAction( 824 ash::UMA_MINIMIZE_PER_KEY); 825 wm::MinimizeWindow(window); 826 return true; 827 } 828 break; 829 } 830 case TOGGLE_FULLSCREEN: { 831 if (key_code == ui::VKEY_MEDIA_LAUNCH_APP2) { 832 shell->delegate()->RecordUserMetricsAction( 833 UMA_ACCEL_FULLSCREEN_F4); 834 } 835 shell->delegate()->ToggleFullscreen(); 836 return true; 837 } 838 case TOGGLE_MAXIMIZED: { 839 shell->delegate()->ToggleMaximized(); 840 return true; 841 } 842 case WINDOW_POSITION_CENTER: { 843 aura::Window* window = wm::GetActiveWindow(); 844 if (window) { 845 wm::CenterWindow(window); 846 return true; 847 } 848 break; 849 } 850 case SCALE_UI_UP: 851 return HandleScaleUI(true /* up */); 852 case SCALE_UI_DOWN: 853 return HandleScaleUI(false /* down */); 854 case SCALE_UI_RESET: 855 return HandleScaleReset(); 856 case ROTATE_WINDOW: 857 return HandleRotateActiveWindow(); 858 case ROTATE_SCREEN: 859 return HandleRotateScreen(); 860 case TOGGLE_DESKTOP_BACKGROUND_MODE: 861 return HandleToggleDesktopBackgroundMode(); 862 case TOGGLE_ROOT_WINDOW_FULL_SCREEN: 863 return HandleToggleRootWindowFullScreen(); 864 case DEBUG_TOGGLE_DEVICE_SCALE_FACTOR: 865 Shell::GetInstance()->display_manager()->ToggleDisplayScaleFactor(); 866 return true; 867 case DEBUG_TOGGLE_SHOW_DEBUG_BORDERS: 868 ash::debug::ToggleShowDebugBorders(); 869 return true; 870 case DEBUG_TOGGLE_SHOW_FPS_COUNTER: 871 ash::debug::ToggleShowFpsCounter(); 872 return true; 873 case DEBUG_TOGGLE_SHOW_PAINT_RECTS: 874 ash::debug::ToggleShowPaintRects(); 875 return true; 876 case MAGNIFY_SCREEN_ZOOM_IN: 877 return HandleMagnifyScreen(1); 878 case MAGNIFY_SCREEN_ZOOM_OUT: 879 return HandleMagnifyScreen(-1); 880 case MEDIA_NEXT_TRACK: 881 return HandleMediaNextTrack(); 882 case MEDIA_PLAY_PAUSE: 883 return HandleMediaPlayPause(); 884 case MEDIA_PREV_TRACK: 885 return HandleMediaPrevTrack(); 886 case POWER_PRESSED: // fallthrough 887 case POWER_RELEASED: 888#if defined(OS_CHROMEOS) 889 if (!base::chromeos::IsRunningOnChromeOS()) { 890 // There is no powerd in linux desktop, so call the 891 // PowerButtonController here. 892 Shell::GetInstance()->power_button_controller()-> 893 OnPowerButtonEvent(action == POWER_PRESSED, base::TimeTicks()); 894 } 895#endif 896 // We don't do anything with these at present on the device, 897 // (power button events are reported to us from powerm via 898 // D-BUS), but we consume them to prevent them from getting 899 // passed to apps -- see http://crbug.com/146609. 900 return true; 901 case LOCK_PRESSED: 902 case LOCK_RELEASED: 903 Shell::GetInstance()->power_button_controller()-> 904 OnLockButtonEvent(action == LOCK_PRESSED, base::TimeTicks()); 905 return true; 906#if !defined(NDEBUG) 907 case PRINT_LAYER_HIERARCHY: 908 return HandlePrintLayerHierarchy(); 909 case PRINT_VIEW_HIERARCHY: 910 return HandlePrintViewHierarchy(); 911 case PRINT_WINDOW_HIERARCHY: 912 return HandlePrintWindowHierarchy(); 913#endif 914 default: 915 NOTREACHED() << "Unhandled action " << action; 916 } 917 return false; 918} 919 920void AcceleratorController::SetBrightnessControlDelegate( 921 scoped_ptr<BrightnessControlDelegate> brightness_control_delegate) { 922 // Install brightness control delegate only when internal 923 // display exists. 924 if (Shell::GetInstance()->display_manager()->HasInternalDisplay() || 925 CommandLine::ForCurrentProcess()->HasSwitch( 926 switches::kAshEnableBrightnessControl)) { 927 brightness_control_delegate_ = brightness_control_delegate.Pass(); 928 } 929} 930 931void AcceleratorController::SetImeControlDelegate( 932 scoped_ptr<ImeControlDelegate> ime_control_delegate) { 933 ime_control_delegate_ = ime_control_delegate.Pass(); 934} 935 936void AcceleratorController::SetScreenshotDelegate( 937 scoped_ptr<ScreenshotDelegate> screenshot_delegate) { 938 screenshot_delegate_ = screenshot_delegate.Pass(); 939} 940 941//////////////////////////////////////////////////////////////////////////////// 942// AcceleratorController, ui::AcceleratorTarget implementation: 943 944bool AcceleratorController::AcceleratorPressed( 945 const ui::Accelerator& accelerator) { 946 std::map<ui::Accelerator, int>::const_iterator it = 947 accelerators_.find(accelerator); 948 DCHECK(it != accelerators_.end()); 949 return PerformAction(static_cast<AcceleratorAction>(it->second), accelerator); 950} 951 952void AcceleratorController::RegisterAccelerators( 953 const AcceleratorData accelerators[], 954 size_t accelerators_length) { 955 for (size_t i = 0; i < accelerators_length; ++i) { 956 ui::Accelerator accelerator(accelerators[i].keycode, 957 accelerators[i].modifiers); 958 accelerator.set_type(accelerators[i].trigger_on_press ? 959 ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED); 960 Register(accelerator, this); 961 accelerators_.insert( 962 std::make_pair(accelerator, accelerators[i].action)); 963 } 964} 965 966void AcceleratorController::SetKeyboardBrightnessControlDelegate( 967 scoped_ptr<KeyboardBrightnessControlDelegate> 968 keyboard_brightness_control_delegate) { 969 keyboard_brightness_control_delegate_ = 970 keyboard_brightness_control_delegate.Pass(); 971} 972 973bool AcceleratorController::CanHandleAccelerators() const { 974 return true; 975} 976 977} // namespace ash 978