1 // Copyright (c) 2012 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 #include "ash/accelerators/accelerator_controller_impl.h"
6 
7 #include <algorithm>
8 #include <cmath>
9 #include <string>
10 #include <utility>
11 
12 #include "ash/accelerators/accelerator_commands.h"
13 #include "ash/accelerators/accelerator_confirmation_dialog.h"
14 #include "ash/accelerators/debug_commands.h"
15 #include "ash/accessibility/accessibility_controller_impl.h"
16 #include "ash/ambient/ambient_controller.h"
17 #include "ash/app_list/app_list_controller_impl.h"
18 #include "ash/assistant/model/assistant_ui_model.h"
19 #include "ash/capture_mode/capture_mode_controller.h"
20 #include "ash/capture_mode/capture_mode_metrics.h"
21 #include "ash/clipboard/clipboard_history_controller_impl.h"
22 #include "ash/debug.h"
23 #include "ash/display/display_configuration_controller.h"
24 #include "ash/display/display_move_window_util.h"
25 #include "ash/display/privacy_screen_controller.h"
26 #include "ash/display/screen_orientation_controller.h"
27 #include "ash/focus_cycler.h"
28 #include "ash/home_screen/home_screen_controller.h"
29 #include "ash/ime/ime_controller_impl.h"
30 #include "ash/ime/ime_switch_type.h"
31 #include "ash/keyboard/ui/keyboard_ui_controller.h"
32 #include "ash/magnifier/docked_magnifier_controller_impl.h"
33 #include "ash/magnifier/magnification_controller.h"
34 #include "ash/media/media_controller_impl.h"
35 #include "ash/metrics/user_metrics_recorder.h"
36 #include "ash/multi_profile_uma.h"
37 #include "ash/public/cpp/ash_features.h"
38 #include "ash/public/cpp/ash_pref_names.h"
39 #include "ash/public/cpp/ash_switches.h"
40 #include "ash/public/cpp/assistant/controller/assistant_ui_controller.h"
41 #include "ash/public/cpp/new_window_delegate.h"
42 #include "ash/public/cpp/notification_utils.h"
43 #include "ash/public/cpp/toast_data.h"
44 #include "ash/resources/vector_icons/vector_icons.h"
45 #include "ash/root_window_controller.h"
46 #include "ash/rotator/window_rotation.h"
47 #include "ash/session/session_controller_impl.h"
48 #include "ash/shelf/home_button.h"
49 #include "ash/shelf/shelf.h"
50 #include "ash/shelf/shelf_focus_cycler.h"
51 #include "ash/shelf/shelf_navigation_widget.h"
52 #include "ash/shelf/shelf_widget.h"
53 #include "ash/shell.h"
54 #include "ash/shell_delegate.h"
55 #include "ash/strings/grit/ash_strings.h"
56 #include "ash/system/accessibility/floating_accessibility_controller.h"
57 #include "ash/system/brightness_control_delegate.h"
58 #include "ash/system/ime_menu/ime_menu_tray.h"
59 #include "ash/system/keyboard_brightness_control_delegate.h"
60 #include "ash/system/model/enterprise_domain_model.h"
61 #include "ash/system/model/system_tray_model.h"
62 #include "ash/system/palette/palette_tray.h"
63 #include "ash/system/palette/palette_utils.h"
64 #include "ash/system/power/power_button_controller.h"
65 #include "ash/system/status_area_widget.h"
66 #include "ash/system/toast/toast_manager_impl.h"
67 #include "ash/system/tray/system_tray_notifier.h"
68 #include "ash/system/unified/unified_system_tray.h"
69 #include "ash/touch/touch_hud_debug.h"
70 #include "ash/utility/screenshot_controller.h"
71 #include "ash/wm/desks/desks_animations.h"
72 #include "ash/wm/desks/desks_controller.h"
73 #include "ash/wm/mru_window_tracker.h"
74 #include "ash/wm/overview/overview_controller.h"
75 #include "ash/wm/overview/overview_session.h"
76 #include "ash/wm/screen_pinning_controller.h"
77 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
78 #include "ash/wm/window_cycle_controller.h"
79 #include "ash/wm/window_positioning_utils.h"
80 #include "ash/wm/window_state.h"
81 #include "ash/wm/window_util.h"
82 #include "ash/wm/wm_event.h"
83 #include "base/bind.h"
84 #include "base/callback_helpers.h"
85 #include "base/command_line.h"
86 #include "base/files/file_util.h"
87 #include "base/json/json_reader.h"
88 #include "base/metrics/histogram_functions.h"
89 #include "base/metrics/histogram_macros.h"
90 #include "base/metrics/user_metrics.h"
91 #include "base/optional.h"
92 #include "base/stl_util.h"
93 #include "base/strings/string_split.h"
94 #include "base/strings/utf_string_conversions.h"
95 #include "base/system/sys_info.h"
96 #include "chromeos/audio/cras_audio_handler.h"
97 #include "chromeos/constants/chromeos_features.h"
98 #include "chromeos/dbus/power/power_manager_client.h"
99 #include "chromeos/ui/vector_icons/vector_icons.h"
100 #include "components/user_manager/user_type.h"
101 #include "ui/base/accelerators/accelerator.h"
102 #include "ui/base/accelerators/accelerator_manager.h"
103 #include "ui/base/l10n/l10n_util.h"
104 #include "ui/base/ui_base_features.h"
105 #include "ui/chromeos/events/keyboard_layout_util.h"
106 #include "ui/compositor/layer.h"
107 #include "ui/compositor/layer_animation_sequence.h"
108 #include "ui/compositor/layer_animator.h"
109 #include "ui/display/display.h"
110 #include "ui/display/manager/managed_display_info.h"
111 #include "ui/display/screen.h"
112 #include "ui/events/devices/device_data_manager.h"
113 #include "ui/events/devices/input_device.h"
114 #include "ui/gfx/paint_vector_icon.h"
115 #include "ui/message_center/message_center.h"
116 
117 namespace ash {
118 
119 const char kNotifierAccelerator[] = "ash.accelerator-controller";
120 
121 const char kTabletCountOfVolumeAdjustType[] = "Tablet.CountOfVolumeAdjustType";
122 
123 const char kHighContrastToggleAccelNotificationId[] =
124     "chrome://settings/accessibility/highcontrast";
125 const char kDockedMagnifierToggleAccelNotificationId[] =
126     "chrome://settings/accessibility/dockedmagnifier";
127 const char kFullscreenMagnifierToggleAccelNotificationId[] =
128     "chrome://settings/accessibility/fullscreenmagnifier";
129 const char kSpokenFeedbackToggleAccelNotificationId[] =
130     "chrome://settings/accessibility/spokenfeedback";
131 
132 const char kAccessibilityHighContrastShortcut[] =
133     "Accessibility.Shortcuts.CrosHighContrast";
134 const char kAccessibilitySpokenFeedbackShortcut[] =
135     "Accessibility.Shortcuts.CrosSpokenFeedback";
136 const char kAccessibilityScreenMagnifierShortcut[] =
137     "Accessibility.Shortcuts.CrosScreenMagnifier";
138 const char kAccessibilityDockedMagnifierShortcut[] =
139     "Accessibility.Shortcuts.CrosDockedMagnifier";
140 
141 const char kAccelWindowSnap[] = "Ash.Accelerators.WindowSnap";
142 
143 namespace {
144 
145 using base::UserMetricsAction;
146 using message_center::Notification;
147 using message_center::SystemNotificationWarningLevel;
148 
149 // Toast id and duration for Assistant shortcuts.
150 constexpr char kAssistantErrorToastId[] = "assistant_error";
151 constexpr int kToastDurationMs = 2500;
152 
153 constexpr char kVirtualDesksToastId[] = "virtual_desks_toast";
154 
155 // Path of the json file that contains side volume button location info.
156 constexpr char kSideVolumeButtonLocationFilePath[] =
157     "/usr/share/chromeos-assets/side_volume_button/location.json";
158 
159 // The interval between two volume control actions within one volume adjust.
160 constexpr base::TimeDelta kVolumeAdjustTimeout =
161     base::TimeDelta::FromSeconds(2);
162 
163 // These values are written to logs.  New enum values can be added, but existing
164 // enums must never be renumbered or deleted and reused.
165 // Records the result of triggering the rotation accelerator.
166 enum class RotationAcceleratorAction {
167   kCancelledDialog = 0,
168   kAcceptedDialog = 1,
169   kAlreadyAcceptedDialog = 2,
170   kMaxValue = kAlreadyAcceptedDialog,
171 };
172 
RecordRotationAcceleratorAction(const RotationAcceleratorAction & action)173 void RecordRotationAcceleratorAction(const RotationAcceleratorAction& action) {
174   UMA_HISTOGRAM_ENUMERATION("Ash.Accelerators.Rotation.Usage", action);
175 }
176 
RecordWindowSnapAcceleratorAction(WindowSnapAcceleratorAction action)177 void RecordWindowSnapAcceleratorAction(WindowSnapAcceleratorAction action) {
178   UMA_HISTOGRAM_ENUMERATION(kAccelWindowSnap, action);
179 }
180 
RecordTabletVolumeAdjustTypeHistogram(TabletModeVolumeAdjustType type)181 void RecordTabletVolumeAdjustTypeHistogram(TabletModeVolumeAdjustType type) {
182   UMA_HISTOGRAM_ENUMERATION(kTabletCountOfVolumeAdjustType, type);
183 }
184 
185 // Ensures that there are no word breaks at the "+"s in the shortcut texts such
186 // as "Ctrl+Shift+Space".
EnsureNoWordBreaks(base::string16 * shortcut_text)187 void EnsureNoWordBreaks(base::string16* shortcut_text) {
188   std::vector<base::string16> keys =
189       base::SplitString(*shortcut_text, base::ASCIIToUTF16("+"),
190                         base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
191 
192   if (keys.size() < 2U)
193     return;
194 
195   // The plus sign surrounded by the word joiner to guarantee an non-breaking
196   // shortcut.
197   const base::string16 non_breaking_plus =
198       base::UTF8ToUTF16("\xe2\x81\xa0+\xe2\x81\xa0");
199   shortcut_text->clear();
200   for (size_t i = 0; i < keys.size() - 1; ++i) {
201     *shortcut_text += keys[i];
202     *shortcut_text += non_breaking_plus;
203   }
204 
205   *shortcut_text += keys.back();
206 }
207 
208 // Gets the notification message after it formats it in such a way that there
209 // are no line breaks in the middle of the shortcut texts.
GetNotificationText(int message_id,int old_shortcut_id,int new_shortcut_id)210 base::string16 GetNotificationText(int message_id,
211                                    int old_shortcut_id,
212                                    int new_shortcut_id) {
213   base::string16 old_shortcut = l10n_util::GetStringUTF16(old_shortcut_id);
214   base::string16 new_shortcut = l10n_util::GetStringUTF16(new_shortcut_id);
215   EnsureNoWordBreaks(&old_shortcut);
216   EnsureNoWordBreaks(&new_shortcut);
217 
218   return l10n_util::GetStringFUTF16(message_id, new_shortcut, old_shortcut);
219 }
220 
221 // Shows a warning the user is using a deprecated accelerator.
ShowDeprecatedAcceleratorNotification(const char * const notification_id,int message_id,int old_shortcut_id,int new_shortcut_id)222 void ShowDeprecatedAcceleratorNotification(const char* const notification_id,
223                                            int message_id,
224                                            int old_shortcut_id,
225                                            int new_shortcut_id) {
226   const base::string16 message =
227       GetNotificationText(message_id, old_shortcut_id, new_shortcut_id);
228   auto delegate =
229       base::MakeRefCounted<message_center::HandleNotificationClickDelegate>(
230           base::BindRepeating([]() {
231             if (!Shell::Get()->session_controller()->IsUserSessionBlocked())
232               Shell::Get()->shell_delegate()->OpenKeyboardShortcutHelpPage();
233           }));
234 
235   std::unique_ptr<Notification> notification = ash::CreateSystemNotification(
236       message_center::NOTIFICATION_TYPE_SIMPLE, notification_id,
237       l10n_util::GetStringUTF16(IDS_DEPRECATED_SHORTCUT_TITLE), message,
238       base::string16(), GURL(),
239       message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
240                                  kNotifierAccelerator),
241       message_center::RichNotificationData(), std::move(delegate),
242       kNotificationKeyboardIcon, SystemNotificationWarningLevel::NORMAL);
243   message_center::MessageCenter::Get()->AddNotification(
244       std::move(notification));
245 }
246 
ShowToast(std::string id,const base::string16 & text)247 void ShowToast(std::string id, const base::string16& text) {
248   ToastData toast(id, text, kToastDurationMs, base::nullopt,
249                   /*visible_on_lock_screen=*/true);
250   Shell::Get()->toast_manager()->Show(toast);
251 }
252 
CreateAccelerator(ui::KeyboardCode keycode,int modifiers,bool trigger_on_press)253 ui::Accelerator CreateAccelerator(ui::KeyboardCode keycode,
254                                   int modifiers,
255                                   bool trigger_on_press) {
256   ui::Accelerator accelerator(keycode, modifiers);
257   accelerator.set_key_state(trigger_on_press
258                                 ? ui::Accelerator::KeyState::PRESSED
259                                 : ui::Accelerator::KeyState::RELEASED);
260   return accelerator;
261 }
262 
RecordUmaHistogram(const char * histogram_name,DeprecatedAcceleratorUsage sample)263 void RecordUmaHistogram(const char* histogram_name,
264                         DeprecatedAcceleratorUsage sample) {
265   auto* histogram = base::LinearHistogram::FactoryGet(
266       histogram_name, 1, DEPRECATED_USAGE_COUNT, DEPRECATED_USAGE_COUNT + 1,
267       base::HistogramBase::kUmaTargetedHistogramFlag);
268   histogram->Add(sample);
269 }
270 
RecordImeSwitchByAccelerator()271 void RecordImeSwitchByAccelerator() {
272   UMA_HISTOGRAM_ENUMERATION("InputMethod.ImeSwitch",
273                             ImeSwitchType::kAccelerator);
274 }
275 
RecordImeSwitchByModeChangeKey()276 void RecordImeSwitchByModeChangeKey() {
277   UMA_HISTOGRAM_ENUMERATION("InputMethod.ImeSwitch",
278                             ImeSwitchType::kModeChangeKey);
279 }
280 
HandleCycleBackwardMRU(const ui::Accelerator & accelerator)281 void HandleCycleBackwardMRU(const ui::Accelerator& accelerator) {
282   if (accelerator.key_code() == ui::VKEY_TAB)
283     base::RecordAction(base::UserMetricsAction("Accel_PrevWindow_Tab"));
284 
285   Shell::Get()->window_cycle_controller()->HandleCycleWindow(
286       WindowCycleController::BACKWARD);
287 }
288 
HandleCycleForwardMRU(const ui::Accelerator & accelerator)289 void HandleCycleForwardMRU(const ui::Accelerator& accelerator) {
290   if (accelerator.key_code() == ui::VKEY_TAB)
291     base::RecordAction(base::UserMetricsAction("Accel_NextWindow_Tab"));
292 
293   Shell::Get()->window_cycle_controller()->HandleCycleWindow(
294       WindowCycleController::FORWARD);
295 }
296 
HandleActivateDesk(const ui::Accelerator & accelerator)297 void HandleActivateDesk(const ui::Accelerator& accelerator) {
298   auto* desks_controller = DesksController::Get();
299   const bool success = desks_controller->ActivateAdjacentDesk(
300       /*going_left=*/
301       (accelerator.key_code() == ui::VKEY_OEM_4 ||
302        accelerator.key_code() == ui::VKEY_LEFT),
303       DesksSwitchSource::kDeskSwitchShortcut);
304   if (!success)
305     return;
306 
307   switch (accelerator.key_code()) {
308     case ui::VKEY_OEM_4:
309     case ui::VKEY_LEFT:
310       base::RecordAction(base::UserMetricsAction("Accel_Desks_ActivateLeft"));
311       break;
312     case ui::VKEY_OEM_6:
313     case ui::VKEY_RIGHT:
314       base::RecordAction(base::UserMetricsAction("Accel_Desks_ActivateRight"));
315       break;
316 
317     default:
318       NOTREACHED();
319   }
320 }
321 
HandleMoveActiveItem(const ui::Accelerator & accelerator)322 void HandleMoveActiveItem(const ui::Accelerator& accelerator) {
323   auto* desks_controller = DesksController::Get();
324   if (desks_controller->AreDesksBeingModified())
325     return;
326 
327   aura::Window* window_to_move = nullptr;
328   auto* overview_controller = Shell::Get()->overview_controller();
329   const bool in_overview = overview_controller->InOverviewSession();
330   if (in_overview) {
331     window_to_move =
332         overview_controller->overview_session()->GetHighlightedWindow();
333   } else {
334     window_to_move = window_util::GetActiveWindow();
335   }
336 
337   if (!window_to_move)
338     return;
339 
340   Desk* target_desk = nullptr;
341   bool going_left = accelerator.key_code() == ui::VKEY_OEM_4 ||
342                     accelerator.key_code() == ui::VKEY_LEFT;
343   if (going_left) {
344     target_desk = desks_controller->GetPreviousDesk();
345     base::RecordAction(base::UserMetricsAction("Accel_Desks_MoveWindowLeft"));
346   } else {
347     DCHECK(accelerator.key_code() == ui::VKEY_OEM_6 ||
348            accelerator.key_code() == ui::VKEY_RIGHT);
349     target_desk = desks_controller->GetNextDesk();
350     base::RecordAction(base::UserMetricsAction("Accel_Desks_MoveWindowRight"));
351   }
352 
353   if (!target_desk)
354     return;
355 
356   if (!in_overview) {
357     desks_animations::PerformWindowMoveToDeskAnimation(
358         window_to_move,
359         /*going_left=*/going_left);
360   }
361 
362   if (!desks_controller->MoveWindowFromActiveDeskTo(
363           window_to_move, target_desk, window_to_move->GetRootWindow(),
364           DesksMoveWindowFromActiveDeskSource::kShortcut)) {
365     return;
366   }
367 
368   if (in_overview) {
369     // We should not exit overview as a result of this shortcut.
370     DCHECK(overview_controller->InOverviewSession());
371     overview_controller->overview_session()->PositionWindows(/*animate=*/true);
372   }
373 }
374 
HandleNewDesk()375 void HandleNewDesk() {
376   auto* desks_controller = DesksController::Get();
377   if (!desks_controller->CanCreateDesks()) {
378     ShowToast(kVirtualDesksToastId,
379               l10n_util::GetStringUTF16(IDS_ASH_DESKS_MAX_NUM_REACHED));
380     return;
381   }
382 
383   if (desks_controller->AreDesksBeingModified())
384     return;
385 
386   // Add a new desk and switch to it.
387   const size_t new_desk_index = desks_controller->desks().size();
388   desks_controller->NewDesk(DesksCreationRemovalSource::kKeyboard);
389   const Desk* desk = desks_controller->desks()[new_desk_index].get();
390   desks_controller->ActivateDesk(desk, DesksSwitchSource::kNewDeskShortcut);
391   base::RecordAction(base::UserMetricsAction("Accel_Desks_NewDesk"));
392 }
393 
HandleRemoveCurrentDesk()394 void HandleRemoveCurrentDesk() {
395   if (window_util::IsAnyWindowDragged())
396     return;
397 
398   auto* desks_controller = DesksController::Get();
399   if (!desks_controller->CanRemoveDesks()) {
400     ShowToast(kVirtualDesksToastId,
401               l10n_util::GetStringUTF16(IDS_ASH_DESKS_MIN_NUM_REACHED));
402     return;
403   }
404 
405   if (desks_controller->AreDesksBeingModified())
406     return;
407 
408   // TODO(afakhry): Finalize the desk removal animation outside of overview with
409   // UX. https://crbug.com/977434.
410   desks_controller->RemoveDesk(desks_controller->active_desk(),
411                                DesksCreationRemovalSource::kKeyboard);
412   base::RecordAction(base::UserMetricsAction("Accel_Desks_RemoveDesk"));
413 }
414 
HandleRotatePaneFocus(FocusCycler::Direction direction)415 void HandleRotatePaneFocus(FocusCycler::Direction direction) {
416   switch (direction) {
417     // TODO(stevet): Not sure if this is the same as IDC_FOCUS_NEXT_PANE.
418     case FocusCycler::FORWARD: {
419       base::RecordAction(UserMetricsAction("Accel_Focus_Next_Pane"));
420       break;
421     }
422     case FocusCycler::BACKWARD: {
423       base::RecordAction(UserMetricsAction("Accel_Focus_Previous_Pane"));
424       break;
425     }
426   }
427   Shell::Get()->focus_cycler()->RotateFocus(direction);
428 }
429 
HandleFocusShelf()430 void HandleFocusShelf() {
431   base::RecordAction(UserMetricsAction("Accel_Focus_Shelf"));
432 
433   if (Shell::Get()->session_controller()->IsRunningInAppMode()) {
434     // If floating accessibility menu is shown, focus on it instead of the
435     // shelf.
436     FloatingAccessibilityController* floating_menu =
437         Shell::Get()->accessibility_controller()->GetFloatingMenuController();
438     if (floating_menu) {
439       floating_menu->FocusOnMenu();
440     }
441     return;
442   }
443 
444   // TODO(jamescook): Should this be GetRootWindowForNewWindows()?
445   // Focus the home button.
446   Shelf* shelf = Shelf::ForWindow(Shell::GetPrimaryRootWindow());
447   shelf->shelf_focus_cycler()->FocusNavigation(false /* lastElement */);
448 }
449 
FindPipWidget()450 views::Widget* FindPipWidget() {
451   return Shell::Get()->focus_cycler()->FindWidget(
452       base::BindRepeating([](views::Widget* widget) {
453         return WindowState::Get(widget->GetNativeWindow())->IsPip();
454       }));
455 }
456 
HandleFocusPip()457 void HandleFocusPip() {
458   base::RecordAction(UserMetricsAction("Accel_Focus_Pip"));
459   auto* widget = FindPipWidget();
460   if (widget)
461     Shell::Get()->focus_cycler()->FocusWidget(widget);
462 }
463 
HandleLaunchAppN(int n)464 void HandleLaunchAppN(int n) {
465   base::RecordAction(UserMetricsAction("Accel_Launch_App"));
466   Shelf::LaunchShelfItem(n);
467 }
468 
HandleLaunchLastApp()469 void HandleLaunchLastApp() {
470   base::RecordAction(UserMetricsAction("Accel_Launch_Last_App"));
471   Shelf::LaunchShelfItem(-1);
472 }
473 
HandleMediaNextTrack()474 void HandleMediaNextTrack() {
475   base::RecordAction(UserMetricsAction("Accel_Media_Next_Track"));
476   Shell::Get()->media_controller()->HandleMediaNextTrack();
477 }
478 
HandleMediaFastForward()479 void HandleMediaFastForward() {
480   base::RecordAction(UserMetricsAction("Accel_Media_Fast_Forward"));
481   Shell::Get()->media_controller()->HandleMediaSeekForward();
482 }
483 
HandleMediaPause()484 void HandleMediaPause() {
485   base::RecordAction(UserMetricsAction("Accel_Media_Pause"));
486   Shell::Get()->media_controller()->HandleMediaPause();
487 }
488 
HandleMediaPlay()489 void HandleMediaPlay() {
490   base::RecordAction(UserMetricsAction("Accel_Media_Play"));
491   Shell::Get()->media_controller()->HandleMediaPlay();
492 }
493 
HandleMediaPlayPause()494 void HandleMediaPlayPause() {
495   base::RecordAction(UserMetricsAction("Accel_Media_PlayPause"));
496   Shell::Get()->media_controller()->HandleMediaPlayPause();
497 }
498 
HandleMediaPrevTrack()499 void HandleMediaPrevTrack() {
500   base::RecordAction(UserMetricsAction("Accel_Media_Prev_Track"));
501   Shell::Get()->media_controller()->HandleMediaPrevTrack();
502 }
HandleMediaRewind()503 void HandleMediaRewind() {
504   base::RecordAction(UserMetricsAction("Accel_Media_Rewind"));
505   Shell::Get()->media_controller()->HandleMediaSeekBackward();
506 }
507 
HandleMediaStop()508 void HandleMediaStop() {
509   base::RecordAction(UserMetricsAction("Accel_Media_Stop"));
510   Shell::Get()->media_controller()->HandleMediaStop();
511 }
512 
HandleToggleMirrorMode()513 void HandleToggleMirrorMode() {
514   base::RecordAction(UserMetricsAction("Accel_Toggle_Mirror_Mode"));
515   bool mirror = !Shell::Get()->display_manager()->IsInMirrorMode();
516   Shell::Get()->display_configuration_controller()->SetMirrorMode(
517       mirror, true /* throttle */);
518 }
519 
CanHandleNewIncognitoWindow()520 bool CanHandleNewIncognitoWindow() {
521   // Guest mode does not use incognito windows. The browser may have other
522   // restrictions on incognito mode (e.g. enterprise policy) but those are rare.
523   // For non-guest mode, consume the key and defer the decision to the browser.
524   base::Optional<user_manager::UserType> user_type =
525       Shell::Get()->session_controller()->GetUserType();
526   return user_type && *user_type != user_manager::USER_TYPE_GUEST;
527 }
528 
HandleNewIncognitoWindow()529 void HandleNewIncognitoWindow() {
530   base::RecordAction(UserMetricsAction("Accel_New_Incognito_Window"));
531   NewWindowDelegate::GetInstance()->NewWindow(true /* is_incognito */);
532 }
533 
HandleNewTab(const ui::Accelerator & accelerator)534 void HandleNewTab(const ui::Accelerator& accelerator) {
535   if (accelerator.key_code() == ui::VKEY_T)
536     base::RecordAction(UserMetricsAction("Accel_NewTab_T"));
537   NewWindowDelegate::GetInstance()->NewTab();
538 }
539 
HandleNewWindow()540 void HandleNewWindow() {
541   base::RecordAction(UserMetricsAction("Accel_New_Window"));
542   NewWindowDelegate::GetInstance()->NewWindow(false /* is_incognito */);
543 }
544 
CanCycleInputMethod()545 bool CanCycleInputMethod() {
546   return Shell::Get()->ime_controller()->CanSwitchIme();
547 }
548 
CanHandleCycleMru(const ui::Accelerator & accelerator)549 bool CanHandleCycleMru(const ui::Accelerator& accelerator) {
550   // Don't do anything when Alt+Tab is hit while a virtual keyboard is showing.
551   // Touchscreen users have better window switching options. It would be
552   // preferable if we could tell whether this event actually came from a virtual
553   // keyboard, but there's no easy way to do so, thus we block Alt+Tab when the
554   // virtual keyboard is showing, even if it came from a real keyboard. See
555   // http://crbug.com/638269
556   return !keyboard::KeyboardUIController::Get()->IsKeyboardVisible();
557 }
558 
HandleSwitchToNextIme(const ui::Accelerator & accelerator)559 void HandleSwitchToNextIme(const ui::Accelerator& accelerator) {
560   base::RecordAction(UserMetricsAction("Accel_Next_Ime"));
561   if (accelerator.key_code() == ui::VKEY_MODECHANGE)
562     RecordImeSwitchByModeChangeKey();
563   else
564     RecordImeSwitchByAccelerator();
565   Shell::Get()->ime_controller()->SwitchToNextIme();
566 }
567 
HandleOpenFeedbackPage()568 void HandleOpenFeedbackPage() {
569   base::RecordAction(UserMetricsAction("Accel_Open_Feedback_Page"));
570   NewWindowDelegate::GetInstance()->OpenFeedbackPage();
571 }
572 
HandleSwitchToLastUsedIme(const ui::Accelerator & accelerator)573 void HandleSwitchToLastUsedIme(const ui::Accelerator& accelerator) {
574   base::RecordAction(UserMetricsAction("Accel_Previous_Ime"));
575   if (accelerator.key_state() == ui::Accelerator::KeyState::PRESSED) {
576     RecordImeSwitchByAccelerator();
577     Shell::Get()->ime_controller()->SwitchToLastUsedIme();
578   }
579   // Else: consume the Ctrl+Space ET_KEY_RELEASED event but do not do anything.
580 }
581 
GetNextRotationInClamshell(display::Display::Rotation current)582 display::Display::Rotation GetNextRotationInClamshell(
583     display::Display::Rotation current) {
584   switch (current) {
585     case display::Display::ROTATE_0:
586       return display::Display::ROTATE_90;
587     case display::Display::ROTATE_90:
588       return display::Display::ROTATE_180;
589     case display::Display::ROTATE_180:
590       return display::Display::ROTATE_270;
591     case display::Display::ROTATE_270:
592       return display::Display::ROTATE_0;
593   }
594   NOTREACHED() << "Unknown rotation:" << current;
595   return display::Display::ROTATE_0;
596 }
597 
GetNextRotationInTabletMode(int64_t display_id,display::Display::Rotation current)598 display::Display::Rotation GetNextRotationInTabletMode(
599     int64_t display_id,
600     display::Display::Rotation current) {
601   Shell* shell = Shell::Get();
602   DCHECK(shell->tablet_mode_controller()->InTabletMode());
603 
604   if (!display::Display::HasInternalDisplay() ||
605       display_id != display::Display::InternalDisplayId()) {
606     return GetNextRotationInClamshell(current);
607   }
608 
609   const OrientationLockType app_requested_lock =
610       shell->screen_orientation_controller()
611           ->GetCurrentAppRequestedOrientationLock();
612 
613   bool add_180_degrees = false;
614   switch (app_requested_lock) {
615     case OrientationLockType::kCurrent:
616     case OrientationLockType::kLandscapePrimary:
617     case OrientationLockType::kLandscapeSecondary:
618     case OrientationLockType::kPortraitPrimary:
619     case OrientationLockType::kPortraitSecondary:
620     case OrientationLockType::kNatural:
621       // Do not change the current orientation.
622       return current;
623 
624     case OrientationLockType::kLandscape:
625     case OrientationLockType::kPortrait:
626       // App allows both primary and secondary orientations in either landscape
627       // or portrait, therefore switch to the next one by adding 180 degrees.
628       add_180_degrees = true;
629       break;
630 
631     default:
632       break;
633   }
634 
635   switch (current) {
636     case display::Display::ROTATE_0:
637       return add_180_degrees ? display::Display::ROTATE_180
638                              : display::Display::ROTATE_90;
639     case display::Display::ROTATE_90:
640       return add_180_degrees ? display::Display::ROTATE_270
641                              : display::Display::ROTATE_180;
642     case display::Display::ROTATE_180:
643       return add_180_degrees ? display::Display::ROTATE_0
644                              : display::Display::ROTATE_270;
645     case display::Display::ROTATE_270:
646       return add_180_degrees ? display::Display::ROTATE_90
647                              : display::Display::ROTATE_0;
648   }
649   NOTREACHED() << "Unknown rotation:" << current;
650   return display::Display::ROTATE_0;
651 }
652 
ShouldLockRotation(int64_t display_id)653 bool ShouldLockRotation(int64_t display_id) {
654   return display::Display::HasInternalDisplay() &&
655          display_id == display::Display::InternalDisplayId() &&
656          Shell::Get()->tablet_mode_controller()->is_in_tablet_physical_state();
657 }
658 
GetDisplayIdForRotation()659 int64_t GetDisplayIdForRotation() {
660   const gfx::Point point = display::Screen::GetScreen()->GetCursorScreenPoint();
661   return display::Screen::GetScreen()->GetDisplayNearestPoint(point).id();
662 }
663 
RotateScreen()664 void RotateScreen() {
665   auto* shell = Shell::Get();
666   const bool in_tablet_mode =
667       Shell::Get()->tablet_mode_controller()->InTabletMode();
668   const int64_t display_id = GetDisplayIdForRotation();
669   const display::ManagedDisplayInfo& display_info =
670       shell->display_manager()->GetDisplayInfo(display_id);
671   const auto active_rotation = display_info.GetActiveRotation();
672   const auto next_rotation =
673       in_tablet_mode ? GetNextRotationInTabletMode(display_id, active_rotation)
674                      : GetNextRotationInClamshell(active_rotation);
675   if (active_rotation == next_rotation)
676     return;
677 
678   // When the device is in a physical tablet state, display rotation requests of
679   // the internal display are treated as requests to lock the user rotation.
680   if (ShouldLockRotation(display_id)) {
681     shell->screen_orientation_controller()->SetLockToRotation(next_rotation);
682     return;
683   }
684 
685   shell->display_configuration_controller()->SetDisplayRotation(
686       display_id, next_rotation, display::Display::RotationSource::USER);
687 }
688 
OnRotationDialogAccepted()689 void OnRotationDialogAccepted() {
690   RecordRotationAcceleratorAction(RotationAcceleratorAction::kAcceptedDialog);
691   RotateScreen();
692   Shell::Get()
693       ->accessibility_controller()
694       ->SetDisplayRotationAcceleratorDialogBeenAccepted();
695 }
696 
OnRotationDialogCancelled()697 void OnRotationDialogCancelled() {
698   RecordRotationAcceleratorAction(RotationAcceleratorAction::kCancelledDialog);
699 }
700 
701 // Rotates the screen.
HandleRotateScreen()702 void HandleRotateScreen() {
703   if (Shell::Get()->display_manager()->IsInUnifiedMode())
704     return;
705 
706   base::RecordAction(UserMetricsAction("Accel_Rotate_Screen"));
707   const bool dialog_ever_accepted =
708       Shell::Get()
709           ->accessibility_controller()
710           ->HasDisplayRotationAcceleratorDialogBeenAccepted();
711 
712   if (!dialog_ever_accepted) {
713     Shell::Get()->accelerator_controller()->MaybeShowConfirmationDialog(
714         IDS_ASH_ROTATE_SCREEN_TITLE, IDS_ASH_ROTATE_SCREEN_BODY,
715         base::BindOnce(&OnRotationDialogAccepted),
716         base::BindOnce(&OnRotationDialogCancelled));
717   } else {
718     RecordRotationAcceleratorAction(
719         RotationAcceleratorAction::kAlreadyAcceptedDialog);
720     RotateScreen();
721   }
722 }
723 
HandleRestoreTab()724 void HandleRestoreTab() {
725   base::RecordAction(UserMetricsAction("Accel_Restore_Tab"));
726   NewWindowDelegate::GetInstance()->RestoreTab();
727 }
728 
729 // Rotate the active window.
HandleRotateActiveWindow()730 void HandleRotateActiveWindow() {
731   base::RecordAction(UserMetricsAction("Accel_Rotate_Active_Window"));
732   aura::Window* active_window = window_util::GetActiveWindow();
733   if (!active_window)
734     return;
735   // The rotation animation bases its target transform on the current
736   // rotation and position. Since there could be an animation in progress
737   // right now, queue this animation so when it starts it picks up a neutral
738   // rotation and position. Use replace so we only enqueue one at a time.
739   active_window->layer()->GetAnimator()->set_preemption_strategy(
740       ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
741   active_window->layer()->GetAnimator()->StartAnimation(
742       new ui::LayerAnimationSequence(
743           std::make_unique<WindowRotation>(360, active_window->layer())));
744 }
745 
HandleShowKeyboardShortcutViewer()746 void HandleShowKeyboardShortcutViewer() {
747   NewWindowDelegate::GetInstance()->ShowKeyboardShortcutViewer();
748 }
749 
CanHandleScreenshot()750 bool CanHandleScreenshot() {
751   // The old screenshot code will handle the different sessions in its own code.
752   if (!features::IsCaptureModeEnabled())
753     return true;
754 
755   return !Shell::Get()->session_controller()->IsUserSessionBlocked();
756 }
757 
758 // Tries to enter capture mode image type with |source|. Returns false if
759 // unsuccessful (capture mode disabled).
MaybeEnterImageCaptureMode(CaptureModeSource source,CaptureModeEntryType entry_type)760 bool MaybeEnterImageCaptureMode(CaptureModeSource source,
761                                 CaptureModeEntryType entry_type) {
762   if (!features::IsCaptureModeEnabled())
763     return false;
764 
765   auto* capture_mode_controller = CaptureModeController::Get();
766   capture_mode_controller->SetSource(source);
767   capture_mode_controller->SetType(CaptureModeType::kImage);
768   capture_mode_controller->Start(entry_type);
769   return true;
770 }
771 
HandleTakeWindowScreenshot()772 void HandleTakeWindowScreenshot() {
773   base::RecordAction(UserMetricsAction("Accel_Take_Window_Screenshot"));
774   if (MaybeEnterImageCaptureMode(
775           CaptureModeSource::kWindow,
776           CaptureModeEntryType::kAccelTakeWindowScreenshot)) {
777     return;
778   }
779 
780   Shell::Get()->screenshot_controller()->StartWindowScreenshotSession();
781 }
782 
HandleTakePartialScreenshot()783 void HandleTakePartialScreenshot() {
784   base::RecordAction(UserMetricsAction("Accel_Take_Partial_Screenshot"));
785   if (MaybeEnterImageCaptureMode(
786           CaptureModeSource::kRegion,
787           CaptureModeEntryType::kAccelTakePartialScreenshot)) {
788     return;
789   }
790 
791   Shell::Get()->screenshot_controller()->StartPartialScreenshotSession(
792       /*draw_overlay_immediately=*/true);
793 }
794 
HandleTakeScreenshot()795 void HandleTakeScreenshot() {
796   base::RecordAction(UserMetricsAction("Accel_Take_Screenshot"));
797   if (!features::IsCaptureModeEnabled())
798     Shell::Get()->screenshot_controller()->TakeScreenshotForAllRootWindows();
799   else
800     CaptureModeController::Get()->CaptureScreenshotsOfAllDisplays();
801 }
802 
HandleToggleSystemTrayBubbleInternal(bool focus_message_center)803 void HandleToggleSystemTrayBubbleInternal(bool focus_message_center) {
804   aura::Window* target_root = Shell::GetRootWindowForNewWindows();
805   UnifiedSystemTray* tray = RootWindowController::ForWindow(target_root)
806                                 ->GetStatusAreaWidget()
807                                 ->unified_system_tray();
808   if (tray->IsBubbleShown()) {
809     tray->CloseBubble();
810   } else {
811     tray->ShowBubble(false /* show_by_click */);
812     tray->ActivateBubble();
813 
814     if (focus_message_center)
815       tray->FocusFirstNotification();
816   }
817 }
818 
HandleToggleSystemTrayBubble()819 void HandleToggleSystemTrayBubble() {
820   base::RecordAction(UserMetricsAction("Accel_Toggle_System_Tray_Bubble"));
821   HandleToggleSystemTrayBubbleInternal(false /*focus_message_center*/);
822 }
823 
HandleToggleMessageCenterBubble()824 void HandleToggleMessageCenterBubble() {
825   base::RecordAction(UserMetricsAction("Accel_Toggle_Message_Center_Bubble"));
826   HandleToggleSystemTrayBubbleInternal(true /*focus_message_center*/);
827 }
828 
HandleShowTaskManager()829 void HandleShowTaskManager() {
830   base::RecordAction(UserMetricsAction("Accel_Show_Task_Manager"));
831   NewWindowDelegate::GetInstance()->ShowTaskManager();
832 }
833 
HandleSwapPrimaryDisplay()834 void HandleSwapPrimaryDisplay() {
835   base::RecordAction(UserMetricsAction("Accel_Swap_Primary_Display"));
836   accelerators::ShiftPrimaryDisplay();
837 }
838 
CanHandleSwitchIme(const ui::Accelerator & accelerator)839 bool CanHandleSwitchIme(const ui::Accelerator& accelerator) {
840   return Shell::Get()->ime_controller()->CanSwitchImeWithAccelerator(
841       accelerator);
842 }
843 
HandleSwitchIme(const ui::Accelerator & accelerator)844 void HandleSwitchIme(const ui::Accelerator& accelerator) {
845   base::RecordAction(UserMetricsAction("Accel_Switch_Ime"));
846   RecordImeSwitchByAccelerator();
847   Shell::Get()->ime_controller()->SwitchImeWithAccelerator(accelerator);
848 }
849 
CanHandleToggleAppList(const ui::Accelerator & accelerator,const ui::Accelerator & previous_accelerator)850 bool CanHandleToggleAppList(const ui::Accelerator& accelerator,
851                             const ui::Accelerator& previous_accelerator) {
852   if (accelerator.key_code() == ui::VKEY_LWIN) {
853     // If something else was pressed between the Search key (LWIN)
854     // being pressed and released, then ignore the release of the
855     // Search key.
856     if (previous_accelerator.key_state() !=
857             ui::Accelerator::KeyState::PRESSED ||
858         previous_accelerator.key_code() != ui::VKEY_LWIN ||
859         previous_accelerator.interrupted_by_mouse_event()) {
860       return false;
861     }
862 
863     // When spoken feedback is enabled, we should neither toggle the list nor
864     // consume the key since Search+Shift is one of the shortcuts the a11y
865     // feature uses. crbug.com/132296
866     if (Shell::Get()->accessibility_controller()->spoken_feedback().enabled())
867       return false;
868   }
869   return true;
870 }
871 
HandleToggleAppList(const ui::Accelerator & accelerator,AppListShowSource show_source)872 void HandleToggleAppList(const ui::Accelerator& accelerator,
873                          AppListShowSource show_source) {
874   if (accelerator.key_code() == ui::VKEY_LWIN)
875     base::RecordAction(UserMetricsAction("Accel_Search_LWin"));
876 
877   aura::Window* const root_window = Shell::GetRootWindowForNewWindows();
878   Shell::Get()->app_list_controller()->ToggleAppList(
879       display::Screen::GetScreen()->GetDisplayNearestWindow(root_window).id(),
880       show_source, accelerator.time_stamp());
881 }
882 
HandleToggleFullscreen(const ui::Accelerator & accelerator)883 void HandleToggleFullscreen(const ui::Accelerator& accelerator) {
884   if (accelerator.key_code() == ui::VKEY_MEDIA_LAUNCH_APP2)
885     base::RecordAction(UserMetricsAction("Accel_Fullscreen_F4"));
886   OverviewController* overview_controller = Shell::Get()->overview_controller();
887   // Disable fullscreen while overview animation is running due to
888   // http://crbug.com/1094739
889   if (!overview_controller->IsInStartAnimation())
890     accelerators::ToggleFullscreen();
891 }
892 
HandleToggleOverview()893 void HandleToggleOverview() {
894   base::RecordAction(base::UserMetricsAction("Accel_Overview_F5"));
895   OverviewController* overview_controller = Shell::Get()->overview_controller();
896   if (overview_controller->InOverviewSession())
897     overview_controller->EndOverview();
898   else
899     overview_controller->StartOverview();
900 }
901 
HandleToggleUnifiedDesktop()902 void HandleToggleUnifiedDesktop() {
903   Shell::Get()->display_manager()->SetUnifiedDesktopEnabled(
904       !Shell::Get()->display_manager()->unified_desktop_enabled());
905 }
906 
CanHandleWindowSnap()907 bool CanHandleWindowSnap() {
908   aura::Window* active_window = window_util::GetActiveWindow();
909   if (!active_window)
910     return false;
911   WindowState* window_state = WindowState::Get(active_window);
912   // Disable window snapping shortcut key for full screen window due to
913   // http://crbug.com/135487.
914   return (window_state && window_state->IsUserPositionable() &&
915           !window_state->IsFullscreen());
916 }
917 
HandleWindowSnap(AcceleratorAction action)918 void HandleWindowSnap(AcceleratorAction action) {
919   Shell* shell = Shell::Get();
920   const bool in_tablet = shell->tablet_mode_controller()->InTabletMode();
921   const bool in_overview = shell->overview_controller()->InOverviewSession();
922   if (action == WINDOW_CYCLE_SNAP_LEFT) {
923     base::RecordAction(UserMetricsAction("Accel_Window_Snap_Left"));
924     if (in_tablet) {
925       RecordWindowSnapAcceleratorAction(
926           WindowSnapAcceleratorAction::kCycleLeftSnapInTablet);
927     } else if (in_overview) {
928       RecordWindowSnapAcceleratorAction(
929           WindowSnapAcceleratorAction::kCycleLeftSnapInClamshellOverview);
930     } else {
931       RecordWindowSnapAcceleratorAction(
932           WindowSnapAcceleratorAction::kCycleLeftSnapInClamshellNoOverview);
933     }
934   } else {
935     base::RecordAction(UserMetricsAction("Accel_Window_Snap_Right"));
936     if (in_tablet) {
937       RecordWindowSnapAcceleratorAction(
938           WindowSnapAcceleratorAction::kCycleRightSnapInTablet);
939     } else if (in_overview) {
940       RecordWindowSnapAcceleratorAction(
941           WindowSnapAcceleratorAction::kCycleRightSnapInClamshellOverview);
942     } else {
943       RecordWindowSnapAcceleratorAction(
944           WindowSnapAcceleratorAction::kCycleRightSnapInClamshellNoOverview);
945     }
946   }
947 
948   const WMEvent event(action == WINDOW_CYCLE_SNAP_LEFT
949                           ? WM_EVENT_CYCLE_SNAP_LEFT
950                           : WM_EVENT_CYCLE_SNAP_RIGHT);
951   aura::Window* active_window = window_util::GetActiveWindow();
952   DCHECK(active_window);
953   WindowState::Get(active_window)->OnWMEvent(&event);
954 }
955 
HandleWindowMinimize()956 void HandleWindowMinimize() {
957   base::RecordAction(base::UserMetricsAction("Accel_Toggle_Minimized_Minus"));
958   accelerators::ToggleMinimized();
959 }
960 
HandleTopWindowMinimizeOnBack()961 void HandleTopWindowMinimizeOnBack() {
962   base::RecordAction(
963       base::UserMetricsAction("Accel_Minimize_Top_Window_On_Back"));
964   WindowState::Get(window_util::GetTopWindow())->Minimize();
965 }
966 
HandleShowImeMenuBubble()967 void HandleShowImeMenuBubble() {
968   base::RecordAction(UserMetricsAction("Accel_Show_Ime_Menu_Bubble"));
969 
970   StatusAreaWidget* status_area_widget =
971       Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetStatusAreaWidget();
972   if (status_area_widget) {
973     ImeMenuTray* ime_menu_tray = status_area_widget->ime_menu_tray();
974     if (ime_menu_tray && ime_menu_tray->GetVisible() &&
975         !ime_menu_tray->GetBubbleView()) {
976       ime_menu_tray->ShowBubble(false /* show_by_click */);
977     }
978   }
979 }
980 
HandleCrosh()981 void HandleCrosh() {
982   base::RecordAction(UserMetricsAction("Accel_Open_Crosh"));
983 
984   NewWindowDelegate::GetInstance()->OpenCrosh();
985 }
986 
CanHandleDisableCapsLock(const ui::Accelerator & previous_accelerator)987 bool CanHandleDisableCapsLock(const ui::Accelerator& previous_accelerator) {
988   ui::KeyboardCode previous_key_code = previous_accelerator.key_code();
989   if (previous_accelerator.key_state() == ui::Accelerator::KeyState::RELEASED ||
990       (previous_key_code != ui::VKEY_LSHIFT &&
991        previous_key_code != ui::VKEY_SHIFT &&
992        previous_key_code != ui::VKEY_RSHIFT)) {
993     // If something else was pressed between the Shift key being pressed
994     // and released, then ignore the release of the Shift key.
995     return false;
996   }
997   return Shell::Get()->ime_controller()->IsCapsLockEnabled();
998 }
999 
HandleDisableCapsLock()1000 void HandleDisableCapsLock() {
1001   base::RecordAction(UserMetricsAction("Accel_Disable_Caps_Lock"));
1002   Shell::Get()->ime_controller()->SetCapsLockEnabled(false);
1003 }
1004 
HandleFileManager()1005 void HandleFileManager() {
1006   base::RecordAction(UserMetricsAction("Accel_Open_File_Manager"));
1007 
1008   NewWindowDelegate::GetInstance()->OpenFileManager();
1009 }
1010 
HandleGetHelp()1011 void HandleGetHelp() {
1012   NewWindowDelegate::GetInstance()->OpenGetHelp();
1013 }
1014 
CanHandleLock()1015 bool CanHandleLock() {
1016   return Shell::Get()->session_controller()->CanLockScreen();
1017 }
1018 
HandleLock()1019 void HandleLock() {
1020   base::RecordAction(UserMetricsAction("Accel_LockScreen_L"));
1021   Shell::Get()->session_controller()->LockScreen();
1022 }
1023 
GetPaletteTray()1024 PaletteTray* GetPaletteTray() {
1025   return Shelf::ForWindow(Shell::GetRootWindowForNewWindows())
1026       ->GetStatusAreaWidget()
1027       ->palette_tray();
1028 }
1029 
HandleShowStylusTools()1030 void HandleShowStylusTools() {
1031   base::RecordAction(UserMetricsAction("Accel_Show_Stylus_Tools"));
1032   GetPaletteTray()->ShowBubble(false /* show_by_click */);
1033 }
1034 
CanHandleShowStylusTools()1035 bool CanHandleShowStylusTools() {
1036   return GetPaletteTray()->ShouldShowPalette();
1037 }
1038 
CanHandleStartAmbientMode()1039 bool CanHandleStartAmbientMode() {
1040   return chromeos::features::IsAmbientModeEnabled();
1041 }
1042 
HandleToggleAmbientMode(const ui::Accelerator & accelerator)1043 void HandleToggleAmbientMode(const ui::Accelerator& accelerator) {
1044   Shell::Get()->ambient_controller()->ToggleInSessionUi();
1045 }
1046 
HandleToggleAssistant(const ui::Accelerator & accelerator)1047 void HandleToggleAssistant(const ui::Accelerator& accelerator) {
1048   if (accelerator.IsCmdDown() && accelerator.key_code() == ui::VKEY_SPACE) {
1049     base::RecordAction(
1050         base::UserMetricsAction("VoiceInteraction.Started.Search_Space"));
1051   } else if (accelerator.IsCmdDown() && accelerator.key_code() == ui::VKEY_A) {
1052     // Search+A shortcut is disabled on device with an assistant key.
1053     if (ui::DeviceKeyboardHasAssistantKey())
1054       return;
1055 
1056     base::RecordAction(
1057         base::UserMetricsAction("VoiceInteraction.Started.Search_A"));
1058   } else if (accelerator.key_code() == ui::VKEY_ASSISTANT) {
1059     base::RecordAction(
1060         base::UserMetricsAction("VoiceInteraction.Started.Assistant"));
1061   }
1062 
1063   using chromeos::assistant::AssistantAllowedState;
1064   switch (AssistantState::Get()->allowed_state().value_or(
1065       AssistantAllowedState::ALLOWED)) {
1066     case AssistantAllowedState::DISALLOWED_BY_NONPRIMARY_USER:
1067       // Show a toast if the active user is not primary.
1068       ShowToast(kAssistantErrorToastId,
1069                 l10n_util::GetStringUTF16(
1070                     IDS_ASH_ASSISTANT_SECONDARY_USER_TOAST_MESSAGE));
1071       return;
1072     case AssistantAllowedState::DISALLOWED_BY_LOCALE:
1073       // Show a toast if the Assistant is disabled due to unsupported
1074       // locales.
1075       ShowToast(kAssistantErrorToastId,
1076                 l10n_util::GetStringUTF16(
1077                     IDS_ASH_ASSISTANT_LOCALE_UNSUPPORTED_TOAST_MESSAGE));
1078       return;
1079     case AssistantAllowedState::DISALLOWED_BY_POLICY:
1080       // Show a toast if the Assistant is disabled due to enterprise policy.
1081       ShowToast(kAssistantErrorToastId,
1082                 l10n_util::GetStringUTF16(
1083                     IDS_ASH_ASSISTANT_DISABLED_BY_POLICY_MESSAGE));
1084       return;
1085     case AssistantAllowedState::DISALLOWED_BY_DEMO_MODE:
1086       // Show a toast if the Assistant is disabled due to being in Demo
1087       // Mode.
1088       ShowToast(kAssistantErrorToastId,
1089                 l10n_util::GetStringUTF16(
1090                     IDS_ASH_ASSISTANT_DISABLED_IN_DEMO_MODE_MESSAGE));
1091       return;
1092     case AssistantAllowedState::DISALLOWED_BY_PUBLIC_SESSION:
1093       // Show a toast if the Assistant is disabled due to being in public
1094       // session.
1095       ShowToast(kAssistantErrorToastId,
1096                 l10n_util::GetStringUTF16(
1097                     IDS_ASH_ASSISTANT_DISABLED_IN_PUBLIC_SESSION_MESSAGE));
1098       return;
1099     case AssistantAllowedState::DISALLOWED_BY_SUPERVISED_USER:
1100       // supervised user is deprecated, wait for the code clean up.
1101       NOTREACHED();
1102       return;
1103     case AssistantAllowedState::DISALLOWED_BY_INCOGNITO:
1104       ShowToast(kAssistantErrorToastId,
1105                 l10n_util::GetStringUTF16(
1106                     IDS_ASH_ASSISTANT_DISABLED_IN_GUEST_MESSAGE));
1107       return;
1108     case AssistantAllowedState::DISALLOWED_BY_ACCOUNT_TYPE:
1109       ShowToast(kAssistantErrorToastId,
1110                 l10n_util::GetStringUTF16(
1111                     IDS_ASH_ASSISTANT_DISABLED_BY_ACCOUNT_MESSAGE));
1112       return;
1113     case AssistantAllowedState::DISALLOWED_BY_KIOSK_MODE:
1114       // No need to show toast in KIOSK mode.
1115       return;
1116     case AssistantAllowedState::ALLOWED:
1117       // Nothing need to do if allowed.
1118       break;
1119   }
1120 
1121   AssistantUiController::Get()->ToggleUi(
1122       /*entry_point=*/chromeos::assistant::AssistantEntryPoint::kHotkey,
1123       /*exit_point=*/chromeos::assistant::AssistantExitPoint::kHotkey);
1124 }
1125 
HandleSuspend()1126 void HandleSuspend() {
1127   base::RecordAction(UserMetricsAction("Accel_Suspend"));
1128   chromeos::PowerManagerClient::Get()->RequestSuspend();
1129 }
1130 
CanHandleCycleUser()1131 bool CanHandleCycleUser() {
1132   return Shell::Get()->session_controller()->NumberOfLoggedInUsers() > 1;
1133 }
1134 
HandleCycleUser(CycleUserDirection direction)1135 void HandleCycleUser(CycleUserDirection direction) {
1136   MultiProfileUMA::RecordSwitchActiveUser(
1137       MultiProfileUMA::SWITCH_ACTIVE_USER_BY_ACCELERATOR);
1138   switch (direction) {
1139     case CycleUserDirection::NEXT:
1140       base::RecordAction(UserMetricsAction("Accel_Switch_To_Next_User"));
1141       break;
1142     case CycleUserDirection::PREVIOUS:
1143       base::RecordAction(UserMetricsAction("Accel_Switch_To_Previous_User"));
1144       break;
1145   }
1146   Shell::Get()->session_controller()->CycleActiveUser(direction);
1147 }
1148 
CanHandleToggleCapsLock(const ui::Accelerator & accelerator,const ui::Accelerator & previous_accelerator,const std::set<ui::KeyboardCode> & currently_pressed_keys)1149 bool CanHandleToggleCapsLock(
1150     const ui::Accelerator& accelerator,
1151     const ui::Accelerator& previous_accelerator,
1152     const std::set<ui::KeyboardCode>& currently_pressed_keys) {
1153   // Iterate the set of pressed keys. If any redundant key is pressed, CapsLock
1154   // should not be triggered. Otherwise, CapsLock may be triggered accidentally.
1155   // See issue 789283 (https://crbug.com/789283)
1156   for (const auto& pressed_key : currently_pressed_keys) {
1157     if (pressed_key != ui::VKEY_LWIN && pressed_key != ui::VKEY_MENU)
1158       return false;
1159   }
1160 
1161   // This shortcust is set to be trigger on release. Either the current
1162   // accelerator is a Search release or Alt release.
1163   if (accelerator.key_code() == ui::VKEY_LWIN &&
1164       accelerator.key_state() == ui::Accelerator::KeyState::RELEASED) {
1165     // The previous must be either an Alt press or Search press:
1166     // 1. Press Alt, Press Search, Release Search, Release Alt.
1167     // 2. Press Search, Press Alt, Release Search, Release Alt.
1168     if (previous_accelerator.key_state() ==
1169             ui::Accelerator::KeyState::PRESSED &&
1170         (previous_accelerator.key_code() == ui::VKEY_LWIN ||
1171          previous_accelerator.key_code() == ui::VKEY_MENU)) {
1172       return true;
1173     }
1174   }
1175 
1176   // Alt release.
1177   if (accelerator.key_code() == ui::VKEY_MENU &&
1178       accelerator.key_state() == ui::Accelerator::KeyState::RELEASED) {
1179     // The previous must be either an Alt press or Search press:
1180     // 3. Press Alt, Press Search, Release Alt, Release Search.
1181     // 4. Press Search, Press Alt, Release Alt, Release Search.
1182     if (previous_accelerator.key_state() ==
1183             ui::Accelerator::KeyState::PRESSED &&
1184         (previous_accelerator.key_code() == ui::VKEY_LWIN ||
1185          previous_accelerator.key_code() == ui::VKEY_MENU)) {
1186       return true;
1187     }
1188   }
1189 
1190   return false;
1191 }
1192 
HandleToggleCapsLock()1193 void HandleToggleCapsLock() {
1194   base::RecordAction(UserMetricsAction("Accel_Toggle_Caps_Lock"));
1195   ImeControllerImpl* ime_controller = Shell::Get()->ime_controller();
1196   ime_controller->SetCapsLockEnabled(!ime_controller->IsCapsLockEnabled());
1197 }
1198 
CanHandleToggleDictation()1199 bool CanHandleToggleDictation() {
1200   return Shell::Get()->accessibility_controller()->dictation().enabled();
1201 }
1202 
HandleToggleDictation()1203 void HandleToggleDictation() {
1204   base::RecordAction(UserMetricsAction("Accel_Toggle_Dictation"));
1205   Shell::Get()->accessibility_controller()->ToggleDictationFromSource(
1206       DictationToggleSource::kKeyboard);
1207 }
1208 
CanHandleToggleOverview()1209 bool CanHandleToggleOverview() {
1210   auto windows =
1211       Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk);
1212   // Do not toggle overview if there is a window being dragged.
1213   for (auto* window : windows) {
1214     if (WindowState::Get(window)->is_dragged())
1215       return false;
1216   }
1217   return true;
1218 }
1219 
CreateAndShowStickyNotification(const base::string16 & title,const base::string16 & message,const std::string & notification_id,const gfx::VectorIcon & icon)1220 void CreateAndShowStickyNotification(const base::string16& title,
1221                                      const base::string16& message,
1222                                      const std::string& notification_id,
1223                                      const gfx::VectorIcon& icon) {
1224   std::unique_ptr<Notification> notification = ash::CreateSystemNotification(
1225       message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, title, message,
1226       base::string16() /* display source */, GURL(),
1227       message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
1228                                  kNotifierAccelerator),
1229       message_center::RichNotificationData(), nullptr, icon,
1230       SystemNotificationWarningLevel::NORMAL);
1231   notification->set_priority(message_center::SYSTEM_PRIORITY);
1232   message_center::MessageCenter::Get()->AddNotification(
1233       std::move(notification));
1234 }
1235 
CreateAndShowStickyNotification(int title_id,int message_id,const std::string & notification_id,const gfx::VectorIcon & icon=kNotificationAccessibilityIcon)1236 void CreateAndShowStickyNotification(
1237     int title_id,
1238     int message_id,
1239     const std::string& notification_id,
1240     const gfx::VectorIcon& icon = kNotificationAccessibilityIcon) {
1241   CreateAndShowStickyNotification(l10n_util::GetStringUTF16(title_id),
1242                                   l10n_util::GetStringUTF16(message_id),
1243                                   notification_id, icon);
1244 }
1245 
NotifyAccessibilityFeatureDisabledByAdmin(int feature_name_id,bool feature_state,const std::string & notification_id)1246 void NotifyAccessibilityFeatureDisabledByAdmin(
1247     int feature_name_id,
1248     bool feature_state,
1249     const std::string& notification_id) {
1250   const base::string16 organization_manager =
1251       base::UTF8ToUTF16(Shell::Get()
1252                             ->system_tray_model()
1253                             ->enterprise_domain()
1254                             ->enterprise_domain_manager());
1255   CreateAndShowStickyNotification(
1256       l10n_util::GetStringUTF16(
1257           IDS_ASH_ACCESSIBILITY_FEATURE_SHORTCUT_DISABLED_TITLE),
1258       l10n_util::GetStringFUTF16(
1259           IDS_ASH_ACCESSIBILITY_FEATURE_SHORTCUT_DISABLED_MSG,
1260           organization_manager,
1261           l10n_util::GetStringUTF16(
1262               feature_state ? IDS_ASH_ACCESSIBILITY_FEATURE_ACTIVATED
1263                             : IDS_ASH_ACCESSIBILITY_FEATURE_DEACTIVATED),
1264           l10n_util::GetStringUTF16(feature_name_id)),
1265       notification_id, chromeos::kEnterpriseIcon);
1266 }
1267 
RemoveStickyNotitification(const std::string & notification_id)1268 void RemoveStickyNotitification(const std::string& notification_id) {
1269   message_center::MessageCenter::Get()->RemoveNotification(notification_id,
1270                                                            false /* by_user */);
1271 }
1272 
1273 // Return false if the accessibility shortcuts have been disabled, or if
1274 // the accessibility feature itself associated with |accessibility_pref_name|
1275 // is being enforced by the administrator.
IsAccessibilityShortcutEnabled(const std::string & accessibility_pref_name)1276 bool IsAccessibilityShortcutEnabled(
1277     const std::string& accessibility_pref_name) {
1278   Shell* shell = Shell::Get();
1279   return shell->accessibility_controller()->accessibility_shortcuts_enabled() &&
1280          !shell->session_controller()
1281               ->GetActivePrefService()
1282               ->IsManagedPreference(accessibility_pref_name);
1283 }
1284 
SetDockedMagnifierEnabled(bool enabled)1285 void SetDockedMagnifierEnabled(bool enabled) {
1286   Shell* shell = Shell::Get();
1287   // Check that the attempt to change the value of the accessibility feature
1288   // will be done only when the accessibility shortcuts are enabled, and
1289   // the feature isn't being enforced by the administrator.
1290   DCHECK(IsAccessibilityShortcutEnabled(prefs::kDockedMagnifierEnabled));
1291 
1292   shell->docked_magnifier_controller()->SetEnabled(enabled);
1293 
1294   RemoveStickyNotitification(kDockedMagnifierToggleAccelNotificationId);
1295   if (shell->docked_magnifier_controller()->GetEnabled()) {
1296     CreateAndShowStickyNotification(IDS_DOCKED_MAGNIFIER_ACCEL_TITLE,
1297                                     IDS_DOCKED_MAGNIFIER_ACCEL_MSG,
1298                                     kDockedMagnifierToggleAccelNotificationId);
1299   }
1300 }
1301 
HandleToggleDockedMagnifier()1302 void HandleToggleDockedMagnifier() {
1303   base::RecordAction(UserMetricsAction("Accel_Toggle_Docked_Magnifier"));
1304 
1305   const bool is_shortcut_enabled =
1306       IsAccessibilityShortcutEnabled(prefs::kDockedMagnifierEnabled);
1307 
1308   base::UmaHistogramBoolean(kAccessibilityDockedMagnifierShortcut,
1309                             is_shortcut_enabled);
1310 
1311   Shell* shell = Shell::Get();
1312 
1313   RemoveStickyNotitification(kDockedMagnifierToggleAccelNotificationId);
1314   if (!is_shortcut_enabled) {
1315     NotifyAccessibilityFeatureDisabledByAdmin(
1316         IDS_ASH_DOCKED_MAGNIFIER_SHORTCUT_DISABLED,
1317         shell->docked_magnifier_controller()->GetEnabled(),
1318         kDockedMagnifierToggleAccelNotificationId);
1319     return;
1320   }
1321 
1322   DockedMagnifierControllerImpl* docked_magnifier_controller =
1323       shell->docked_magnifier_controller();
1324   AccessibilityControllerImpl* accessibility_controller =
1325       shell->accessibility_controller();
1326 
1327   const bool current_enabled = docked_magnifier_controller->GetEnabled();
1328   const bool dialog_ever_accepted =
1329       accessibility_controller->docked_magnifier().WasDialogAccepted();
1330 
1331   if (!current_enabled && !dialog_ever_accepted) {
1332     shell->accelerator_controller()->MaybeShowConfirmationDialog(
1333         IDS_ASH_DOCKED_MAGNIFIER_TITLE, IDS_ASH_DOCKED_MAGNIFIER_BODY,
1334         base::BindOnce([]() {
1335           Shell::Get()
1336               ->accessibility_controller()
1337               ->docked_magnifier()
1338               .SetDialogAccepted();
1339           SetDockedMagnifierEnabled(true);
1340         }),
1341         base::DoNothing());
1342   } else {
1343     SetDockedMagnifierEnabled(!current_enabled);
1344   }
1345 }
1346 
SetFullscreenMagnifierEnabled(bool enabled)1347 void SetFullscreenMagnifierEnabled(bool enabled) {
1348   // TODO (afakhry): Move the below into a single call (crbug/817157).
1349   // Necessary to make magnification controller in ash observe changes to the
1350   // prefs iteself.
1351   Shell* shell = Shell::Get();
1352   // Check that the attempt to change the value of the accessibility feature
1353   // will be done only when the accessibility shortcuts are enabled, and
1354   // the feature isn't being enforced by the administrator.
1355   DCHECK(IsAccessibilityShortcutEnabled(
1356       prefs::kAccessibilityScreenMagnifierEnabled));
1357 
1358   shell->accessibility_controller()->fullscreen_magnifier().SetEnabled(enabled);
1359 
1360   RemoveStickyNotitification(kFullscreenMagnifierToggleAccelNotificationId);
1361   if (shell->magnification_controller()->IsEnabled()) {
1362     CreateAndShowStickyNotification(
1363         IDS_FULLSCREEN_MAGNIFIER_ACCEL_TITLE,
1364         IDS_FULLSCREEN_MAGNIFIER_ACCEL_MSG,
1365         kFullscreenMagnifierToggleAccelNotificationId);
1366   }
1367 }
1368 
SetHighContrastEnabled(bool enabled)1369 void SetHighContrastEnabled(bool enabled) {
1370   Shell* shell = Shell::Get();
1371   // Check that the attempt to change the value of the accessibility feature
1372   // will be done only when the accessibility shortcuts are enabled, and
1373   // the feature isn't being enforced by the administrator.
1374   DCHECK(
1375       IsAccessibilityShortcutEnabled(prefs::kAccessibilityHighContrastEnabled));
1376 
1377   shell->accessibility_controller()->high_contrast().SetEnabled(enabled);
1378 
1379   RemoveStickyNotitification(kHighContrastToggleAccelNotificationId);
1380   if (shell->accessibility_controller()->high_contrast().enabled()) {
1381     CreateAndShowStickyNotification(IDS_HIGH_CONTRAST_ACCEL_TITLE,
1382                                     IDS_HIGH_CONTRAST_ACCEL_MSG,
1383                                     kHighContrastToggleAccelNotificationId);
1384   }
1385 }
1386 
HandleToggleHighContrast()1387 void HandleToggleHighContrast() {
1388   base::RecordAction(UserMetricsAction("Accel_Toggle_High_Contrast"));
1389 
1390   const bool is_shortcut_enabled =
1391       IsAccessibilityShortcutEnabled(prefs::kAccessibilityHighContrastEnabled);
1392 
1393   base::UmaHistogramBoolean(kAccessibilityHighContrastShortcut,
1394                             is_shortcut_enabled);
1395 
1396   Shell* shell = Shell::Get();
1397 
1398   RemoveStickyNotitification(kHighContrastToggleAccelNotificationId);
1399   if (!is_shortcut_enabled) {
1400     NotifyAccessibilityFeatureDisabledByAdmin(
1401         IDS_ASH_HIGH_CONTRAST_SHORTCUT_DISABLED,
1402         shell->accessibility_controller()->high_contrast().enabled(),
1403         kHighContrastToggleAccelNotificationId);
1404     return;
1405   }
1406 
1407   AccessibilityControllerImpl* controller = shell->accessibility_controller();
1408   const bool current_enabled = controller->high_contrast().enabled();
1409   const bool dialog_ever_accepted =
1410       controller->high_contrast().WasDialogAccepted();
1411 
1412   if (!current_enabled && !dialog_ever_accepted) {
1413     shell->accelerator_controller()->MaybeShowConfirmationDialog(
1414         IDS_ASH_HIGH_CONTRAST_TITLE, IDS_ASH_HIGH_CONTRAST_BODY,
1415         base::BindOnce([]() {
1416           Shell::Get()
1417               ->accessibility_controller()
1418               ->high_contrast()
1419               .SetDialogAccepted();
1420           SetHighContrastEnabled(true);
1421         }),
1422         base::DoNothing());
1423   } else {
1424     SetHighContrastEnabled(!current_enabled);
1425   }
1426 }
1427 
HandleToggleFullscreenMagnifier()1428 void HandleToggleFullscreenMagnifier() {
1429   base::RecordAction(UserMetricsAction("Accel_Toggle_Fullscreen_Magnifier"));
1430 
1431   const bool is_shortcut_enabled = IsAccessibilityShortcutEnabled(
1432       prefs::kAccessibilityScreenMagnifierEnabled);
1433 
1434   base::UmaHistogramBoolean(kAccessibilityScreenMagnifierShortcut,
1435                             is_shortcut_enabled);
1436 
1437   Shell* shell = Shell::Get();
1438 
1439   RemoveStickyNotitification(kFullscreenMagnifierToggleAccelNotificationId);
1440   if (!is_shortcut_enabled) {
1441     NotifyAccessibilityFeatureDisabledByAdmin(
1442         IDS_ASH_FULLSCREEN_MAGNIFIER_SHORTCUT_DISABLED,
1443         shell->magnification_controller()->IsEnabled(),
1444         kFullscreenMagnifierToggleAccelNotificationId);
1445     return;
1446   }
1447 
1448   MagnificationController* magnification_controller =
1449       shell->magnification_controller();
1450   AccessibilityControllerImpl* accessibility_controller =
1451       shell->accessibility_controller();
1452 
1453   const bool current_enabled = magnification_controller->IsEnabled();
1454   const bool dialog_ever_accepted =
1455       accessibility_controller->fullscreen_magnifier().WasDialogAccepted();
1456 
1457   if (!current_enabled && !dialog_ever_accepted) {
1458     shell->accelerator_controller()->MaybeShowConfirmationDialog(
1459         IDS_ASH_SCREEN_MAGNIFIER_TITLE, IDS_ASH_SCREEN_MAGNIFIER_BODY,
1460         base::BindOnce([]() {
1461           Shell::Get()
1462               ->accessibility_controller()
1463               ->fullscreen_magnifier()
1464               .SetDialogAccepted();
1465           SetFullscreenMagnifierEnabled(true);
1466         }),
1467         base::DoNothing());
1468   } else {
1469     SetFullscreenMagnifierEnabled(!current_enabled);
1470   }
1471 }
1472 
HandleToggleSpokenFeedback()1473 void HandleToggleSpokenFeedback() {
1474   base::RecordAction(UserMetricsAction("Accel_Toggle_Spoken_Feedback"));
1475 
1476   const bool is_shortcut_enabled = IsAccessibilityShortcutEnabled(
1477       prefs::kAccessibilitySpokenFeedbackEnabled);
1478 
1479   base::UmaHistogramBoolean(kAccessibilitySpokenFeedbackShortcut,
1480                             is_shortcut_enabled);
1481 
1482   Shell* shell = Shell::Get();
1483   const bool old_value =
1484       shell->accessibility_controller()->spoken_feedback().enabled();
1485 
1486   RemoveStickyNotitification(kSpokenFeedbackToggleAccelNotificationId);
1487   if (!is_shortcut_enabled) {
1488     NotifyAccessibilityFeatureDisabledByAdmin(
1489         IDS_ASH_SPOKEN_FEEDBACK_SHORTCUT_DISABLED, old_value,
1490         kSpokenFeedbackToggleAccelNotificationId);
1491     return;
1492   }
1493 
1494   shell->accessibility_controller()->SetSpokenFeedbackEnabled(
1495       !old_value, A11Y_NOTIFICATION_SHOW);
1496 }
1497 
CanHandleTogglePrivacyScreen()1498 bool CanHandleTogglePrivacyScreen() {
1499   return Shell::Get()->privacy_screen_controller()->IsSupported();
1500 }
1501 
HandleTogglePrivacyScreen()1502 void HandleTogglePrivacyScreen() {
1503   base::RecordAction(UserMetricsAction("Accel_Toggle_Privacy_Screen"));
1504 
1505   PrivacyScreenController* controller =
1506       Shell::Get()->privacy_screen_controller();
1507   controller->SetEnabled(
1508       !controller->GetEnabled(),
1509       PrivacyScreenController::kToggleUISurfaceKeyboardShortcut);
1510 }
1511 
1512 // Percent by which the volume should be changed when a volume key is pressed.
1513 const double kStepPercentage = 4.0;
1514 
HandleVolumeDown()1515 void HandleVolumeDown() {
1516   base::RecordAction(UserMetricsAction("Accel_VolumeDown_F9"));
1517 
1518   chromeos::CrasAudioHandler* audio_handler = chromeos::CrasAudioHandler::Get();
1519   if (audio_handler->IsOutputMuted()) {
1520     audio_handler->SetOutputVolumePercent(0);
1521   } else {
1522     audio_handler->AdjustOutputVolumeByPercent(-kStepPercentage);
1523     if (audio_handler->IsOutputVolumeBelowDefaultMuteLevel())
1524       audio_handler->SetOutputMute(true);
1525     else
1526       AcceleratorController::PlayVolumeAdjustmentSound();
1527   }
1528 }
1529 
HandleVolumeMute(const ui::Accelerator & accelerator)1530 void HandleVolumeMute(const ui::Accelerator& accelerator) {
1531   if (accelerator.key_code() == ui::VKEY_VOLUME_MUTE)
1532     base::RecordAction(UserMetricsAction("Accel_VolumeMute_F8"));
1533 
1534   chromeos::CrasAudioHandler::Get()->SetOutputMute(true);
1535 }
1536 
HandleVolumeUp()1537 void HandleVolumeUp() {
1538   base::RecordAction(UserMetricsAction("Accel_VolumeUp_F10"));
1539 
1540   chromeos::CrasAudioHandler* audio_handler = chromeos::CrasAudioHandler::Get();
1541   bool play_sound = false;
1542   if (audio_handler->IsOutputMuted()) {
1543     audio_handler->SetOutputMute(false);
1544     audio_handler->AdjustOutputVolumeToAudibleLevel();
1545     play_sound = true;
1546   } else {
1547     play_sound = audio_handler->GetOutputVolumePercent() != 100;
1548     audio_handler->AdjustOutputVolumeByPercent(kStepPercentage);
1549   }
1550 
1551   if (play_sound)
1552     AcceleratorController::PlayVolumeAdjustmentSound();
1553 }
1554 
CanHandleActiveMagnifierZoom()1555 bool CanHandleActiveMagnifierZoom() {
1556   return Shell::Get()->magnification_controller()->IsEnabled() ||
1557          Shell::Get()->docked_magnifier_controller()->GetEnabled();
1558 }
1559 
1560 // Change the scale of the active magnifier.
HandleActiveMagnifierZoom(int delta_index)1561 void HandleActiveMagnifierZoom(int delta_index) {
1562   if (Shell::Get()->magnification_controller()->IsEnabled()) {
1563     Shell::Get()->magnification_controller()->StepToNextScaleValue(delta_index);
1564     return;
1565   }
1566 
1567   if (Shell::Get()->docked_magnifier_controller()->GetEnabled()) {
1568     Shell::Get()->docked_magnifier_controller()->StepToNextScaleValue(
1569         delta_index);
1570   }
1571 }
1572 
CanHandleTouchHud()1573 bool CanHandleTouchHud() {
1574   return RootWindowController::ForTargetRootWindow()->touch_hud_debug();
1575 }
1576 
HandleTouchHudClear()1577 void HandleTouchHudClear() {
1578   RootWindowController::ForTargetRootWindow()->touch_hud_debug()->Clear();
1579 }
1580 
HandleTouchHudModeChange()1581 void HandleTouchHudModeChange() {
1582   RootWindowController* controller =
1583       RootWindowController::ForTargetRootWindow();
1584   controller->touch_hud_debug()->ChangeToNextMode();
1585 }
1586 
1587 }  // namespace
1588 
1589 constexpr const char* AcceleratorControllerImpl::kVolumeButtonRegion;
1590 constexpr const char* AcceleratorControllerImpl::kVolumeButtonSide;
1591 constexpr const char* AcceleratorControllerImpl::kVolumeButtonRegionKeyboard;
1592 constexpr const char* AcceleratorControllerImpl::kVolumeButtonRegionScreen;
1593 constexpr const char* AcceleratorControllerImpl::kVolumeButtonSideLeft;
1594 constexpr const char* AcceleratorControllerImpl::kVolumeButtonSideRight;
1595 constexpr const char* AcceleratorControllerImpl::kVolumeButtonSideTop;
1596 constexpr const char* AcceleratorControllerImpl::kVolumeButtonSideBottom;
1597 
1598 ////////////////////////////////////////////////////////////////////////////////
1599 // AcceleratorControllerImpl, public:
1600 
TestApi(AcceleratorControllerImpl * controller)1601 AcceleratorControllerImpl::TestApi::TestApi(
1602     AcceleratorControllerImpl* controller)
1603     : controller_(controller) {
1604   DCHECK(controller_);
1605 }
1606 
TriggerTabletModeVolumeAdjustTimer()1607 bool AcceleratorControllerImpl::TestApi::TriggerTabletModeVolumeAdjustTimer() {
1608   if (!controller_->tablet_mode_volume_adjust_timer_.IsRunning())
1609     return false;
1610 
1611   controller_->tablet_mode_volume_adjust_timer_.FireNow();
1612   return true;
1613 }
1614 
RegisterAccelerators(const AcceleratorData accelerators[],size_t accelerators_length)1615 void AcceleratorControllerImpl::TestApi::RegisterAccelerators(
1616     const AcceleratorData accelerators[],
1617     size_t accelerators_length) {
1618   controller_->RegisterAccelerators(accelerators, accelerators_length);
1619 }
1620 
1621 const DeprecatedAcceleratorData*
GetDeprecatedAcceleratorData(AcceleratorAction action)1622 AcceleratorControllerImpl::TestApi::GetDeprecatedAcceleratorData(
1623     AcceleratorAction action) {
1624   auto it = controller_->actions_with_deprecations_.find(action);
1625   if (it == controller_->actions_with_deprecations_.end())
1626     return nullptr;
1627 
1628   return it->second;
1629 }
1630 
1631 AcceleratorConfirmationDialog*
GetConfirmationDialog()1632 AcceleratorControllerImpl::TestApi::GetConfirmationDialog() {
1633   return controller_->confirmation_dialog_.get();
1634 }
1635 
SetSideVolumeButtonFilePath(base::FilePath path)1636 void AcceleratorControllerImpl::TestApi::SetSideVolumeButtonFilePath(
1637     base::FilePath path) {
1638   controller_->side_volume_button_location_file_path_ = path;
1639 }
1640 
SetSideVolumeButtonLocation(const std::string & region,const std::string & side)1641 void AcceleratorControllerImpl::TestApi::SetSideVolumeButtonLocation(
1642     const std::string& region,
1643     const std::string& side) {
1644   controller_->side_volume_button_location_.region = region;
1645   controller_->side_volume_button_location_.side = side;
1646 }
1647 
AcceleratorControllerImpl()1648 AcceleratorControllerImpl::AcceleratorControllerImpl()
1649     : accelerator_manager_(std::make_unique<ui::AcceleratorManager>()),
1650       accelerator_history_(std::make_unique<ui::AcceleratorHistory>()),
1651       side_volume_button_location_file_path_(
1652           base::FilePath(kSideVolumeButtonLocationFilePath)) {
1653   Init();
1654 
1655   ParseSideVolumeButtonLocationInfo();
1656 }
1657 
1658 AcceleratorControllerImpl::~AcceleratorControllerImpl() = default;
1659 
Register(const std::vector<ui::Accelerator> & accelerators,ui::AcceleratorTarget * target)1660 void AcceleratorControllerImpl::Register(
1661     const std::vector<ui::Accelerator>& accelerators,
1662     ui::AcceleratorTarget* target) {
1663   accelerator_manager_->Register(
1664       accelerators, ui::AcceleratorManager::kNormalPriority, target);
1665 }
1666 
Unregister(const ui::Accelerator & accelerator,ui::AcceleratorTarget * target)1667 void AcceleratorControllerImpl::Unregister(const ui::Accelerator& accelerator,
1668                                            ui::AcceleratorTarget* target) {
1669   accelerator_manager_->Unregister(accelerator, target);
1670 }
1671 
UnregisterAll(ui::AcceleratorTarget * target)1672 void AcceleratorControllerImpl::UnregisterAll(ui::AcceleratorTarget* target) {
1673   accelerator_manager_->UnregisterAll(target);
1674 }
1675 
IsActionForAcceleratorEnabled(const ui::Accelerator & accelerator) const1676 bool AcceleratorControllerImpl::IsActionForAcceleratorEnabled(
1677     const ui::Accelerator& accelerator) const {
1678   std::map<ui::Accelerator, AcceleratorAction>::const_iterator it =
1679       accelerators_.find(accelerator);
1680   return it != accelerators_.end() && CanPerformAction(it->second, accelerator);
1681 }
1682 
Process(const ui::Accelerator & accelerator)1683 bool AcceleratorControllerImpl::Process(const ui::Accelerator& accelerator) {
1684   return accelerator_manager_->Process(accelerator);
1685 }
1686 
IsDeprecated(const ui::Accelerator & accelerator) const1687 bool AcceleratorControllerImpl::IsDeprecated(
1688     const ui::Accelerator& accelerator) const {
1689   return deprecated_accelerators_.count(accelerator) != 0;
1690 }
1691 
PerformActionIfEnabled(AcceleratorAction action,const ui::Accelerator & accelerator)1692 bool AcceleratorControllerImpl::PerformActionIfEnabled(
1693     AcceleratorAction action,
1694     const ui::Accelerator& accelerator) {
1695   if (CanPerformAction(action, accelerator)) {
1696     PerformAction(action, accelerator);
1697     return true;
1698   }
1699   return false;
1700 }
1701 
OnMenuAccelerator(const ui::Accelerator & accelerator)1702 bool AcceleratorControllerImpl::OnMenuAccelerator(
1703     const ui::Accelerator& accelerator) {
1704   accelerator_history()->StoreCurrentAccelerator(accelerator);
1705 
1706   auto itr = accelerators_.find(accelerator);
1707   if (itr == accelerators_.end())
1708     return false;  // Menu shouldn't be closed for an invalid accelerator.
1709 
1710   AcceleratorAction action = itr->second;
1711   return actions_keeping_menu_open_.count(action) == 0;
1712 }
1713 
IsRegistered(const ui::Accelerator & accelerator) const1714 bool AcceleratorControllerImpl::IsRegistered(
1715     const ui::Accelerator& accelerator) const {
1716   return accelerator_manager_->IsRegistered(accelerator);
1717 }
1718 
GetAcceleratorHistory()1719 ui::AcceleratorHistory* AcceleratorControllerImpl::GetAcceleratorHistory() {
1720   return accelerator_history_.get();
1721 }
1722 
IsPreferred(const ui::Accelerator & accelerator) const1723 bool AcceleratorControllerImpl::IsPreferred(
1724     const ui::Accelerator& accelerator) const {
1725   std::map<ui::Accelerator, AcceleratorAction>::const_iterator iter =
1726       accelerators_.find(accelerator);
1727   if (iter == accelerators_.end())
1728     return false;  // not an accelerator.
1729 
1730   return preferred_actions_.find(iter->second) != preferred_actions_.end();
1731 }
1732 
IsReserved(const ui::Accelerator & accelerator) const1733 bool AcceleratorControllerImpl::IsReserved(
1734     const ui::Accelerator& accelerator) const {
1735   std::map<ui::Accelerator, AcceleratorAction>::const_iterator iter =
1736       accelerators_.find(accelerator);
1737   if (iter == accelerators_.end())
1738     return false;  // not an accelerator.
1739 
1740   return reserved_actions_.find(iter->second) != reserved_actions_.end();
1741 }
1742 
1743 AcceleratorControllerImpl::AcceleratorProcessingRestriction
GetCurrentAcceleratorRestriction()1744 AcceleratorControllerImpl::GetCurrentAcceleratorRestriction() {
1745   return GetAcceleratorProcessingRestriction(-1);
1746 }
1747 
1748 ////////////////////////////////////////////////////////////////////////////////
1749 // AcceleratorControllerImpl, ui::AcceleratorTarget implementation:
1750 
AcceleratorPressed(const ui::Accelerator & accelerator)1751 bool AcceleratorControllerImpl::AcceleratorPressed(
1752     const ui::Accelerator& accelerator) {
1753   std::map<ui::Accelerator, AcceleratorAction>::const_iterator it =
1754       accelerators_.find(accelerator);
1755   DCHECK(it != accelerators_.end());
1756   AcceleratorAction action = it->second;
1757   if (!CanPerformAction(action, accelerator))
1758     return false;
1759 
1760   // Handling the deprecated accelerators (if any) only if action can be
1761   // performed.
1762   if (MaybeDeprecatedAcceleratorPressed(action, accelerator) ==
1763       AcceleratorProcessingStatus::STOP) {
1764     return false;
1765   }
1766 
1767   PerformAction(action, accelerator);
1768   return ShouldActionConsumeKeyEvent(action);
1769 }
1770 
CanHandleAccelerators() const1771 bool AcceleratorControllerImpl::CanHandleAccelerators() const {
1772   return true;
1773 }
1774 
1775 ///////////////////////////////////////////////////////////////////////////////
1776 // AcceleratorControllerImpl, private:
1777 
Init()1778 void AcceleratorControllerImpl::Init() {
1779   for (size_t i = 0; i < kActionsAllowedAtLoginOrLockScreenLength; ++i) {
1780     actions_allowed_at_login_screen_.insert(
1781         kActionsAllowedAtLoginOrLockScreen[i]);
1782     actions_allowed_at_lock_screen_.insert(
1783         kActionsAllowedAtLoginOrLockScreen[i]);
1784   }
1785   for (size_t i = 0; i < kActionsAllowedAtLockScreenLength; ++i)
1786     actions_allowed_at_lock_screen_.insert(kActionsAllowedAtLockScreen[i]);
1787   for (size_t i = 0; i < kActionsAllowedAtPowerMenuLength; ++i)
1788     actions_allowed_at_power_menu_.insert(kActionsAllowedAtPowerMenu[i]);
1789   for (size_t i = 0; i < kActionsAllowedAtModalWindowLength; ++i)
1790     actions_allowed_at_modal_window_.insert(kActionsAllowedAtModalWindow[i]);
1791   for (size_t i = 0; i < kPreferredActionsLength; ++i)
1792     preferred_actions_.insert(kPreferredActions[i]);
1793   for (size_t i = 0; i < kReservedActionsLength; ++i)
1794     reserved_actions_.insert(kReservedActions[i]);
1795   for (size_t i = 0; i < kRepeatableActionsLength; ++i)
1796     repeatable_actions_.insert(kRepeatableActions[i]);
1797   for (size_t i = 0; i < kActionsAllowedInAppModeOrPinnedModeLength; ++i) {
1798     actions_allowed_in_app_mode_.insert(
1799         kActionsAllowedInAppModeOrPinnedMode[i]);
1800     actions_allowed_in_pinned_mode_.insert(
1801         kActionsAllowedInAppModeOrPinnedMode[i]);
1802   }
1803   for (size_t i = 0; i < kActionsAllowedInPinnedModeLength; ++i)
1804     actions_allowed_in_pinned_mode_.insert(kActionsAllowedInPinnedMode[i]);
1805   for (size_t i = 0; i < kActionsAllowedInAppModeLength; ++i)
1806     actions_allowed_in_app_mode_.insert(kActionsAllowedInAppMode[i]);
1807   for (size_t i = 0; i < kActionsNeedingWindowLength; ++i)
1808     actions_needing_window_.insert(kActionsNeedingWindow[i]);
1809   for (size_t i = 0; i < kActionsKeepingMenuOpenLength; ++i)
1810     actions_keeping_menu_open_.insert(kActionsKeepingMenuOpen[i]);
1811 
1812   RegisterAccelerators(kAcceleratorData, kAcceleratorDataLength);
1813 
1814   if (::features::IsNewShortcutMappingEnabled()) {
1815     RegisterAccelerators(kEnableWithNewMappingAcceleratorData,
1816                          kEnableWithNewMappingAcceleratorDataLength);
1817   } else {
1818     RegisterAccelerators(kDisableWithNewMappingAcceleratorData,
1819                          kDisableWithNewMappingAcceleratorDataLength);
1820   }
1821 
1822   RegisterDeprecatedAccelerators();
1823 
1824   if (debug::DebugAcceleratorsEnabled()) {
1825     RegisterAccelerators(kDebugAcceleratorData, kDebugAcceleratorDataLength);
1826     // All debug accelerators are reserved.
1827     for (size_t i = 0; i < kDebugAcceleratorDataLength; ++i)
1828       reserved_actions_.insert(kDebugAcceleratorData[i].action);
1829   }
1830 
1831   if (debug::DeveloperAcceleratorsEnabled()) {
1832     RegisterAccelerators(kDeveloperAcceleratorData,
1833                          kDeveloperAcceleratorDataLength);
1834     // Developer accelerators are also reserved.
1835     for (size_t i = 0; i < kDeveloperAcceleratorDataLength; ++i)
1836       reserved_actions_.insert(kDeveloperAcceleratorData[i].action);
1837   }
1838 }
1839 
RegisterAccelerators(const AcceleratorData accelerators[],size_t accelerators_length)1840 void AcceleratorControllerImpl::RegisterAccelerators(
1841     const AcceleratorData accelerators[],
1842     size_t accelerators_length) {
1843   std::vector<ui::Accelerator> ui_accelerators;
1844   for (size_t i = 0; i < accelerators_length; ++i) {
1845     ui::Accelerator accelerator =
1846         CreateAccelerator(accelerators[i].keycode, accelerators[i].modifiers,
1847                           accelerators[i].trigger_on_press);
1848     ui_accelerators.push_back(accelerator);
1849     accelerators_.insert(std::make_pair(accelerator, accelerators[i].action));
1850   }
1851   Register(ui_accelerators, this);
1852 }
1853 
RegisterDeprecatedAccelerators()1854 void AcceleratorControllerImpl::RegisterDeprecatedAccelerators() {
1855   for (size_t i = 0; i < kDeprecatedAcceleratorsDataLength; ++i) {
1856     const DeprecatedAcceleratorData* data = &kDeprecatedAcceleratorsData[i];
1857     actions_with_deprecations_[data->action] = data;
1858   }
1859 
1860   std::vector<ui::Accelerator> ui_accelerators;
1861   for (size_t i = 0; i < kDeprecatedAcceleratorsLength; ++i) {
1862     const AcceleratorData& accelerator_data = kDeprecatedAccelerators[i];
1863     const ui::Accelerator deprecated_accelerator =
1864         CreateAccelerator(accelerator_data.keycode, accelerator_data.modifiers,
1865                           accelerator_data.trigger_on_press);
1866 
1867     ui_accelerators.push_back(deprecated_accelerator);
1868     accelerators_[deprecated_accelerator] = accelerator_data.action;
1869     deprecated_accelerators_.insert(deprecated_accelerator);
1870   }
1871   Register(ui_accelerators, this);
1872 }
1873 
CanPerformAction(AcceleratorAction action,const ui::Accelerator & accelerator) const1874 bool AcceleratorControllerImpl::CanPerformAction(
1875     AcceleratorAction action,
1876     const ui::Accelerator& accelerator) const {
1877   if (accelerator.IsRepeat() && !repeatable_actions_.count(action))
1878     return false;
1879 
1880   AcceleratorProcessingRestriction restriction =
1881       GetAcceleratorProcessingRestriction(action);
1882   if (restriction != RESTRICTION_NONE)
1883     return restriction == RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION;
1884 
1885   const ui::Accelerator& previous_accelerator =
1886       accelerator_history_->previous_accelerator();
1887 
1888   // True should be returned if running |action| does something. Otherwise,
1889   // false should be returned to give the web contents a chance at handling the
1890   // accelerator.
1891   switch (action) {
1892     case CYCLE_BACKWARD_MRU:
1893     case CYCLE_FORWARD_MRU:
1894       return CanHandleCycleMru(accelerator);
1895     case DESKS_ACTIVATE_DESK:
1896     case DESKS_MOVE_ACTIVE_ITEM:
1897     case DESKS_NEW_DESK:
1898     case DESKS_REMOVE_CURRENT_DESK:
1899       return true;
1900     case DEBUG_PRINT_LAYER_HIERARCHY:
1901     case DEBUG_PRINT_VIEW_HIERARCHY:
1902     case DEBUG_PRINT_WINDOW_HIERARCHY:
1903     case DEBUG_SHOW_TOAST:
1904     case DEBUG_TOGGLE_DEVICE_SCALE_FACTOR:
1905     case DEBUG_TOGGLE_SHOW_DEBUG_BORDERS:
1906     case DEBUG_TOGGLE_SHOW_FPS_COUNTER:
1907     case DEBUG_TOGGLE_SHOW_PAINT_RECTS:
1908     case DEBUG_TOGGLE_TOUCH_PAD:
1909     case DEBUG_TOGGLE_TOUCH_SCREEN:
1910     case DEBUG_TOGGLE_TABLET_MODE:
1911     case DEBUG_TOGGLE_WALLPAPER_MODE:
1912     case DEBUG_TRIGGER_CRASH:
1913     case DEBUG_TOGGLE_HUD_DISPLAY:
1914       return debug::DebugAcceleratorsEnabled();
1915     case DEV_ADD_REMOVE_DISPLAY:
1916     case DEV_TOGGLE_UNIFIED_DESKTOP:
1917       return debug::DeveloperAcceleratorsEnabled();
1918     case DISABLE_CAPS_LOCK:
1919       return CanHandleDisableCapsLock(previous_accelerator);
1920     case LOCK_SCREEN:
1921       return CanHandleLock();
1922     case MAGNIFIER_ZOOM_IN:
1923     case MAGNIFIER_ZOOM_OUT:
1924       return CanHandleActiveMagnifierZoom();
1925     case MOVE_ACTIVE_WINDOW_BETWEEN_DISPLAYS:
1926       return display_move_window_util::
1927           CanHandleMoveActiveWindowBetweenDisplays();
1928     case NEW_INCOGNITO_WINDOW:
1929       return CanHandleNewIncognitoWindow();
1930     case PRIVACY_SCREEN_TOGGLE:
1931       return CanHandleTogglePrivacyScreen();
1932     case ROTATE_SCREEN:
1933       return true;
1934     case SCALE_UI_DOWN:
1935     case SCALE_UI_RESET:
1936     case SCALE_UI_UP:
1937       return true;
1938     case SHOW_STYLUS_TOOLS:
1939       return CanHandleShowStylusTools();
1940     case START_AMBIENT_MODE:
1941       return CanHandleStartAmbientMode();
1942     case START_ASSISTANT:
1943       return true;
1944     case SWAP_PRIMARY_DISPLAY:
1945       return display::Screen::GetScreen()->GetNumDisplays() > 1;
1946     case SWITCH_IME:
1947       return CanHandleSwitchIme(accelerator);
1948     case SWITCH_TO_NEXT_IME:
1949       return CanCycleInputMethod();
1950     case SWITCH_TO_LAST_USED_IME:
1951       return CanCycleInputMethod();
1952     case SWITCH_TO_PREVIOUS_USER:
1953     case SWITCH_TO_NEXT_USER:
1954       return CanHandleCycleUser();
1955     case TOGGLE_APP_LIST:
1956     case TOGGLE_APP_LIST_FULLSCREEN:
1957       return CanHandleToggleAppList(accelerator, previous_accelerator);
1958     case TOGGLE_CAPS_LOCK:
1959       return CanHandleToggleCapsLock(
1960           accelerator, previous_accelerator,
1961           accelerator_history_->currently_pressed_keys());
1962     case TOGGLE_DICTATION:
1963       return CanHandleToggleDictation();
1964     case TOGGLE_DOCKED_MAGNIFIER:
1965       return true;
1966     case TOGGLE_FULLSCREEN_MAGNIFIER:
1967       return true;
1968     case TOGGLE_MESSAGE_CENTER_BUBBLE:
1969       return true;
1970     case TOGGLE_MIRROR_MODE:
1971       return true;
1972     case TOGGLE_OVERVIEW:
1973       return CanHandleToggleOverview();
1974     case TOUCH_HUD_CLEAR:
1975     case TOUCH_HUD_MODE_CHANGE:
1976       return CanHandleTouchHud();
1977     case UNPIN:
1978       return accelerators::CanUnpinWindow();
1979     case WINDOW_CYCLE_SNAP_LEFT:
1980     case WINDOW_CYCLE_SNAP_RIGHT:
1981       return CanHandleWindowSnap();
1982     case FOCUS_PIP:
1983       return !!FindPipWidget();
1984     case MINIMIZE_TOP_WINDOW_ON_BACK:
1985       return window_util::ShouldMinimizeTopWindowOnBack();
1986     case TAKE_PARTIAL_SCREENSHOT:
1987     case TAKE_SCREENSHOT:
1988     case TAKE_WINDOW_SCREENSHOT:
1989       return CanHandleScreenshot();
1990 
1991     // The following are always enabled.
1992     case BRIGHTNESS_DOWN:
1993     case BRIGHTNESS_UP:
1994     case EXIT:
1995     case FOCUS_NEXT_PANE:
1996     case FOCUS_PREVIOUS_PANE:
1997     case FOCUS_SHELF:
1998     case KEYBOARD_BRIGHTNESS_DOWN:
1999     case KEYBOARD_BRIGHTNESS_UP:
2000     case LAUNCH_APP_0:
2001     case LAUNCH_APP_1:
2002     case LAUNCH_APP_2:
2003     case LAUNCH_APP_3:
2004     case LAUNCH_APP_4:
2005     case LAUNCH_APP_5:
2006     case LAUNCH_APP_6:
2007     case LAUNCH_APP_7:
2008     case LAUNCH_LAST_APP:
2009     case LOCK_PRESSED:
2010     case LOCK_RELEASED:
2011     case MEDIA_FAST_FORWARD:
2012     case MEDIA_NEXT_TRACK:
2013     case MEDIA_PAUSE:
2014     case MEDIA_PLAY:
2015     case MEDIA_PLAY_PAUSE:
2016     case MEDIA_PREV_TRACK:
2017     case MEDIA_REWIND:
2018     case MEDIA_STOP:
2019     case NEW_TAB:
2020     case NEW_WINDOW:
2021     case OPEN_CROSH:
2022     case OPEN_FEEDBACK_PAGE:
2023     case OPEN_FILE_MANAGER:
2024     case OPEN_GET_HELP:
2025     case POWER_PRESSED:
2026     case POWER_RELEASED:
2027     case PRINT_UI_HIERARCHIES:
2028     case RESTORE_TAB:
2029     case ROTATE_WINDOW:
2030     case SHOW_IME_MENU_BUBBLE:
2031     case SHOW_SHORTCUT_VIEWER:
2032     case SHOW_TASK_MANAGER:
2033     case SUSPEND:
2034     case TOGGLE_FULLSCREEN:
2035     case TOGGLE_HIGH_CONTRAST:
2036     case TOGGLE_MAXIMIZED:
2037     case TOGGLE_SPOKEN_FEEDBACK:
2038     case TOGGLE_SYSTEM_TRAY_BUBBLE:
2039     case TOGGLE_WIFI:
2040     case VOLUME_DOWN:
2041     case VOLUME_MUTE:
2042     case VOLUME_UP:
2043     case WINDOW_MINIMIZE:
2044       return true;
2045   }
2046 }
2047 
PerformAction(AcceleratorAction action,const ui::Accelerator & accelerator)2048 void AcceleratorControllerImpl::PerformAction(
2049     AcceleratorAction action,
2050     const ui::Accelerator& accelerator) {
2051   AcceleratorProcessingRestriction restriction =
2052       GetAcceleratorProcessingRestriction(action);
2053   if (restriction != RESTRICTION_NONE)
2054     return;
2055 
2056   if ((action == VOLUME_DOWN || action == VOLUME_UP) &&
2057       Shell::Get()->tablet_mode_controller()->InTabletMode()) {
2058     if (ShouldSwapSideVolumeButtons(accelerator.source_device_id()))
2059       action = action == VOLUME_DOWN ? VOLUME_UP : VOLUME_DOWN;
2060 
2061     StartTabletModeVolumeAdjustTimer(action);
2062   }
2063 
2064   // If your accelerator invokes more than one line of code, please either
2065   // implement it in your module's controller code or pull it into a HandleFoo()
2066   // function above.
2067   switch (action) {
2068     case BRIGHTNESS_DOWN: {
2069       BrightnessControlDelegate* delegate =
2070           Shell::Get()->brightness_control_delegate();
2071       if (delegate)
2072         delegate->HandleBrightnessDown(accelerator);
2073       break;
2074     }
2075     case BRIGHTNESS_UP: {
2076       BrightnessControlDelegate* delegate =
2077           Shell::Get()->brightness_control_delegate();
2078       if (delegate)
2079         delegate->HandleBrightnessUp(accelerator);
2080       break;
2081     }
2082     case CYCLE_BACKWARD_MRU:
2083       HandleCycleBackwardMRU(accelerator);
2084       break;
2085     case CYCLE_FORWARD_MRU:
2086       HandleCycleForwardMRU(accelerator);
2087       break;
2088     case DESKS_ACTIVATE_DESK:
2089       HandleActivateDesk(accelerator);
2090       break;
2091     case DESKS_MOVE_ACTIVE_ITEM:
2092       HandleMoveActiveItem(accelerator);
2093       break;
2094     case DESKS_NEW_DESK:
2095       HandleNewDesk();
2096       break;
2097     case DESKS_REMOVE_CURRENT_DESK:
2098       HandleRemoveCurrentDesk();
2099       break;
2100     case DEBUG_PRINT_LAYER_HIERARCHY:
2101     case DEBUG_PRINT_VIEW_HIERARCHY:
2102     case DEBUG_PRINT_WINDOW_HIERARCHY:
2103     case DEBUG_SHOW_TOAST:
2104     case DEBUG_TOGGLE_DEVICE_SCALE_FACTOR:
2105       debug::PerformDebugActionIfEnabled(action);
2106       break;
2107     case DEBUG_TOGGLE_SHOW_DEBUG_BORDERS:
2108       debug::ToggleShowDebugBorders();
2109       break;
2110     case DEBUG_TOGGLE_SHOW_FPS_COUNTER:
2111       debug::ToggleShowFpsCounter();
2112       break;
2113     case DEBUG_TOGGLE_SHOW_PAINT_RECTS:
2114       debug::ToggleShowPaintRects();
2115       break;
2116     case DEBUG_TOGGLE_TOUCH_PAD:
2117     case DEBUG_TOGGLE_TOUCH_SCREEN:
2118     case DEBUG_TOGGLE_TABLET_MODE:
2119     case DEBUG_TOGGLE_WALLPAPER_MODE:
2120     case DEBUG_TRIGGER_CRASH:
2121     case DEBUG_TOGGLE_HUD_DISPLAY:
2122       debug::PerformDebugActionIfEnabled(action);
2123       break;
2124     case DEV_ADD_REMOVE_DISPLAY:
2125       Shell::Get()->display_manager()->AddRemoveDisplay();
2126       break;
2127     case DEV_TOGGLE_UNIFIED_DESKTOP:
2128       HandleToggleUnifiedDesktop();
2129       break;
2130     case DISABLE_CAPS_LOCK:
2131       HandleDisableCapsLock();
2132       break;
2133     case EXIT:
2134       // UMA metrics are recorded in the handler.
2135       exit_warning_handler_.HandleAccelerator();
2136       break;
2137     case FOCUS_NEXT_PANE:
2138       HandleRotatePaneFocus(FocusCycler::FORWARD);
2139       break;
2140     case FOCUS_PREVIOUS_PANE:
2141       HandleRotatePaneFocus(FocusCycler::BACKWARD);
2142       break;
2143     case FOCUS_SHELF:
2144       HandleFocusShelf();
2145       break;
2146     case FOCUS_PIP:
2147       HandleFocusPip();
2148       break;
2149     case KEYBOARD_BRIGHTNESS_DOWN: {
2150       KeyboardBrightnessControlDelegate* delegate =
2151           Shell::Get()->keyboard_brightness_control_delegate();
2152       if (delegate)
2153         delegate->HandleKeyboardBrightnessDown(accelerator);
2154       break;
2155     }
2156     case KEYBOARD_BRIGHTNESS_UP: {
2157       KeyboardBrightnessControlDelegate* delegate =
2158           Shell::Get()->keyboard_brightness_control_delegate();
2159       if (delegate)
2160         delegate->HandleKeyboardBrightnessUp(accelerator);
2161       break;
2162     }
2163     case LAUNCH_APP_0:
2164       HandleLaunchAppN(0);
2165       break;
2166     case LAUNCH_APP_1:
2167       HandleLaunchAppN(1);
2168       break;
2169     case LAUNCH_APP_2:
2170       HandleLaunchAppN(2);
2171       break;
2172     case LAUNCH_APP_3:
2173       HandleLaunchAppN(3);
2174       break;
2175     case LAUNCH_APP_4:
2176       HandleLaunchAppN(4);
2177       break;
2178     case LAUNCH_APP_5:
2179       HandleLaunchAppN(5);
2180       break;
2181     case LAUNCH_APP_6:
2182       HandleLaunchAppN(6);
2183       break;
2184     case LAUNCH_APP_7:
2185       HandleLaunchAppN(7);
2186       break;
2187     case LAUNCH_LAST_APP:
2188       HandleLaunchLastApp();
2189       break;
2190     case LOCK_PRESSED:
2191     case LOCK_RELEASED:
2192       Shell::Get()->power_button_controller()->OnLockButtonEvent(
2193           action == LOCK_PRESSED, base::TimeTicks());
2194       break;
2195     case LOCK_SCREEN:
2196       HandleLock();
2197       break;
2198     case MAGNIFIER_ZOOM_IN:
2199       HandleActiveMagnifierZoom(1);
2200       break;
2201     case MAGNIFIER_ZOOM_OUT:
2202       HandleActiveMagnifierZoom(-1);
2203       break;
2204     case MEDIA_FAST_FORWARD:
2205       HandleMediaFastForward();
2206       break;
2207     case MEDIA_NEXT_TRACK:
2208       HandleMediaNextTrack();
2209       break;
2210     case MEDIA_PAUSE:
2211       HandleMediaPause();
2212       break;
2213     case MEDIA_PLAY:
2214       HandleMediaPlay();
2215       break;
2216     case MEDIA_PLAY_PAUSE:
2217       HandleMediaPlayPause();
2218       break;
2219     case MEDIA_PREV_TRACK:
2220       HandleMediaPrevTrack();
2221       break;
2222     case MEDIA_REWIND:
2223       HandleMediaRewind();
2224       break;
2225     case MEDIA_STOP:
2226       HandleMediaStop();
2227       break;
2228     case MOVE_ACTIVE_WINDOW_BETWEEN_DISPLAYS:
2229       display_move_window_util::HandleMoveActiveWindowBetweenDisplays();
2230       break;
2231     case NEW_INCOGNITO_WINDOW:
2232       HandleNewIncognitoWindow();
2233       break;
2234     case NEW_TAB:
2235       HandleNewTab(accelerator);
2236       break;
2237     case NEW_WINDOW:
2238       HandleNewWindow();
2239       break;
2240     case OPEN_CROSH:
2241       HandleCrosh();
2242       break;
2243     case OPEN_FEEDBACK_PAGE:
2244       HandleOpenFeedbackPage();
2245       break;
2246     case OPEN_FILE_MANAGER:
2247       HandleFileManager();
2248       break;
2249     case OPEN_GET_HELP:
2250       HandleGetHelp();
2251       break;
2252     case POWER_PRESSED:
2253     case POWER_RELEASED:
2254       if (!base::SysInfo::IsRunningOnChromeOS()) {
2255         // There is no powerd, the Chrome OS power manager, in linux desktop,
2256         // so call the PowerButtonController here.
2257         Shell::Get()->power_button_controller()->OnPowerButtonEvent(
2258             action == POWER_PRESSED, base::TimeTicks());
2259       }
2260       // We don't do anything with these at present on the device,
2261       // (power button events are reported to us from powerm via
2262       // D-BUS), but we consume them to prevent them from getting
2263       // passed to apps -- see http://crbug.com/146609.
2264       break;
2265     case PRINT_UI_HIERARCHIES:
2266       debug::PrintUIHierarchies();
2267       break;
2268     case PRIVACY_SCREEN_TOGGLE:
2269       HandleTogglePrivacyScreen();
2270       break;
2271     case ROTATE_SCREEN:
2272       HandleRotateScreen();
2273       break;
2274     case RESTORE_TAB:
2275       HandleRestoreTab();
2276       break;
2277     case ROTATE_WINDOW:
2278       HandleRotateActiveWindow();
2279       break;
2280     case SCALE_UI_DOWN:
2281       accelerators::ZoomDisplay(false /* down */);
2282       break;
2283     case SCALE_UI_RESET:
2284       accelerators::ResetDisplayZoom();
2285       break;
2286     case SCALE_UI_UP:
2287       accelerators::ZoomDisplay(true /* up */);
2288       break;
2289     case SHOW_IME_MENU_BUBBLE:
2290       HandleShowImeMenuBubble();
2291       break;
2292     case SHOW_SHORTCUT_VIEWER:
2293       HandleShowKeyboardShortcutViewer();
2294       break;
2295     case SHOW_STYLUS_TOOLS:
2296       HandleShowStylusTools();
2297       break;
2298     case SHOW_TASK_MANAGER:
2299       HandleShowTaskManager();
2300       break;
2301     case START_AMBIENT_MODE:
2302       HandleToggleAmbientMode(accelerator);
2303       break;
2304     case START_ASSISTANT:
2305       HandleToggleAssistant(accelerator);
2306       break;
2307     case SUSPEND:
2308       HandleSuspend();
2309       break;
2310     case SWAP_PRIMARY_DISPLAY:
2311       HandleSwapPrimaryDisplay();
2312       break;
2313     case SWITCH_IME:
2314       HandleSwitchIme(accelerator);
2315       break;
2316     case SWITCH_TO_LAST_USED_IME:
2317       HandleSwitchToLastUsedIme(accelerator);
2318       break;
2319     case SWITCH_TO_NEXT_IME:
2320       HandleSwitchToNextIme(accelerator);
2321       break;
2322     case SWITCH_TO_NEXT_USER:
2323       HandleCycleUser(CycleUserDirection::NEXT);
2324       break;
2325     case SWITCH_TO_PREVIOUS_USER:
2326       HandleCycleUser(CycleUserDirection::PREVIOUS);
2327       break;
2328     case TAKE_PARTIAL_SCREENSHOT:
2329       HandleTakePartialScreenshot();
2330       break;
2331     case TAKE_SCREENSHOT:
2332       HandleTakeScreenshot();
2333       break;
2334     case TAKE_WINDOW_SCREENSHOT:
2335       HandleTakeWindowScreenshot();
2336       break;
2337     case TOGGLE_APP_LIST:
2338       HandleToggleAppList(accelerator, kSearchKey);
2339       break;
2340     case TOGGLE_APP_LIST_FULLSCREEN:
2341       HandleToggleAppList(accelerator, kSearchKeyFullscreen);
2342       break;
2343     case TOGGLE_CAPS_LOCK:
2344       HandleToggleCapsLock();
2345       break;
2346     case TOGGLE_DICTATION:
2347       HandleToggleDictation();
2348       break;
2349     case TOGGLE_DOCKED_MAGNIFIER:
2350       HandleToggleDockedMagnifier();
2351       break;
2352     case TOGGLE_FULLSCREEN:
2353       HandleToggleFullscreen(accelerator);
2354       break;
2355     case TOGGLE_FULLSCREEN_MAGNIFIER:
2356       HandleToggleFullscreenMagnifier();
2357       break;
2358     case TOGGLE_HIGH_CONTRAST:
2359       HandleToggleHighContrast();
2360       break;
2361     case TOGGLE_MAXIMIZED:
2362       accelerators::ToggleMaximized();
2363       break;
2364     case TOGGLE_MESSAGE_CENTER_BUBBLE:
2365       HandleToggleMessageCenterBubble();
2366       break;
2367     case TOGGLE_MIRROR_MODE:
2368       HandleToggleMirrorMode();
2369       break;
2370     case TOGGLE_OVERVIEW:
2371       HandleToggleOverview();
2372       break;
2373     case TOGGLE_SPOKEN_FEEDBACK:
2374       HandleToggleSpokenFeedback();
2375       break;
2376     case TOGGLE_SYSTEM_TRAY_BUBBLE:
2377       HandleToggleSystemTrayBubble();
2378       break;
2379     case TOGGLE_WIFI:
2380       Shell::Get()->system_tray_notifier()->NotifyRequestToggleWifi();
2381       break;
2382     case TOUCH_HUD_CLEAR:
2383       HandleTouchHudClear();
2384       break;
2385     case TOUCH_HUD_MODE_CHANGE:
2386       HandleTouchHudModeChange();
2387       break;
2388     case UNPIN:
2389       accelerators::UnpinWindow();
2390       break;
2391     case VOLUME_DOWN:
2392       HandleVolumeDown();
2393       break;
2394     case VOLUME_MUTE:
2395       HandleVolumeMute(accelerator);
2396       break;
2397     case VOLUME_UP:
2398       HandleVolumeUp();
2399       break;
2400     case WINDOW_CYCLE_SNAP_LEFT:
2401     case WINDOW_CYCLE_SNAP_RIGHT:
2402       HandleWindowSnap(action);
2403       break;
2404     case WINDOW_MINIMIZE:
2405       HandleWindowMinimize();
2406       break;
2407     case MINIMIZE_TOP_WINDOW_ON_BACK:
2408       HandleTopWindowMinimizeOnBack();
2409       break;
2410   }
2411 }
2412 
ShouldActionConsumeKeyEvent(AcceleratorAction action)2413 bool AcceleratorControllerImpl::ShouldActionConsumeKeyEvent(
2414     AcceleratorAction action) {
2415   // Adding new exceptions is *STRONGLY* discouraged.
2416   return true;
2417 }
2418 
2419 AcceleratorControllerImpl::AcceleratorProcessingRestriction
GetAcceleratorProcessingRestriction(int action) const2420 AcceleratorControllerImpl::GetAcceleratorProcessingRestriction(
2421     int action) const {
2422   if (Shell::Get()->screen_pinning_controller()->IsPinned() &&
2423       actions_allowed_in_pinned_mode_.find(action) ==
2424           actions_allowed_in_pinned_mode_.end()) {
2425     return RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION;
2426   }
2427   if (!Shell::Get()->session_controller()->IsActiveUserSessionStarted() &&
2428       actions_allowed_at_login_screen_.find(action) ==
2429           actions_allowed_at_login_screen_.end()) {
2430     return RESTRICTION_PREVENT_PROCESSING;
2431   }
2432   if (Shell::Get()->session_controller()->IsScreenLocked() &&
2433       actions_allowed_at_lock_screen_.find(action) ==
2434           actions_allowed_at_lock_screen_.end()) {
2435     return RESTRICTION_PREVENT_PROCESSING;
2436   }
2437   if (Shell::Get()->power_button_controller()->IsMenuOpened() &&
2438       !base::Contains(actions_allowed_at_power_menu_, action)) {
2439     return RESTRICTION_PREVENT_PROCESSING;
2440   }
2441   if (Shell::Get()->session_controller()->IsRunningInAppMode() &&
2442       actions_allowed_in_app_mode_.find(action) ==
2443           actions_allowed_in_app_mode_.end()) {
2444     return RESTRICTION_PREVENT_PROCESSING;
2445   }
2446   if (Shell::IsSystemModalWindowOpen() &&
2447       actions_allowed_at_modal_window_.find(action) ==
2448           actions_allowed_at_modal_window_.end()) {
2449     // Note we prevent the shortcut from propagating so it will not
2450     // be passed to the modal window. This is important for things like
2451     // Alt+Tab that would cause an undesired effect in the modal window by
2452     // cycling through its window elements.
2453     return RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION;
2454   }
2455   if (base::Contains(actions_needing_window_, action) &&
2456       Shell::Get()
2457           ->mru_window_tracker()
2458           ->BuildMruWindowList(kActiveDesk)
2459           .empty()) {
2460     Shell::Get()->accessibility_controller()->TriggerAccessibilityAlert(
2461         AccessibilityAlert::WINDOW_NEEDED);
2462     return RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION;
2463   }
2464   return RESTRICTION_NONE;
2465 }
2466 
2467 AcceleratorControllerImpl::AcceleratorProcessingStatus
MaybeDeprecatedAcceleratorPressed(AcceleratorAction action,const ui::Accelerator & accelerator) const2468 AcceleratorControllerImpl::MaybeDeprecatedAcceleratorPressed(
2469     AcceleratorAction action,
2470     const ui::Accelerator& accelerator) const {
2471   auto itr = actions_with_deprecations_.find(action);
2472   if (itr == actions_with_deprecations_.end()) {
2473     // The action is not associated with any deprecated accelerators, and hence
2474     // should be performed normally.
2475     return AcceleratorProcessingStatus::PROCEED;
2476   }
2477 
2478   // This action is associated with new and deprecated accelerators, find which
2479   // one is |accelerator|.
2480   const DeprecatedAcceleratorData* data = itr->second;
2481   if (!deprecated_accelerators_.count(accelerator)) {
2482     // This is a new accelerator replacing the old deprecated one.
2483     // Record UMA stats and proceed normally to perform it.
2484     RecordUmaHistogram(data->uma_histogram_name, NEW_USED);
2485     return AcceleratorProcessingStatus::PROCEED;
2486   }
2487 
2488   // This accelerator has been deprecated and should be treated according
2489   // to its |DeprecatedAcceleratorData|.
2490 
2491   // Record UMA stats.
2492   RecordUmaHistogram(data->uma_histogram_name, DEPRECATED_USED);
2493 
2494   // We always display the notification as long as this |data| entry exists.
2495   ShowDeprecatedAcceleratorNotification(
2496       data->uma_histogram_name, data->notification_message_id,
2497       data->old_shortcut_id, data->new_shortcut_id);
2498 
2499   if (!data->deprecated_enabled)
2500     return AcceleratorProcessingStatus::STOP;
2501 
2502   return AcceleratorProcessingStatus::PROCEED;
2503 }
2504 
MaybeShowConfirmationDialog(int window_title_text_id,int dialog_text_id,base::OnceClosure on_accept_callback,base::OnceClosure on_cancel_callback)2505 void AcceleratorControllerImpl::MaybeShowConfirmationDialog(
2506     int window_title_text_id,
2507     int dialog_text_id,
2508     base::OnceClosure on_accept_callback,
2509     base::OnceClosure on_cancel_callback) {
2510   // An active dialog exists already.
2511   if (confirmation_dialog_)
2512     return;
2513 
2514   auto* dialog = new AcceleratorConfirmationDialog(
2515       window_title_text_id, dialog_text_id, std::move(on_accept_callback),
2516       std::move(on_cancel_callback));
2517   confirmation_dialog_ = dialog->GetWeakPtr();
2518 }
2519 
ParseSideVolumeButtonLocationInfo()2520 void AcceleratorControllerImpl::ParseSideVolumeButtonLocationInfo() {
2521   std::string location_info;
2522   const base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
2523   if (cl->HasSwitch(switches::kAshSideVolumeButtonPosition)) {
2524     location_info =
2525         cl->GetSwitchValueASCII(switches::kAshSideVolumeButtonPosition);
2526   } else if (!base::PathExists(side_volume_button_location_file_path_) ||
2527              !base::ReadFileToString(side_volume_button_location_file_path_,
2528                                      &location_info) ||
2529              location_info.empty()) {
2530     return;
2531   }
2532 
2533   std::unique_ptr<base::DictionaryValue> info_in_dict =
2534       base::DictionaryValue::From(
2535           base::JSONReader::ReadDeprecated(location_info));
2536   if (!info_in_dict) {
2537     LOG(ERROR) << "JSONReader failed reading side volume button location info: "
2538                << location_info;
2539     return;
2540   }
2541   info_in_dict->GetString(kVolumeButtonRegion,
2542                           &side_volume_button_location_.region);
2543   info_in_dict->GetString(kVolumeButtonSide,
2544                           &side_volume_button_location_.side);
2545 }
2546 
IsInternalKeyboardOrUncategorizedDevice(int source_device_id) const2547 bool AcceleratorControllerImpl::IsInternalKeyboardOrUncategorizedDevice(
2548     int source_device_id) const {
2549   if (source_device_id == ui::ED_UNKNOWN_DEVICE)
2550     return false;
2551 
2552   for (const ui::InputDevice& keyboard :
2553        ui::DeviceDataManager::GetInstance()->GetKeyboardDevices()) {
2554     if (keyboard.type == ui::InputDeviceType::INPUT_DEVICE_INTERNAL &&
2555         keyboard.id == source_device_id) {
2556       return true;
2557     }
2558   }
2559 
2560   for (const ui::InputDevice& uncategorized_device :
2561        ui::DeviceDataManager::GetInstance()->GetUncategorizedDevices()) {
2562     if (uncategorized_device.id == source_device_id &&
2563         uncategorized_device.type ==
2564             ui::InputDeviceType::INPUT_DEVICE_INTERNAL) {
2565       return true;
2566     }
2567   }
2568   return false;
2569 }
2570 
IsValidSideVolumeButtonLocation() const2571 bool AcceleratorControllerImpl::IsValidSideVolumeButtonLocation() const {
2572   const std::string region = side_volume_button_location_.region;
2573   const std::string side = side_volume_button_location_.side;
2574   if (region != kVolumeButtonRegionKeyboard &&
2575       region != kVolumeButtonRegionScreen) {
2576     return false;
2577   }
2578   if (side != kVolumeButtonSideLeft && side != kVolumeButtonSideRight &&
2579       side != kVolumeButtonSideTop && side != kVolumeButtonSideBottom) {
2580     return false;
2581   }
2582   return true;
2583 }
2584 
ShouldSwapSideVolumeButtons(int source_device_id) const2585 bool AcceleratorControllerImpl::ShouldSwapSideVolumeButtons(
2586     int source_device_id) const {
2587   if (!features::IsSwapSideVolumeButtonsForOrientationEnabled() ||
2588       !IsInternalKeyboardOrUncategorizedDevice(source_device_id)) {
2589     return false;
2590   }
2591 
2592   if (!IsValidSideVolumeButtonLocation())
2593     return false;
2594 
2595   OrientationLockType screen_orientation =
2596       Shell::Get()->screen_orientation_controller()->GetCurrentOrientation();
2597   const std::string side = side_volume_button_location_.side;
2598   const bool is_landscape_secondary_or_portrait_primary =
2599       screen_orientation == OrientationLockType::kLandscapeSecondary ||
2600       screen_orientation == OrientationLockType::kPortraitPrimary;
2601 
2602   if (side_volume_button_location_.region == kVolumeButtonRegionKeyboard) {
2603     if (side == kVolumeButtonSideLeft || side == kVolumeButtonSideRight)
2604       return IsPrimaryOrientation(screen_orientation);
2605     return is_landscape_secondary_or_portrait_primary;
2606   }
2607 
2608   DCHECK_EQ(kVolumeButtonRegionScreen, side_volume_button_location_.region);
2609   if (side == kVolumeButtonSideLeft || side == kVolumeButtonSideRight)
2610     return !IsPrimaryOrientation(screen_orientation);
2611   return is_landscape_secondary_or_portrait_primary;
2612 }
2613 
UpdateTabletModeVolumeAdjustHistogram()2614 void AcceleratorControllerImpl::UpdateTabletModeVolumeAdjustHistogram() {
2615   const int volume_percent =
2616       chromeos::CrasAudioHandler::Get()->GetOutputVolumePercent();
2617   const bool swapped = features::IsSwapSideVolumeButtonsForOrientationEnabled();
2618   if ((volume_adjust_starts_with_up_ &&
2619        volume_percent >= initial_volume_percent_) ||
2620       (!volume_adjust_starts_with_up_ &&
2621        volume_percent <= initial_volume_percent_)) {
2622     RecordTabletVolumeAdjustTypeHistogram(
2623         swapped ? TabletModeVolumeAdjustType::kNormalAdjustWithSwapEnabled
2624                 : TabletModeVolumeAdjustType::kNormalAdjustWithSwapDisabled);
2625   } else {
2626     RecordTabletVolumeAdjustTypeHistogram(
2627         swapped
2628             ? TabletModeVolumeAdjustType::kAccidentalAdjustWithSwapEnabled
2629             : TabletModeVolumeAdjustType::kAccidentalAdjustWithSwapDisabled);
2630   }
2631 }
2632 
StartTabletModeVolumeAdjustTimer(AcceleratorAction action)2633 void AcceleratorControllerImpl::StartTabletModeVolumeAdjustTimer(
2634     AcceleratorAction action) {
2635   if (!tablet_mode_volume_adjust_timer_.IsRunning()) {
2636     volume_adjust_starts_with_up_ = action == VOLUME_UP;
2637     initial_volume_percent_ =
2638         chromeos::CrasAudioHandler::Get()->GetOutputVolumePercent();
2639   }
2640   tablet_mode_volume_adjust_timer_.Start(
2641       FROM_HERE, kVolumeAdjustTimeout, this,
2642       &AcceleratorControllerImpl::UpdateTabletModeVolumeAdjustHistogram);
2643 }
2644 
2645 }  // namespace ash
2646