- add sources.
[platform/framework/web/crosswalk.git] / src / media / base / user_input_monitor_win.cc
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.
4
5 #include "media/base/user_input_monitor.h"
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/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"
19
20 namespace media {
21 namespace {
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 base::SupportsWeakPtr<UserInputMonitorWinCore>,
32       public base::MessageLoop::DestructionObserver {
33  public:
34   enum EventBitMask {
35     MOUSE_EVENT_MASK = 1,
36     KEYBOARD_EVENT_MASK = 2,
37   };
38
39   explicit UserInputMonitorWinCore(
40       scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
41       const scoped_refptr<UserInputMonitor::MouseListenerList>&
42           mouse_listeners);
43   ~UserInputMonitorWinCore();
44
45   // DestructionObserver overrides.
46   virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
47
48   size_t GetKeyPressCount() const;
49   void StartMonitor(EventBitMask type);
50   void StopMonitor(EventBitMask type);
51
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);
61
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_;
66
67   // These members are only accessed on the UI thread.
68   scoped_ptr<base::win::MessageWindow> window_;
69   uint8 events_monitored_;
70   KeyboardEventCounter counter_;
71
72   DISALLOW_COPY_AND_ASSIGN(UserInputMonitorWinCore);
73 };
74
75 class UserInputMonitorWin : public UserInputMonitor {
76  public:
77   explicit UserInputMonitorWin(
78       const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner);
79   virtual ~UserInputMonitorWin();
80
81   // Public UserInputMonitor overrides.
82   virtual size_t GetKeyPressCount() const OVERRIDE;
83
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;
90
91   scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
92   UserInputMonitorWinCore* core_;
93
94   DISALLOW_COPY_AND_ASSIGN(UserInputMonitorWin);
95 };
96
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) {}
103
104 UserInputMonitorWinCore::~UserInputMonitorWinCore() {
105   DCHECK(!window_);
106   DCHECK(!events_monitored_);
107 }
108
109 void UserInputMonitorWinCore::WillDestroyCurrentMessageLoop() {
110   DCHECK(ui_task_runner_->BelongsToCurrentThread());
111   StopMonitor(MOUSE_EVENT_MASK);
112   StopMonitor(KEYBOARD_EVENT_MASK);
113 }
114
115 size_t UserInputMonitorWinCore::GetKeyPressCount() const {
116   return counter_.GetKeyPressCount();
117 }
118
119 void UserInputMonitorWinCore::StartMonitor(EventBitMask type) {
120   DCHECK(ui_task_runner_->BelongsToCurrentThread());
121
122   if (events_monitored_ & type)
123     return;
124
125   if (type == KEYBOARD_EVENT_MASK)
126     counter_.Reset();
127
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;
135     }
136   }
137
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;
145   }
146
147   // Start observing message loop destruction if we start monitoring the first
148   // event.
149   if (!events_monitored_)
150     base::MessageLoop::current()->AddDestructionObserver(this);
151
152   events_monitored_ |= type;
153 }
154
155 void UserInputMonitorWinCore::StopMonitor(EventBitMask type) {
156   DCHECK(ui_task_runner_->BelongsToCurrentThread());
157
158   if (!(events_monitored_ & type))
159     return;
160
161   // Stop receiving raw input.
162   DCHECK(window_);
163   scoped_ptr<RAWINPUTDEVICE> device(GetRawInputDevices(type, RIDEV_REMOVE));
164
165   if (!RegisterRawInputDevices(device.get(), 1, sizeof(*device))) {
166     LOG_GETLASTERROR(INFO)
167         << "RegisterRawInputDevices() failed for RIDEV_REMOVE";
168   }
169
170   events_monitored_ &= ~type;
171   if (events_monitored_ == 0) {
172     window_.reset();
173
174     // Stop observing message loop destruction if no event is being monitored.
175     base::MessageLoop::current()->RemoveDestructionObserver(this);
176   }
177 }
178
179 LRESULT UserInputMonitorWinCore::OnInput(HRAWINPUT input_handle) {
180   DCHECK(ui_task_runner_->BelongsToCurrentThread());
181
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;
189   }
190   DCHECK_EQ(0u, result);
191
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;
200   }
201   DCHECK_EQ(size, result);
202
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;
209     }
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);
221   }
222
223   return DefRawInputProc(&input, 1, sizeof(RAWINPUTHEADER));
224 }
225
226 bool UserInputMonitorWinCore::HandleMessage(UINT message,
227                                             WPARAM wparam,
228                                             LPARAM lparam,
229                                             LRESULT* result) {
230   DCHECK(ui_task_runner_->BelongsToCurrentThread());
231
232   switch (message) {
233     case WM_INPUT:
234       *result = OnInput(reinterpret_cast<HRAWINPUT>(lparam));
235       return true;
236
237     default:
238       return false;
239   }
240 }
241
242 RAWINPUTDEVICE* UserInputMonitorWinCore::GetRawInputDevices(EventBitMask event,
243                                                             DWORD flags) {
244   DCHECK(ui_task_runner_->BelongsToCurrentThread());
245
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();
258   }
259   return device.release();
260 }
261
262 //
263 // Implementation of UserInputMonitorWin.
264 //
265
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())) {}
270
271 UserInputMonitorWin::~UserInputMonitorWin() {
272   if (!ui_task_runner_->DeleteSoon(FROM_HERE, core_))
273     delete core_;
274 }
275
276 size_t UserInputMonitorWin::GetKeyPressCount() const {
277   return core_->GetKeyPressCount();
278 }
279
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));
286 }
287
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));
294 }
295
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));
302 }
303
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));
310 }
311
312 }  // namespace
313
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));
318 }
319
320 }  // namespace media