| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/host/event_executor.h" | 5 #include "remoting/host/event_executor.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include <X11/Xlib.h> | 9 #include <X11/Xlib.h> |
| 10 #include <X11/XF86keysym.h> | |
| 11 #include <X11/keysym.h> | |
| 12 #include <X11/extensions/XTest.h> | 10 #include <X11/extensions/XTest.h> |
| 13 | 11 |
| 14 #include "base/basictypes.h" | 12 #include "base/basictypes.h" |
| 15 #include "base/bind.h" | 13 #include "base/bind.h" |
| 16 #include "base/compiler_specific.h" | 14 #include "base/compiler_specific.h" |
| 17 #include "base/location.h" | 15 #include "base/location.h" |
| 18 #include "base/logging.h" | 16 #include "base/logging.h" |
| 19 #include "base/single_thread_task_runner.h" | 17 #include "base/single_thread_task_runner.h" |
| 20 #include "remoting/proto/internal.pb.h" | 18 #include "remoting/proto/internal.pb.h" |
| 21 #include "third_party/skia/include/core/SkPoint.h" | 19 #include "third_party/skia/include/core/SkPoint.h" |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 return (dx > 0 ? 6 : 7); | 95 return (dx > 0 ? 6 : 7); |
| 98 } | 96 } |
| 99 | 97 |
| 100 | 98 |
| 101 int VerticalScrollWheelToX11ButtonNumber(int dy) { | 99 int VerticalScrollWheelToX11ButtonNumber(int dy) { |
| 102 // Positive y-values are wheel scroll-up events (button 4), negative y-values | 100 // Positive y-values are wheel scroll-up events (button 4), negative y-values |
| 103 // are wheel scroll-down events (button 5). | 101 // are wheel scroll-down events (button 5). |
| 104 return (dy > 0 ? 4 : 5); | 102 return (dy > 0 ? 4 : 5); |
| 105 } | 103 } |
| 106 | 104 |
| 107 // Hard-coded mapping from Virtual Key codes to X11 KeySyms. | |
| 108 // This mapping is only valid if both client and host are using a | |
| 109 // US English keyboard layout. | |
| 110 // Because we're passing VK codes on the wire, with no Scancode, | |
| 111 // "extended" flag, etc, things like distinguishing left & right | |
| 112 // Shift keys doesn't work. | |
| 113 // | |
| 114 // TODO(wez): Replace this with something more closely tied to what | |
| 115 // WebInputEventFactory does on Linux/GTK, and which respects the | |
| 116 // host's keyboard layout (see http://crbug.com/74550 ). | |
| 117 const int kUsVkeyToKeysym[256] = { | |
| 118 // 0x00 - 0x07 | |
| 119 -1, -1, -1, XK_Cancel, | |
| 120 // 0x04 - 0x07 | |
| 121 -1, -1, -1, -1, | |
| 122 // 0x08 - 0x0B | |
| 123 XK_BackSpace, XK_Tab, -1, -1, | |
| 124 // 0x0C - 0x0F | |
| 125 XK_Clear, XK_Return, -1, -1, | |
| 126 | |
| 127 // 0x10 - 0x13 | |
| 128 XK_Shift_L, XK_Control_L, XK_Alt_L, XK_Pause, | |
| 129 // 0x14 - 0x17 | |
| 130 XK_Caps_Lock, XK_Kana_Shift, -1, XK_Hangul_Jeonja, | |
| 131 // 0x18 - 0x1B | |
| 132 XK_Hangul_End, XK_Kanji, -1, XK_Escape, | |
| 133 // 0x1C - 0x1F | |
| 134 XK_Henkan, XK_Muhenkan, /* VKEY_ACCEPT */ -1, XK_Mode_switch, | |
| 135 | |
| 136 // 0x20 - 0x23 | |
| 137 XK_space, XK_Prior, XK_Next, XK_End, | |
| 138 // 0x24 - 0x27 | |
| 139 XK_Home, XK_Left, XK_Up, XK_Right, | |
| 140 // 0x28 - 0x2B | |
| 141 XK_Down, XK_Select, /* VK_PRINT */ -1, XK_Execute, | |
| 142 // 0x2C - 0x2F | |
| 143 XK_Print, XK_Insert, XK_Delete, XK_Help, | |
| 144 | |
| 145 // 0x30 - 0x33 | |
| 146 XK_0, XK_1, XK_2, XK_3, | |
| 147 // 0x34 - 0x37 | |
| 148 XK_4, XK_5, XK_6, XK_7, | |
| 149 // 0x38 - 0x3B | |
| 150 XK_8, XK_9, -1, -1, | |
| 151 // 0x3C - 0x3F | |
| 152 -1, -1, -1, -1, | |
| 153 | |
| 154 // 0x40 - 0x43 | |
| 155 -1, XK_A, XK_B, XK_C, | |
| 156 // 0x44 - 0x47 | |
| 157 XK_D, XK_E, XK_F, XK_G, | |
| 158 // 0x48 - 0x4B | |
| 159 XK_H, XK_I, XK_J, XK_K, | |
| 160 // 0x4C - 0x4F | |
| 161 XK_L, XK_M, XK_N, XK_O, | |
| 162 | |
| 163 // 0x50 - 0x53 | |
| 164 XK_P, XK_Q, XK_R, XK_S, | |
| 165 // 0x54 - 0x57 | |
| 166 XK_T, XK_U, XK_V, XK_W, | |
| 167 // 0x58 - 0x5B | |
| 168 XK_X, XK_Y, XK_Z, XK_Super_L, | |
| 169 // 0x5C - 0x5F | |
| 170 XK_Super_R, XK_Menu, -1, /* VKEY_SLEEP */ -1, | |
| 171 | |
| 172 // 0x60 - 0x63 | |
| 173 XK_KP_0, XK_KP_1, XK_KP_2, XK_KP_3, | |
| 174 // 0x64 - 0x67 | |
| 175 XK_KP_4, XK_KP_5, XK_KP_6, XK_KP_7, | |
| 176 // 0x68 - 0x6B | |
| 177 XK_KP_8, XK_KP_9, XK_KP_Multiply, XK_KP_Add, | |
| 178 // 0x6C - 0x6F | |
| 179 XK_KP_Separator, XK_KP_Subtract, XK_KP_Decimal, XK_KP_Divide, | |
| 180 | |
| 181 // 0x70 - 0x73 | |
| 182 XK_F1, XK_F2, XK_F3, XK_F4, | |
| 183 // 0x74 - 0x77 | |
| 184 XK_F5, XK_F6, XK_F7, XK_F8, | |
| 185 // 0x78 - 0x7B | |
| 186 XK_F9, XK_F10, XK_F11, XK_F12, | |
| 187 // 0x7C - 0x7F | |
| 188 XK_F13, XK_F14, XK_F15, XK_F16, | |
| 189 | |
| 190 // 0x80 - 0x83 | |
| 191 XK_F17, XK_F18, XK_F19, XK_F20, | |
| 192 // 0x84 - 0x87 | |
| 193 XK_F21, XK_F22, XK_F23, XK_F24, | |
| 194 // 0x88 - 0x8B | |
| 195 -1, -1, -1, -1, | |
| 196 // 0x8C - 0x8F | |
| 197 -1, -1, -1, -1, | |
| 198 | |
| 199 // 0x90 - 0x93 | |
| 200 XK_Num_Lock, XK_Scroll_Lock, -1, -1, | |
| 201 // 0x94 - 0x97 | |
| 202 -1, -1, -1, -1, | |
| 203 // 0x98 - 0x9B | |
| 204 -1, -1, -1, -1, | |
| 205 // 0x9C - 0x9F | |
| 206 -1, -1, -1, -1, | |
| 207 | |
| 208 // 0xA0 - 0xA3 | |
| 209 XK_Shift_L, XK_Shift_R, XK_Control_L, XK_Control_R, | |
| 210 // 0xA4 - 0xA7 | |
| 211 XK_Meta_L, XK_Meta_R, XF86XK_Back, XF86XK_Forward, | |
| 212 // 0xA8 - 0xAB | |
| 213 XF86XK_Refresh, XF86XK_Stop, XF86XK_Search, XF86XK_Favorites, | |
| 214 // 0xAC - 0xAF | |
| 215 XF86XK_HomePage, XF86XK_AudioMute, XF86XK_AudioLowerVolume, | |
| 216 XF86XK_AudioRaiseVolume, | |
| 217 | |
| 218 // 0xB0 - 0xB3 | |
| 219 XF86XK_AudioNext, XF86XK_AudioPrev, XF86XK_AudioStop, XF86XK_AudioPause, | |
| 220 // 0xB4 - 0xB7 | |
| 221 XF86XK_Mail, XF86XK_AudioMedia, XF86XK_Launch0, XF86XK_Launch1, | |
| 222 // 0xB8 - 0xBB | |
| 223 -1, -1, XK_semicolon, XK_plus, | |
| 224 // 0xBC - 0xBF | |
| 225 XK_comma, XK_minus, XK_period, XK_slash, | |
| 226 | |
| 227 // 0xC0 - 0xC3 | |
| 228 XK_grave, -1, -1, -1, | |
| 229 // 0xC4 - 0xC7 | |
| 230 -1, -1, -1, -1, | |
| 231 // 0xC8 - 0xCB | |
| 232 -1, -1, -1, -1, | |
| 233 // 0xCC - 0xCF | |
| 234 -1, -1, -1, -1, | |
| 235 | |
| 236 // 0xD0 - 0xD3 | |
| 237 -1, -1, -1, -1, | |
| 238 // 0xD4 - 0xD7 | |
| 239 -1, -1, -1, -1, | |
| 240 // 0xD8 - 0xDB | |
| 241 -1, -1, -1, XK_bracketleft, | |
| 242 // 0xDC - 0xDF | |
| 243 XK_backslash, XK_bracketright, XK_apostrophe, | |
| 244 /* VKEY_OEM_8 */ -1, | |
| 245 | |
| 246 // 0xE0 - 0xE3 | |
| 247 -1, -1, /* VKEY_OEM_102 */ -1, -1, | |
| 248 // 0xE4 - 0xE7 | |
| 249 -1, /* VKEY_PROCESSKEY */ -1, -1, /* VKEY_PACKET */ -1, | |
| 250 // 0xE8 - 0xEB | |
| 251 -1, -1, -1, -1, | |
| 252 // 0xEC - 0xEF | |
| 253 -1, -1, -1, -1, | |
| 254 | |
| 255 // 0xF0 - 0xF3 | |
| 256 -1, -1, -1, -1, | |
| 257 // 0xF4 - 0xF7 | |
| 258 -1, -1, /* VKEY_ATTN */ -1, /* VKEY_CRSEL */ -1, | |
| 259 // 0xF8 - 0xFB | |
| 260 /* VKEY_EXSEL */ -1, /* VKEY_EREOF */ -1, /* VKEY_PLAY */ -1, | |
| 261 /* VKEY_ZOOM */ -1, | |
| 262 // 0xFC - 0xFF | |
| 263 /* VKEY_NONAME */ -1, /* VKEY_PA1 */ -1, /* VKEY_OEM_CLEAR */ -1, -1 | |
| 264 }; | |
| 265 | |
| 266 int ChromotocolKeycodeToX11Keysym(int32_t keycode) { | |
| 267 if (keycode < 0 || keycode > 255) | |
| 268 return kInvalidKeycode; | |
| 269 | |
| 270 return kUsVkeyToKeysym[keycode]; | |
| 271 } | |
| 272 | |
| 273 EventExecutorLinux::EventExecutorLinux( | 105 EventExecutorLinux::EventExecutorLinux( |
| 274 scoped_refptr<base::SingleThreadTaskRunner> task_runner) | 106 scoped_refptr<base::SingleThreadTaskRunner> task_runner) |
| 275 : task_runner_(task_runner), | 107 : task_runner_(task_runner), |
| 276 latest_mouse_position_(SkIPoint::Make(-1, -1)), | 108 latest_mouse_position_(SkIPoint::Make(-1, -1)), |
| 277 display_(XOpenDisplay(NULL)), | 109 display_(XOpenDisplay(NULL)), |
| 278 root_window_(BadValue) { | 110 root_window_(BadValue) { |
| 279 } | 111 } |
| 280 | 112 |
| 281 EventExecutorLinux::~EventExecutorLinux() { | 113 EventExecutorLinux::~EventExecutorLinux() { |
| 282 CHECK(pressed_keys_.empty()); | 114 CHECK(pressed_keys_.empty()); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 303 return true; | 135 return true; |
| 304 } | 136 } |
| 305 | 137 |
| 306 void EventExecutorLinux::InjectClipboardEvent(const ClipboardEvent& event) { | 138 void EventExecutorLinux::InjectClipboardEvent(const ClipboardEvent& event) { |
| 307 // TODO(simonmorris): Implement clipboard injection. | 139 // TODO(simonmorris): Implement clipboard injection. |
| 308 } | 140 } |
| 309 | 141 |
| 310 void EventExecutorLinux::InjectKeyEvent(const KeyEvent& event) { | 142 void EventExecutorLinux::InjectKeyEvent(const KeyEvent& event) { |
| 311 // HostEventDispatcher should filter events missing the pressed field. | 143 // HostEventDispatcher should filter events missing the pressed field. |
| 312 DCHECK(event.has_pressed()); | 144 DCHECK(event.has_pressed()); |
| 145 DCHECK(event.has_usb_keycode()); |
| 313 | 146 |
| 314 if (!task_runner_->BelongsToCurrentThread()) { | 147 if (!task_runner_->BelongsToCurrentThread()) { |
| 315 task_runner_->PostTask( | 148 task_runner_->PostTask( |
| 316 FROM_HERE, | 149 FROM_HERE, |
| 317 base::Bind(&EventExecutorLinux::InjectKeyEvent, base::Unretained(this), | 150 base::Bind(&EventExecutorLinux::InjectKeyEvent, base::Unretained(this), |
| 318 event)); | 151 event)); |
| 319 return; | 152 return; |
| 320 } | 153 } |
| 321 | 154 |
| 322 int keycode = kInvalidKeycode; | 155 keycode = UsbKeycodeToNativeKeycode(event.usb_keycode()); |
| 323 if (event.has_usb_keycode()) { | 156 VLOG(3) << "Converting USB keycode: " << std::hex << event.usb_keycode() |
| 324 keycode = UsbKeycodeToNativeKeycode(event.usb_keycode()); | 157 << " to keycode: " << keycode << std::dec; |
| 325 VLOG(3) << "Converting USB keycode: " << std::hex << event.usb_keycode() | |
| 326 << " to keycode: " << keycode << std::dec; | |
| 327 } else if (event.has_keycode()) { | |
| 328 // Fall back to keysym translation. | |
| 329 // TODO(garykac) Remove this once we switch entirely over to USB keycodes. | |
| 330 int keysym = ChromotocolKeycodeToX11Keysym(event.keycode()); | |
| 331 keycode = XKeysymToKeycode(display_, keysym); | |
| 332 VLOG(3) << "Converting VKEY: " << std::hex << event.keycode() | |
| 333 << " to keysym: " << keysym | |
| 334 << " to keycode: " << keycode << std::dec; | |
| 335 } | |
| 336 | 158 |
| 337 // Ignore events with no VK- or USB-keycode, or which can't be mapped. | 159 // Ignore events which can't be mapped. |
| 338 if (keycode == kInvalidKeycode) | 160 if (keycode == kInvalidKeycode) |
| 339 return; | 161 return; |
| 340 | 162 |
| 341 if (event.pressed()) { | 163 if (event.pressed()) { |
| 342 if (pressed_keys_.find(keycode) != pressed_keys_.end()) { | 164 if (pressed_keys_.find(keycode) != pressed_keys_.end()) { |
| 343 // Key is already held down, so lift the key up to ensure this repeated | 165 // Key is already held down, so lift the key up to ensure this repeated |
| 344 // press takes effect. | 166 // press takes effect. |
| 345 XTestFakeKeyEvent(display_, keycode, False, CurrentTime); | 167 XTestFakeKeyEvent(display_, keycode, False, CurrentTime); |
| 346 } else { | 168 } else { |
| 347 // Key is not currently held down, so disable auto-repeat for this | 169 // Key is not currently held down, so disable auto-repeat for this |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 454 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, | 276 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, |
| 455 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { | 277 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { |
| 456 scoped_ptr<EventExecutorLinux> executor( | 278 scoped_ptr<EventExecutorLinux> executor( |
| 457 new EventExecutorLinux(main_task_runner)); | 279 new EventExecutorLinux(main_task_runner)); |
| 458 if (!executor->Init()) | 280 if (!executor->Init()) |
| 459 return scoped_ptr<EventExecutor>(NULL); | 281 return scoped_ptr<EventExecutor>(NULL); |
| 460 return executor.PassAs<EventExecutor>(); | 282 return executor.PassAs<EventExecutor>(); |
| 461 } | 283 } |
| 462 | 284 |
| 463 } // namespace remoting | 285 } // namespace remoting |
| OLD | NEW |