OLD | NEW |
(Empty) | |
| 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 |
| 5 #include "remoting/host/linux/x11_keyboard_impl.h" |
| 6 |
| 7 #include <X11/extensions/XInput.h> |
| 8 #include <X11/extensions/XTest.h> |
| 9 #include <X11/XKBlib.h> |
| 10 |
| 11 #include "base/strings/stringprintf.h" |
| 12 #include "remoting/host/linux/unicode_to_keysym.h" |
| 13 #include "ui/gfx/x/x11_types.h" |
| 14 |
| 15 namespace { |
| 16 |
| 17 bool FindKeycodeForKeySym(Display* display, |
| 18 KeySym key_sym, |
| 19 uint32_t* keycode, |
| 20 uint32_t* modifiers) { |
| 21 uint32_t found_keycode = XKeysymToKeycode(display, key_sym); |
| 22 |
| 23 const uint32_t kModifiersToTry[] = { |
| 24 0, |
| 25 ShiftMask, |
| 26 Mod2Mask, |
| 27 Mod3Mask, |
| 28 Mod4Mask, |
| 29 ShiftMask | Mod2Mask, |
| 30 ShiftMask | Mod3Mask, |
| 31 ShiftMask | Mod4Mask, |
| 32 }; |
| 33 |
| 34 // TODO(sergeyu): Is there a better way to find modifiers state? |
| 35 for (size_t i = 0; i < arraysize(kModifiersToTry); ++i) { |
| 36 unsigned long key_sym_with_mods; |
| 37 if (XkbLookupKeySym(display, found_keycode, kModifiersToTry[i], nullptr, |
| 38 &key_sym_with_mods) && |
| 39 key_sym_with_mods == key_sym) { |
| 40 *modifiers = kModifiersToTry[i]; |
| 41 *keycode = found_keycode; |
| 42 return true; |
| 43 } |
| 44 } |
| 45 return false; |
| 46 } |
| 47 |
| 48 } // namespace |
| 49 |
| 50 namespace remoting { |
| 51 |
| 52 X11KeyboardImpl::X11KeyboardImpl(Display* display) : display_(display) {} |
| 53 |
| 54 X11KeyboardImpl::~X11KeyboardImpl() {} |
| 55 |
| 56 std::vector<uint32_t> X11KeyboardImpl::GetUnusedKeycodes() { |
| 57 std::vector<uint32_t> unused_keycodes_; |
| 58 int min_keycode; |
| 59 int max_keycode; |
| 60 XDisplayKeycodes(display_, &min_keycode, &max_keycode); |
| 61 uint32_t keycode_count = max_keycode - min_keycode + 1; |
| 62 |
| 63 int sym_per_key; |
| 64 gfx::XScopedPtr<KeySym> mapping( |
| 65 XGetKeyboardMapping(display_, min_keycode, keycode_count, &sym_per_key)); |
| 66 for (int keycode = max_keycode; keycode >= min_keycode; keycode--) { |
| 67 bool used = false; |
| 68 int offset = (keycode - min_keycode) * sym_per_key; |
| 69 for (int level = 0; level < sym_per_key; level++) { |
| 70 if (mapping.get()[offset + level]) { |
| 71 used = true; |
| 72 break; |
| 73 } |
| 74 } |
| 75 if (!used) { |
| 76 unused_keycodes_.push_back(keycode); |
| 77 } |
| 78 } |
| 79 return unused_keycodes_; |
| 80 } |
| 81 |
| 82 void X11KeyboardImpl::PressKey(uint32_t keycode, uint32_t modifiers) { |
| 83 XkbLockModifiers(display_, XkbUseCoreKbd, modifiers, modifiers); |
| 84 |
| 85 XTestFakeKeyEvent(display_, keycode, True, CurrentTime); |
| 86 XTestFakeKeyEvent(display_, keycode, False, CurrentTime); |
| 87 |
| 88 XkbLockModifiers(display_, XkbUseCoreKbd, modifiers, 0); |
| 89 } |
| 90 |
| 91 bool X11KeyboardImpl::FindKeycode(uint32_t code_point, |
| 92 uint32_t* keycode, |
| 93 uint32_t* modifiers) { |
| 94 for (uint32_t keysym : GetKeySymsForUnicode(code_point)) { |
| 95 if (FindKeycodeForKeySym(display_, keysym, keycode, modifiers)) { |
| 96 return true; |
| 97 } |
| 98 } |
| 99 return false; |
| 100 } |
| 101 |
| 102 bool X11KeyboardImpl::ChangeKeyMapping(uint32_t keycode, uint32_t code_point) { |
| 103 KeySym sym = NoSymbol; |
| 104 if (code_point > 0) { |
| 105 std::string sym_hex = base::StringPrintf("U%x", code_point); |
| 106 sym = XStringToKeysym(sym_hex.c_str()); |
| 107 if (sym == NoSymbol) { |
| 108 // The server may not support Unicode-to-KeySym translation. |
| 109 return false; |
| 110 } |
| 111 } |
| 112 |
| 113 KeySym syms[2]{sym, sym}; // {lower-case, upper-case} |
| 114 XChangeKeyboardMapping(display_, keycode, 2, syms, 1); |
| 115 return true; |
| 116 } |
| 117 |
| 118 void X11KeyboardImpl::Flush() { |
| 119 XFlush(display_); |
| 120 } |
| 121 |
| 122 void X11KeyboardImpl::Sync() { |
| 123 XSync(display_, false); |
| 124 } |
| 125 |
| 126 } // namespace remoting |
OLD | NEW |