Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "mozilla/layers/KeyboardMap.h"
7 :
8 : #include "mozilla/TextEvents.h" // for IgnoreModifierState, ShortcutKeyCandidate
9 :
10 : namespace mozilla {
11 : namespace layers {
12 :
13 0 : KeyboardShortcut::KeyboardShortcut()
14 : {
15 0 : }
16 :
17 0 : KeyboardShortcut::KeyboardShortcut(KeyboardInput::KeyboardEventType aEventType,
18 : uint32_t aKeyCode,
19 : uint32_t aCharCode,
20 : Modifiers aModifiers,
21 : Modifiers aModifiersMask,
22 0 : const KeyboardScrollAction& aAction)
23 : : mAction(aAction)
24 : , mKeyCode(aKeyCode)
25 : , mCharCode(aCharCode)
26 : , mModifiers(aModifiers)
27 : , mModifiersMask(aModifiersMask)
28 : , mEventType(aEventType)
29 0 : , mDispatchToContent(false)
30 : {
31 0 : }
32 :
33 0 : KeyboardShortcut::KeyboardShortcut(KeyboardInput::KeyboardEventType aEventType,
34 : uint32_t aKeyCode,
35 : uint32_t aCharCode,
36 : Modifiers aModifiers,
37 0 : Modifiers aModifiersMask)
38 : : mKeyCode(aKeyCode)
39 : , mCharCode(aCharCode)
40 : , mModifiers(aModifiers)
41 : , mModifiersMask(aModifiersMask)
42 : , mEventType(aEventType)
43 0 : , mDispatchToContent(true)
44 : {
45 0 : }
46 :
47 : /* static */ void
48 0 : KeyboardShortcut::AppendHardcodedShortcuts(nsTArray<KeyboardShortcut>& aShortcuts)
49 : {
50 : // Tab
51 0 : KeyboardShortcut tab1;
52 0 : tab1.mDispatchToContent = true;
53 0 : tab1.mKeyCode = NS_VK_TAB;
54 0 : tab1.mCharCode = 0;
55 0 : tab1.mModifiers = 0;
56 0 : tab1.mModifiersMask = 0;
57 0 : tab1.mEventType = KeyboardInput::KEY_PRESS;
58 0 : aShortcuts.AppendElement(tab1);
59 :
60 : // F6
61 0 : KeyboardShortcut tab2;
62 0 : tab2.mDispatchToContent = true;
63 0 : tab2.mKeyCode = NS_VK_F6;
64 0 : tab2.mCharCode = 0;
65 0 : tab2.mModifiers = 0;
66 0 : tab2.mModifiersMask = 0;
67 0 : tab2.mEventType = KeyboardInput::KEY_PRESS;
68 0 : aShortcuts.AppendElement(tab2);
69 0 : }
70 :
71 : bool
72 0 : KeyboardShortcut::Matches(const KeyboardInput& aInput,
73 : const IgnoreModifierState& aIgnore,
74 : uint32_t aOverrideCharCode) const
75 : {
76 0 : return mEventType == aInput.mType &&
77 0 : MatchesKey(aInput, aOverrideCharCode) &&
78 0 : MatchesModifiers(aInput, aIgnore);
79 : }
80 :
81 : bool
82 0 : KeyboardShortcut::MatchesKey(const KeyboardInput& aInput,
83 : uint32_t aOverrideCharCode) const
84 : {
85 : // Compare by the key code if we have one
86 0 : if (!mCharCode) {
87 0 : return mKeyCode == aInput.mKeyCode;
88 : }
89 :
90 : // We are comparing by char code
91 : uint32_t charCode;
92 :
93 : // If we are comparing against a shortcut candidate then we might
94 : // have an override char code
95 0 : if (aOverrideCharCode) {
96 0 : charCode = aOverrideCharCode;
97 : } else {
98 0 : charCode = aInput.mCharCode;
99 : }
100 :
101 : // Both char codes must be in lowercase to compare correctly
102 0 : if (IS_IN_BMP(charCode)) {
103 0 : charCode = ToLowerCase(static_cast<char16_t>(charCode));
104 : }
105 :
106 0 : return mCharCode == charCode;
107 : }
108 :
109 : bool
110 0 : KeyboardShortcut::MatchesModifiers(const KeyboardInput& aInput,
111 : const IgnoreModifierState& aIgnore) const
112 : {
113 0 : Modifiers modifiersMask = mModifiersMask;
114 :
115 : // If we are ignoring Shift or OS, then unset that part of the mask
116 0 : if (aIgnore.mOS) {
117 0 : modifiersMask &= ~MODIFIER_OS;
118 : }
119 0 : if (aIgnore.mShift) {
120 0 : modifiersMask &= ~MODIFIER_SHIFT;
121 : }
122 :
123 : // Mask off the modifiers we are ignoring from the keyboard input
124 0 : return (aInput.modifiers & modifiersMask) == mModifiers;
125 : }
126 :
127 0 : KeyboardMap::KeyboardMap(nsTArray<KeyboardShortcut>&& aShortcuts)
128 0 : : mShortcuts(aShortcuts)
129 : {
130 0 : }
131 :
132 1 : KeyboardMap::KeyboardMap()
133 : {
134 1 : }
135 :
136 : Maybe<KeyboardShortcut>
137 0 : KeyboardMap::FindMatch(const KeyboardInput& aEvent) const
138 : {
139 : // If there are no shortcut candidates, then just search with with the
140 : // keyboard input
141 0 : if (aEvent.mShortcutCandidates.IsEmpty()) {
142 0 : return FindMatchInternal(aEvent, IgnoreModifierState());
143 : }
144 :
145 : // Otherwise do a search with each shortcut candidate in order
146 0 : for (auto& key : aEvent.mShortcutCandidates) {
147 0 : IgnoreModifierState ignoreModifierState;
148 0 : ignoreModifierState.mShift = key.mIgnoreShift;
149 :
150 0 : auto match = FindMatchInternal(aEvent, ignoreModifierState, key.mCharCode);
151 0 : if (match) {
152 0 : return match;
153 : }
154 : }
155 0 : return Nothing();
156 : }
157 :
158 : Maybe<KeyboardShortcut>
159 0 : KeyboardMap::FindMatchInternal(const KeyboardInput& aEvent,
160 : const IgnoreModifierState& aIgnore,
161 : uint32_t aOverrideCharCode) const
162 : {
163 0 : for (auto& shortcut : mShortcuts) {
164 0 : if (shortcut.Matches(aEvent, aIgnore, aOverrideCharCode)) {
165 0 : return Some(shortcut);
166 : }
167 : }
168 :
169 : #ifdef XP_WIN
170 : // Windows native applications ignore Windows-Logo key state when checking
171 : // shortcut keys even if the key is pressed. Therefore, if there is no
172 : // shortcut key which exactly matches current modifier state, we should
173 : // retry to look for a shortcut key without the Windows-Logo key press.
174 : if (!aIgnore.mOS && (aEvent.modifiers & MODIFIER_OS)) {
175 : IgnoreModifierState ignoreModifierState(aIgnore);
176 : ignoreModifierState.mOS = true;
177 : return FindMatchInternal(aEvent, ignoreModifierState, aOverrideCharCode);
178 : }
179 : #endif
180 :
181 0 : return Nothing();
182 : }
183 :
184 : } // namespace layers
185 : } // namespace mozilla
|