// Copyright 2020 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/gfx/x/keyboard_state.h" #include "base/i18n/case_conversion.h" #include "ui/gfx/x/connection.h" #include "ui/gfx/x/keysyms/keysyms.h" #include "ui/gfx/x/xkb.h" #include "ui/gfx/x/xproto.h" namespace x11 { namespace { constexpr KeySym kNoSymbol = static_cast(0); void ConvertCaseImpl(uint32_t sym, uint32_t* lower, uint32_t* upper); void ConvertCase(KeySym sym, KeySym* lower, KeySym* upper) { uint32_t lower32; uint32_t upper32; ConvertCaseImpl(static_cast(sym), &lower32, &upper32); *lower = static_cast(lower32); *upper = static_cast(upper32); } bool IsPublicOrPrivateKeypadKey(KeySym keysym) { auto key = static_cast(keysym); return (key >= XK_KP_Space && key <= XK_KP_Equal) || (key >= 0x11000000 && key <= 0x1100FFFF); } int GetXkbGroupFromState(int state) { return (state >> 13) & 0x3; } #include "third_party/libx11/src/KeyBind.c" #include "third_party/libx11/src/xkb/XKBBind.c" #include "third_party/libxcb-keysyms/keysyms/keysyms.c" } // namespace KeyboardState::KeyboardState() = default; KeyboardState::~KeyboardState() = default; // Non-XKB (core protocol) implementation of KeysymToKeycode and // KeycodeToKeysym. class CoreKeyboardState : public KeyboardState { public: explicit CoreKeyboardState(Connection* connection) : connection_(connection) { UpdateMapping(); } ~CoreKeyboardState() override = default; KeyCode KeysymToKeycode(uint32_t keysym) const override { auto min_keycode = static_cast(connection_->setup().min_keycode); auto max_keycode = static_cast(connection_->setup().max_keycode); int count = max_keycode - min_keycode + 1; DCHECK_EQ(count * keyboard_mapping_.keysyms_per_keycode, static_cast(keyboard_mapping_.keysyms.size())); for (size_t i = 0; i < keyboard_mapping_.keysyms.size(); i++) { auto keycode = min_keycode + i / keyboard_mapping_.keysyms_per_keycode; if (keyboard_mapping_.keysyms[i] == static_cast(keysym)) return static_cast(keycode); } return {}; } uint32_t KeycodeToKeysym(KeyCode keycode, uint32_t modifiers) const override { auto sym = static_cast(KeycodeToKeysymCoreImpl( keycode, modifiers, connection_, keyboard_mapping_, lock_meaning_, mode_switch_, num_lock_)); return sym == XK_VoidSymbol ? 0 : sym; } private: void UpdateMapping() override { UpdateMappingImpl(connection_, &keyboard_mapping_, &lock_meaning_, &mode_switch_, &num_lock_); } x11::Connection* const connection_; GetKeyboardMappingReply keyboard_mapping_; uint16_t lock_meaning_ = 0; uint8_t mode_switch_ = 0; uint8_t num_lock_ = 0; }; // XKB implementation of KeysymToKeycode and KeycodeToKeysym. class XkbKeyboardState : public KeyboardState { public: explicit XkbKeyboardState(Connection* connection) : connection_(connection) { UpdateMapping(); } ~XkbKeyboardState() override = default; KeyCode KeysymToKeycode(uint32_t keysym) const override { int first_keycode = static_cast(map_.firstKeySym); for (int keycode = 0; keycode < map_.nKeySyms; keycode++) { for (auto sym : map_.syms_rtrn->at(keycode).syms) { if (static_cast(sym) == keysym) return static_cast(keycode + first_keycode); } } return {}; } uint32_t KeycodeToKeysym(KeyCode key, uint32_t modifiers) const override { return KeycodeToKeysymXkbImpl(key, modifiers, map_); } private: void UpdateMapping() override { auto future = connection_->xkb().GetMap( {static_cast(Xkb::Id::UseCoreKbd), Xkb::MapPart::KeyTypes | Xkb::MapPart::KeySyms}); if (auto response = future.Sync()) map_ = std::move(*response.reply); } x11::Connection* const connection_; Xkb::GetMapReply map_; }; std::unique_ptr CreateKeyboardState(Connection* connection) { if (connection->xkb().present()) return std::make_unique(connection); return std::make_unique(connection); } } // namespace x11