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.
5 #include "remoting/host/local_input_monitor.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"
22 const wchar_t kWindowClassFormat
[] = L
"Chromoting_LocalInputMonitorWin_%p";
24 // From the HID Usage Tables specification.
25 const USHORT kGenericDesktopPage
= 1;
26 const USHORT kMouseUsage
= 2;
28 class LocalInputMonitorWin
: public base::NonThreadSafe
,
29 public LocalInputMonitor
{
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();
38 // The actual implementation resides in LocalInputMonitorWin::Core class.
39 class Core
: public base::RefCountedThreadSafe
<Core
> {
41 Core(scoped_refptr
<base::SingleThreadTaskRunner
> caller_task_runner
,
42 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner
,
43 base::WeakPtr
<ClientSessionControl
> client_session_control
);
49 friend class base::RefCountedThreadSafe
<Core
>;
52 void StartOnUiThread();
53 void StopOnUiThread();
55 // Handles WM_INPUT messages.
56 LRESULT
OnInput(HRAWINPUT input_handle
);
58 // Handles messages received by |window_|.
59 bool HandleMessage(UINT message
,
64 // Task runner on which public methods of this class must be called.
65 scoped_refptr
<base::SingleThreadTaskRunner
> caller_task_runner_
;
67 // Task runner on which |window_| is created.
68 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner_
;
70 // Used to receive raw input.
71 scoped_ptr
<base::win::MessageWindow
> window_
;
73 // Points to the object receiving mouse event notifications.
74 base::WeakPtr
<ClientSessionControl
> client_session_control_
;
76 DISALLOW_COPY_AND_ASSIGN(Core
);
79 scoped_refptr
<Core
> core_
;
81 DISALLOW_COPY_AND_ASSIGN(LocalInputMonitorWin
);
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
,
90 client_session_control
)) {
94 LocalInputMonitorWin::~LocalInputMonitorWin() {
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_
);
108 void LocalInputMonitorWin::Core::Start() {
109 DCHECK(caller_task_runner_
->BelongsToCurrentThread());
111 ui_task_runner_
->PostTask(FROM_HERE
,
112 base::Bind(&Core::StartOnUiThread
, this));
115 void LocalInputMonitorWin::Core::Stop() {
116 DCHECK(caller_task_runner_
->BelongsToCurrentThread());
118 ui_task_runner_
->PostTask(FROM_HERE
, base::Bind(&Core::StopOnUiThread
, this));
121 LocalInputMonitorWin::Core::~Core() {
125 void LocalInputMonitorWin::Core::StartOnUiThread() {
126 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
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";
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_
));
142 void LocalInputMonitorWin::Core::StopOnUiThread() {
143 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
145 // Stop receiving raw mouse input.
147 RAWINPUTDEVICE device
= {0};
148 device
.dwFlags
= RIDEV_REMOVE
;
149 device
.usUsagePage
= kGenericDesktopPage
;
150 device
.usUsage
= kMouseUsage
;
151 device
.hwndTarget
= nullptr;
153 // The error is harmless, ignore it.
154 RegisterRawInputDevices(&device
, 1, sizeof(device
));
160 LRESULT
LocalInputMonitorWin::Core::OnInput(HRAWINPUT input_handle
) {
161 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
163 // Get the size of the input record.
165 UINT result
= GetRawInputData(input_handle
,
169 sizeof(RAWINPUTHEADER
));
171 PLOG(ERROR
) << "GetRawInputData() failed";
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
,
182 sizeof(RAWINPUTHEADER
));
184 PLOG(ERROR
) << "GetRawInputData() failed";
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
!= nullptr) {
193 if (!GetCursorPos(&position
)) {
198 caller_task_runner_
->PostTask(
199 FROM_HERE
, base::Bind(&ClientSessionControl::OnLocalMouseMoved
,
200 client_session_control_
,
201 webrtc::DesktopVector(position
.x
, position
.y
)));
204 return DefRawInputProc(&input
, 1, sizeof(RAWINPUTHEADER
));
207 bool LocalInputMonitorWin::Core::HandleMessage(
208 UINT message
, WPARAM wparam
, LPARAM lparam
, LRESULT
* result
) {
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
))) {
220 PLOG(ERROR
) << "RegisterRawInputDevices() failed";
227 *result
= OnInput(reinterpret_cast<HRAWINPUT
>(lparam
));
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 make_scoped_ptr(new LocalInputMonitorWin(
243 caller_task_runner
, ui_task_runner
, client_session_control
));
246 } // namespace remoting