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

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

Issue 12760012: Rename EventExecutor to InputInjector. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Replace some missed occurrences and remove unused include. Created 7 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « remoting/host/event_executor_mac.cc ('k') | remoting/host/host_mock_objects.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/event_executor.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 EventExecutorWin : public EventExecutor {
36 public:
37 EventExecutorWin(scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
38 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
39 virtual ~EventExecutorWin();
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 // EventExecutor interface.
49 virtual void Start(
50 scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE;
51
52 private:
53 // The actual implementation resides in EventExecutorWin::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 EventExecutor 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(EventExecutorWin);
88 };
89
90 EventExecutorWin::EventExecutorWin(
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 EventExecutorWin::~EventExecutorWin() {
97 core_->Stop();
98 }
99
100 void EventExecutorWin::InjectClipboardEvent(const ClipboardEvent& event) {
101 core_->InjectClipboardEvent(event);
102 }
103
104 void EventExecutorWin::InjectKeyEvent(const KeyEvent& event) {
105 core_->InjectKeyEvent(event);
106 }
107
108 void EventExecutorWin::InjectMouseEvent(const MouseEvent& event) {
109 core_->InjectMouseEvent(event);
110 }
111
112 void EventExecutorWin::Start(
113 scoped_ptr<protocol::ClipboardStub> client_clipboard) {
114 core_->Start(client_clipboard.Pass());
115 }
116
117 EventExecutorWin::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 EventExecutorWin::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 EventExecutorWin::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 EventExecutorWin::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 EventExecutorWin::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 EventExecutorWin::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 EventExecutorWin::Core::~Core() {
178 }
179
180 void EventExecutorWin::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 EventExecutorWin::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<EventExecutor> EventExecutor::Create(
313 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
314 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
315 return scoped_ptr<EventExecutor>(
316 new EventExecutorWin(main_task_runner, ui_task_runner));
317 }
318
319 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/event_executor_mac.cc ('k') | remoting/host/host_mock_objects.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698