Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(642)

Side by Side Diff: media/base/user_input_monitor_win.cc

Issue 23702008: Adds the UserInputMonitor implementation for Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/base/user_input_monitor_unittest.cc ('k') | media/media.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/base/user_input_monitor.h" 5 #include "media/base/user_input_monitor.h"
6 6
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/observer_list_threadsafe.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/base/keycodes/keyboard_code_conversion_win.h"
19
7 namespace media { 20 namespace media {
8 21 namespace {
9 // TODO(jiayl): add the implementation. 22
23 // From the HID Usage Tables specification.
24 const USHORT kGenericDesktopPage = 1;
25 const USHORT kMouseUsage = 2;
26 const USHORT kKeyboardUsage = 6;
27
28 class UserInputMonitorWin : public UserInputMonitor {
29 public:
30 explicit UserInputMonitorWin(
31 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner);
32 virtual ~UserInputMonitorWin();
33
34 // Public interface of UserInputMonitor.
35 virtual void AddMouseListener(MouseEventListener* listener) OVERRIDE;
36 virtual void RemoveMouseListener(MouseEventListener* listener) OVERRIDE;
37 virtual size_t GetKeyPressCount() const OVERRIDE;
38
39 private:
40 // Private interface of UserInputMonitor.
Sergey Ulanov 2013/09/10 18:28:39 nit: It's more common to say something like "UserI
jiayl 2013/09/10 18:34:15 Done.
41 virtual void StartKeyboardMonitoring() OVERRIDE;
42 virtual void StopKeyboardMonitoring() OVERRIDE;
43
44 class Core;
Sergey Ulanov 2013/09/10 18:28:39 nit: class declaration should be before the method
jiayl 2013/09/10 18:34:15 Done.
45 Core* core_;
46
47 DISALLOW_COPY_AND_ASSIGN(UserInputMonitorWin);
48 };
49
50 // This is the actual implementation of event monitoring. It's separated from
51 // UserInputMonitorWin since it needs to be deleted on the UI thread.
52 class UserInputMonitorWin::Core {
53 public:
54 explicit Core(scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
55 ~Core();
56
57 void AddMouseListener(MouseEventListener* listener);
58 void RemoveMouseListener(MouseEventListener* listener);
59 size_t GetKeyPressCount() const;
60 void StartKeyboardMonitoring();
61 void StopKeyboardMonitoring();
62 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner() {
63 return ui_task_runner_;
64 }
65
66 private:
67 enum EventBitMask {
68 MOUSE_EVENT_MASK = 1,
69 KEYBOARD_EVENT_MASK = 2,
70 };
71
72 void StartMonitor(EventBitMask type);
73 void StopMonitor(EventBitMask type);
74
75 // Handles WM_INPUT messages.
76 LRESULT OnInput(HRAWINPUT input_handle);
77 // Handles messages received by |window_|.
78 bool HandleMessage(UINT message,
79 WPARAM wparam,
80 LPARAM lparam,
81 LRESULT* result);
82 RAWINPUTDEVICE* GetRawInputDevices(EventBitMask event, DWORD flags);
83
84 // Task runner on which |window_| is created.
85 base::Lock lock_;
86 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
87 scoped_refptr<ObserverListThreadSafe<MouseEventListener> > mouse_listeners_;
88 size_t mouse_listeners_count_;
89
90 // These members are only accessed on the UI thread.
91 scoped_ptr<base::win::MessageWindow> window_;
92 uint8 events_monitored_;
93 KeyboardEventCounter counter_;
94 base::WeakPtrFactory<Core> weak_factory_;
95
96 DISALLOW_COPY_AND_ASSIGN(Core);
97 };
98
99 UserInputMonitorWin::Core::Core(
100 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
101 : ui_task_runner_(ui_task_runner),
102 events_monitored_(0),
103 weak_factory_(this) {}
104
105 UserInputMonitorWin::Core::~Core() {
106 DCHECK(!window_);
107 DCHECK(!events_monitored_);
108 }
109
110 void UserInputMonitorWin::Core::AddMouseListener(MouseEventListener* listener) {
111 mouse_listeners_->AddObserver(listener);
112 {
113 base::AutoLock auto_lock(lock_);
114 mouse_listeners_count_++;
115 if (mouse_listeners_count_ == 1) {
116 ui_task_runner_->PostTask(FROM_HERE,
117 base::Bind(&Core::StartMonitor,
118 weak_factory_.GetWeakPtr(),
119 MOUSE_EVENT_MASK));
120 DVLOG(2) << "Started mouse monitoring.";
121 }
122 }
123 }
124
125 void UserInputMonitorWin::Core::RemoveMouseListener(
126 MouseEventListener* listener) {
127 mouse_listeners_->RemoveObserver(listener);
128 {
129 base::AutoLock auto_lock(lock_);
130 mouse_listeners_count_--;
131 if (mouse_listeners_count_ == 0) {
132 ui_task_runner_->PostTask(FROM_HERE,
133 base::Bind(&Core::StopMonitor,
134 weak_factory_.GetWeakPtr(),
135 MOUSE_EVENT_MASK));
136 DVLOG(2) << "Stopped mouse monitoring.";
137 }
138 }
139 }
140
141 size_t UserInputMonitorWin::Core::GetKeyPressCount() const {
142 return counter_.GetKeyPressCount();
143 }
144
145 void UserInputMonitorWin::Core::StartKeyboardMonitoring() {
146 ui_task_runner_->PostTask(FROM_HERE,
147 base::Bind(&Core::StartMonitor,
148 weak_factory_.GetWeakPtr(),
149 KEYBOARD_EVENT_MASK));
150 }
151
152 void UserInputMonitorWin::Core::StopKeyboardMonitoring() {
153 ui_task_runner_->PostTask(
154 FROM_HERE,
155 base::Bind(
156 &Core::StopMonitor, weak_factory_.GetWeakPtr(), KEYBOARD_EVENT_MASK));
157 }
158
159 void UserInputMonitorWin::Core::StartMonitor(EventBitMask type) {
160 DCHECK(ui_task_runner_->BelongsToCurrentThread());
161
162 if (events_monitored_ & type)
163 return;
164
165 if (type == KEYBOARD_EVENT_MASK)
166 counter_.Reset();
167
168 if (!window_) {
169 window_.reset(new base::win::MessageWindow());
170 if (!window_->Create(
171 base::Bind(&Core::HandleMessage, base::Unretained(this)))) {
172 LOG_GETLASTERROR(ERROR) << "Failed to create the raw input window";
173 window_.reset();
174 return;
175 }
176 }
177
178 // Register to receive raw mouse and/or keyboard input.
179 scoped_ptr<RAWINPUTDEVICE> device(GetRawInputDevices(type, RIDEV_INPUTSINK));
180 if (!RegisterRawInputDevices(device.get(), 1, sizeof(*device))) {
181 LOG_GETLASTERROR(ERROR)
182 << "RegisterRawInputDevices() failed for RIDEV_INPUTSINK";
183 return;
184 }
185 events_monitored_ |= type;
186 }
187
188 void UserInputMonitorWin::Core::StopMonitor(EventBitMask type) {
189 DCHECK(ui_task_runner_->BelongsToCurrentThread());
190
191 if (!(events_monitored_ & type))
192 return;
193
194 // Stop receiving raw input.
195 DCHECK(window_);
196 scoped_ptr<RAWINPUTDEVICE> device(GetRawInputDevices(type, RIDEV_REMOVE));
197
198 if (!RegisterRawInputDevices(device.get(), 1, sizeof(*device))) {
199 LOG_GETLASTERROR(INFO)
200 << "RegisterRawInputDevices() failed for RIDEV_REMOVE";
201 }
202
203 events_monitored_ &= ~type;
204 if (events_monitored_ == 0)
205 window_.reset();
206 }
207
208 LRESULT UserInputMonitorWin::Core::OnInput(HRAWINPUT input_handle) {
209 DCHECK(ui_task_runner_->BelongsToCurrentThread());
210
211 // Get the size of the input record.
212 UINT size = 0;
213 UINT result = GetRawInputData(
214 input_handle, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
215 if (result == -1) {
216 LOG_GETLASTERROR(ERROR) << "GetRawInputData() failed";
217 return 0;
218 }
219 DCHECK_EQ(0u, result);
220
221 // Retrieve the input record itself.
222 scoped_ptr<uint8[]> buffer(new uint8[size]);
223 RAWINPUT* input = reinterpret_cast<RAWINPUT*>(buffer.get());
224 result = GetRawInputData(
225 input_handle, RID_INPUT, buffer.get(), &size, sizeof(RAWINPUTHEADER));
226 if (result == -1) {
227 LOG_GETLASTERROR(ERROR) << "GetRawInputData() failed";
228 return 0;
229 }
230 DCHECK_EQ(size, result);
231
232 // Notify the observer about events generated locally.
233 if (input->header.dwType == RIM_TYPEMOUSE && input->header.hDevice != NULL) {
234 POINT position;
235 if (!GetCursorPos(&position)) {
236 position.x = 0;
237 position.y = 0;
238 }
239 mouse_listeners_->Notify(&MouseEventListener::OnMouseMoved,
240 SkIPoint::Make(position.x, position.y));
241 } else if (input->header.dwType == RIM_TYPEKEYBOARD &&
242 input->header.hDevice != NULL) {
243 ui::EventType event = (input->data.keyboard.Flags & RI_KEY_BREAK)
244 ? ui::ET_KEY_RELEASED
Sergey Ulanov 2013/09/10 18:28:39 nit: Operators normally should not be wrapped, i.e
245 : ui::ET_KEY_PRESSED;
246 ui::KeyboardCode key_code =
247 ui::KeyboardCodeForWindowsKeyCode(input->data.keyboard.VKey);
248 counter_.OnKeyboardEvent(event, key_code);
249 }
250
251 return DefRawInputProc(&input, 1, sizeof(RAWINPUTHEADER));
252 }
253
254 bool UserInputMonitorWin::Core::HandleMessage(UINT message,
255 WPARAM wparam,
256 LPARAM lparam,
257 LRESULT* result) {
258 DCHECK(ui_task_runner_->BelongsToCurrentThread());
259
260 switch (message) {
261 case WM_INPUT:
262 *result = OnInput(reinterpret_cast<HRAWINPUT>(lparam));
263 return true;
264
265 default:
266 return false;
267 }
268 }
269
270 RAWINPUTDEVICE* UserInputMonitorWin::Core::GetRawInputDevices(
271 EventBitMask event,
272 DWORD flags) {
273 DCHECK(ui_task_runner_->BelongsToCurrentThread());
274
275 scoped_ptr<RAWINPUTDEVICE> device(new RAWINPUTDEVICE());
276 if (event == MOUSE_EVENT_MASK) {
277 device->dwFlags = flags;
278 device->usUsagePage = kGenericDesktopPage;
279 device->usUsage = kMouseUsage;
280 device->hwndTarget = window_->hwnd();
281 } else {
282 DCHECK_EQ(KEYBOARD_EVENT_MASK, event);
283 device->dwFlags = flags;
284 device->usUsagePage = kGenericDesktopPage;
285 device->usUsage = kKeyboardUsage;
286 device->hwndTarget = window_->hwnd();
287 }
288 return device.release();
289 }
290
291 //
292 // Implementation of UserInputMonitorWin.
293 //
294
295 UserInputMonitorWin::UserInputMonitorWin(
296 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
297 : core_(new Core(ui_task_runner)) {}
298 UserInputMonitorWin::~UserInputMonitorWin() {
Sergey Ulanov 2013/09/10 18:28:39 nit: empty lines between methods please.
jiayl 2013/09/10 18:34:15 Done.
299 if (!core_->ui_task_runner()->DeleteSoon(FROM_HERE, core_))
300 delete core_;
301 }
302 void UserInputMonitorWin::AddMouseListener(MouseEventListener* listener) {
303 core_->AddMouseListener(listener);
304 }
305 void UserInputMonitorWin::RemoveMouseListener(MouseEventListener* listener) {
306 core_->RemoveMouseListener(listener);
307 }
308 size_t UserInputMonitorWin::GetKeyPressCount() const {
309 return core_->GetKeyPressCount();
310 }
311 void UserInputMonitorWin::StartKeyboardMonitoring() {
312 core_->StartKeyboardMonitoring();
313 }
314 void UserInputMonitorWin::StopKeyboardMonitoring() {
315 core_->StopKeyboardMonitoring();
316 }
317
318 } // namespace
319
10 scoped_ptr<UserInputMonitor> UserInputMonitor::Create( 320 scoped_ptr<UserInputMonitor> UserInputMonitor::Create(
11 const scoped_refptr<base::SingleThreadTaskRunner>& input_task_runner, 321 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
12 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) { 322 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
13 return scoped_ptr<UserInputMonitor>(); 323 return scoped_ptr<UserInputMonitor>(new UserInputMonitorWin(ui_task_runner));
14 } 324 }
15 325
16 } // namespace media 326 } // namespace media
OLDNEW
« no previous file with comments | « media/base/user_input_monitor_unittest.cc ('k') | media/media.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698