x11_keyboard_impl.cc 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // Copyright 2016 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "remoting/host/linux/x11_keyboard_impl.h"
  5. #include "remoting/host/linux/unicode_to_keysym.h"
  6. #include "ui/gfx/x/future.h"
  7. #include "ui/gfx/x/xkb.h"
  8. #include "ui/gfx/x/xproto.h"
  9. #include "ui/gfx/x/xtest.h"
  10. namespace {
  11. bool FindKeycodeForKeySym(x11::Connection* connection,
  12. uint32_t key_sym,
  13. uint32_t* keycode,
  14. uint32_t* modifiers) {
  15. auto found_keycode = connection->KeysymToKeycode(key_sym);
  16. const x11::KeyButMask kModifiersToTry[] = {
  17. {},
  18. x11::KeyButMask::Shift,
  19. x11::KeyButMask::Mod2,
  20. x11::KeyButMask::Mod3,
  21. x11::KeyButMask::Mod4,
  22. x11::KeyButMask::Shift | x11::KeyButMask::Mod2,
  23. x11::KeyButMask::Shift | x11::KeyButMask::Mod3,
  24. x11::KeyButMask::Shift | x11::KeyButMask::Mod4,
  25. };
  26. // TODO(sergeyu): Is there a better way to find modifiers state?
  27. for (auto i : kModifiersToTry) {
  28. auto mods = static_cast<uint32_t>(i);
  29. if (connection->KeycodeToKeysym(found_keycode, mods) == key_sym) {
  30. *modifiers = mods;
  31. *keycode = static_cast<uint8_t>(found_keycode);
  32. return true;
  33. }
  34. }
  35. return false;
  36. }
  37. // This is ported from XStringToKeysym
  38. // https://gitlab.freedesktop.org/xorg/lib/libx11/-/blob/2b7598221d87049d03e9a95fcb541c37c8728184/src/StrKeysym.c#L147-154
  39. uint32_t UnicodeToKeysym(uint32_t u) {
  40. if (u > 0x10ffff || u < 0x20 || (u > 0x7e && u < 0xa0))
  41. return 0;
  42. if (u < 0x100)
  43. return u;
  44. return u | 0x01000000;
  45. }
  46. } // namespace
  47. namespace remoting {
  48. X11KeyboardImpl::X11KeyboardImpl(x11::Connection* connection)
  49. : connection_(connection) {}
  50. X11KeyboardImpl::~X11KeyboardImpl() = default;
  51. std::vector<uint32_t> X11KeyboardImpl::GetUnusedKeycodes() {
  52. std::vector<uint32_t> unused_keycodes_;
  53. uint8_t min_keycode = static_cast<uint8_t>(connection_->setup().min_keycode);
  54. uint8_t max_keycode = static_cast<uint8_t>(connection_->setup().max_keycode);
  55. uint8_t keycode_count = max_keycode - min_keycode + 1;
  56. auto req = connection_->GetKeyboardMapping(
  57. {connection_->setup().min_keycode, keycode_count});
  58. if (auto reply = req.Sync()) {
  59. for (int keycode = max_keycode; keycode >= min_keycode; keycode--) {
  60. bool used = false;
  61. int offset = (keycode - min_keycode) * reply->keysyms_per_keycode;
  62. for (int level = 0; level < reply->keysyms_per_keycode; level++) {
  63. if (reply->keysyms[offset + level] != x11::KeySym{}) {
  64. used = true;
  65. break;
  66. }
  67. }
  68. if (!used)
  69. unused_keycodes_.push_back(keycode);
  70. }
  71. }
  72. return unused_keycodes_;
  73. }
  74. void X11KeyboardImpl::PressKey(uint32_t keycode, uint32_t modifiers) {
  75. connection_->xkb().LatchLockState(
  76. {static_cast<x11::Xkb::DeviceSpec>(x11::Xkb::Id::UseCoreKbd),
  77. static_cast<x11::ModMask>(modifiers),
  78. static_cast<x11::ModMask>(modifiers)});
  79. connection_->xtest().FakeInput(
  80. {x11::KeyEvent::Press, static_cast<uint8_t>(keycode)});
  81. connection_->xtest().FakeInput(
  82. {x11::KeyEvent::Release, static_cast<uint8_t>(keycode)});
  83. connection_->xkb().LatchLockState(
  84. {static_cast<x11::Xkb::DeviceSpec>(x11::Xkb::Id::UseCoreKbd),
  85. static_cast<x11::ModMask>(modifiers), x11::ModMask{}});
  86. }
  87. bool X11KeyboardImpl::FindKeycode(uint32_t code_point,
  88. uint32_t* keycode,
  89. uint32_t* modifiers) {
  90. for (uint32_t keysym : GetKeySymsForUnicode(code_point)) {
  91. if (FindKeycodeForKeySym(connection_, keysym, keycode, modifiers))
  92. return true;
  93. }
  94. return false;
  95. }
  96. bool X11KeyboardImpl::ChangeKeyMapping(uint32_t keycode, uint32_t code_point) {
  97. if (!code_point)
  98. return false;
  99. auto keysym = UnicodeToKeysym(code_point);
  100. if (!keysym)
  101. return false;
  102. connection_->ChangeKeyboardMapping({
  103. .keycode_count = 1,
  104. .first_keycode = static_cast<x11::KeyCode>(keycode),
  105. .keysyms_per_keycode = 2,
  106. .keysyms = {static_cast<x11::KeySym>(keysym) /* lower-case */,
  107. static_cast<x11::KeySym>(keysym) /* upper-case */},
  108. });
  109. return true;
  110. }
  111. void X11KeyboardImpl::Flush() {
  112. connection_->Flush();
  113. }
  114. void X11KeyboardImpl::Sync() {
  115. connection_->Sync();
  116. }
  117. } // namespace remoting