Chromium Code Reviews| Index: remoting/host/linux/x_server_keyboard_interface.cc |
| diff --git a/remoting/host/linux/x_server_keyboard_interface.cc b/remoting/host/linux/x_server_keyboard_interface.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..94077973661c3107aafb2e65e350a0669e5e447a |
| --- /dev/null |
| +++ b/remoting/host/linux/x_server_keyboard_interface.cc |
| @@ -0,0 +1,142 @@ |
| +// Copyright 2016 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 "remoting/host/linux/x_server_keyboard_interface.h" |
| + |
| +#include <X11/extensions/XInput.h> |
| +#include <X11/extensions/XTest.h> |
| +#include <X11/XKBlib.h> |
| + |
| +#include "base/strings/stringprintf.h" |
| +#include "remoting/host/linux/unicode_to_keysym.h" |
| +#include "ui/gfx/x/x11_types.h" |
| + |
| +namespace { |
| + |
| +bool FindKeycodeForKeySym(Display* display, |
| + KeySym key_sym, |
| + uint32_t* keycode, |
| + uint32_t* modifiers) { |
| + *keycode = XKeysymToKeycode(display, key_sym); |
| + |
| + const uint32_t kModifiersToTry[] = { |
| + 0, |
| + ShiftMask, |
| + Mod2Mask, |
| + Mod3Mask, |
| + Mod4Mask, |
| + ShiftMask | Mod2Mask, |
| + ShiftMask | Mod3Mask, |
| + ShiftMask | Mod4Mask, |
| + }; |
| + |
| + // TODO(sergeyu): Is there a better way to find modifiers state? |
| + for (size_t i = 0; i < arraysize(kModifiersToTry); ++i) { |
| + unsigned long key_sym_with_mods; |
| + if (XkbLookupKeySym(display, *keycode, kModifiersToTry[i], nullptr, |
| + &key_sym_with_mods) && |
| + key_sym_with_mods == key_sym) { |
| + *modifiers = kModifiersToTry[i]; |
| + return true; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| +KeySym CodePointToKeySym(uint32_t code_point) { |
| + if (code_point == 0) { |
| + return NoSymbol; |
| + } |
| + std::string sym_hex = base::StringPrintf("U%x", code_point); |
| + return XStringToKeysym(sym_hex.c_str()); |
| +} |
| + |
| +} // namespace |
| + |
| +namespace remoting { |
| + |
| +XServerKeyboardInterface::XServerKeyboardInterface(Display* display) : |
| + display_(display) {} |
| + |
| +XServerKeyboardInterface::~XServerKeyboardInterface() {} |
| + |
| +std::vector<uint32_t> XServerKeyboardInterface::GetUnusedKeycodes() { |
| + std::vector<uint32_t> unused_keycodes_; |
| + int min_keycode; |
| + int max_keycode; |
| + XDisplayKeycodes(display_, &min_keycode, &max_keycode); |
| + uint32_t keycode_count = max_keycode - min_keycode + 1; |
| + |
| + int sym_per_key; |
| + gfx::XScopedPtr<KeySym> mapping(XGetKeyboardMapping( |
| + display_, min_keycode, keycode_count, &sym_per_key)); |
| + for (int keycode = max_keycode; keycode >= min_keycode; keycode--) { |
| + bool used = false; |
| + int offset = (keycode - min_keycode) * sym_per_key; |
| + for (int level = 0; level < sym_per_key; level++) { |
| + if (mapping.get()[offset + level]) { |
| + used = true; |
| + break; |
| + } |
| + } |
| + if (!used) { |
| + unused_keycodes_.push_back(keycode); |
| + } |
| + } |
| + return unused_keycodes_; |
| +} |
| + |
| +void XServerKeyboardInterface::PressKey(uint32_t keycode, uint32_t modifiers) { |
| + XkbLockModifiers(display_, XkbUseCoreKbd, modifiers, modifiers); |
| + |
| + XTestFakeKeyEvent(display_, keycode, True, CurrentTime); |
| + XTestFakeKeyEvent(display_, keycode, False, CurrentTime); |
| + |
| + XkbLockModifiers(display_, XkbUseCoreKbd, modifiers, 0); |
| +} |
| + |
| +bool XServerKeyboardInterface::FindKeycode(uint32_t code_point, |
| + uint32_t* keycode, |
| + uint32_t* modifiers) { |
| + std::vector<uint32_t> keysyms; |
| + GetKeySymsForUnicode(code_point, &keysyms); |
| + |
| + for (std::vector<uint32_t>::iterator it = keysyms.begin(); |
|
Sergey Ulanov
2016/09/21 19:59:23
Use range loop please:
for (auto& keysym : keysy
Yuwei
2016/09/23 01:40:38
Done.
|
| + it != keysyms.end(); ++it) { |
| + if (FindKeycodeForKeySym(display_, *it, keycode, modifiers)) { |
| + return true; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| +bool XServerKeyboardInterface::ChangeKeyMapping( |
| + uint32_t keycode, |
|
Sergey Ulanov
2016/09/21 19:59:23
int instead of uint32_t.
Yuwei
2016/09/23 01:40:37
Is there any reason we prefer int? Looks like keyc
|
| + uint32_t lower_case_code_point, |
| + uint32_t upper_case_code_point) { |
|
Sergey Ulanov
2016/09/21 19:59:23
Maybe use KeySym for these two parameters?
Sergey Ulanov
2016/09/21 19:59:24
Do we need it here? It doesn't appear to be useful
Yuwei
2016/09/23 01:40:37
Removed.
I just thought it could be useful if we
Yuwei
2016/09/23 01:40:37
KeySym is tyepdef'ed as unsigned int. I tried to a
|
| + KeySym lower_case_keysym = CodePointToKeySym(lower_case_code_point); |
| + KeySym upper_case_keysum = (lower_case_code_point == upper_case_code_point) ? |
| + lower_case_keysym : CodePointToKeySym(upper_case_code_point); |
| + if ((lower_case_code_point && !lower_case_keysym) || |
| + (upper_case_code_point && !upper_case_keysum)) { |
| + // Non-null code point translated to NoSymbol. The server may not support |
| + // Unicode-to-KeySym translation. |
| + return false; |
| + } |
| + KeySym syms[2]; |
|
Sergey Ulanov
2016/09/21 19:59:24
= {lower_case_keysym, upper_case_keysum};
Yuwei
2016/09/23 01:40:37
Done.
|
| + syms[0] = lower_case_keysym; |
| + syms[1] = upper_case_keysum; |
| + XChangeKeyboardMapping(display_, keycode, 2, syms, 1); |
| + return true; |
| +} |
| + |
| +void XServerKeyboardInterface::Flush() { |
| + XFlush(display_); |
| +} |
| + |
| +void XServerKeyboardInterface::Sync() { |
| + XSync(display_, false); |
| +} |
| + |
| +} // namespace remoting |