| Index: media/base/user_input_monitor_win.cc
|
| diff --git a/media/base/user_input_monitor_win.cc b/media/base/user_input_monitor_win.cc
|
| index 4ffad42a72d9b479d1611e4a10fea96ae41e0e5d..70f9e021ec8a28f405df6f518bc495483870c6d2 100644
|
| --- a/media/base/user_input_monitor_win.cc
|
| +++ b/media/base/user_input_monitor_win.cc
|
| @@ -4,13 +4,318 @@
|
|
|
| #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/observer_list_threadsafe.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/base/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;
|
| +
|
| +class UserInputMonitorWin : public UserInputMonitor {
|
| + public:
|
| + explicit UserInputMonitorWin(
|
| + const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner);
|
| + virtual ~UserInputMonitorWin();
|
| +
|
| + // Public interface of UserInputMonitor.
|
| + virtual void AddMouseListener(MouseEventListener* listener) OVERRIDE;
|
| + virtual void RemoveMouseListener(MouseEventListener* listener) OVERRIDE;
|
| + virtual size_t GetKeyPressCount() const OVERRIDE;
|
| +
|
| + private:
|
| + // Private interface of UserInputMonitor.
|
| + virtual void StartKeyboardMonitoring() OVERRIDE;
|
| + virtual void StopKeyboardMonitoring() OVERRIDE;
|
| +
|
| + class Core;
|
| + Core* core_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(UserInputMonitorWin);
|
| +};
|
| +
|
| +// This is the actual implementation of event monitoring. It's separated from
|
| +// UserInputMonitorWin since it needs to be deleted on the UI thread.
|
| +class UserInputMonitorWin::Core {
|
| + public:
|
| + explicit Core(scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
|
| + ~Core();
|
| +
|
| + void AddMouseListener(MouseEventListener* listener);
|
| + void RemoveMouseListener(MouseEventListener* listener);
|
| + size_t GetKeyPressCount() const;
|
| + void StartKeyboardMonitoring();
|
| + void StopKeyboardMonitoring();
|
| + scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner() {
|
| + return ui_task_runner_;
|
| + }
|
| +
|
| + private:
|
| + enum EventBitMask {
|
| + MOUSE_EVENT_MASK = 1,
|
| + KEYBOARD_EVENT_MASK = 2,
|
| + };
|
| +
|
| + void StartMonitor(EventBitMask type);
|
| + void StopMonitor(EventBitMask type);
|
| +
|
| + // 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.
|
| + base::Lock lock_;
|
| + scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
|
| + scoped_refptr<ObserverListThreadSafe<MouseEventListener> > mouse_listeners_;
|
| + size_t mouse_listeners_count_;
|
| +
|
| + // These members are only accessed on the UI thread.
|
| + scoped_ptr<base::win::MessageWindow> window_;
|
| + uint8 events_monitored_;
|
| + KeyboardEventCounter counter_;
|
| + base::WeakPtrFactory<Core> weak_factory_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(Core);
|
| +};
|
| +
|
| +UserInputMonitorWin::Core::Core(
|
| + scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
|
| + : ui_task_runner_(ui_task_runner),
|
| + events_monitored_(0),
|
| + weak_factory_(this) {}
|
| +
|
| +UserInputMonitorWin::Core::~Core() {}
|
| +
|
| +void UserInputMonitorWin::Core::AddMouseListener(MouseEventListener* listener) {
|
| + mouse_listeners_->AddObserver(listener);
|
| + {
|
| + base::AutoLock auto_lock(lock_);
|
| + mouse_listeners_count_++;
|
| + if (mouse_listeners_count_ == 1) {
|
| + StartMonitor(MOUSE_EVENT_MASK);
|
| + DVLOG(2) << "Started mouse monitoring.";
|
| + }
|
| + }
|
| +}
|
| +
|
| +void UserInputMonitorWin::Core::RemoveMouseListener(
|
| + MouseEventListener* listener) {
|
| + mouse_listeners_->RemoveObserver(listener);
|
| + {
|
| + base::AutoLock auto_lock(lock_);
|
| + mouse_listeners_count_--;
|
| + if (mouse_listeners_count_ == 0) {
|
| + StopMonitor(MOUSE_EVENT_MASK);
|
| + DVLOG(2) << "Stopped mouse monitoring.";
|
| + }
|
| + }
|
| +}
|
| +
|
| +size_t UserInputMonitorWin::Core::GetKeyPressCount() const {
|
| + return counter_.GetKeyPressCount();
|
| +}
|
| +
|
| +void UserInputMonitorWin::Core::StartKeyboardMonitoring() {
|
| + StartMonitor(KEYBOARD_EVENT_MASK);
|
| +}
|
| +
|
| +void UserInputMonitorWin::Core::StopKeyboardMonitoring() {
|
| + StopMonitor(KEYBOARD_EVENT_MASK);
|
| +}
|
| +
|
| +void UserInputMonitorWin::Core::StartMonitor(EventBitMask type) {
|
| + if (!ui_task_runner_->BelongsToCurrentThread()) {
|
| + ui_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&Core::StartMonitor, weak_factory_.GetWeakPtr(), type));
|
| + return;
|
| + }
|
| +
|
| + 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(&Core::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 UserInputMonitorWin::Core::StopMonitor(EventBitMask type) {
|
| + if (!ui_task_runner_->BelongsToCurrentThread()) {
|
| + ui_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&Core::StopMonitor, weak_factory_.GetWeakPtr(), type));
|
| + return;
|
| + }
|
| +
|
| + 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 UserInputMonitorWin::Core::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(&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 UserInputMonitorWin::Core::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* UserInputMonitorWin::Core::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)
|
| + : core_(new Core(ui_task_runner)) {}
|
| +UserInputMonitorWin::~UserInputMonitorWin() {
|
| + if (!core_->ui_task_runner()->DeleteSoon(FROM_HERE, core_))
|
| + delete core_;
|
| +}
|
| +void UserInputMonitorWin::AddMouseListener(MouseEventListener* listener) {
|
| + core_->AddMouseListener(listener);
|
| +}
|
| +void UserInputMonitorWin::RemoveMouseListener(MouseEventListener* listener) {
|
| + core_->RemoveMouseListener(listener);
|
| +}
|
| +size_t UserInputMonitorWin::GetKeyPressCount() const {
|
| + return core_->GetKeyPressCount();
|
| +}
|
| +void UserInputMonitorWin::StartKeyboardMonitoring() {
|
| + core_->StartKeyboardMonitoring();
|
| +}
|
| +void UserInputMonitorWin::StopKeyboardMonitoring() {
|
| + core_->StopKeyboardMonitoring();
|
| +}
|
| +
|
| +} // 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
|
|
|