Source code

Revision control

Other Tools

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/layers/KeyboardMap.h"
#include "mozilla/TextEvents.h" // for IgnoreModifierState, ShortcutKeyCandidate
namespace mozilla {
namespace layers {
KeyboardShortcut::KeyboardShortcut()
: mKeyCode(0),
mCharCode(0),
mModifiers(0),
mModifiersMask(0),
mEventType(KeyboardInput::KeyboardEventType::KEY_OTHER),
mDispatchToContent(false) {}
KeyboardShortcut::KeyboardShortcut(KeyboardInput::KeyboardEventType aEventType,
uint32_t aKeyCode, uint32_t aCharCode,
Modifiers aModifiers,
Modifiers aModifiersMask,
const KeyboardScrollAction& aAction)
: mAction(aAction),
mKeyCode(aKeyCode),
mCharCode(aCharCode),
mModifiers(aModifiers),
mModifiersMask(aModifiersMask),
mEventType(aEventType),
mDispatchToContent(false) {}
KeyboardShortcut::KeyboardShortcut(KeyboardInput::KeyboardEventType aEventType,
uint32_t aKeyCode, uint32_t aCharCode,
Modifiers aModifiers,
Modifiers aModifiersMask)
: mKeyCode(aKeyCode),
mCharCode(aCharCode),
mModifiers(aModifiers),
mModifiersMask(aModifiersMask),
mEventType(aEventType),
mDispatchToContent(true) {}
/* static */
void KeyboardShortcut::AppendHardcodedShortcuts(
nsTArray<KeyboardShortcut>& aShortcuts) {
// Tab
KeyboardShortcut tab1;
tab1.mDispatchToContent = true;
tab1.mKeyCode = NS_VK_TAB;
tab1.mCharCode = 0;
tab1.mModifiers = 0;
tab1.mModifiersMask = 0;
tab1.mEventType = KeyboardInput::KEY_PRESS;
aShortcuts.AppendElement(tab1);
// F6
KeyboardShortcut tab2;
tab2.mDispatchToContent = true;
tab2.mKeyCode = NS_VK_F6;
tab2.mCharCode = 0;
tab2.mModifiers = 0;
tab2.mModifiersMask = 0;
tab2.mEventType = KeyboardInput::KEY_PRESS;
aShortcuts.AppendElement(tab2);
}
bool KeyboardShortcut::Matches(const KeyboardInput& aInput,
const IgnoreModifierState& aIgnore,
uint32_t aOverrideCharCode) const {
return mEventType == aInput.mType && MatchesKey(aInput, aOverrideCharCode) &&
MatchesModifiers(aInput, aIgnore);
}
bool KeyboardShortcut::MatchesKey(const KeyboardInput& aInput,
uint32_t aOverrideCharCode) const {
// Compare by the key code if we have one
if (!mCharCode) {
return mKeyCode == aInput.mKeyCode;
}
// We are comparing by char code
uint32_t charCode;
// If we are comparing against a shortcut candidate then we might
// have an override char code
if (aOverrideCharCode) {
charCode = aOverrideCharCode;
} else {
charCode = aInput.mCharCode;
}
// Both char codes must be in lowercase to compare correctly
if (IS_IN_BMP(charCode)) {
charCode = ToLowerCase(static_cast<char16_t>(charCode));
}
return mCharCode == charCode;
}
bool KeyboardShortcut::MatchesModifiers(
const KeyboardInput& aInput, const IgnoreModifierState& aIgnore) const {
Modifiers modifiersMask = mModifiersMask;
// If we are ignoring Shift or OS, then unset that part of the mask
if (aIgnore.mOS) {
modifiersMask &= ~MODIFIER_OS;
}
if (aIgnore.mShift) {
modifiersMask &= ~MODIFIER_SHIFT;
}
// Mask off the modifiers we are ignoring from the keyboard input
return (aInput.modifiers & modifiersMask) == mModifiers;
}
KeyboardMap::KeyboardMap(nsTArray<KeyboardShortcut>&& aShortcuts)
: mShortcuts(aShortcuts) {}
KeyboardMap::KeyboardMap() = default;
Maybe<KeyboardShortcut> KeyboardMap::FindMatch(
const KeyboardInput& aEvent) const {
// If there are no shortcut candidates, then just search with with the
// keyboard input
if (aEvent.mShortcutCandidates.IsEmpty()) {
return FindMatchInternal(aEvent, IgnoreModifierState());
}
// Otherwise do a search with each shortcut candidate in order
for (auto& key : aEvent.mShortcutCandidates) {
IgnoreModifierState ignoreModifierState;
ignoreModifierState.mShift = key.mIgnoreShift;
auto match = FindMatchInternal(aEvent, ignoreModifierState, key.mCharCode);
if (match) {
return match;
}
}
return Nothing();
}
Maybe<KeyboardShortcut> KeyboardMap::FindMatchInternal(
const KeyboardInput& aEvent, const IgnoreModifierState& aIgnore,
uint32_t aOverrideCharCode) const {
for (auto& shortcut : mShortcuts) {
if (shortcut.Matches(aEvent, aIgnore, aOverrideCharCode)) {
return Some(shortcut);
}
}
#ifdef XP_WIN
// Windows native applications ignore Windows-Logo key state when checking
// shortcut keys even if the key is pressed. Therefore, if there is no
// shortcut key which exactly matches current modifier state, we should
// retry to look for a shortcut key without the Windows-Logo key press.
if (!aIgnore.mOS && (aEvent.modifiers & MODIFIER_OS)) {
IgnoreModifierState ignoreModifierState(aIgnore);
ignoreModifierState.mOS = true;
return FindMatchInternal(aEvent, ignoreModifierState, aOverrideCharCode);
}
#endif
return Nothing();
}
} // namespace layers
} // namespace mozilla