OLD | NEW |
| (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 | |
OLD | NEW |