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/local_input_monitor.h"
6
7 #include "base/bind.h"
8 #include "base/compiler_specific.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/threading/non_thread_safe.h"
14 #include "base/win/message_window.h"
15 #include "remoting/host/client_session_control.h"
16 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
17
18 namespace remoting {
19
20 namespace {
21
22 const wchar_t kWindowClassFormat[] = L"Chromoting_LocalInputMonitorWin_%p";
23
24 // From the HID Usage Tables specification.
25 const USHORT kGenericDesktopPage = 1;
26 const USHORT kMouseUsage = 2;
27
28 class LocalInputMonitorWin : public base::NonThreadSafe,
29 public LocalInputMonitor {
30 public:
31 LocalInputMonitorWin(
32 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
33 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
34 base::WeakPtr<ClientSessionControl> client_session_control);
35 ~LocalInputMonitorWin();
36
37 private:
38 // The actual implementation resides in LocalInputMonitorWin::Core class.
39 class Core : public base::RefCountedThreadSafe<Core> {
40 public:
41 Core(scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
42 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
43 base::WeakPtr<ClientSessionControl> client_session_control);
44
45 void Start();
46 void Stop();
47
48 private:
49 friend class base::RefCountedThreadSafe<Core>;
50 virtual ~Core();
51
52 void StartOnUiThread();
53 void StopOnUiThread();
54
55 // Handles WM_INPUT messages.
56 LRESULT OnInput(HRAWINPUT input_handle);
57
58 // Handles messages received by |window_|.
59 bool HandleMessage(UINT message,
60 WPARAM wparam,
61 LPARAM lparam,
62 LRESULT* result);
63
64 // Task runner on which public methods of this class must be called.
65 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
66
67 // Task runner on which |window_| is created.
68 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
69
70 // Used to receive raw input.
71 scoped_ptr<base::win::MessageWindow> window_;
72
73 // Points to the object receiving mouse event notifications.
74 base::WeakPtr<ClientSessionControl> client_session_control_;
75
76 DISALLOW_COPY_AND_ASSIGN(Core);
77 };
78
79 scoped_refptr<Core> core_;
80
81 DISALLOW_COPY_AND_ASSIGN(LocalInputMonitorWin);
82 };
83
LocalInputMonitorWin(scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,base::WeakPtr<ClientSessionControl> client_session_control)84 LocalInputMonitorWin::LocalInputMonitorWin(
85 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
86 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
87 base::WeakPtr<ClientSessionControl> client_session_control)
88 : core_(new Core(caller_task_runner,
89 ui_task_runner,
90 client_session_control)) {
91 core_->Start();
92 }
93
~LocalInputMonitorWin()94 LocalInputMonitorWin::~LocalInputMonitorWin() {
95 core_->Stop();
96 }
97
Core(scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,base::WeakPtr<ClientSessionControl> client_session_control)98 LocalInputMonitorWin::Core::Core(
99 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
100 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
101 base::WeakPtr<ClientSessionControl> client_session_control)
102 : caller_task_runner_(caller_task_runner),
103 ui_task_runner_(ui_task_runner),
104 client_session_control_(client_session_control) {
105 DCHECK(client_session_control_);
106 }
107
Start()108 void LocalInputMonitorWin::Core::Start() {
109 DCHECK(caller_task_runner_->BelongsToCurrentThread());
110
111 ui_task_runner_->PostTask(FROM_HERE,
112 base::Bind(&Core::StartOnUiThread, this));
113 }
114
Stop()115 void LocalInputMonitorWin::Core::Stop() {
116 DCHECK(caller_task_runner_->BelongsToCurrentThread());
117
118 ui_task_runner_->PostTask(FROM_HERE, base::Bind(&Core::StopOnUiThread, this));
119 }
120
~Core()121 LocalInputMonitorWin::Core::~Core() {
122 DCHECK(!window_);
123 }
124
StartOnUiThread()125 void LocalInputMonitorWin::Core::StartOnUiThread() {
126 DCHECK(ui_task_runner_->BelongsToCurrentThread());
127
128 window_.reset(new base::win::MessageWindow());
129 if (!window_->Create(base::Bind(&Core::HandleMessage,
130 base::Unretained(this)))) {
131 PLOG(ERROR) << "Failed to create the raw input window";
132 window_.reset();
133
134 // If the local input cannot be monitored, the remote user can take over
135 // the session. Disconnect the session now to prevent this.
136 caller_task_runner_->PostTask(
137 FROM_HERE, base::Bind(&ClientSessionControl::DisconnectSession,
138 client_session_control_));
139 }
140 }
141
StopOnUiThread()142 void LocalInputMonitorWin::Core::StopOnUiThread() {
143 DCHECK(ui_task_runner_->BelongsToCurrentThread());
144
145 // Stop receiving raw mouse input.
146 if (window_) {
147 RAWINPUTDEVICE device = {0};
148 device.dwFlags = RIDEV_REMOVE;
149 device.usUsagePage = kGenericDesktopPage;
150 device.usUsage = kMouseUsage;
151 device.hwndTarget = NULL;
152
153 // The error is harmless, ignore it.
154 RegisterRawInputDevices(&device, 1, sizeof(device));
155 }
156
157 window_.reset();
158 }
159
OnInput(HRAWINPUT input_handle)160 LRESULT LocalInputMonitorWin::Core::OnInput(HRAWINPUT input_handle) {
161 DCHECK(ui_task_runner_->BelongsToCurrentThread());
162
163 // Get the size of the input record.
164 UINT size = 0;
165 UINT result = GetRawInputData(input_handle,
166 RID_INPUT,
167 NULL,
168 &size,
169 sizeof(RAWINPUTHEADER));
170 if (result == -1) {
171 PLOG(ERROR) << "GetRawInputData() failed";
172 return 0;
173 }
174
175 // Retrieve the input record itself.
176 scoped_ptr<uint8[]> buffer(new uint8[size]);
177 RAWINPUT* input = reinterpret_cast<RAWINPUT*>(buffer.get());
178 result = GetRawInputData(input_handle,
179 RID_INPUT,
180 buffer.get(),
181 &size,
182 sizeof(RAWINPUTHEADER));
183 if (result == -1) {
184 PLOG(ERROR) << "GetRawInputData() failed";
185 return 0;
186 }
187
188 // Notify the observer about mouse events generated locally. Remote (injected)
189 // mouse events do not specify a device handle (based on observed behavior).
190 if (input->header.dwType == RIM_TYPEMOUSE &&
191 input->header.hDevice != NULL) {
192 POINT position;
193 if (!GetCursorPos(&position)) {
194 position.x = 0;
195 position.y = 0;
196 }
197
198 caller_task_runner_->PostTask(
199 FROM_HERE, base::Bind(&ClientSessionControl::OnLocalMouseMoved,
200 client_session_control_,
201 webrtc::DesktopVector(position.x, position.y)));
202 }
203
204 return DefRawInputProc(&input, 1, sizeof(RAWINPUTHEADER));
205 }
206
HandleMessage(UINT message,WPARAM wparam,LPARAM lparam,LRESULT * result)207 bool LocalInputMonitorWin::Core::HandleMessage(
208 UINT message, WPARAM wparam, LPARAM lparam, LRESULT* result) {
209 switch (message) {
210 case WM_CREATE: {
211 // Register to receive raw mouse input.
212 RAWINPUTDEVICE device = {0};
213 device.dwFlags = RIDEV_INPUTSINK;
214 device.usUsagePage = kGenericDesktopPage;
215 device.usUsage = kMouseUsage;
216 device.hwndTarget = window_->hwnd();
217 if (RegisterRawInputDevices(&device, 1, sizeof(device))) {
218 *result = 0;
219 } else {
220 PLOG(ERROR) << "RegisterRawInputDevices() failed";
221 *result = -1;
222 }
223 return true;
224 }
225
226 case WM_INPUT:
227 *result = OnInput(reinterpret_cast<HRAWINPUT>(lparam));
228 return true;
229
230 default:
231 return false;
232 }
233 }
234
235 } // namespace
236
Create(scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,base::WeakPtr<ClientSessionControl> client_session_control)237 scoped_ptr<LocalInputMonitor> LocalInputMonitor::Create(
238 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
239 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
240 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
241 base::WeakPtr<ClientSessionControl> client_session_control) {
242 return scoped_ptr<LocalInputMonitor>(
243 new LocalInputMonitorWin(caller_task_runner,
244 ui_task_runner,
245 client_session_control));
246 }
247
248 } // namespace remoting
249