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

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 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.
41 virtual void StartKeyboardMonitoring() OVERRIDE;
42 virtual void StopKeyboardMonitoring() OVERRIDE;
43
44 class Core;
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
107 void UserInputMonitorWin::Core::AddMouseListener(MouseEventListener* listener) {
108 mouse_listeners_->AddObserver(listener);
109 {
110 base::AutoLock auto_lock(lock_);
111 mouse_listeners_count_++;
112 if (mouse_listeners_count_ == 1) {
113 StartMonitor(MOUSE_EVENT_MASK);
114 DVLOG(2) << "Started mouse monitoring.";
115 }
116 }
117 }
118
119 void UserInputMonitorWin::Core::RemoveMouseListener(
120 MouseEventListener* listener) {
121 mouse_listeners_->RemoveObserver(listener);
122 {
123 base::AutoLock auto_lock(lock_);
124 mouse_listeners_count_--;
125 if (mouse_listeners_count_ == 0) {
126 StopMonitor(MOUSE_EVENT_MASK);
127 DVLOG(2) << "Stopped mouse monitoring.";
128 }
129 }
130 }
131
132 size_t UserInputMonitorWin::Core::GetKeyPressCount() const {
133 return counter_.GetKeyPressCount();
134 }
135
136 void UserInputMonitorWin::Core::StartKeyboardMonitoring() {
137 StartMonitor(KEYBOARD_EVENT_MASK);
138 }
139
140 void UserInputMonitorWin::Core::StopKeyboardMonitoring() {
141 StopMonitor(KEYBOARD_EVENT_MASK);
142 }
143
144 void UserInputMonitorWin::Core::StartMonitor(EventBitMask type) {
145 if (!ui_task_runner_->BelongsToCurrentThread()) {
146 ui_task_runner_->PostTask(
147 FROM_HERE,
148 base::Bind(&Core::StartMonitor, weak_factory_.GetWeakPtr(), type));
149 return;
150 }
151
152 if (events_monitored_ & type)
153 return;
154
155 if (type == KEYBOARD_EVENT_MASK)
156 counter_.Reset();
157
158 if (!window_) {
159 window_.reset(new base::win::MessageWindow());
160 if (!window_->Create(
161 base::Bind(&Core::HandleMessage, base::Unretained(this)))) {
162 LOG_GETLASTERROR(ERROR) << "Failed to create the raw input window";
163 window_.reset();
164 return;
165 }
166 }
167
168 // Register to receive raw mouse and/or keyboard input.
169 scoped_ptr<RAWINPUTDEVICE> device(GetRawInputDevices(type, RIDEV_INPUTSINK));
170 if (!RegisterRawInputDevices(device.get(), 1, sizeof(*device))) {
171 LOG_GETLASTERROR(ERROR)
172 << "RegisterRawInputDevices() failed for RIDEV_INPUTSINK";
173 return;
174 }
175 events_monitored_ |= type;
176 }
177
178 void UserInputMonitorWin::Core::StopMonitor(EventBitMask type) {
179 if (!ui_task_runner_->BelongsToCurrentThread()) {
180 ui_task_runner_->PostTask(
181 FROM_HERE,
182 base::Bind(&Core::StopMonitor, weak_factory_.GetWeakPtr(), type));
183 return;
184 }
185
186 if (!(events_monitored_ & type))
187 return;
188
189 // Stop receiving raw input.
190 DCHECK(window_);
191 scoped_ptr<RAWINPUTDEVICE> device(GetRawInputDevices(type, RIDEV_REMOVE));
192
193 if (!RegisterRawInputDevices(device.get(), 1, sizeof(*device))) {
194 LOG_GETLASTERROR(INFO)
195 << "RegisterRawInputDevices() failed for RIDEV_REMOVE";
196 }
197
198 events_monitored_ &= ~type;
199 if (events_monitored_ == 0)
200 window_.reset();
201 }
202
203 LRESULT UserInputMonitorWin::Core::OnInput(HRAWINPUT input_handle) {
204 DCHECK(ui_task_runner_->BelongsToCurrentThread());
205
206 // Get the size of the input record.
207 UINT size = 0;
208 UINT result = GetRawInputData(
209 input_handle, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
210 if (result == -1) {
211 LOG_GETLASTERROR(ERROR) << "GetRawInputData() failed";
212 return 0;
213 }
214 DCHECK_EQ(0u, result);
215
216 // Retrieve the input record itself.
217 scoped_ptr<uint8[]> buffer(new uint8[size]);
218 RAWINPUT* input = reinterpret_cast<RAWINPUT*>(buffer.get());
219 result = GetRawInputData(
220 input_handle, RID_INPUT, buffer.get(), &size, sizeof(RAWINPUTHEADER));
221 if (result == -1) {
222 LOG_GETLASTERROR(ERROR) << "GetRawInputData() failed";
223 return 0;
224 }
225 DCHECK_EQ(size, result);
226
227 // Notify the observer about events generated locally.
228 if (input->header.dwType == RIM_TYPEMOUSE && input->header.hDevice != NULL) {
229 POINT position;
230 if (!GetCursorPos(&position)) {
231 position.x = 0;
232 position.y = 0;
233 }
234 mouse_listeners_->Notify(&MouseEventListener::OnMouseMoved,
235 SkIPoint::Make(position.x, position.y));
236 } else if (input->header.dwType == RIM_TYPEKEYBOARD &&
237 input->header.hDevice != NULL) {
238 ui::EventType event = (input->data.keyboard.Flags & RI_KEY_BREAK)
239 ? ui::ET_KEY_RELEASED
240 : ui::ET_KEY_PRESSED;
241 ui::KeyboardCode key_code =
242 ui::KeyboardCodeForWindowsKeyCode(input->data.keyboard.VKey);
243 counter_.OnKeyboardEvent(event, key_code);
244 }
245
246 return DefRawInputProc(&input, 1, sizeof(RAWINPUTHEADER));
247 }
248
249 bool UserInputMonitorWin::Core::HandleMessage(UINT message,
250 WPARAM wparam,
251 LPARAM lparam,
252 LRESULT* result) {
253 DCHECK(ui_task_runner_->BelongsToCurrentThread());
254
255 switch (message) {
256 case WM_INPUT:
257 *result = OnInput(reinterpret_cast<HRAWINPUT>(lparam));
258 return true;
259
260 default:
261 return false;
262 }
263 }
264
265 RAWINPUTDEVICE* UserInputMonitorWin::Core::GetRawInputDevices(
266 EventBitMask event,
267 DWORD flags) {
268 DCHECK(ui_task_runner_->BelongsToCurrentThread());
269
270 scoped_ptr<RAWINPUTDEVICE> device(new RAWINPUTDEVICE());
271 if (event == MOUSE_EVENT_MASK) {
272 device->dwFlags = flags;
273 device->usUsagePage = kGenericDesktopPage;
274 device->usUsage = kMouseUsage;
275 device->hwndTarget = window_->hwnd();
276 } else {
277 DCHECK_EQ(KEYBOARD_EVENT_MASK, event);
278 device->dwFlags = flags;
279 device->usUsagePage = kGenericDesktopPage;
280 device->usUsage = kKeyboardUsage;
281 device->hwndTarget = window_->hwnd();
282 }
283 return device.release();
284 }
285
286 //
287 // Implementation of UserInputMonitorWin.
288 //
289
290 UserInputMonitorWin::UserInputMonitorWin(
291 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
292 : core_(new Core(ui_task_runner)) {}
293 UserInputMonitorWin::~UserInputMonitorWin() {
294 if (!core_->ui_task_runner()->DeleteSoon(FROM_HERE, core_))
295 delete core_;
296 }
297 void UserInputMonitorWin::AddMouseListener(MouseEventListener* listener) {
298 core_->AddMouseListener(listener);
299 }
300 void UserInputMonitorWin::RemoveMouseListener(MouseEventListener* listener) {
301 core_->RemoveMouseListener(listener);
302 }
303 size_t UserInputMonitorWin::GetKeyPressCount() const {
304 return core_->GetKeyPressCount();
305 }
306 void UserInputMonitorWin::StartKeyboardMonitoring() {
307 core_->StartKeyboardMonitoring();
308 }
309 void UserInputMonitorWin::StopKeyboardMonitoring() {
310 core_->StopKeyboardMonitoring();
311 }
312
313 } // namespace
314
10 scoped_ptr<UserInputMonitor> UserInputMonitor::Create( 315 scoped_ptr<UserInputMonitor> UserInputMonitor::Create(
11 const scoped_refptr<base::SingleThreadTaskRunner>& input_task_runner, 316 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
12 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) { 317 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
13 return scoped_ptr<UserInputMonitor>(); 318 return scoped_ptr<UserInputMonitor>(new UserInputMonitorWin(ui_task_runner));
14 } 319 }
15 320
16 } // namespace media 321 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698