| // 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/future.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<KeySym>(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<uint32_t>(sym), &lower32, &upper32); |
| *lower = static_cast<KeySym>(lower32); |
| *upper = static_cast<KeySym>(upper32); |
| } |
| |
| bool IsPublicOrPrivateKeypadKey(KeySym keysym) { |
| auto key = static_cast<uint32_t>(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<uint8_t>(connection_->setup().min_keycode); |
| auto max_keycode = static_cast<uint8_t>(connection_->setup().max_keycode); |
| int count = max_keycode - min_keycode + 1; |
| DCHECK_EQ(count * keyboard_mapping_.keysyms_per_keycode, |
| static_cast<int>(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>(keysym)) |
| return static_cast<KeyCode>(keycode); |
| } |
| return {}; |
| } |
| |
| uint32_t KeycodeToKeysym(KeyCode keycode, uint32_t modifiers) const override { |
| auto sym = static_cast<uint32_t>(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_); |
| } |
| |
| 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<int>(map_.firstKeySym); |
| for (int keycode = 0; keycode < map_.nKeySyms; keycode++) { |
| for (auto sym : map_.syms_rtrn->at(keycode).syms) { |
| if (static_cast<uint32_t>(sym) == keysym) |
| return static_cast<KeyCode>(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::DeviceSpec>(Xkb::Id::UseCoreKbd), |
| Xkb::MapPart::KeyTypes | Xkb::MapPart::KeySyms}); |
| if (auto response = future.Sync()) |
| map_ = std::move(*response.reply); |
| } |
| |
| Connection* const connection_; |
| Xkb::GetMapReply map_; |
| }; |
| |
| std::unique_ptr<KeyboardState> CreateKeyboardState(Connection* connection) { |
| if (connection->xkb().present()) |
| return std::make_unique<XkbKeyboardState>(connection); |
| return std::make_unique<CoreKeyboardState>(connection); |
| } |
| |
| } // namespace x11 |