Source code

Revision control

Other Tools

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