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