• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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