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

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
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 // 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:
32 enum EventBitMask {
33 MOUSE_EVENT_MASK = 1,
34 KEYBOARD_EVENT_MASK = 2,
35 };
36
37 explicit UserInputMonitorWinCore(
38 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
39 ~UserInputMonitorWinCore();
40
41 void AddMouseListener(UserInputMonitor::MouseEventListener* listener);
42 void RemoveMouseListener(UserInputMonitor::MouseEventListener* listener);
43 size_t GetKeyPressCount() const;
44 void StartMonitor(EventBitMask type);
45 void StopMonitor(EventBitMask type);
46
47 base::WeakPtr<UserInputMonitorWinCore> GetWeakPtr() {
48 return weak_factory_.GetWeakPtr();
49 }
50
51 private:
52 void OnMouseListenerAdded();
53 void OnMouseListenerRemoved();
54 // Handles WM_INPUT messages.
55 LRESULT OnInput(HRAWINPUT input_handle);
56 // Handles messages received by |window_|.
57 bool HandleMessage(UINT message,
58 WPARAM wparam,
59 LPARAM lparam,
60 LRESULT* result);
61 RAWINPUTDEVICE* GetRawInputDevices(EventBitMask event, DWORD flags);
62
63 // Task runner on which |window_| is created.
64 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
65 scoped_refptr<ObserverListThreadSafe<UserInputMonitor::MouseEventListener> >
66 mouse_listeners_;
67
68 // These members are only accessed on the UI thread.
69 size_t mouse_listeners_count_;
70 scoped_ptr<base::win::MessageWindow> window_;
71 uint8 events_monitored_;
72 KeyboardEventCounter counter_;
73 base::WeakPtrFactory<UserInputMonitorWinCore> weak_factory_;
74
75 DISALLOW_COPY_AND_ASSIGN(UserInputMonitorWinCore);
76 };
77
78 class UserInputMonitorWin : public UserInputMonitor {
79 public:
80 explicit UserInputMonitorWin(
81 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner);
82 virtual ~UserInputMonitorWin();
83
84 // Public UserInputMonitor overrides.
85 virtual void AddMouseListener(MouseEventListener* listener) OVERRIDE;
86 virtual void RemoveMouseListener(MouseEventListener* listener) OVERRIDE;
87 virtual size_t GetKeyPressCount() const OVERRIDE;
88
89 private:
90 // Private UserInputMonitor overrides.
91 virtual void StartKeyboardMonitoring() OVERRIDE;
92 virtual void StopKeyboardMonitoring() OVERRIDE;
93
94 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
95 UserInputMonitorWinCore* core_;
96
97 DISALLOW_COPY_AND_ASSIGN(UserInputMonitorWin);
98 };
99
100 UserInputMonitorWinCore::UserInputMonitorWinCore(
101 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
102 : ui_task_runner_(ui_task_runner),
103 events_monitored_(0),
104 weak_factory_(this) {}
105
106 UserInputMonitorWinCore::~UserInputMonitorWinCore() {
107 DCHECK(!window_);
108 DCHECK(!events_monitored_);
109 mouse_listeners_->AssertEmpty();
110 }
111
112 void UserInputMonitorWinCore::AddMouseListener(
113 UserInputMonitor::MouseEventListener* listener) {
114 mouse_listeners_->AddObserver(listener);
115 ui_task_runner_->PostTask(
116 FROM_HERE,
117 base::Bind(&UserInputMonitorWinCore::OnMouseListenerAdded,
118 weak_factory_.GetWeakPtr()));
119 }
120
121 void UserInputMonitorWinCore::RemoveMouseListener(
122 UserInputMonitor::MouseEventListener* listener) {
123 mouse_listeners_->RemoveObserver(listener);
124 ui_task_runner_->PostTask(
125 FROM_HERE,
126 base::Bind(&UserInputMonitorWinCore::OnMouseListenerRemoved,
127 weak_factory_.GetWeakPtr()));
128 }
129
130 size_t UserInputMonitorWinCore::GetKeyPressCount() const {
131 return counter_.GetKeyPressCount();
132 }
133
134 void UserInputMonitorWinCore::StartMonitor(EventBitMask type) {
135 DCHECK(ui_task_runner_->BelongsToCurrentThread());
136
137 if (events_monitored_ & type)
138 return;
139
140 if (type == KEYBOARD_EVENT_MASK)
141 counter_.Reset();
142
143 if (!window_) {
144 window_.reset(new base::win::MessageWindow());
145 if (!window_->Create(base::Bind(&UserInputMonitorWinCore::HandleMessage,
146 base::Unretained(this)))) {
147 LOG_GETLASTERROR(ERROR) << "Failed to create the raw input window";
148 window_.reset();
149 return;
150 }
151 }
152
153 // Register to receive raw mouse and/or keyboard input.
154 scoped_ptr<RAWINPUTDEVICE> device(GetRawInputDevices(type, RIDEV_INPUTSINK));
155 if (!RegisterRawInputDevices(device.get(), 1, sizeof(*device))) {
156 LOG_GETLASTERROR(ERROR)
157 << "RegisterRawInputDevices() failed for RIDEV_INPUTSINK";
158 return;
159 }
160 events_monitored_ |= type;
161 }
162
163 void UserInputMonitorWinCore::StopMonitor(EventBitMask type) {
164 DCHECK(ui_task_runner_->BelongsToCurrentThread());
165
166 if (!(events_monitored_ & type))
167 return;
168
169 // Stop receiving raw input.
170 DCHECK(window_);
171 scoped_ptr<RAWINPUTDEVICE> device(GetRawInputDevices(type, RIDEV_REMOVE));
172
173 if (!RegisterRawInputDevices(device.get(), 1, sizeof(*device))) {
174 LOG_GETLASTERROR(INFO)
175 << "RegisterRawInputDevices() failed for RIDEV_REMOVE";
176 }
177
178 events_monitored_ &= ~type;
179 if (events_monitored_ == 0)
180 window_.reset();
181 }
182
183 LRESULT UserInputMonitorWinCore::OnInput(HRAWINPUT input_handle) {
184 DCHECK(ui_task_runner_->BelongsToCurrentThread());
185
186 // Get the size of the input record.
187 UINT size = 0;
188 UINT result = GetRawInputData(
189 input_handle, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
190 if (result == -1) {
191 LOG_GETLASTERROR(ERROR) << "GetRawInputData() failed";
192 return 0;
193 }
194 DCHECK_EQ(0u, result);
195
196 // Retrieve the input record itself.
197 scoped_ptr<uint8[]> buffer(new uint8[size]);
198 RAWINPUT* input = reinterpret_cast<RAWINPUT*>(buffer.get());
199 result = GetRawInputData(
200 input_handle, RID_INPUT, buffer.get(), &size, sizeof(RAWINPUTHEADER));
201 if (result == -1) {
202 LOG_GETLASTERROR(ERROR) << "GetRawInputData() failed";
203 return 0;
204 }
205 DCHECK_EQ(size, result);
206
207 // Notify the observer about events generated locally.
208 if (input->header.dwType == RIM_TYPEMOUSE && input->header.hDevice != NULL) {
209 POINT position;
210 if (!GetCursorPos(&position)) {
211 position.x = 0;
212 position.y = 0;
213 }
214 mouse_listeners_->Notify(
215 &UserInputMonitor::MouseEventListener::OnMouseMoved,
216 SkIPoint::Make(position.x, position.y));
217 } else if (input->header.dwType == RIM_TYPEKEYBOARD &&
218 input->header.hDevice != NULL) {
219 ui::EventType event = (input->data.keyboard.Flags & RI_KEY_BREAK)
220 ? ui::ET_KEY_RELEASED
221 : ui::ET_KEY_PRESSED;
222 ui::KeyboardCode key_code =
223 ui::KeyboardCodeForWindowsKeyCode(input->data.keyboard.VKey);
224 counter_.OnKeyboardEvent(event, key_code);
225 }
226
227 return DefRawInputProc(&input, 1, sizeof(RAWINPUTHEADER));
228 }
229
230 void UserInputMonitorWinCore::OnMouseListenerAdded() {
231 DCHECK(ui_task_runner_->BelongsToCurrentThread());
232 mouse_listeners_count_++;
233 if (mouse_listeners_count_ == 1) {
234 StartMonitor(MOUSE_EVENT_MASK);
235 DVLOG(2) << "Started mouse monitoring.";
236 }
237 }
238
239 void UserInputMonitorWinCore::OnMouseListenerRemoved() {
240 DCHECK(ui_task_runner_->BelongsToCurrentThread());
241 mouse_listeners_count_--;
242 if (mouse_listeners_count_ == 0) {
243 StopMonitor(MOUSE_EVENT_MASK);
244 DVLOG(2) << "Stopped mouse monitoring.";
245 }
246 }
247
248 bool UserInputMonitorWinCore::HandleMessage(UINT message,
249 WPARAM wparam,
250 LPARAM lparam,
251 LRESULT* result) {
252 DCHECK(ui_task_runner_->BelongsToCurrentThread());
253
254 switch (message) {
255 case WM_INPUT:
256 *result = OnInput(reinterpret_cast<HRAWINPUT>(lparam));
257 return true;
258
259 default:
260 return false;
261 }
262 }
263
264 RAWINPUTDEVICE* UserInputMonitorWinCore::GetRawInputDevices(EventBitMask event,
265 DWORD flags) {
266 DCHECK(ui_task_runner_->BelongsToCurrentThread());
267
268 scoped_ptr<RAWINPUTDEVICE> device(new RAWINPUTDEVICE());
269 if (event == MOUSE_EVENT_MASK) {
270 device->dwFlags = flags;
271 device->usUsagePage = kGenericDesktopPage;
272 device->usUsage = kMouseUsage;
273 device->hwndTarget = window_->hwnd();
274 } else {
275 DCHECK_EQ(KEYBOARD_EVENT_MASK, event);
276 device->dwFlags = flags;
277 device->usUsagePage = kGenericDesktopPage;
278 device->usUsage = kKeyboardUsage;
279 device->hwndTarget = window_->hwnd();
280 }
281 return device.release();
282 }
283
284 //
285 // Implementation of UserInputMonitorWin.
286 //
287
288 UserInputMonitorWin::UserInputMonitorWin(
289 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
290 : ui_task_runner_(ui_task_runner),
291 core_(new UserInputMonitorWinCore(ui_task_runner)) {}
292
293 UserInputMonitorWin::~UserInputMonitorWin() {
294 if (!ui_task_runner_->DeleteSoon(FROM_HERE, core_))
295 delete core_;
296 }
297
298 void UserInputMonitorWin::AddMouseListener(MouseEventListener* listener) {
299 core_->AddMouseListener(listener);
300 }
301
302 void UserInputMonitorWin::RemoveMouseListener(MouseEventListener* listener) {
303 core_->RemoveMouseListener(listener);
304 }
305
306 size_t UserInputMonitorWin::GetKeyPressCount() const {
307 return core_->GetKeyPressCount();
308 }
309
310 void UserInputMonitorWin::StartKeyboardMonitoring() {
311 ui_task_runner_->PostTask(
312 FROM_HERE,
313 base::Bind(&UserInputMonitorWinCore::StartMonitor,
314 core_->GetWeakPtr(),
315 UserInputMonitorWinCore::KEYBOARD_EVENT_MASK));
316 }
317
318 void UserInputMonitorWin::StopKeyboardMonitoring() {
319 ui_task_runner_->PostTask(
320 FROM_HERE,
321 base::Bind(&UserInputMonitorWinCore::StopMonitor,
322 core_->GetWeakPtr(),
323 UserInputMonitorWinCore::KEYBOARD_EVENT_MASK));
324 }
325
326 } // namespace
327
10 scoped_ptr<UserInputMonitor> UserInputMonitor::Create( 328 scoped_ptr<UserInputMonitor> UserInputMonitor::Create(
11 const scoped_refptr<base::SingleThreadTaskRunner>& input_task_runner, 329 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
12 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) { 330 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
13 return scoped_ptr<UserInputMonitor>(); 331 return scoped_ptr<UserInputMonitor>(new UserInputMonitorWin(ui_task_runner));
14 } 332 }
15 333
16 } // namespace media 334 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698