summaryrefslogtreecommitdiff
path: root/chromium/media/base/user_input_monitor_win.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/media/base/user_input_monitor_win.cc')
-rw-r--r--chromium/media/base/user_input_monitor_win.cc298
1 files changed, 298 insertions, 0 deletions
diff --git a/chromium/media/base/user_input_monitor_win.cc b/chromium/media/base/user_input_monitor_win.cc
new file mode 100644
index 00000000000..13b826f01eb
--- /dev/null
+++ b/chromium/media/base/user_input_monitor_win.cc
@@ -0,0 +1,298 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/base/user_input_monitor.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/lock.h"
+#include "base/win/message_window.h"
+#include "media/base/keyboard_event_counter.h"
+#include "third_party/skia/include/core/SkPoint.h"
+#include "ui/events/keycodes/keyboard_code_conversion_win.h"
+
+namespace media {
+namespace {
+
+// From the HID Usage Tables specification.
+const USHORT kGenericDesktopPage = 1;
+const USHORT kMouseUsage = 2;
+const USHORT kKeyboardUsage = 6;
+
+// This is the actual implementation of event monitoring. It's separated from
+// UserInputMonitorWin since it needs to be deleted on the UI thread.
+class UserInputMonitorWinCore
+ : public base::SupportsWeakPtr<UserInputMonitorWinCore> {
+ public:
+ enum EventBitMask {
+ MOUSE_EVENT_MASK = 1,
+ KEYBOARD_EVENT_MASK = 2,
+ };
+
+ explicit UserInputMonitorWinCore(
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ const scoped_refptr<UserInputMonitor::MouseListenerList>&
+ mouse_listeners);
+ ~UserInputMonitorWinCore();
+
+ size_t GetKeyPressCount() const;
+ void StartMonitor(EventBitMask type);
+ void StopMonitor(EventBitMask type);
+
+ private:
+ // Handles WM_INPUT messages.
+ LRESULT OnInput(HRAWINPUT input_handle);
+ // Handles messages received by |window_|.
+ bool HandleMessage(UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
+ LRESULT* result);
+ RAWINPUTDEVICE* GetRawInputDevices(EventBitMask event, DWORD flags);
+
+ // Task runner on which |window_| is created.
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
+ scoped_refptr<ObserverListThreadSafe<UserInputMonitor::MouseEventListener> >
+ mouse_listeners_;
+
+ // These members are only accessed on the UI thread.
+ scoped_ptr<base::win::MessageWindow> window_;
+ uint8 events_monitored_;
+ KeyboardEventCounter counter_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserInputMonitorWinCore);
+};
+
+class UserInputMonitorWin : public UserInputMonitor {
+ public:
+ explicit UserInputMonitorWin(
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner);
+ virtual ~UserInputMonitorWin();
+
+ // Public UserInputMonitor overrides.
+ virtual size_t GetKeyPressCount() const OVERRIDE;
+
+ private:
+ // Private UserInputMonitor overrides.
+ virtual void StartKeyboardMonitoring() OVERRIDE;
+ virtual void StopKeyboardMonitoring() OVERRIDE;
+ virtual void StartMouseMonitoring() OVERRIDE;
+ virtual void StopMouseMonitoring() OVERRIDE;
+
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
+ UserInputMonitorWinCore* core_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserInputMonitorWin);
+};
+
+UserInputMonitorWinCore::UserInputMonitorWinCore(
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ const scoped_refptr<UserInputMonitor::MouseListenerList>& mouse_listeners)
+ : ui_task_runner_(ui_task_runner),
+ mouse_listeners_(mouse_listeners),
+ events_monitored_(0) {}
+
+UserInputMonitorWinCore::~UserInputMonitorWinCore() {
+ DCHECK(!window_);
+ DCHECK(!events_monitored_);
+}
+
+size_t UserInputMonitorWinCore::GetKeyPressCount() const {
+ return counter_.GetKeyPressCount();
+}
+
+void UserInputMonitorWinCore::StartMonitor(EventBitMask type) {
+ DCHECK(ui_task_runner_->BelongsToCurrentThread());
+
+ if (events_monitored_ & type)
+ return;
+
+ if (type == KEYBOARD_EVENT_MASK)
+ counter_.Reset();
+
+ if (!window_) {
+ window_.reset(new base::win::MessageWindow());
+ if (!window_->Create(base::Bind(&UserInputMonitorWinCore::HandleMessage,
+ base::Unretained(this)))) {
+ LOG_GETLASTERROR(ERROR) << "Failed to create the raw input window";
+ window_.reset();
+ return;
+ }
+ }
+
+ // Register to receive raw mouse and/or keyboard input.
+ scoped_ptr<RAWINPUTDEVICE> device(GetRawInputDevices(type, RIDEV_INPUTSINK));
+ if (!RegisterRawInputDevices(device.get(), 1, sizeof(*device))) {
+ LOG_GETLASTERROR(ERROR)
+ << "RegisterRawInputDevices() failed for RIDEV_INPUTSINK";
+ return;
+ }
+ events_monitored_ |= type;
+}
+
+void UserInputMonitorWinCore::StopMonitor(EventBitMask type) {
+ DCHECK(ui_task_runner_->BelongsToCurrentThread());
+
+ if (!(events_monitored_ & type))
+ return;
+
+ // Stop receiving raw input.
+ DCHECK(window_);
+ scoped_ptr<RAWINPUTDEVICE> device(GetRawInputDevices(type, RIDEV_REMOVE));
+
+ if (!RegisterRawInputDevices(device.get(), 1, sizeof(*device))) {
+ LOG_GETLASTERROR(INFO)
+ << "RegisterRawInputDevices() failed for RIDEV_REMOVE";
+ }
+
+ events_monitored_ &= ~type;
+ if (events_monitored_ == 0)
+ window_.reset();
+}
+
+LRESULT UserInputMonitorWinCore::OnInput(HRAWINPUT input_handle) {
+ DCHECK(ui_task_runner_->BelongsToCurrentThread());
+
+ // Get the size of the input record.
+ UINT size = 0;
+ UINT result = GetRawInputData(
+ input_handle, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
+ if (result == -1) {
+ LOG_GETLASTERROR(ERROR) << "GetRawInputData() failed";
+ return 0;
+ }
+ DCHECK_EQ(0u, result);
+
+ // Retrieve the input record itself.
+ scoped_ptr<uint8[]> buffer(new uint8[size]);
+ RAWINPUT* input = reinterpret_cast<RAWINPUT*>(buffer.get());
+ result = GetRawInputData(
+ input_handle, RID_INPUT, buffer.get(), &size, sizeof(RAWINPUTHEADER));
+ if (result == -1) {
+ LOG_GETLASTERROR(ERROR) << "GetRawInputData() failed";
+ return 0;
+ }
+ DCHECK_EQ(size, result);
+
+ // Notify the observer about events generated locally.
+ if (input->header.dwType == RIM_TYPEMOUSE && input->header.hDevice != NULL) {
+ POINT position;
+ if (!GetCursorPos(&position)) {
+ position.x = 0;
+ position.y = 0;
+ }
+ mouse_listeners_->Notify(
+ &UserInputMonitor::MouseEventListener::OnMouseMoved,
+ SkIPoint::Make(position.x, position.y));
+ } else if (input->header.dwType == RIM_TYPEKEYBOARD &&
+ input->header.hDevice != NULL) {
+ ui::EventType event = (input->data.keyboard.Flags & RI_KEY_BREAK)
+ ? ui::ET_KEY_RELEASED
+ : ui::ET_KEY_PRESSED;
+ ui::KeyboardCode key_code =
+ ui::KeyboardCodeForWindowsKeyCode(input->data.keyboard.VKey);
+ counter_.OnKeyboardEvent(event, key_code);
+ }
+
+ return DefRawInputProc(&input, 1, sizeof(RAWINPUTHEADER));
+}
+
+bool UserInputMonitorWinCore::HandleMessage(UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
+ LRESULT* result) {
+ DCHECK(ui_task_runner_->BelongsToCurrentThread());
+
+ switch (message) {
+ case WM_INPUT:
+ *result = OnInput(reinterpret_cast<HRAWINPUT>(lparam));
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+RAWINPUTDEVICE* UserInputMonitorWinCore::GetRawInputDevices(EventBitMask event,
+ DWORD flags) {
+ DCHECK(ui_task_runner_->BelongsToCurrentThread());
+
+ scoped_ptr<RAWINPUTDEVICE> device(new RAWINPUTDEVICE());
+ if (event == MOUSE_EVENT_MASK) {
+ device->dwFlags = flags;
+ device->usUsagePage = kGenericDesktopPage;
+ device->usUsage = kMouseUsage;
+ device->hwndTarget = window_->hwnd();
+ } else {
+ DCHECK_EQ(KEYBOARD_EVENT_MASK, event);
+ device->dwFlags = flags;
+ device->usUsagePage = kGenericDesktopPage;
+ device->usUsage = kKeyboardUsage;
+ device->hwndTarget = window_->hwnd();
+ }
+ return device.release();
+}
+
+//
+// Implementation of UserInputMonitorWin.
+//
+
+UserInputMonitorWin::UserInputMonitorWin(
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
+ : ui_task_runner_(ui_task_runner),
+ core_(new UserInputMonitorWinCore(ui_task_runner, mouse_listeners())) {}
+
+UserInputMonitorWin::~UserInputMonitorWin() {
+ if (!ui_task_runner_->DeleteSoon(FROM_HERE, core_))
+ delete core_;
+}
+
+size_t UserInputMonitorWin::GetKeyPressCount() const {
+ return core_->GetKeyPressCount();
+}
+
+void UserInputMonitorWin::StartKeyboardMonitoring() {
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UserInputMonitorWinCore::StartMonitor,
+ core_->AsWeakPtr(),
+ UserInputMonitorWinCore::KEYBOARD_EVENT_MASK));
+}
+
+void UserInputMonitorWin::StopKeyboardMonitoring() {
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UserInputMonitorWinCore::StopMonitor,
+ core_->AsWeakPtr(),
+ UserInputMonitorWinCore::KEYBOARD_EVENT_MASK));
+}
+
+void UserInputMonitorWin::StartMouseMonitoring() {
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UserInputMonitorWinCore::StartMonitor,
+ core_->AsWeakPtr(),
+ UserInputMonitorWinCore::MOUSE_EVENT_MASK));
+}
+
+void UserInputMonitorWin::StopMouseMonitoring() {
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UserInputMonitorWinCore::StopMonitor,
+ core_->AsWeakPtr(),
+ UserInputMonitorWinCore::MOUSE_EVENT_MASK));
+}
+
+} // namespace
+
+scoped_ptr<UserInputMonitor> UserInputMonitor::Create(
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
+ return scoped_ptr<UserInputMonitor>(new UserInputMonitorWin(ui_task_runner));
+}
+
+} // namespace media