123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- // Copyright 2021 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ui/base/x/x11_keyboard_hook.h"
- #include <memory>
- #include <utility>
- #include "base/check_op.h"
- #include "ui/events/event.h"
- #include "ui/events/keycodes/dom/dom_code.h"
- #include "ui/events/keycodes/dom/keycode_converter.h"
- #include "ui/gfx/x/future.h"
- #include "ui/gfx/x/xproto.h"
- namespace ui {
- namespace {
- static XKeyboardHook* g_instance = nullptr;
- // GrabKey essentially requires the modifier mask to explicitly be specified.
- // One can specify 'x11::ModMask::Any' however doing so means the call to
- // GrabKey will fail if that key has been grabbed with any combination of
- // modifiers. The common practice is to call GrabKey with each individual
- // modifier mask to avoid that problem.
- const x11::ModMask kModifierMasks[] = {
- {}, // No additional modifier.
- x11::ModMask::c_2, // Num lock
- x11::ModMask::Lock, // Caps lock
- x11::ModMask::c_5, // Scroll lock
- x11::ModMask::c_2 | x11::ModMask::Lock,
- x11::ModMask::c_2 | x11::ModMask::c_5,
- x11::ModMask::Lock | x11::ModMask::c_5,
- x11::ModMask::c_2 | x11::ModMask::Lock | x11::ModMask::c_5};
- // This is the set of keys to lock when the website requests that all keys be
- // locked.
- const DomCode kDomCodesForLockAllKeys[] = {
- DomCode::ESCAPE, DomCode::CONTEXT_MENU, DomCode::CONTROL_LEFT,
- DomCode::SHIFT_LEFT, DomCode::ALT_LEFT, DomCode::META_LEFT,
- DomCode::CONTROL_RIGHT, DomCode::SHIFT_RIGHT, DomCode::ALT_RIGHT,
- DomCode::META_RIGHT};
- } // namespace
- XKeyboardHook::XKeyboardHook(gfx::AcceleratedWidget accelerated_widget)
- : connection_(x11::Connection::Get()),
- x_window_(static_cast<x11::Window>(accelerated_widget)) {}
- XKeyboardHook::~XKeyboardHook() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK_EQ(g_instance, this);
- g_instance = nullptr;
- // Use UngrabKey for each key that has been grabbed. UngrabKeyboard
- // purportedly releases all keys when called and would not require the nested
- // loops, however in practice the keys are not actually released.
- for (int native_key_code : grabbed_keys_) {
- for (auto modifier : kModifierMasks) {
- connection_->UngrabKey(
- {static_cast<x11::KeyCode>(native_key_code), x_window_, modifier});
- }
- }
- }
- bool XKeyboardHook::RegisterHook(
- const absl::optional<base::flat_set<DomCode>>& dom_codes) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- // Only one instance of this class can be registered at a time.
- DCHECK(!g_instance);
- g_instance = this;
- if (dom_codes.has_value())
- CaptureSpecificKeys(dom_codes);
- else
- CaptureAllKeys();
- return true;
- }
- void XKeyboardHook::CaptureAllKeys() {
- // We could have used the XGrabKeyboard API here instead of calling XGrabKeys
- // on a hard-coded set of shortcut keys. Calling XGrabKeyboard would make
- // this work much simpler, however it has side-effects which prevents its use.
- // An example side-effect is that it prevents the lock screen from starting as
- // the screensaver process also calls XGrabKeyboard but will receive an error
- // since it was already grabbed by the window with KeyboardLock.
- for (auto kDomCodesForLockAllKey : kDomCodesForLockAllKeys)
- CaptureKeyForDomCode(kDomCodesForLockAllKey);
- }
- void XKeyboardHook::CaptureSpecificKeys(
- const absl::optional<base::flat_set<DomCode>>& dom_codes) {
- for (DomCode dom_code : dom_codes.value())
- CaptureKeyForDomCode(dom_code);
- }
- void XKeyboardHook::CaptureKeyForDomCode(DomCode dom_code) {
- int native_key_code = KeycodeConverter::DomCodeToNativeKeycode(dom_code);
- if (native_key_code == KeycodeConverter::InvalidNativeKeycode())
- return;
- for (auto modifier : kModifierMasks) {
- connection_->GrabKey({
- .owner_events = false,
- .grab_window = x_window_,
- .modifiers = modifier,
- .key = static_cast<x11::KeyCode>(native_key_code),
- .pointer_mode = x11::GrabMode::Async,
- .keyboard_mode = x11::GrabMode::Async,
- });
- }
- grabbed_keys_.push_back(native_key_code);
- }
- } // namespace ui
|