Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(23)

Side by Side Diff: remoting/host/input_injector_win.cc

Issue 1865543003: Update input_injector_win.cc to support injecting wheel-x and wheel-y events together (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Revert last change Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/input_injector.h" 5 #include "remoting/host/input_injector.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <windows.h> 8 #include <windows.h>
9 9
10 #include <utility> 10 #include <utility>
11 #include <vector>
11 12
12 #include "base/bind.h" 13 #include "base/bind.h"
13 #include "base/compiler_specific.h" 14 #include "base/compiler_specific.h"
14 #include "base/location.h" 15 #include "base/location.h"
15 #include "base/macros.h" 16 #include "base/macros.h"
16 #include "base/memory/ref_counted.h" 17 #include "base/memory/ref_counted.h"
17 #include "base/single_thread_task_runner.h" 18 #include "base/single_thread_task_runner.h"
18 #include "base/strings/string16.h" 19 #include "base/strings/string16.h"
19 #include "base/strings/utf_string_conversions.h" 20 #include "base/strings/utf_string_conversions.h"
20 #include "remoting/base/util.h" 21 #include "remoting/base/util.h"
21 #include "remoting/host/clipboard.h" 22 #include "remoting/host/clipboard.h"
22 #include "remoting/host/touch_injector_win.h" 23 #include "remoting/host/touch_injector_win.h"
23 #include "remoting/proto/event.pb.h" 24 #include "remoting/proto/event.pb.h"
24 #include "ui/events/keycodes/dom/keycode_converter.h" 25 #include "ui/events/keycodes/dom/keycode_converter.h"
25 26
26 namespace remoting { 27 namespace remoting {
27 28
28 namespace { 29 namespace {
29 30
31 using protocol::ClipboardEvent;
32 using protocol::KeyEvent;
33 using protocol::TextEvent;
34 using protocol::MouseEvent;
35 using protocol::TouchEvent;
36
30 // Helper used to call SendInput() API. 37 // Helper used to call SendInput() API.
31 void SendKeyboardInput(uint32_t flags, uint16_t scancode) { 38 void SendKeyboardInput(uint32_t flags, uint16_t scancode) {
32 // Populate a Windows INPUT structure for the event. 39 // Populate a Windows INPUT structure for the event.
33 INPUT input; 40 INPUT input;
34 memset(&input, 0, sizeof(input)); 41 memset(&input, 0, sizeof(input));
35 input.type = INPUT_KEYBOARD; 42 input.type = INPUT_KEYBOARD;
36 input.ki.time = 0; 43 input.ki.time = 0;
37 input.ki.dwFlags = flags; 44 input.ki.dwFlags = flags;
38 input.ki.wScan = scancode; 45 input.ki.wScan = scancode;
39 46
40 if ((flags & KEYEVENTF_UNICODE) == 0) { 47 if ((flags & KEYEVENTF_UNICODE) == 0) {
41 // Windows scancodes are only 8-bit, so store the low-order byte into the 48 // Windows scancodes are only 8-bit, so store the low-order byte into the
42 // event and set the extended flag if any high-order bits are set. The only 49 // event and set the extended flag if any high-order bits are set. The only
43 // high-order values we should see are 0xE0 or 0xE1. The extended bit 50 // high-order values we should see are 0xE0 or 0xE1. The extended bit
44 // usually distinguishes keys with the same meaning, e.g. left & right 51 // usually distinguishes keys with the same meaning, e.g. left & right
45 // shift. 52 // shift.
46 input.ki.wScan &= 0xFF; 53 input.ki.wScan &= 0xFF;
47 if ((scancode & 0xFF00) != 0x0000) 54 if ((scancode & 0xFF00) != 0x0000)
48 input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY; 55 input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
49 } 56 }
50 57
51 if (SendInput(1, &input, sizeof(INPUT)) == 0) 58 if (SendInput(1, &input, sizeof(INPUT)) == 0)
52 PLOG(ERROR) << "Failed to inject a key event"; 59 PLOG(ERROR) << "Failed to inject a key event";
53 } 60 }
54 61
55 using protocol::ClipboardEvent; 62 // Parse move related operations from the input MouseEvent, and insert the
56 using protocol::KeyEvent; 63 // result into output.
57 using protocol::TextEvent; 64 void ParseMouseMoveEvent(const MouseEvent& event, std::vector<INPUT>* output) {
58 using protocol::MouseEvent; 65 INPUT input = {0};
59 using protocol::TouchEvent; 66 input.type = INPUT_MOUSE;
67
68 if (event.has_delta_x() && event.has_delta_y()) {
69 input.mi.dx = event.delta_x();
70 input.mi.dy = event.delta_y();
71 input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_VIRTUALDESK;
72 } else if (event.has_x() && event.has_y()) {
73 int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
74 int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
75 if (width > 1 && height > 1) {
76 int x = std::max(0, std::min(width, event.x()));
77 int y = std::max(0, std::min(height, event.y()));
78 input.mi.dx = static_cast<int>((x * 65535) / (width - 1));
79 input.mi.dy = static_cast<int>((y * 65535) / (height - 1));
80 input.mi.dwFlags =
81 MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK;
82 }
83 } else {
84 return;
85 }
86
87 output->push_back(std::move(input));
88 }
89
90 // Parse click related operations from the input MouseEvent, and insert the
91 // result into output.
92 void ParseMouseClickEvent(const MouseEvent& event, std::vector<INPUT>* output) {
93 if (event.has_button() && event.has_button_down()) {
94 INPUT input = {0};
95 input.type = INPUT_MOUSE;
96
97 MouseEvent::MouseButton button = event.button();
98 bool down = event.button_down();
99
100 // If the host is configured to swap left & right buttons, inject swapped
101 // events to un-do that re-mapping.
102 if (GetSystemMetrics(SM_SWAPBUTTON)) {
103 if (button == MouseEvent::BUTTON_LEFT) {
104 button = MouseEvent::BUTTON_RIGHT;
105 } else if (button == MouseEvent::BUTTON_RIGHT) {
106 button = MouseEvent::BUTTON_LEFT;
107 }
108 }
109
110 if (button == MouseEvent::BUTTON_MIDDLE) {
111 input.mi.dwFlags = down ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP;
112 } else if (button == MouseEvent::BUTTON_RIGHT) {
113 input.mi.dwFlags = down ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP;
114 } else {
115 input.mi.dwFlags = down ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP;
116 }
117
118 output->push_back(std::move(input));
119 }
120 }
121
122 // Parse wheel related operations from the input MouseEvent, and insert the
123 // result into output.
124 void ParseMouseWheelEvent(const MouseEvent& event, std::vector<INPUT>* output) {
125 if (event.has_wheel_delta_x()) {
126 int delta = static_cast<int>(event.wheel_delta_x());
127 if (delta != 0) {
128 INPUT input = {0};
129 input.type = INPUT_MOUSE;
130 input.mi.mouseData = delta;
131 // According to MSDN, MOUSEEVENTF_HWHELL and MOUSEEVENTF_WHEEL are both
132 // required for a horizontal wheel event.
133 input.mi.dwFlags = MOUSEEVENTF_HWHEEL | MOUSEEVENTF_WHEEL;
134 output->push_back(std::move(input));
135 }
136 }
137
138 if (event.has_wheel_delta_y()) {
139 int delta = static_cast<int>(event.wheel_delta_y());
140 if (delta != 0) {
141 INPUT input = {0};
142 input.type = INPUT_MOUSE;
143 input.mi.mouseData = delta;
144 input.mi.dwFlags = MOUSEEVENTF_WHEEL;
145 output->push_back(std::move(input));
146 }
147 }
148 }
60 149
61 // A class to generate events on Windows. 150 // A class to generate events on Windows.
62 class InputInjectorWin : public InputInjector { 151 class InputInjectorWin : public InputInjector {
63 public: 152 public:
64 InputInjectorWin(scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 153 InputInjectorWin(scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
65 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner); 154 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
66 ~InputInjectorWin() override; 155 ~InputInjectorWin() override;
67 156
68 // ClipboardStub interface. 157 // ClipboardStub interface.
69 void InjectClipboardEvent(const ClipboardEvent& event) override; 158 void InjectClipboardEvent(const ClipboardEvent& event) override;
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 it != text.end(); ++it) { 358 it != text.end(); ++it) {
270 SendKeyboardInput(KEYEVENTF_UNICODE, *it); 359 SendKeyboardInput(KEYEVENTF_UNICODE, *it);
271 SendKeyboardInput(KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, *it); 360 SendKeyboardInput(KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, *it);
272 } 361 }
273 } 362 }
274 363
275 void InputInjectorWin::Core::HandleMouse(const MouseEvent& event) { 364 void InputInjectorWin::Core::HandleMouse(const MouseEvent& event) {
276 // Reset the system idle suspend timeout. 365 // Reset the system idle suspend timeout.
277 SetThreadExecutionState(ES_SYSTEM_REQUIRED); 366 SetThreadExecutionState(ES_SYSTEM_REQUIRED);
278 367
279 INPUT input; 368 std::vector<INPUT> inputs;
280 memset(&input, 0, sizeof(input)); 369 ParseMouseMoveEvent(event, &inputs);
281 input.type = INPUT_MOUSE; 370 ParseMouseClickEvent(event, &inputs);
371 ParseMouseWheelEvent(event, &inputs);
282 372
283 if (event.has_delta_x() && event.has_delta_y()) { 373 if (!inputs.empty()) {
284 input.mi.dx = event.delta_x(); 374 if (SendInput(inputs.size(), inputs.data(), sizeof(INPUT)) != inputs.size())
285 input.mi.dy = event.delta_y();
286 input.mi.dwFlags |= MOUSEEVENTF_MOVE | MOUSEEVENTF_VIRTUALDESK;
287 } else if (event.has_x() && event.has_y()) {
288 int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
289 int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
290 if (width > 1 && height > 1) {
291 int x = std::max(0, std::min(width, event.x()));
292 int y = std::max(0, std::min(height, event.y()));
293 input.mi.dx = static_cast<int>((x * 65535) / (width - 1));
294 input.mi.dy = static_cast<int>((y * 65535) / (height - 1));
295 input.mi.dwFlags |=
296 MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK;
297 }
298 }
299
300 int wheel_delta_x = 0;
301 int wheel_delta_y = 0;
302 if (event.has_wheel_delta_x() && event.has_wheel_delta_y()) {
303 wheel_delta_x = static_cast<int>(event.wheel_delta_x());
304 wheel_delta_y = static_cast<int>(event.wheel_delta_y());
305 }
306
307 if (wheel_delta_x != 0 || wheel_delta_y != 0) {
308 if (wheel_delta_x != 0) {
309 input.mi.mouseData = wheel_delta_x;
310 input.mi.dwFlags |= MOUSEEVENTF_HWHEEL;
311 }
312 if (wheel_delta_y != 0) {
313 input.mi.mouseData = wheel_delta_y;
314 input.mi.dwFlags |= MOUSEEVENTF_WHEEL;
315 }
316 }
317
318 if (event.has_button() && event.has_button_down()) {
319 MouseEvent::MouseButton button = event.button();
320 bool down = event.button_down();
321
322 // If the host is configured to swap left & right buttons, inject swapped
323 // events to un-do that re-mapping.
324 if (GetSystemMetrics(SM_SWAPBUTTON)) {
325 if (button == MouseEvent::BUTTON_LEFT) {
326 button = MouseEvent::BUTTON_RIGHT;
327 } else if (button == MouseEvent::BUTTON_RIGHT) {
328 button = MouseEvent::BUTTON_LEFT;
329 }
330 }
331
332 if (button == MouseEvent::BUTTON_LEFT) {
333 input.mi.dwFlags |= down ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP;
334 } else if (button == MouseEvent::BUTTON_MIDDLE) {
335 input.mi.dwFlags |= down ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP;
336 } else if (button == MouseEvent::BUTTON_RIGHT) {
337 input.mi.dwFlags |= down ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP;
338 } else {
339 input.mi.dwFlags |= down ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP;
340 }
341 }
342
343 if (input.mi.dwFlags) {
344 if (SendInput(1, &input, sizeof(INPUT)) == 0)
345 PLOG(ERROR) << "Failed to inject a mouse event"; 375 PLOG(ERROR) << "Failed to inject a mouse event";
346 } 376 }
347 } 377 }
348 378
349 void InputInjectorWin::Core::HandleTouch(const TouchEvent& event) { 379 void InputInjectorWin::Core::HandleTouch(const TouchEvent& event) {
350 touch_injector_.InjectTouchEvent(event); 380 touch_injector_.InjectTouchEvent(event);
351 } 381 }
352 382
353 } // namespace 383 } // namespace
354 384
355 // static 385 // static
356 scoped_ptr<InputInjector> InputInjector::Create( 386 scoped_ptr<InputInjector> InputInjector::Create(
357 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 387 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
358 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { 388 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
359 return make_scoped_ptr( 389 return make_scoped_ptr(
360 new InputInjectorWin(main_task_runner, ui_task_runner)); 390 new InputInjectorWin(main_task_runner, ui_task_runner));
361 } 391 }
362 392
363 // static 393 // static
364 bool InputInjector::SupportsTouchEvents() { 394 bool InputInjector::SupportsTouchEvents() {
365 return TouchInjectorWinDelegate::Create() != nullptr; 395 return TouchInjectorWinDelegate::Create() != nullptr;
366 } 396 }
367 397
368 } // namespace remoting 398 } // namespace remoting
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698