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 3 // found in the LICENSE file. 4 5 #include "remoting/host/input_injector.h" 6 7 #include <windows.h> 8 9 #include "base/bind.h" 10 #include "base/compiler_specific.h" 11 #include "base/location.h" 12 #include "base/memory/ref_counted.h" 13 #include "base/single_thread_task_runner.h" 14 #include "remoting/base/util.h" 15 #include "remoting/host/clipboard.h" 16 #include "remoting/proto/event.pb.h" 17 // SkSize.h assumes that stdint.h-style types are already defined. 18 #include "third_party/skia/include/core/SkTypes.h" 19 #include "third_party/skia/include/core/SkSize.h" 20 21 namespace remoting { 22 23 namespace { 24 25 using protocol::ClipboardEvent; 26 using protocol::KeyEvent; 27 using protocol::MouseEvent; 28 29 // USB to XKB keycode map table. 30 #define USB_KEYMAP(usb, xkb, win, mac) {usb, win} 31 #include "ui/base/keycodes/usb_keycode_map.h" 32 #undef USB_KEYMAP 33 34 // A class to generate events on Windows. 35 class InputInjectorWin : public InputInjector { 36 public: 37 InputInjectorWin(scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 38 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner); 39 virtual ~InputInjectorWin(); 40 41 // ClipboardStub interface. 42 virtual void InjectClipboardEvent(const ClipboardEvent& event) OVERRIDE; 43 44 // InputStub interface. 45 virtual void InjectKeyEvent(const KeyEvent& event) OVERRIDE; 46 virtual void InjectMouseEvent(const MouseEvent& event) OVERRIDE; 47 48 // InputInjector interface. 49 virtual void Start( 50 scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE; 51 52 private: 53 // The actual implementation resides in InputInjectorWin::Core class. 54 class Core : public base::RefCountedThreadSafe<Core> { 55 public: 56 Core(scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 57 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner); 58 59 // Mirrors the ClipboardStub interface. 60 void InjectClipboardEvent(const ClipboardEvent& event); 61 62 // Mirrors the InputStub interface. 63 void InjectKeyEvent(const KeyEvent& event); 64 void InjectMouseEvent(const MouseEvent& event); 65 66 // Mirrors the InputInjector interface. 67 void Start(scoped_ptr<protocol::ClipboardStub> client_clipboard); 68 69 void Stop(); 70 71 private: 72 friend class base::RefCountedThreadSafe<Core>; 73 virtual ~Core(); 74 75 void HandleKey(const KeyEvent& event); 76 void HandleMouse(const MouseEvent& event); 77 78 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; 79 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; 80 scoped_ptr<Clipboard> clipboard_; 81 82 DISALLOW_COPY_AND_ASSIGN(Core); 83 }; 84 85 scoped_refptr<Core> core_; 86 87 DISALLOW_COPY_AND_ASSIGN(InputInjectorWin); 88 }; 89 90 InputInjectorWin::InputInjectorWin( 91 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 92 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { 93 core_ = new Core(main_task_runner, ui_task_runner); 94 } 95 96 InputInjectorWin::~InputInjectorWin() { 97 core_->Stop(); 98 } 99 100 void InputInjectorWin::InjectClipboardEvent(const ClipboardEvent& event) { 101 core_->InjectClipboardEvent(event); 102 } 103 104 void InputInjectorWin::InjectKeyEvent(const KeyEvent& event) { 105 core_->InjectKeyEvent(event); 106 } 107 108 void InputInjectorWin::InjectMouseEvent(const MouseEvent& event) { 109 core_->InjectMouseEvent(event); 110 } 111 112 void InputInjectorWin::Start( 113 scoped_ptr<protocol::ClipboardStub> client_clipboard) { 114 core_->Start(client_clipboard.Pass()); 115 } 116 117 InputInjectorWin::Core::Core( 118 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 119 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) 120 : main_task_runner_(main_task_runner), 121 ui_task_runner_(ui_task_runner), 122 clipboard_(Clipboard::Create()) { 123 } 124 125 void InputInjectorWin::Core::InjectClipboardEvent(const ClipboardEvent& event) { 126 if (!ui_task_runner_->BelongsToCurrentThread()) { 127 ui_task_runner_->PostTask( 128 FROM_HERE, base::Bind(&Core::InjectClipboardEvent, this, event)); 129 return; 130 } 131 132 // |clipboard_| will ignore unknown MIME-types, and verify the data's format. 133 clipboard_->InjectClipboardEvent(event); 134 } 135 136 void InputInjectorWin::Core::InjectKeyEvent(const KeyEvent& event) { 137 if (!main_task_runner_->BelongsToCurrentThread()) { 138 main_task_runner_->PostTask(FROM_HERE, 139 base::Bind(&Core::InjectKeyEvent, this, event)); 140 return; 141 } 142 143 HandleKey(event); 144 } 145 146 void InputInjectorWin::Core::InjectMouseEvent(const MouseEvent& event) { 147 if (!main_task_runner_->BelongsToCurrentThread()) { 148 main_task_runner_->PostTask( 149 FROM_HERE, base::Bind(&Core::InjectMouseEvent, this, event)); 150 return; 151 } 152 153 HandleMouse(event); 154 } 155 156 void InputInjectorWin::Core::Start( 157 scoped_ptr<protocol::ClipboardStub> client_clipboard) { 158 if (!ui_task_runner_->BelongsToCurrentThread()) { 159 ui_task_runner_->PostTask( 160 FROM_HERE, 161 base::Bind(&Core::Start, this, base::Passed(&client_clipboard))); 162 return; 163 } 164 165 clipboard_->Start(client_clipboard.Pass()); 166 } 167 168 void InputInjectorWin::Core::Stop() { 169 if (!ui_task_runner_->BelongsToCurrentThread()) { 170 ui_task_runner_->PostTask(FROM_HERE, base::Bind(&Core::Stop, this)); 171 return; 172 } 173 174 clipboard_->Stop(); 175 } 176 177 InputInjectorWin::Core::~Core() { 178 } 179 180 void InputInjectorWin::Core::HandleKey(const KeyEvent& event) { 181 // HostEventDispatcher should filter events missing the pressed field. 182 if (!event.has_pressed() || !event.has_usb_keycode()) 183 return; 184 185 // Reset the system idle suspend timeout. 186 SetThreadExecutionState(ES_SYSTEM_REQUIRED); 187 188 int scancode = UsbKeycodeToNativeKeycode(event.usb_keycode()); 189 190 VLOG(3) << "Converting USB keycode: " << std::hex << event.usb_keycode() 191 << " to scancode: " << scancode << std::dec; 192 193 // Ignore events which can't be mapped. 194 if (scancode == InvalidNativeKeycode()) 195 return; 196 197 // Populate the a Windows INPUT structure for the event. 198 INPUT input; 199 memset(&input, 0, sizeof(input)); 200 input.type = INPUT_KEYBOARD; 201 input.ki.time = 0; 202 input.ki.dwFlags = KEYEVENTF_SCANCODE; 203 if (!event.pressed()) 204 input.ki.dwFlags |= KEYEVENTF_KEYUP; 205 206 // Windows scancodes are only 8-bit, so store the low-order byte into the 207 // event and set the extended flag if any high-order bits are set. The only 208 // high-order values we should see are 0xE0 or 0xE1. The extended bit usually 209 // distinguishes keys with the same meaning, e.g. left & right shift. 210 input.ki.wScan = scancode & 0xFF; 211 if ((scancode & 0xFF00) != 0x0000) 212 input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY; 213 214 if (SendInput(1, &input, sizeof(INPUT)) == 0) 215 LOG_GETLASTERROR(ERROR) << "Failed to inject a key event"; 216 } 217 218 void InputInjectorWin::Core::HandleMouse(const MouseEvent& event) { 219 // Reset the system idle suspend timeout. 220 SetThreadExecutionState(ES_SYSTEM_REQUIRED); 221 222 // TODO(garykac) Collapse mouse (x,y) and button events into a single 223 // input event when possible. 224 if (event.has_x() && event.has_y()) { 225 int x = event.x(); 226 int y = event.y(); 227 228 INPUT input; 229 input.type = INPUT_MOUSE; 230 input.mi.time = 0; 231 SkISize screen_size(SkISize::Make(GetSystemMetrics(SM_CXVIRTUALSCREEN), 232 GetSystemMetrics(SM_CYVIRTUALSCREEN))); 233 if ((screen_size.width() > 1) && (screen_size.height() > 1)) { 234 x = std::max(0, std::min(screen_size.width(), x)); 235 y = std::max(0, std::min(screen_size.height(), y)); 236 input.mi.dx = static_cast<int>((x * 65535) / (screen_size.width() - 1)); 237 input.mi.dy = static_cast<int>((y * 65535) / (screen_size.height() - 1)); 238 input.mi.dwFlags = 239 MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK; 240 if (SendInput(1, &input, sizeof(INPUT)) == 0) 241 LOG_GETLASTERROR(ERROR) << "Failed to inject a mouse move event"; 242 } 243 } 244 245 int wheel_delta_x = 0; 246 int wheel_delta_y = 0; 247 if (event.has_wheel_delta_x() && event.has_wheel_delta_y()) { 248 wheel_delta_x = static_cast<int>(event.wheel_delta_x()); 249 wheel_delta_y = static_cast<int>(event.wheel_delta_y()); 250 } 251 252 if (wheel_delta_x != 0 || wheel_delta_y != 0) { 253 INPUT wheel; 254 wheel.type = INPUT_MOUSE; 255 wheel.mi.time = 0; 256 257 if (wheel_delta_x != 0) { 258 wheel.mi.mouseData = wheel_delta_x; 259 wheel.mi.dwFlags = MOUSEEVENTF_HWHEEL; 260 if (SendInput(1, &wheel, sizeof(INPUT)) == 0) 261 LOG_GETLASTERROR(ERROR) << "Failed to inject a mouse wheel(x) event"; 262 } 263 if (wheel_delta_y != 0) { 264 wheel.mi.mouseData = wheel_delta_y; 265 wheel.mi.dwFlags = MOUSEEVENTF_WHEEL; 266 if (SendInput(1, &wheel, sizeof(INPUT)) == 0) 267 LOG_GETLASTERROR(ERROR) << "Failed to inject a mouse wheel(y) event"; 268 } 269 } 270 271 if (event.has_button() && event.has_button_down()) { 272 INPUT button_event; 273 button_event.type = INPUT_MOUSE; 274 button_event.mi.time = 0; 275 button_event.mi.dx = 0; 276 button_event.mi.dy = 0; 277 278 MouseEvent::MouseButton button = event.button(); 279 bool down = event.button_down(); 280 281 // If the host is configured to swap left & right buttons, inject swapped 282 // events to un-do that re-mapping. 283 if (GetSystemMetrics(SM_SWAPBUTTON)) { 284 if (button == MouseEvent::BUTTON_LEFT) { 285 button = MouseEvent::BUTTON_RIGHT; 286 } else if (button == MouseEvent::BUTTON_RIGHT) { 287 button = MouseEvent::BUTTON_LEFT; 288 } 289 } 290 291 if (button == MouseEvent::BUTTON_LEFT) { 292 button_event.mi.dwFlags = 293 down ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP; 294 } else if (button == MouseEvent::BUTTON_MIDDLE) { 295 button_event.mi.dwFlags = 296 down ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP; 297 } else if (button == MouseEvent::BUTTON_RIGHT) { 298 button_event.mi.dwFlags = 299 down ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP; 300 } else { 301 button_event.mi.dwFlags = 302 down ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP; 303 } 304 305 if (SendInput(1, &button_event, sizeof(INPUT)) == 0) 306 LOG_GETLASTERROR(ERROR) << "Failed to inject a mouse button event"; 307 } 308 } 309 310 } // namespace 311 312 scoped_ptr<InputInjector> InputInjector::Create( 313 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 314 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { 315 return scoped_ptr<InputInjector>( 316 new InputInjectorWin(main_task_runner, ui_task_runner)); 317 } 318 319 } // namespace remoting 320