1 // Copyright 2009 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/global_keyboard_shortcuts_mac.h"
7 #include <AppKit/NSEvent.h>
8 #include <Carbon/Carbon.h>
11 #include <initializer_list>
13 #include "base/check_op.h"
14 #include "chrome/app/chrome_command_ids.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "ui/base/buildflags.h"
17 #include "ui/events/keycodes/keyboard_code_conversion_mac.h"
21 enum class CommandKeyState : bool {
25 enum class ShiftKeyState : bool {
29 enum class OptionKeyState : bool {
33 enum class ControlKeyState : bool {
38 int CommandForKeys(int vkey_code,
39 CommandKeyState command,
40 ShiftKeyState shift = ShiftKeyState::kUp,
41 OptionKeyState option = OptionKeyState::kUp,
42 ControlKeyState control = ControlKeyState::kUp) {
43 NSUInteger modifier_flags = 0;
44 if (command == CommandKeyState::kDown)
45 modifier_flags |= NSEventModifierFlagCommand;
46 if (shift == ShiftKeyState::kDown)
47 modifier_flags |= NSEventModifierFlagShift;
48 if (option == OptionKeyState::kDown)
49 modifier_flags |= NSEventModifierFlagOption;
50 if (control == ControlKeyState::kDown)
51 modifier_flags |= NSEventModifierFlagControl;
58 // Docs say that this is set for numpad *and* arrow keys.
59 modifier_flags |= NSEventModifierFlagNumericPad;
62 case kVK_ForwardDelete:
67 // Docs say that this is set for function keys *and* the cluster of six
68 // navigation keys in the center of the keyboard *and* arrow keys.
69 modifier_flags |= NSEventModifierFlagFunction;
75 unichar shifted_character;
77 int result = ui::MacKeyCodeForWindowsKeyCode(
78 ui::KeyboardCodeFromKeyCode(vkey_code), modifier_flags,
79 &shifted_character, &character);
80 DCHECK_NE(result, -1);
82 NSEvent* event = [NSEvent
83 keyEventWithType:NSEventTypeKeyDown
85 modifierFlags:modifier_flags
89 characters:[NSString stringWithFormat:@"%C", character]
90 charactersIgnoringModifiers:[NSString
91 stringWithFormat:@"%C", shifted_character]
95 return CommandForKeyEvent(event).chrome_command;
100 TEST(GlobalKeyboardShortcuts, BasicFunctionality) {
101 // Test that an invalid shortcut translates into an invalid command id.
102 const int kInvalidCommandId = -1;
103 const int no_key_code = 0;
106 CommandForKeys(no_key_code, CommandKeyState::kUp, ShiftKeyState::kUp,
107 OptionKeyState::kUp, ControlKeyState::kUp));
109 // Check that all known keyboard shortcuts return valid results.
110 for (const auto& shortcut : GetShortcutsNotPresentInMainMenu()) {
111 CommandKeyState command =
112 shortcut.command_key ? CommandKeyState::kDown : CommandKeyState::kUp;
113 ShiftKeyState shift =
114 shortcut.shift_key ? ShiftKeyState::kDown : ShiftKeyState::kUp;
115 OptionKeyState option =
116 shortcut.opt_key ? OptionKeyState::kDown : OptionKeyState::kUp;
117 ControlKeyState control =
118 shortcut.cntrl_key ? ControlKeyState::kDown : ControlKeyState::kUp;
121 CommandForKeys(shortcut.vkey_code, command, shift, option, control);
122 EXPECT_EQ(cmd_num, shortcut.chrome_command);
124 // Test that switching tabs triggers off keycodes and not characters (visible
125 // with the Italian keyboard layout).
128 CommandForKeys(kVK_ANSI_1, CommandKeyState::kDown, ShiftKeyState::kUp,
129 OptionKeyState::kUp, ControlKeyState::kUp));
132 TEST(GlobalKeyboardShortcuts, KeypadNumberKeysMatch) {
133 // Test that the shortcuts that are generated by keypad number keys match the
135 static const struct {
139 {kVK_ANSI_0, kVK_ANSI_Keypad0},
140 {kVK_ANSI_1, kVK_ANSI_Keypad1},
141 {kVK_ANSI_2, kVK_ANSI_Keypad2},
142 {kVK_ANSI_3, kVK_ANSI_Keypad3},
143 {kVK_ANSI_4, kVK_ANSI_Keypad4},
144 {kVK_ANSI_5, kVK_ANSI_Keypad5},
145 {kVK_ANSI_6, kVK_ANSI_Keypad6},
146 {kVK_ANSI_7, kVK_ANSI_Keypad7},
147 {kVK_ANSI_8, kVK_ANSI_Keypad8},
148 {kVK_ANSI_9, kVK_ANSI_Keypad9},
151 // We only consider unshifted keys. A shifted numpad key gives a different
152 // keyEquivalent than a shifted number key.
153 const ShiftKeyState shift = ShiftKeyState::kUp;
154 for (auto equivalent : equivalents) {
155 for (CommandKeyState command :
156 {CommandKeyState::kUp, CommandKeyState::kDown}) {
157 for (OptionKeyState option :
158 {OptionKeyState::kUp, OptionKeyState::kDown}) {
159 for (ControlKeyState control :
160 {ControlKeyState::kUp, ControlKeyState::kDown}) {
161 EXPECT_EQ(CommandForKeys(equivalent.keycode, command, shift, option,
163 CommandForKeys(equivalent.keypad_keycode, command, shift,