Roll src/third_party/WebKit f36d5e0:68b67cd (svn 193299:193303)
[chromium-blink-merge.git] / remoting / host / local_input_monitor_win.cc
blob969c5a9760dbdb2d93a211c50fcd73c19de0a977
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"
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"
18 namespace remoting {
20 namespace {
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 {
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();
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);
45 void Start();
46 void Stop();
48 private:
49 friend class base::RefCountedThreadSafe<Core>;
50 virtual ~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,
60 WPARAM wparam,
61 LPARAM lparam,
62 LRESULT* result);
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,
89 ui_task_runner,
90 client_session_control)) {
91 core_->Start();
94 LocalInputMonitorWin::~LocalInputMonitorWin() {
95 core_->Stop();
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() {
122 DCHECK(!window_);
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";
132 window_.reset();
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.
146 if (window_) {
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));
157 window_.reset();
160 LRESULT LocalInputMonitorWin::Core::OnInput(HRAWINPUT input_handle) {
161 DCHECK(ui_task_runner_->BelongsToCurrentThread());
163 // Get the size of the input record.
164 UINT size = 0;
165 UINT result = GetRawInputData(input_handle,
166 RID_INPUT,
167 nullptr,
168 &size,
169 sizeof(RAWINPUTHEADER));
170 if (result == -1) {
171 PLOG(ERROR) << "GetRawInputData() failed";
172 return 0;
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;
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) {
192 POINT position;
193 if (!GetCursorPos(&position)) {
194 position.x = 0;
195 position.y = 0;
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) {
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;
223 return true;
226 case WM_INPUT:
227 *result = OnInput(reinterpret_cast<HRAWINPUT>(lparam));
228 return true;
230 default:
231 return false;
235 } // namespace
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