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 LOG_GETLASTERROR(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 LOG_GETLASTERROR(ERROR
)
141 << "RegisterRawInputDevices() failed for RIDEV_INPUTSINK";
146 // Start observing message loop destruction if we start monitoring the first
148 if (!events_monitored_
)
149 base::MessageLoop::current()->AddDestructionObserver(this);
151 events_monitored_
|= type
;
154 void UserInputMonitorWinCore::StopMonitor(EventBitMask type
) {
155 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
157 if (!(events_monitored_
& type
))
160 // Stop receiving raw input.
162 scoped_ptr
<RAWINPUTDEVICE
> device(GetRawInputDevices(type
, RIDEV_REMOVE
));
164 if (!RegisterRawInputDevices(device
.get(), 1, sizeof(*device
))) {
165 LOG_GETLASTERROR(INFO
)
166 << "RegisterRawInputDevices() failed for RIDEV_REMOVE";
169 events_monitored_
&= ~type
;
170 if (events_monitored_
== 0) {
173 // Stop observing message loop destruction if no event is being monitored.
174 base::MessageLoop::current()->RemoveDestructionObserver(this);
178 LRESULT
UserInputMonitorWinCore::OnInput(HRAWINPUT input_handle
) {
179 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
181 // Get the size of the input record.
183 UINT result
= GetRawInputData(
184 input_handle
, RID_INPUT
, NULL
, &size
, sizeof(RAWINPUTHEADER
));
186 LOG_GETLASTERROR(ERROR
) << "GetRawInputData() failed";
189 DCHECK_EQ(0u, result
);
191 // Retrieve the input record itself.
192 scoped_ptr
<uint8
[]> buffer(new uint8
[size
]);
193 RAWINPUT
* input
= reinterpret_cast<RAWINPUT
*>(buffer
.get());
194 result
= GetRawInputData(
195 input_handle
, RID_INPUT
, buffer
.get(), &size
, sizeof(RAWINPUTHEADER
));
197 LOG_GETLASTERROR(ERROR
) << "GetRawInputData() failed";
200 DCHECK_EQ(size
, result
);
202 // Notify the observer about events generated locally.
203 if (input
->header
.dwType
== RIM_TYPEMOUSE
&& input
->header
.hDevice
!= NULL
) {
205 if (!GetCursorPos(&position
)) {
209 mouse_listeners_
->Notify(
210 &UserInputMonitor::MouseEventListener::OnMouseMoved
,
211 SkIPoint::Make(position
.x
, position
.y
));
212 } else if (input
->header
.dwType
== RIM_TYPEKEYBOARD
&&
213 input
->header
.hDevice
!= NULL
) {
214 ui::EventType event
= (input
->data
.keyboard
.Flags
& RI_KEY_BREAK
)
215 ? ui::ET_KEY_RELEASED
216 : ui::ET_KEY_PRESSED
;
217 ui::KeyboardCode key_code
=
218 ui::KeyboardCodeForWindowsKeyCode(input
->data
.keyboard
.VKey
);
219 counter_
.OnKeyboardEvent(event
, key_code
);
222 return DefRawInputProc(&input
, 1, sizeof(RAWINPUTHEADER
));
225 bool UserInputMonitorWinCore::HandleMessage(UINT message
,
229 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
233 *result
= OnInput(reinterpret_cast<HRAWINPUT
>(lparam
));
241 RAWINPUTDEVICE
* UserInputMonitorWinCore::GetRawInputDevices(EventBitMask event
,
243 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
245 scoped_ptr
<RAWINPUTDEVICE
> device(new RAWINPUTDEVICE());
246 if (event
== MOUSE_EVENT_MASK
) {
247 device
->dwFlags
= flags
;
248 device
->usUsagePage
= kGenericDesktopPage
;
249 device
->usUsage
= kMouseUsage
;
250 device
->hwndTarget
= window_
->hwnd();
252 DCHECK_EQ(KEYBOARD_EVENT_MASK
, event
);
253 device
->dwFlags
= flags
;
254 device
->usUsagePage
= kGenericDesktopPage
;
255 device
->usUsage
= kKeyboardUsage
;
256 device
->hwndTarget
= window_
->hwnd();
258 return device
.release();
262 // Implementation of UserInputMonitorWin.
265 UserInputMonitorWin::UserInputMonitorWin(
266 const scoped_refptr
<base::SingleThreadTaskRunner
>& ui_task_runner
)
267 : ui_task_runner_(ui_task_runner
),
268 core_(new UserInputMonitorWinCore(ui_task_runner
, mouse_listeners())) {}
270 UserInputMonitorWin::~UserInputMonitorWin() {
271 if (!ui_task_runner_
->DeleteSoon(FROM_HERE
, core_
))
275 size_t UserInputMonitorWin::GetKeyPressCount() const {
276 return core_
->GetKeyPressCount();
279 void UserInputMonitorWin::StartKeyboardMonitoring() {
280 ui_task_runner_
->PostTask(
282 base::Bind(&UserInputMonitorWinCore::StartMonitor
,
284 UserInputMonitorWinCore::KEYBOARD_EVENT_MASK
));
287 void UserInputMonitorWin::StopKeyboardMonitoring() {
288 ui_task_runner_
->PostTask(
290 base::Bind(&UserInputMonitorWinCore::StopMonitor
,
292 UserInputMonitorWinCore::KEYBOARD_EVENT_MASK
));
295 void UserInputMonitorWin::StartMouseMonitoring() {
296 ui_task_runner_
->PostTask(
298 base::Bind(&UserInputMonitorWinCore::StartMonitor
,
300 UserInputMonitorWinCore::MOUSE_EVENT_MASK
));
303 void UserInputMonitorWin::StopMouseMonitoring() {
304 ui_task_runner_
->PostTask(
306 base::Bind(&UserInputMonitorWinCore::StopMonitor
,
308 UserInputMonitorWinCore::MOUSE_EVENT_MASK
));
313 scoped_ptr
<UserInputMonitor
> UserInputMonitor::Create(
314 const scoped_refptr
<base::SingleThreadTaskRunner
>& io_task_runner
,
315 const scoped_refptr
<base::SingleThreadTaskRunner
>& ui_task_runner
) {
316 return scoped_ptr
<UserInputMonitor
>(new UserInputMonitorWin(ui_task_runner
));