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/. */
7 #include "mozilla/layers/KeyboardMap.h"
9 #include "mozilla/TextEvents.h" // for IgnoreModifierState, ShortcutKeyCandidate
14 KeyboardShortcut::KeyboardShortcut()
19 mEventType(KeyboardInput::KeyboardEventType::KEY_OTHER
),
20 mDispatchToContent(false) {}
22 KeyboardShortcut::KeyboardShortcut(KeyboardInput::KeyboardEventType aEventType
,
23 uint32_t aKeyCode
, uint32_t aCharCode
,
25 Modifiers aModifiersMask
,
26 const KeyboardScrollAction
& aAction
)
30 mModifiers(aModifiers
),
31 mModifiersMask(aModifiersMask
),
32 mEventType(aEventType
),
33 mDispatchToContent(false) {}
35 KeyboardShortcut::KeyboardShortcut(KeyboardInput::KeyboardEventType aEventType
,
36 uint32_t aKeyCode
, uint32_t aCharCode
,
38 Modifiers aModifiersMask
)
41 mModifiers(aModifiers
),
42 mModifiersMask(aModifiersMask
),
43 mEventType(aEventType
),
44 mDispatchToContent(true) {}
47 void KeyboardShortcut::AppendHardcodedShortcuts(
48 nsTArray
<KeyboardShortcut
>& aShortcuts
) {
50 KeyboardShortcut tab1
;
51 tab1
.mDispatchToContent
= true;
52 tab1
.mKeyCode
= NS_VK_TAB
;
55 tab1
.mModifiersMask
= 0;
56 tab1
.mEventType
= KeyboardInput::KEY_PRESS
;
57 aShortcuts
.AppendElement(tab1
);
60 KeyboardShortcut tab2
;
61 tab2
.mDispatchToContent
= true;
62 tab2
.mKeyCode
= NS_VK_F6
;
65 tab2
.mModifiersMask
= 0;
66 tab2
.mEventType
= KeyboardInput::KEY_PRESS
;
67 aShortcuts
.AppendElement(tab2
);
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
);
77 bool KeyboardShortcut::MatchesKey(const KeyboardInput
& aInput
,
78 uint32_t aOverrideCharCode
) const {
79 // Compare by the key code if we have one
81 return mKeyCode
== aInput
.mKeyCode
;
84 // We are comparing by char code
87 // If we are comparing against a shortcut candidate then we might
88 // have an override char code
89 if (aOverrideCharCode
) {
90 charCode
= aOverrideCharCode
;
92 charCode
= aInput
.mCharCode
;
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
));
100 return mCharCode
== charCode
;
103 bool KeyboardShortcut::MatchesModifiers(
104 const KeyboardInput
& aInput
, const IgnoreModifierState
& aIgnore
) const {
105 Modifiers modifiersMask
= mModifiersMask
;
107 // If we are ignoring Shift or Meta (Windows key), then unset that part of the
110 modifiersMask
&= ~MODIFIER_META
;
112 if (aIgnore
.mShift
) {
113 modifiersMask
&= ~MODIFIER_SHIFT
;
116 // Mask off the modifiers we are ignoring from the keyboard input
117 return (aInput
.modifiers
& modifiersMask
) == mModifiers
;
120 KeyboardMap::KeyboardMap(nsTArray
<KeyboardShortcut
>&& aShortcuts
)
121 : mShortcuts(aShortcuts
) {}
123 KeyboardMap::KeyboardMap() = default;
125 Maybe
<KeyboardShortcut
> KeyboardMap::FindMatch(
126 const KeyboardInput
& aEvent
) const {
127 // If there are no shortcut candidates, then just search with with the
129 if (aEvent
.mShortcutCandidates
.IsEmpty()) {
130 return FindMatchInternal(aEvent
, IgnoreModifierState());
133 // Otherwise do a search with each shortcut candidate in order
134 for (const auto& key
: aEvent
.mShortcutCandidates
) {
135 IgnoreModifierState ignoreModifierState
;
136 ignoreModifierState
.mShift
=
137 key
.mShiftState
== ShortcutKeyCandidate::ShiftState::Ignorable
;
139 auto match
= FindMatchInternal(aEvent
, ignoreModifierState
, key
.mCharCode
);
147 Maybe
<KeyboardShortcut
> KeyboardMap::FindMatchInternal(
148 const KeyboardInput
& aEvent
, const IgnoreModifierState
& aIgnore
,
149 uint32_t aOverrideCharCode
) const {
150 for (auto& shortcut
: mShortcuts
) {
151 if (shortcut
.Matches(aEvent
, aIgnore
, aOverrideCharCode
)) {
152 return Some(shortcut
);
157 // Windows native applications ignore Windows-Logo key state when checking
158 // shortcut keys even if the key is pressed. Therefore, if there is no
159 // shortcut key which exactly matches current modifier state, we should
160 // retry to look for a shortcut key without the Windows-Logo key press.
161 if (!aIgnore
.mMeta
&& (aEvent
.modifiers
& MODIFIER_META
)) {
162 IgnoreModifierState
ignoreModifierState(aIgnore
);
163 ignoreModifierState
.mMeta
= true;
164 return FindMatchInternal(aEvent
, ignoreModifierState
, aOverrideCharCode
);
171 } // namespace layers
172 } // namespace mozilla