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 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 94 LocalInputMonitorWin::~LocalInputMonitorWin() { 95 core_->Stop(); 96 } 97 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 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 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 121 LocalInputMonitorWin::Core::~Core() { 122 DCHECK(!window_); 123 } 124 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 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 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 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 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