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 // From the HID Usage Tables specification.
23 const USHORT kGenericDesktopPage
= 1;
24 const USHORT kMouseUsage
= 2;
26 class LocalInputMonitorWin
: public base::NonThreadSafe
,
27 public LocalInputMonitor
{
30 scoped_refptr
<base::SingleThreadTaskRunner
> caller_task_runner
,
31 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner
,
32 base::WeakPtr
<ClientSessionControl
> client_session_control
);
33 ~LocalInputMonitorWin() override
;
36 // The actual implementation resides in LocalInputMonitorWin::Core class.
37 class Core
: public base::RefCountedThreadSafe
<Core
> {
39 Core(scoped_refptr
<base::SingleThreadTaskRunner
> caller_task_runner
,
40 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner
,
41 base::WeakPtr
<ClientSessionControl
> client_session_control
);
47 friend class base::RefCountedThreadSafe
<Core
>;
50 void StartOnUiThread();
51 void StopOnUiThread();
53 // Handles WM_INPUT messages.
54 LRESULT
OnInput(HRAWINPUT input_handle
);
56 // Handles messages received by |window_|.
57 bool HandleMessage(UINT message
,
62 // Task runner on which public methods of this class must be called.
63 scoped_refptr
<base::SingleThreadTaskRunner
> caller_task_runner_
;
65 // Task runner on which |window_| is created.
66 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner_
;
68 // Used to receive raw input.
69 scoped_ptr
<base::win::MessageWindow
> window_
;
71 // Points to the object receiving mouse event notifications.
72 base::WeakPtr
<ClientSessionControl
> client_session_control_
;
74 DISALLOW_COPY_AND_ASSIGN(Core
);
77 scoped_refptr
<Core
> core_
;
79 DISALLOW_COPY_AND_ASSIGN(LocalInputMonitorWin
);
82 LocalInputMonitorWin::LocalInputMonitorWin(
83 scoped_refptr
<base::SingleThreadTaskRunner
> caller_task_runner
,
84 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner
,
85 base::WeakPtr
<ClientSessionControl
> client_session_control
)
86 : core_(new Core(caller_task_runner
,
88 client_session_control
)) {
92 LocalInputMonitorWin::~LocalInputMonitorWin() {
96 LocalInputMonitorWin::Core::Core(
97 scoped_refptr
<base::SingleThreadTaskRunner
> caller_task_runner
,
98 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner
,
99 base::WeakPtr
<ClientSessionControl
> client_session_control
)
100 : caller_task_runner_(caller_task_runner
),
101 ui_task_runner_(ui_task_runner
),
102 client_session_control_(client_session_control
) {
103 DCHECK(client_session_control_
);
106 void LocalInputMonitorWin::Core::Start() {
107 DCHECK(caller_task_runner_
->BelongsToCurrentThread());
109 ui_task_runner_
->PostTask(FROM_HERE
,
110 base::Bind(&Core::StartOnUiThread
, this));
113 void LocalInputMonitorWin::Core::Stop() {
114 DCHECK(caller_task_runner_
->BelongsToCurrentThread());
116 ui_task_runner_
->PostTask(FROM_HERE
, base::Bind(&Core::StopOnUiThread
, this));
119 LocalInputMonitorWin::Core::~Core() {
123 void LocalInputMonitorWin::Core::StartOnUiThread() {
124 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
126 window_
.reset(new base::win::MessageWindow());
127 if (!window_
->Create(base::Bind(&Core::HandleMessage
,
128 base::Unretained(this)))) {
129 PLOG(ERROR
) << "Failed to create the raw input window";
132 // If the local input cannot be monitored, the remote user can take over
133 // the session. Disconnect the session now to prevent this.
134 caller_task_runner_
->PostTask(
135 FROM_HERE
, base::Bind(&ClientSessionControl::DisconnectSession
,
136 client_session_control_
));
140 void LocalInputMonitorWin::Core::StopOnUiThread() {
141 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
143 // Stop receiving raw mouse input.
145 RAWINPUTDEVICE device
= {0};
146 device
.dwFlags
= RIDEV_REMOVE
;
147 device
.usUsagePage
= kGenericDesktopPage
;
148 device
.usUsage
= kMouseUsage
;
149 device
.hwndTarget
= nullptr;
151 // The error is harmless, ignore it.
152 RegisterRawInputDevices(&device
, 1, sizeof(device
));
158 LRESULT
LocalInputMonitorWin::Core::OnInput(HRAWINPUT input_handle
) {
159 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
161 // Get the size of the input record.
163 UINT result
= GetRawInputData(input_handle
,
167 sizeof(RAWINPUTHEADER
));
169 PLOG(ERROR
) << "GetRawInputData() failed";
173 // Retrieve the input record itself.
174 scoped_ptr
<uint8
[]> buffer(new uint8
[size
]);
175 RAWINPUT
* input
= reinterpret_cast<RAWINPUT
*>(buffer
.get());
176 result
= GetRawInputData(input_handle
,
180 sizeof(RAWINPUTHEADER
));
182 PLOG(ERROR
) << "GetRawInputData() failed";
186 // Notify the observer about mouse events generated locally. Remote (injected)
187 // mouse events do not specify a device handle (based on observed behavior).
188 if (input
->header
.dwType
== RIM_TYPEMOUSE
&&
189 input
->header
.hDevice
!= nullptr) {
191 if (!GetCursorPos(&position
)) {
196 caller_task_runner_
->PostTask(
197 FROM_HERE
, base::Bind(&ClientSessionControl::OnLocalMouseMoved
,
198 client_session_control_
,
199 webrtc::DesktopVector(position
.x
, position
.y
)));
202 return DefRawInputProc(&input
, 1, sizeof(RAWINPUTHEADER
));
205 bool LocalInputMonitorWin::Core::HandleMessage(
206 UINT message
, WPARAM wparam
, LPARAM lparam
, LRESULT
* result
) {
209 // Register to receive raw mouse input.
210 RAWINPUTDEVICE device
= {0};
211 device
.dwFlags
= RIDEV_INPUTSINK
;
212 device
.usUsagePage
= kGenericDesktopPage
;
213 device
.usUsage
= kMouseUsage
;
214 device
.hwndTarget
= window_
->hwnd();
215 if (RegisterRawInputDevices(&device
, 1, sizeof(device
))) {
218 PLOG(ERROR
) << "RegisterRawInputDevices() failed";
225 *result
= OnInput(reinterpret_cast<HRAWINPUT
>(lparam
));
235 scoped_ptr
<LocalInputMonitor
> LocalInputMonitor::Create(
236 scoped_refptr
<base::SingleThreadTaskRunner
> caller_task_runner
,
237 scoped_refptr
<base::SingleThreadTaskRunner
> input_task_runner
,
238 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner
,
239 base::WeakPtr
<ClientSessionControl
> client_session_control
) {
240 return make_scoped_ptr(new LocalInputMonitorWin(
241 caller_task_runner
, ui_task_runner
, client_session_control
));
244 } // namespace remoting