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/x_server_keyboard_interface.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 *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, *keycode, kModifiersToTry[i], nullptr, | |
38 &key_sym_with_mods) && | |
39 key_sym_with_mods == key_sym) { | |
40 *modifiers = kModifiersToTry[i]; | |
41 return true; | |
42 } | |
43 } | |
44 return false; | |
45 } | |
46 | |
47 KeySym CodePointToKeySym(uint32_t code_point) { | |
48 if (code_point == 0) { | |
49 return NoSymbol; | |
50 } | |
51 std::string sym_hex = base::StringPrintf("U%x", code_point); | |
52 return XStringToKeysym(sym_hex.c_str()); | |
53 } | |
54 | |
55 } // namespace | |
56 | |
57 namespace remoting { | |
58 | |
59 XServerKeyboardInterface::XServerKeyboardInterface(Display* display) : | |
60 display_(display) {} | |
61 | |
62 XServerKeyboardInterface::~XServerKeyboardInterface() {} | |
63 | |
64 std::vector<uint32_t> XServerKeyboardInterface::GetUnusedKeycodes() { | |
65 std::vector<uint32_t> unused_keycodes_; | |
66 int min_keycode; | |
67 int max_keycode; | |
68 XDisplayKeycodes(display_, &min_keycode, &max_keycode); | |
69 uint32_t keycode_count = max_keycode - min_keycode + 1; | |
70 | |
71 int sym_per_key; | |
72 gfx::XScopedPtr<KeySym> mapping(XGetKeyboardMapping( | |
73 display_, min_keycode, keycode_count, &sym_per_key)); | |
74 for (int keycode = max_keycode; keycode >= min_keycode; keycode--) { | |
75 bool used = false; | |
76 int offset = (keycode - min_keycode) * sym_per_key; | |
77 for (int level = 0; level < sym_per_key; level++) { | |
78 if (mapping.get()[offset + level]) { | |
79 used = true; | |
80 break; | |
81 } | |
82 } | |
83 if (!used) { | |
84 unused_keycodes_.push_back(keycode); | |
85 } | |
86 } | |
87 return unused_keycodes_; | |
88 } | |
89 | |
90 void XServerKeyboardInterface::PressKey(uint32_t keycode, uint32_t modifiers) { | |
91 XkbLockModifiers(display_, XkbUseCoreKbd, modifiers, modifiers); | |
92 | |
93 XTestFakeKeyEvent(display_, keycode, True, CurrentTime); | |
94 XTestFakeKeyEvent(display_, keycode, False, CurrentTime); | |
95 | |
96 XkbLockModifiers(display_, XkbUseCoreKbd, modifiers, 0); | |
97 } | |
98 | |
99 bool XServerKeyboardInterface::FindKeycode(uint32_t code_point, | |
100 uint32_t* keycode, | |
101 uint32_t* modifiers) { | |
102 std::vector<uint32_t> keysyms; | |
103 GetKeySymsForUnicode(code_point, &keysyms); | |
104 | |
105 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.
| |
106 it != keysyms.end(); ++it) { | |
107 if (FindKeycodeForKeySym(display_, *it, keycode, modifiers)) { | |
108 return true; | |
109 } | |
110 } | |
111 return false; | |
112 } | |
113 | |
114 bool XServerKeyboardInterface::ChangeKeyMapping( | |
115 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
| |
116 uint32_t lower_case_code_point, | |
117 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
| |
118 KeySym lower_case_keysym = CodePointToKeySym(lower_case_code_point); | |
119 KeySym upper_case_keysum = (lower_case_code_point == upper_case_code_point) ? | |
120 lower_case_keysym : CodePointToKeySym(upper_case_code_point); | |
121 if ((lower_case_code_point && !lower_case_keysym) || | |
122 (upper_case_code_point && !upper_case_keysum)) { | |
123 // Non-null code point translated to NoSymbol. The server may not support | |
124 // Unicode-to-KeySym translation. | |
125 return false; | |
126 } | |
127 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.
| |
128 syms[0] = lower_case_keysym; | |
129 syms[1] = upper_case_keysum; | |
130 XChangeKeyboardMapping(display_, keycode, 2, syms, 1); | |
131 return true; | |
132 } | |
133 | |
134 void XServerKeyboardInterface::Flush() { | |
135 XFlush(display_); | |
136 } | |
137 | |
138 void XServerKeyboardInterface::Sync() { | |
139 XSync(display_, false); | |
140 } | |
141 | |
142 } // namespace remoting | |
OLD | NEW |