cc: Fix logic for detecting when raster tasks were throttled
[chromium-blink-merge.git] / media / base / user_input_monitor_win.cc
blob29cedc8b63165cd50f0441f906c23caaaedfb8c7
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"
7 #include "base/bind.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"
20 namespace media {
21 namespace {
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 {
33 public:
34 enum EventBitMask {
35 MOUSE_EVENT_MASK = 1,
36 KEYBOARD_EVENT_MASK = 2,
39 explicit UserInputMonitorWinCore(
40 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
41 const scoped_refptr<UserInputMonitor::MouseListenerList>&
42 mouse_listeners);
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);
52 private:
53 // Handles WM_INPUT messages.
54 LRESULT OnInput(HRAWINPUT input_handle);
55 // Handles messages received by |window_|.
56 bool HandleMessage(UINT message,
57 WPARAM wparam,
58 LPARAM lparam,
59 LRESULT* result);
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> >
65 mouse_listeners_;
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 {
76 public:
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;
84 private:
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() {
105 DCHECK(!window_);
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)
123 return;
125 if (type == KEYBOARD_EVENT_MASK)
126 counter_.Reset();
128 if (!window_) {
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";
133 window_.reset();
134 return;
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";
143 window_.reset();
144 return;
147 // Start observing message loop destruction if we start monitoring the first
148 // event.
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))
159 return;
161 // Stop receiving raw input.
162 DCHECK(window_);
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) {
172 window_.reset();
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.
183 UINT size = 0;
184 UINT result = GetRawInputData(
185 input_handle, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
186 if (result == -1) {
187 LOG_GETLASTERROR(ERROR) << "GetRawInputData() failed";
188 return 0;
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));
197 if (result == -1) {
198 LOG_GETLASTERROR(ERROR) << "GetRawInputData() failed";
199 return 0;
201 DCHECK_EQ(size, result);
203 // Notify the observer about events generated locally.
204 if (input->header.dwType == RIM_TYPEMOUSE && input->header.hDevice != NULL) {
205 POINT position;
206 if (!GetCursorPos(&position)) {
207 position.x = 0;
208 position.y = 0;
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,
227 WPARAM wparam,
228 LPARAM lparam,
229 LRESULT* result) {
230 DCHECK(ui_task_runner_->BelongsToCurrentThread());
232 switch (message) {
233 case WM_INPUT:
234 *result = OnInput(reinterpret_cast<HRAWINPUT>(lparam));
235 return true;
237 default:
238 return false;
242 RAWINPUTDEVICE* UserInputMonitorWinCore::GetRawInputDevices(EventBitMask event,
243 DWORD flags) {
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();
252 } else {
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_))
273 delete core_;
276 size_t UserInputMonitorWin::GetKeyPressCount() const {
277 return core_->GetKeyPressCount();
280 void UserInputMonitorWin::StartKeyboardMonitoring() {
281 ui_task_runner_->PostTask(
282 FROM_HERE,
283 base::Bind(&UserInputMonitorWinCore::StartMonitor,
284 core_->AsWeakPtr(),
285 UserInputMonitorWinCore::KEYBOARD_EVENT_MASK));
288 void UserInputMonitorWin::StopKeyboardMonitoring() {
289 ui_task_runner_->PostTask(
290 FROM_HERE,
291 base::Bind(&UserInputMonitorWinCore::StopMonitor,
292 core_->AsWeakPtr(),
293 UserInputMonitorWinCore::KEYBOARD_EVENT_MASK));
296 void UserInputMonitorWin::StartMouseMonitoring() {
297 ui_task_runner_->PostTask(
298 FROM_HERE,
299 base::Bind(&UserInputMonitorWinCore::StartMonitor,
300 core_->AsWeakPtr(),
301 UserInputMonitorWinCore::MOUSE_EVENT_MASK));
304 void UserInputMonitorWin::StopMouseMonitoring() {
305 ui_task_runner_->PostTask(
306 FROM_HERE,
307 base::Bind(&UserInputMonitorWinCore::StopMonitor,
308 core_->AsWeakPtr(),
309 UserInputMonitorWinCore::MOUSE_EVENT_MASK));
312 } // namespace
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));
320 } // namespace media