1 // Copyright 2013 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 "media/base/user_input_monitor.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/synchronization/lock.h"
14 #include "base/win/message_window.h"
15 #include "media/base/keyboard_event_counter.h"
16 #include "third_party/skia/include/core/SkPoint.h"
17 #include "ui/events/keycodes/keyboard_code_conversion_win.h"
22 // From the HID Usage Tables specification.
23 const USHORT kGenericDesktopPage
= 1;
24 const USHORT kMouseUsage
= 2;
25 const USHORT kKeyboardUsage
= 6;
27 // This is the actual implementation of event monitoring. It's separated from
28 // UserInputMonitorWin since it needs to be deleted on the UI thread.
29 class UserInputMonitorWinCore
30 : public base::SupportsWeakPtr
<UserInputMonitorWinCore
>,
31 public base::MessageLoop::DestructionObserver
{
35 KEYBOARD_EVENT_MASK
= 2,
38 explicit UserInputMonitorWinCore(
39 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner
,
40 const scoped_refptr
<UserInputMonitor::MouseListenerList
>&
42 ~UserInputMonitorWinCore();
44 // DestructionObserver overrides.
45 virtual void WillDestroyCurrentMessageLoop() override
;
47 size_t GetKeyPressCount() const;
48 void StartMonitor(EventBitMask type
);
49 void StopMonitor(EventBitMask type
);
52 // Handles WM_INPUT messages.
53 LRESULT
OnInput(HRAWINPUT input_handle
);
54 // Handles messages received by |window_|.
55 bool HandleMessage(UINT message
,
59 RAWINPUTDEVICE
* GetRawInputDevices(EventBitMask event
, DWORD flags
);
61 // Task runner on which |window_| is created.
62 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner_
;
63 scoped_refptr
<ObserverListThreadSafe
<UserInputMonitor::MouseEventListener
> >
66 // These members are only accessed on the UI thread.
67 scoped_ptr
<base::win::MessageWindow
> window_
;
68 uint8 events_monitored_
;
69 KeyboardEventCounter counter_
;
71 DISALLOW_COPY_AND_ASSIGN(UserInputMonitorWinCore
);
74 class UserInputMonitorWin
: public UserInputMonitor
{
76 explicit UserInputMonitorWin(
77 const scoped_refptr
<base::SingleThreadTaskRunner
>& ui_task_runner
);
78 virtual ~UserInputMonitorWin();
80 // Public UserInputMonitor overrides.
81 virtual size_t GetKeyPressCount() const override
;
84 // Private UserInputMonitor overrides.
85 virtual void StartKeyboardMonitoring() override
;
86 virtual void StopKeyboardMonitoring() override
;
87 virtual void StartMouseMonitoring() override
;
88 virtual void StopMouseMonitoring() override
;
90 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner_
;
91 UserInputMonitorWinCore
* core_
;
93 DISALLOW_COPY_AND_ASSIGN(UserInputMonitorWin
);
96 UserInputMonitorWinCore::UserInputMonitorWinCore(
97 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner
,
98 const scoped_refptr
<UserInputMonitor::MouseListenerList
>& mouse_listeners
)
99 : ui_task_runner_(ui_task_runner
),
100 mouse_listeners_(mouse_listeners
),
101 events_monitored_(0) {}
103 UserInputMonitorWinCore::~UserInputMonitorWinCore() {
105 DCHECK(!events_monitored_
);
108 void UserInputMonitorWinCore::WillDestroyCurrentMessageLoop() {
109 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
110 StopMonitor(MOUSE_EVENT_MASK
);
111 StopMonitor(KEYBOARD_EVENT_MASK
);
114 size_t UserInputMonitorWinCore::GetKeyPressCount() const {
115 return counter_
.GetKeyPressCount();
118 void UserInputMonitorWinCore::StartMonitor(EventBitMask type
) {
119 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
121 if (events_monitored_
& type
)
124 if (type
== KEYBOARD_EVENT_MASK
)
128 window_
.reset(new base::win::MessageWindow());
129 if (!window_
->Create(base::Bind(&UserInputMonitorWinCore::HandleMessage
,
130 base::Unretained(this)))) {
131 PLOG(ERROR
) << "Failed to create the raw input window";
137 // Register to receive raw mouse and/or keyboard input.
138 scoped_ptr
<RAWINPUTDEVICE
> device(GetRawInputDevices(type
, RIDEV_INPUTSINK
));
139 if (!RegisterRawInputDevices(device
.get(), 1, sizeof(*device
))) {
140 PLOG(ERROR
) << "RegisterRawInputDevices() failed for RIDEV_INPUTSINK";
145 // Start observing message loop destruction if we start monitoring the first
147 if (!events_monitored_
)
148 base::MessageLoop::current()->AddDestructionObserver(this);
150 events_monitored_
|= type
;
153 void UserInputMonitorWinCore::StopMonitor(EventBitMask type
) {
154 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
156 if (!(events_monitored_
& type
))
159 // Stop receiving raw input.
161 scoped_ptr
<RAWINPUTDEVICE
> device(GetRawInputDevices(type
, RIDEV_REMOVE
));
163 if (!RegisterRawInputDevices(device
.get(), 1, sizeof(*device
))) {
164 PLOG(INFO
) << "RegisterRawInputDevices() failed for RIDEV_REMOVE";
167 events_monitored_
&= ~type
;
168 if (events_monitored_
== 0) {
171 // Stop observing message loop destruction if no event is being monitored.
172 base::MessageLoop::current()->RemoveDestructionObserver(this);
176 LRESULT
UserInputMonitorWinCore::OnInput(HRAWINPUT input_handle
) {
177 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
179 // Get the size of the input record.
181 UINT result
= GetRawInputData(
182 input_handle
, RID_INPUT
, NULL
, &size
, sizeof(RAWINPUTHEADER
));
184 PLOG(ERROR
) << "GetRawInputData() failed";
187 DCHECK_EQ(0u, result
);
189 // Retrieve the input record itself.
190 scoped_ptr
<uint8
[]> buffer(new uint8
[size
]);
191 RAWINPUT
* input
= reinterpret_cast<RAWINPUT
*>(buffer
.get());
192 result
= GetRawInputData(
193 input_handle
, RID_INPUT
, buffer
.get(), &size
, sizeof(RAWINPUTHEADER
));
195 PLOG(ERROR
) << "GetRawInputData() failed";
198 DCHECK_EQ(size
, result
);
200 // Notify the observer about events generated locally.
201 if (input
->header
.dwType
== RIM_TYPEMOUSE
&& input
->header
.hDevice
!= NULL
) {
203 if (!GetCursorPos(&position
)) {
207 mouse_listeners_
->Notify(
208 &UserInputMonitor::MouseEventListener::OnMouseMoved
,
209 SkIPoint::Make(position
.x
, position
.y
));
210 } else if (input
->header
.dwType
== RIM_TYPEKEYBOARD
&&
211 input
->header
.hDevice
!= NULL
) {
212 ui::EventType event
= (input
->data
.keyboard
.Flags
& RI_KEY_BREAK
)
213 ? ui::ET_KEY_RELEASED
214 : ui::ET_KEY_PRESSED
;
215 ui::KeyboardCode key_code
=
216 ui::KeyboardCodeForWindowsKeyCode(input
->data
.keyboard
.VKey
);
217 counter_
.OnKeyboardEvent(event
, key_code
);
220 return DefRawInputProc(&input
, 1, sizeof(RAWINPUTHEADER
));
223 bool UserInputMonitorWinCore::HandleMessage(UINT message
,
227 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
231 *result
= OnInput(reinterpret_cast<HRAWINPUT
>(lparam
));
239 RAWINPUTDEVICE
* UserInputMonitorWinCore::GetRawInputDevices(EventBitMask event
,
241 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
243 scoped_ptr
<RAWINPUTDEVICE
> device(new RAWINPUTDEVICE());
244 if (event
== MOUSE_EVENT_MASK
) {
245 device
->dwFlags
= flags
;
246 device
->usUsagePage
= kGenericDesktopPage
;
247 device
->usUsage
= kMouseUsage
;
248 device
->hwndTarget
= window_
->hwnd();
250 DCHECK_EQ(KEYBOARD_EVENT_MASK
, event
);
251 device
->dwFlags
= flags
;
252 device
->usUsagePage
= kGenericDesktopPage
;
253 device
->usUsage
= kKeyboardUsage
;
254 device
->hwndTarget
= window_
->hwnd();
256 return device
.release();
260 // Implementation of UserInputMonitorWin.
263 UserInputMonitorWin::UserInputMonitorWin(
264 const scoped_refptr
<base::SingleThreadTaskRunner
>& ui_task_runner
)
265 : ui_task_runner_(ui_task_runner
),
266 core_(new UserInputMonitorWinCore(ui_task_runner
, mouse_listeners())) {}
268 UserInputMonitorWin::~UserInputMonitorWin() {
269 if (!ui_task_runner_
->DeleteSoon(FROM_HERE
, core_
))
273 size_t UserInputMonitorWin::GetKeyPressCount() const {
274 return core_
->GetKeyPressCount();
277 void UserInputMonitorWin::StartKeyboardMonitoring() {
278 ui_task_runner_
->PostTask(
280 base::Bind(&UserInputMonitorWinCore::StartMonitor
,
282 UserInputMonitorWinCore::KEYBOARD_EVENT_MASK
));
285 void UserInputMonitorWin::StopKeyboardMonitoring() {
286 ui_task_runner_
->PostTask(
288 base::Bind(&UserInputMonitorWinCore::StopMonitor
,
290 UserInputMonitorWinCore::KEYBOARD_EVENT_MASK
));
293 void UserInputMonitorWin::StartMouseMonitoring() {
294 ui_task_runner_
->PostTask(
296 base::Bind(&UserInputMonitorWinCore::StartMonitor
,
298 UserInputMonitorWinCore::MOUSE_EVENT_MASK
));
301 void UserInputMonitorWin::StopMouseMonitoring() {
302 ui_task_runner_
->PostTask(
304 base::Bind(&UserInputMonitorWinCore::StopMonitor
,
306 UserInputMonitorWinCore::MOUSE_EVENT_MASK
));
311 scoped_ptr
<UserInputMonitor
> UserInputMonitor::Create(
312 const scoped_refptr
<base::SingleThreadTaskRunner
>& io_task_runner
,
313 const scoped_refptr
<base::SingleThreadTaskRunner
>& ui_task_runner
) {
314 return scoped_ptr
<UserInputMonitor
>(new UserInputMonitorWin(ui_task_runner
));