| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "remoting/host/input_monitor/local_pointer_input_monitor.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/location.h" |
| #include "base/single_thread_task_runner.h" |
| #include "remoting/host/input_monitor/local_input_monitor_win.h" |
| #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" |
| #include "ui/events/event.h" |
| |
| namespace remoting { |
| |
| namespace { |
| |
| // From the HID Usage Tables specification. |
| const USHORT kGenericDesktopPage = 1; |
| const USHORT kMouseUsage = 2; |
| |
| class MouseRawInputHandlerWin : public LocalInputMonitorWin::RawInputHandler { |
| public: |
| MouseRawInputHandlerWin( |
| scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, |
| scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, |
| LocalInputMonitor::PointerMoveCallback on_mouse_move, |
| base::OnceClosure disconnect_callback); |
| ~MouseRawInputHandlerWin() override; |
| |
| // LocalInputMonitorWin::RawInputHandler implementation. |
| bool Register(HWND hwnd) override; |
| void Unregister() override; |
| void OnInputEvent(const RAWINPUT* input) override; |
| void OnError() override; |
| |
| scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_; |
| scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; |
| |
| LocalInputMonitor::PointerMoveCallback on_mouse_move_; |
| base::OnceClosure disconnect_callback_; |
| |
| webrtc::DesktopVector mouse_position_; |
| |
| // Tracks whether the instance is registered to receive raw input events. |
| bool registered_ = false; |
| |
| DISALLOW_COPY_AND_ASSIGN(MouseRawInputHandlerWin); |
| }; |
| |
| MouseRawInputHandlerWin::MouseRawInputHandlerWin( |
| scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, |
| scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, |
| LocalInputMonitor::PointerMoveCallback on_mouse_move, |
| base::OnceClosure disconnect_callback) |
| : caller_task_runner_(caller_task_runner), |
| ui_task_runner_(ui_task_runner), |
| on_mouse_move_(std::move(on_mouse_move)), |
| disconnect_callback_(std::move(disconnect_callback)) {} |
| |
| MouseRawInputHandlerWin::~MouseRawInputHandlerWin() { |
| DCHECK(!registered_); |
| } |
| |
| bool MouseRawInputHandlerWin::Register(HWND hwnd) { |
| DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| |
| // Register to receive raw keyboard input. |
| RAWINPUTDEVICE device = {0}; |
| device.dwFlags = RIDEV_INPUTSINK; |
| device.usUsagePage = kGenericDesktopPage; |
| device.usUsage = kMouseUsage; |
| device.hwndTarget = hwnd; |
| if (!RegisterRawInputDevices(&device, 1, sizeof(device))) { |
| PLOG(ERROR) << "RegisterRawInputDevices() failed"; |
| return false; |
| } |
| |
| registered_ = true; |
| return true; |
| } |
| |
| void MouseRawInputHandlerWin::Unregister() { |
| DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| |
| RAWINPUTDEVICE device = {0}; |
| device.dwFlags = RIDEV_REMOVE; |
| device.usUsagePage = kGenericDesktopPage; |
| device.usUsage = kMouseUsage; |
| device.hwndTarget = nullptr; |
| |
| // The error is harmless, ignore it. |
| RegisterRawInputDevices(&device, 1, sizeof(device)); |
| registered_ = false; |
| } |
| |
| void MouseRawInputHandlerWin::OnInputEvent(const RAWINPUT* input) { |
| DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| |
| // Notify the observer about mouse events generated locally. Remote (injected) |
| // mouse events do not specify a device handle (based on observed behavior). |
| if (input->header.dwType != RIM_TYPEMOUSE || |
| input->header.hDevice == nullptr) { |
| return; |
| } |
| |
| POINT position; |
| if (!GetCursorPos(&position)) { |
| position.x = 0; |
| position.y = 0; |
| } |
| webrtc::DesktopVector new_position(position.x, position.y); |
| |
| // Ignore the event if the cursor position or button states have not changed. |
| // Note: If GetCursorPos fails above, we err on the safe side and treat it |
| // like a movement. |
| if (mouse_position_.equals(new_position) && |
| !input->data.mouse.usButtonFlags && !new_position.is_zero()) { |
| return; |
| } |
| |
| mouse_position_ = new_position; |
| |
| caller_task_runner_->PostTask( |
| FROM_HERE, base::BindOnce(on_mouse_move_, std::move(new_position), |
| ui::ET_MOUSE_MOVED)); |
| } |
| |
| void MouseRawInputHandlerWin::OnError() { |
| DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| |
| if (disconnect_callback_) { |
| caller_task_runner_->PostTask(FROM_HERE, std::move(disconnect_callback_)); |
| } |
| } |
| |
| // Note that this class does not detect touch input and so is named accordingly. |
| class LocalMouseInputMonitorWin : public LocalPointerInputMonitor { |
| public: |
| explicit LocalMouseInputMonitorWin( |
| std::unique_ptr<LocalInputMonitorWin> local_input_monitor); |
| ~LocalMouseInputMonitorWin() override; |
| |
| private: |
| std::unique_ptr<LocalInputMonitorWin> local_input_monitor_; |
| }; |
| |
| LocalMouseInputMonitorWin::LocalMouseInputMonitorWin( |
| std::unique_ptr<LocalInputMonitorWin> local_input_monitor) |
| : local_input_monitor_(std::move(local_input_monitor)) {} |
| |
| LocalMouseInputMonitorWin::~LocalMouseInputMonitorWin() = default; |
| |
| } // namespace |
| |
| std::unique_ptr<LocalPointerInputMonitor> LocalPointerInputMonitor::Create( |
| scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, |
| scoped_refptr<base::SingleThreadTaskRunner> input_task_runner, |
| scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, |
| LocalInputMonitor::PointerMoveCallback on_mouse_move, |
| base::OnceClosure disconnect_callback) { |
| auto raw_input_handler = std::make_unique<MouseRawInputHandlerWin>( |
| caller_task_runner, ui_task_runner, std::move(on_mouse_move), |
| std::move(disconnect_callback)); |
| |
| return std::make_unique<LocalMouseInputMonitorWin>( |
| LocalInputMonitorWin::Create(caller_task_runner, ui_task_runner, |
| std::move(raw_input_handler))); |
| } |
| |
| } // namespace remoting |