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