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/memory/weak_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/synchronization/lock.h"
15 #include "base/win/message_window.h"
16 #include "media/base/keyboard_event_counter.h"
17 #include "third_party/skia/include/core/SkPoint.h"
18 #include "ui/events/keycodes/keyboard_code_conversion_win.h"
23 // From the HID Usage Tables specification.
24 const USHORT kGenericDesktopPage
= 1;
25 const USHORT kMouseUsage
= 2;
26 const USHORT kKeyboardUsage
= 6;
28 // This is the actual implementation of event monitoring. It's separated from
29 // UserInputMonitorWin since it needs to be deleted on the UI thread.
30 class UserInputMonitorWinCore
31 : public base::SupportsWeakPtr
<UserInputMonitorWinCore
>,
32 public base::MessageLoop::DestructionObserver
{
36 KEYBOARD_EVENT_MASK
= 2,
39 explicit UserInputMonitorWinCore(
40 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner
,
41 const scoped_refptr
<UserInputMonitor::MouseListenerList
>&
43 ~UserInputMonitorWinCore();
45 // DestructionObserver overrides.
46 virtual void WillDestroyCurrentMessageLoop() OVERRIDE
;
48 size_t GetKeyPressCount() const;
49 void StartMonitor(EventBitMask type
);
50 void StopMonitor(EventBitMask type
);
53 // Handles WM_INPUT messages.
54 LRESULT
OnInput(HRAWINPUT input_handle
);
55 // Handles messages received by |window_|.
56 bool HandleMessage(UINT message
,
60 RAWINPUTDEVICE
* GetRawInputDevices(EventBitMask event
, DWORD flags
);
62 // Task runner on which |window_| is created.
63 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner_
;
64 scoped_refptr
<ObserverListThreadSafe
<UserInputMonitor::MouseEventListener
> >
67 // These members are only accessed on the UI thread.
68 scoped_ptr
<base::win::MessageWindow
> window_
;
69 uint8 events_monitored_
;
70 KeyboardEventCounter counter_
;
72 DISALLOW_COPY_AND_ASSIGN(UserInputMonitorWinCore
);
75 class UserInputMonitorWin
: public UserInputMonitor
{
77 explicit UserInputMonitorWin(
78 const scoped_refptr
<base::SingleThreadTaskRunner
>& ui_task_runner
);
79 virtual ~UserInputMonitorWin();
81 // Public UserInputMonitor overrides.
82 virtual size_t GetKeyPressCount() const OVERRIDE
;
85 // Private UserInputMonitor overrides.
86 virtual void StartKeyboardMonitoring() OVERRIDE
;
87 virtual void StopKeyboardMonitoring() OVERRIDE
;
88 virtual void StartMouseMonitoring() OVERRIDE
;
89 virtual void StopMouseMonitoring() OVERRIDE
;
91 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner_
;
92 UserInputMonitorWinCore
* core_
;
94 DISALLOW_COPY_AND_ASSIGN(UserInputMonitorWin
);
97 UserInputMonitorWinCore::UserInputMonitorWinCore(
98 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner
,
99 const scoped_refptr
<UserInputMonitor::MouseListenerList
>& mouse_listeners
)
100 : ui_task_runner_(ui_task_runner
),
101 mouse_listeners_(mouse_listeners
),
102 events_monitored_(0) {}
104 UserInputMonitorWinCore::~UserInputMonitorWinCore() {
106 DCHECK(!events_monitored_
);
109 void UserInputMonitorWinCore::WillDestroyCurrentMessageLoop() {
110 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
111 StopMonitor(MOUSE_EVENT_MASK
);
112 StopMonitor(KEYBOARD_EVENT_MASK
);
115 size_t UserInputMonitorWinCore::GetKeyPressCount() const {
116 return counter_
.GetKeyPressCount();
119 void UserInputMonitorWinCore::StartMonitor(EventBitMask type
) {
120 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
122 if (events_monitored_
& type
)
125 if (type
== KEYBOARD_EVENT_MASK
)
129 window_
.reset(new base::win::MessageWindow());
130 if (!window_
->Create(base::Bind(&UserInputMonitorWinCore::HandleMessage
,
131 base::Unretained(this)))) {
132 LOG_GETLASTERROR(ERROR
) << "Failed to create the raw input window";
138 // Register to receive raw mouse and/or keyboard input.
139 scoped_ptr
<RAWINPUTDEVICE
> device(GetRawInputDevices(type
, RIDEV_INPUTSINK
));
140 if (!RegisterRawInputDevices(device
.get(), 1, sizeof(*device
))) {
141 LOG_GETLASTERROR(ERROR
)
142 << "RegisterRawInputDevices() failed for RIDEV_INPUTSINK";
147 // Start observing message loop destruction if we start monitoring the first
149 if (!events_monitored_
)
150 base::MessageLoop::current()->AddDestructionObserver(this);
152 events_monitored_
|= type
;
155 void UserInputMonitorWinCore::StopMonitor(EventBitMask type
) {
156 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
158 if (!(events_monitored_
& type
))
161 // Stop receiving raw input.
163 scoped_ptr
<RAWINPUTDEVICE
> device(GetRawInputDevices(type
, RIDEV_REMOVE
));
165 if (!RegisterRawInputDevices(device
.get(), 1, sizeof(*device
))) {
166 LOG_GETLASTERROR(INFO
)
167 << "RegisterRawInputDevices() failed for RIDEV_REMOVE";
170 events_monitored_
&= ~type
;
171 if (events_monitored_
== 0) {
174 // Stop observing message loop destruction if no event is being monitored.
175 base::MessageLoop::current()->RemoveDestructionObserver(this);
179 LRESULT
UserInputMonitorWinCore::OnInput(HRAWINPUT input_handle
) {
180 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
182 // Get the size of the input record.
184 UINT result
= GetRawInputData(
185 input_handle
, RID_INPUT
, NULL
, &size
, sizeof(RAWINPUTHEADER
));
187 LOG_GETLASTERROR(ERROR
) << "GetRawInputData() failed";
190 DCHECK_EQ(0u, result
);
192 // Retrieve the input record itself.
193 scoped_ptr
<uint8
[]> buffer(new uint8
[size
]);
194 RAWINPUT
* input
= reinterpret_cast<RAWINPUT
*>(buffer
.get());
195 result
= GetRawInputData(
196 input_handle
, RID_INPUT
, buffer
.get(), &size
, sizeof(RAWINPUTHEADER
));
198 LOG_GETLASTERROR(ERROR
) << "GetRawInputData() failed";
201 DCHECK_EQ(size
, result
);
203 // Notify the observer about events generated locally.
204 if (input
->header
.dwType
== RIM_TYPEMOUSE
&& input
->header
.hDevice
!= NULL
) {
206 if (!GetCursorPos(&position
)) {
210 mouse_listeners_
->Notify(
211 &UserInputMonitor::MouseEventListener::OnMouseMoved
,
212 SkIPoint::Make(position
.x
, position
.y
));
213 } else if (input
->header
.dwType
== RIM_TYPEKEYBOARD
&&
214 input
->header
.hDevice
!= NULL
) {
215 ui::EventType event
= (input
->data
.keyboard
.Flags
& RI_KEY_BREAK
)
216 ? ui::ET_KEY_RELEASED
217 : ui::ET_KEY_PRESSED
;
218 ui::KeyboardCode key_code
=
219 ui::KeyboardCodeForWindowsKeyCode(input
->data
.keyboard
.VKey
);
220 counter_
.OnKeyboardEvent(event
, key_code
);
223 return DefRawInputProc(&input
, 1, sizeof(RAWINPUTHEADER
));
226 bool UserInputMonitorWinCore::HandleMessage(UINT message
,
230 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
234 *result
= OnInput(reinterpret_cast<HRAWINPUT
>(lparam
));
242 RAWINPUTDEVICE
* UserInputMonitorWinCore::GetRawInputDevices(EventBitMask event
,
244 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
246 scoped_ptr
<RAWINPUTDEVICE
> device(new RAWINPUTDEVICE());
247 if (event
== MOUSE_EVENT_MASK
) {
248 device
->dwFlags
= flags
;
249 device
->usUsagePage
= kGenericDesktopPage
;
250 device
->usUsage
= kMouseUsage
;
251 device
->hwndTarget
= window_
->hwnd();
253 DCHECK_EQ(KEYBOARD_EVENT_MASK
, event
);
254 device
->dwFlags
= flags
;
255 device
->usUsagePage
= kGenericDesktopPage
;
256 device
->usUsage
= kKeyboardUsage
;
257 device
->hwndTarget
= window_
->hwnd();
259 return device
.release();
263 // Implementation of UserInputMonitorWin.
266 UserInputMonitorWin::UserInputMonitorWin(
267 const scoped_refptr
<base::SingleThreadTaskRunner
>& ui_task_runner
)
268 : ui_task_runner_(ui_task_runner
),
269 core_(new UserInputMonitorWinCore(ui_task_runner
, mouse_listeners())) {}
271 UserInputMonitorWin::~UserInputMonitorWin() {
272 if (!ui_task_runner_
->DeleteSoon(FROM_HERE
, core_
))
276 size_t UserInputMonitorWin::GetKeyPressCount() const {
277 return core_
->GetKeyPressCount();
280 void UserInputMonitorWin::StartKeyboardMonitoring() {
281 ui_task_runner_
->PostTask(
283 base::Bind(&UserInputMonitorWinCore::StartMonitor
,
285 UserInputMonitorWinCore::KEYBOARD_EVENT_MASK
));
288 void UserInputMonitorWin::StopKeyboardMonitoring() {
289 ui_task_runner_
->PostTask(
291 base::Bind(&UserInputMonitorWinCore::StopMonitor
,
293 UserInputMonitorWinCore::KEYBOARD_EVENT_MASK
));
296 void UserInputMonitorWin::StartMouseMonitoring() {
297 ui_task_runner_
->PostTask(
299 base::Bind(&UserInputMonitorWinCore::StartMonitor
,
301 UserInputMonitorWinCore::MOUSE_EVENT_MASK
));
304 void UserInputMonitorWin::StopMouseMonitoring() {
305 ui_task_runner_
->PostTask(
307 base::Bind(&UserInputMonitorWinCore::StopMonitor
,
309 UserInputMonitorWinCore::MOUSE_EVENT_MASK
));
314 scoped_ptr
<UserInputMonitor
> UserInputMonitor::Create(
315 const scoped_refptr
<base::SingleThreadTaskRunner
>& io_task_runner
,
316 const scoped_refptr
<base::SingleThreadTaskRunner
>& ui_task_runner
) {
317 return scoped_ptr
<UserInputMonitor
>(new UserInputMonitorWin(ui_task_runner
));