KeyboardMap.cpp (5660B)
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 Meta (Windows key), then unset that part of the 108 // mask 109 if (aIgnore.mMeta) { 110 modifiersMask &= ~MODIFIER_META; 111 } 112 if (aIgnore.mShift) { 113 modifiersMask &= ~MODIFIER_SHIFT; 114 } 115 116 // Mask off the modifiers we are ignoring from the keyboard input 117 return (aInput.modifiers & modifiersMask) == mModifiers; 118 } 119 120 KeyboardMap::KeyboardMap(nsTArray<KeyboardShortcut>&& aShortcuts) 121 : mShortcuts(aShortcuts) {} 122 123 KeyboardMap::KeyboardMap() = default; 124 125 Maybe<KeyboardShortcut> KeyboardMap::FindMatch( 126 const KeyboardInput& aEvent) const { 127 // If there are no shortcut candidates, then just search with with the 128 // keyboard input 129 if (aEvent.mShortcutCandidates.IsEmpty()) { 130 return FindMatchInternal(aEvent, IgnoreModifierState()); 131 } 132 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; 138 139 auto match = FindMatchInternal(aEvent, ignoreModifierState, key.mCharCode); 140 if (match) { 141 return match; 142 } 143 } 144 return Nothing(); 145 } 146 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); 153 } 154 } 155 156 #ifdef XP_WIN 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); 165 } 166 #endif 167 168 return Nothing(); 169 } 170 171 } // namespace layers 172 } // namespace mozilla