[App banners] Add RAPPOR support
[chromium-blink-merge.git] / media / base / user_input_monitor_win.cc
blobd06b82435a337e42f3daf49bcb7a4af7d60d8ddc
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/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"
19 namespace media {
20 namespace {
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 {
32 public:
33 enum EventBitMask {
34 MOUSE_EVENT_MASK = 1,
35 KEYBOARD_EVENT_MASK = 2,
38 explicit UserInputMonitorWinCore(
39 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
40 const scoped_refptr<UserInputMonitor::MouseListenerList>&
41 mouse_listeners);
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);
51 private:
52 // Handles WM_INPUT messages.
53 LRESULT OnInput(HRAWINPUT input_handle);
54 // Handles messages received by |window_|.
55 bool HandleMessage(UINT message,
56 WPARAM wparam,
57 LPARAM lparam,
58 LRESULT* result);
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> >
64 mouse_listeners_;
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 {
75 public:
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;
83 private:
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() {
104 DCHECK(!window_);
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)
122 return;
124 if (type == KEYBOARD_EVENT_MASK)
125 counter_.Reset();
127 if (!window_) {
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";
132 window_.reset();
133 return;
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";
141 window_.reset();
142 return;
145 // Start observing message loop destruction if we start monitoring the first
146 // event.
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))
157 return;
159 // Stop receiving raw input.
160 DCHECK(window_);
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) {
169 window_.reset();
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.
180 UINT size = 0;
181 UINT result = GetRawInputData(
182 input_handle, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
183 if (result == -1) {
184 PLOG(ERROR) << "GetRawInputData() failed";
185 return 0;
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));
194 if (result == -1) {
195 PLOG(ERROR) << "GetRawInputData() failed";
196 return 0;
198 DCHECK_EQ(size, result);
200 // Notify the observer about events generated locally.
201 if (input->header.dwType == RIM_TYPEMOUSE && input->header.hDevice != NULL) {
202 POINT position;
203 if (!GetCursorPos(&position)) {
204 position.x = 0;
205 position.y = 0;
207 mouse_listeners_->Notify(
208 FROM_HERE, &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,
224 WPARAM wparam,
225 LPARAM lparam,
226 LRESULT* result) {
227 DCHECK(ui_task_runner_->BelongsToCurrentThread());
229 switch (message) {
230 case WM_INPUT:
231 *result = OnInput(reinterpret_cast<HRAWINPUT>(lparam));
232 return true;
234 default:
235 return false;
239 RAWINPUTDEVICE* UserInputMonitorWinCore::GetRawInputDevices(EventBitMask event,
240 DWORD flags) {
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();
249 } else {
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_))
270 delete core_;
273 size_t UserInputMonitorWin::GetKeyPressCount() const {
274 return core_->GetKeyPressCount();
277 void UserInputMonitorWin::StartKeyboardMonitoring() {
278 ui_task_runner_->PostTask(
279 FROM_HERE,
280 base::Bind(&UserInputMonitorWinCore::StartMonitor,
281 core_->AsWeakPtr(),
282 UserInputMonitorWinCore::KEYBOARD_EVENT_MASK));
285 void UserInputMonitorWin::StopKeyboardMonitoring() {
286 ui_task_runner_->PostTask(
287 FROM_HERE,
288 base::Bind(&UserInputMonitorWinCore::StopMonitor,
289 core_->AsWeakPtr(),
290 UserInputMonitorWinCore::KEYBOARD_EVENT_MASK));
293 void UserInputMonitorWin::StartMouseMonitoring() {
294 ui_task_runner_->PostTask(
295 FROM_HERE,
296 base::Bind(&UserInputMonitorWinCore::StartMonitor,
297 core_->AsWeakPtr(),
298 UserInputMonitorWinCore::MOUSE_EVENT_MASK));
301 void UserInputMonitorWin::StopMouseMonitoring() {
302 ui_task_runner_->PostTask(
303 FROM_HERE,
304 base::Bind(&UserInputMonitorWinCore::StopMonitor,
305 core_->AsWeakPtr(),
306 UserInputMonitorWinCore::MOUSE_EVENT_MASK));
309 } // namespace
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));
317 } // namespace media