tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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