diff options
author | Torne (Richard Coles) <torne@google.com> | 2013-09-19 22:36:51 +0100 |
---|---|---|
committer | Torne (Richard Coles) <torne@google.com> | 2013-09-19 22:36:51 +0100 |
commit | d0247b1b59f9c528cb6df88b4f2b9afaf80d181e (patch) | |
tree | 5c397fadc190cc71bffe2ffad1efc27a5b95309d /media/base/user_input_monitor_win.cc | |
parent | f7571f5f07547e2f3e0addf48d1f2a7ec3632957 (diff) | |
download | chromium_org-d0247b1b59f9c528cb6df88b4f2b9afaf80d181e.tar.gz |
Merge from Chromium at DEPS revision 224184
This commit was generated by merge_to_master.py.
Change-Id: Ia3424df5abed9bea642c522b9e2358dceabd8423
Diffstat (limited to 'media/base/user_input_monitor_win.cc')
-rw-r--r-- | media/base/user_input_monitor_win.cc | 288 |
1 files changed, 285 insertions, 3 deletions
diff --git a/media/base/user_input_monitor_win.cc b/media/base/user_input_monitor_win.cc index 4ffad42a72..13b826f01e 100644 --- a/media/base/user_input_monitor_win.cc +++ b/media/base/user_input_monitor_win.cc @@ -4,13 +4,295 @@ #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 -// TODO(jiayl): add the implementation. scoped_ptr<UserInputMonitor> UserInputMonitor::Create( - const scoped_refptr<base::SingleThreadTaskRunner>& input_task_runner, + const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) { - return scoped_ptr<UserInputMonitor>(); + return scoped_ptr<UserInputMonitor>(new UserInputMonitorWin(ui_task_runner)); } } // namespace media |