Home | History | Annotate | Download | only in base
      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/message_loop/message_loop.h"
     11 #include "base/single_thread_task_runner.h"
     12 #include "base/strings/stringprintf.h"
     13 #include "base/synchronization/lock.h"
     14 #include "base/win/message_window.h"
     15 #include "media/base/keyboard_event_counter.h"
     16 #include "third_party/skia/include/core/SkPoint.h"
     17 #include "ui/events/keycodes/keyboard_code_conversion_win.h"
     18 
     19 namespace media {
     20 namespace {
     21 
     22 // From the HID Usage Tables specification.
     23 const USHORT kGenericDesktopPage = 1;
     24 const USHORT kMouseUsage = 2;
     25 const USHORT kKeyboardUsage = 6;
     26 
     27 // This is the actual implementation of event monitoring. It's separated from
     28 // UserInputMonitorWin since it needs to be deleted on the UI thread.
     29 class UserInputMonitorWinCore
     30     : public base::SupportsWeakPtr<UserInputMonitorWinCore>,
     31       public base::MessageLoop::DestructionObserver {
     32  public:
     33   enum EventBitMask {
     34     MOUSE_EVENT_MASK = 1,
     35     KEYBOARD_EVENT_MASK = 2,
     36   };
     37 
     38   explicit UserInputMonitorWinCore(
     39       scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
     40       const scoped_refptr<UserInputMonitor::MouseListenerList>&
     41           mouse_listeners);
     42   ~UserInputMonitorWinCore();
     43 
     44   // DestructionObserver overrides.
     45   virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
     46 
     47   size_t GetKeyPressCount() const;
     48   void StartMonitor(EventBitMask type);
     49   void StopMonitor(EventBitMask type);
     50 
     51  private:
     52   // Handles WM_INPUT messages.
     53   LRESULT OnInput(HRAWINPUT input_handle);
     54   // Handles messages received by |window_|.
     55   bool HandleMessage(UINT message,
     56                      WPARAM wparam,
     57                      LPARAM lparam,
     58                      LRESULT* result);
     59   RAWINPUTDEVICE* GetRawInputDevices(EventBitMask event, DWORD flags);
     60 
     61   // Task runner on which |window_| is created.
     62   scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
     63   scoped_refptr<ObserverListThreadSafe<UserInputMonitor::MouseEventListener> >
     64       mouse_listeners_;
     65 
     66   // These members are only accessed on the UI thread.
     67   scoped_ptr<base::win::MessageWindow> window_;
     68   uint8 events_monitored_;
     69   KeyboardEventCounter counter_;
     70 
     71   DISALLOW_COPY_AND_ASSIGN(UserInputMonitorWinCore);
     72 };
     73 
     74 class UserInputMonitorWin : public UserInputMonitor {
     75  public:
     76   explicit UserInputMonitorWin(
     77       const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner);
     78   virtual ~UserInputMonitorWin();
     79 
     80   // Public UserInputMonitor overrides.
     81   virtual size_t GetKeyPressCount() const OVERRIDE;
     82 
     83  private:
     84   // Private UserInputMonitor overrides.
     85   virtual void StartKeyboardMonitoring() OVERRIDE;
     86   virtual void StopKeyboardMonitoring() OVERRIDE;
     87   virtual void StartMouseMonitoring() OVERRIDE;
     88   virtual void StopMouseMonitoring() OVERRIDE;
     89 
     90   scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
     91   UserInputMonitorWinCore* core_;
     92 
     93   DISALLOW_COPY_AND_ASSIGN(UserInputMonitorWin);
     94 };
     95 
     96 UserInputMonitorWinCore::UserInputMonitorWinCore(
     97     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
     98     const scoped_refptr<UserInputMonitor::MouseListenerList>& mouse_listeners)
     99     : ui_task_runner_(ui_task_runner),
    100       mouse_listeners_(mouse_listeners),
    101       events_monitored_(0) {}
    102 
    103 UserInputMonitorWinCore::~UserInputMonitorWinCore() {
    104   DCHECK(!window_);
    105   DCHECK(!events_monitored_);
    106 }
    107 
    108 void UserInputMonitorWinCore::WillDestroyCurrentMessageLoop() {
    109   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    110   StopMonitor(MOUSE_EVENT_MASK);
    111   StopMonitor(KEYBOARD_EVENT_MASK);
    112 }
    113 
    114 size_t UserInputMonitorWinCore::GetKeyPressCount() const {
    115   return counter_.GetKeyPressCount();
    116 }
    117 
    118 void UserInputMonitorWinCore::StartMonitor(EventBitMask type) {
    119   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    120 
    121   if (events_monitored_ & type)
    122     return;
    123 
    124   if (type == KEYBOARD_EVENT_MASK)
    125     counter_.Reset();
    126 
    127   if (!window_) {
    128     window_.reset(new base::win::MessageWindow());
    129     if (!window_->Create(base::Bind(&UserInputMonitorWinCore::HandleMessage,
    130                                     base::Unretained(this)))) {
    131       PLOG(ERROR) << "Failed to create the raw input window";
    132       window_.reset();
    133       return;
    134     }
    135   }
    136 
    137   // Register to receive raw mouse and/or keyboard input.
    138   scoped_ptr<RAWINPUTDEVICE> device(GetRawInputDevices(type, RIDEV_INPUTSINK));
    139   if (!RegisterRawInputDevices(device.get(), 1, sizeof(*device))) {
    140     PLOG(ERROR) << "RegisterRawInputDevices() failed for RIDEV_INPUTSINK";
    141     window_.reset();
    142     return;
    143   }
    144 
    145   // Start observing message loop destruction if we start monitoring the first
    146   // event.
    147   if (!events_monitored_)
    148     base::MessageLoop::current()->AddDestructionObserver(this);
    149 
    150   events_monitored_ |= type;
    151 }
    152 
    153 void UserInputMonitorWinCore::StopMonitor(EventBitMask type) {
    154   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    155 
    156   if (!(events_monitored_ & type))
    157     return;
    158 
    159   // Stop receiving raw input.
    160   DCHECK(window_);
    161   scoped_ptr<RAWINPUTDEVICE> device(GetRawInputDevices(type, RIDEV_REMOVE));
    162 
    163   if (!RegisterRawInputDevices(device.get(), 1, sizeof(*device))) {
    164     PLOG(INFO) << "RegisterRawInputDevices() failed for RIDEV_REMOVE";
    165   }
    166 
    167   events_monitored_ &= ~type;
    168   if (events_monitored_ == 0) {
    169     window_.reset();
    170 
    171     // Stop observing message loop destruction if no event is being monitored.
    172     base::MessageLoop::current()->RemoveDestructionObserver(this);
    173   }
    174 }
    175 
    176 LRESULT UserInputMonitorWinCore::OnInput(HRAWINPUT input_handle) {
    177   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    178 
    179   // Get the size of the input record.
    180   UINT size = 0;
    181   UINT result = GetRawInputData(
    182       input_handle, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
    183   if (result == -1) {
    184     PLOG(ERROR) << "GetRawInputData() failed";
    185     return 0;
    186   }
    187   DCHECK_EQ(0u, result);
    188 
    189   // Retrieve the input record itself.
    190   scoped_ptr<uint8[]> buffer(new uint8[size]);
    191   RAWINPUT* input = reinterpret_cast<RAWINPUT*>(buffer.get());
    192   result = GetRawInputData(
    193       input_handle, RID_INPUT, buffer.get(), &size, sizeof(RAWINPUTHEADER));
    194   if (result == -1) {
    195     PLOG(ERROR) << "GetRawInputData() failed";
    196     return 0;
    197   }
    198   DCHECK_EQ(size, result);
    199 
    200   // Notify the observer about events generated locally.
    201   if (input->header.dwType == RIM_TYPEMOUSE && input->header.hDevice != NULL) {
    202     POINT position;
    203     if (!GetCursorPos(&position)) {
    204       position.x = 0;
    205       position.y = 0;
    206     }
    207     mouse_listeners_->Notify(
    208         &UserInputMonitor::MouseEventListener::OnMouseMoved,
    209         SkIPoint::Make(position.x, position.y));
    210   } else if (input->header.dwType == RIM_TYPEKEYBOARD &&
    211              input->header.hDevice != NULL) {
    212     ui::EventType event = (input->data.keyboard.Flags & RI_KEY_BREAK)
    213                               ? ui::ET_KEY_RELEASED
    214                               : ui::ET_KEY_PRESSED;
    215     ui::KeyboardCode key_code =
    216         ui::KeyboardCodeForWindowsKeyCode(input->data.keyboard.VKey);
    217     counter_.OnKeyboardEvent(event, key_code);
    218   }
    219 
    220   return DefRawInputProc(&input, 1, sizeof(RAWINPUTHEADER));
    221 }
    222 
    223 bool UserInputMonitorWinCore::HandleMessage(UINT message,
    224                                             WPARAM wparam,
    225                                             LPARAM lparam,
    226                                             LRESULT* result) {
    227   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    228 
    229   switch (message) {
    230     case WM_INPUT:
    231       *result = OnInput(reinterpret_cast<HRAWINPUT>(lparam));
    232       return true;
    233 
    234     default:
    235       return false;
    236   }
    237 }
    238 
    239 RAWINPUTDEVICE* UserInputMonitorWinCore::GetRawInputDevices(EventBitMask event,
    240                                                             DWORD flags) {
    241   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    242 
    243   scoped_ptr<RAWINPUTDEVICE> device(new RAWINPUTDEVICE());
    244   if (event == MOUSE_EVENT_MASK) {
    245     device->dwFlags = flags;
    246     device->usUsagePage = kGenericDesktopPage;
    247     device->usUsage = kMouseUsage;
    248     device->hwndTarget = window_->hwnd();
    249   } else {
    250     DCHECK_EQ(KEYBOARD_EVENT_MASK, event);
    251     device->dwFlags = flags;
    252     device->usUsagePage = kGenericDesktopPage;
    253     device->usUsage = kKeyboardUsage;
    254     device->hwndTarget = window_->hwnd();
    255   }
    256   return device.release();
    257 }
    258 
    259 //
    260 // Implementation of UserInputMonitorWin.
    261 //
    262 
    263 UserInputMonitorWin::UserInputMonitorWin(
    264     const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
    265     : ui_task_runner_(ui_task_runner),
    266       core_(new UserInputMonitorWinCore(ui_task_runner, mouse_listeners())) {}
    267 
    268 UserInputMonitorWin::~UserInputMonitorWin() {
    269   if (!ui_task_runner_->DeleteSoon(FROM_HERE, core_))
    270     delete core_;
    271 }
    272 
    273 size_t UserInputMonitorWin::GetKeyPressCount() const {
    274   return core_->GetKeyPressCount();
    275 }
    276 
    277 void UserInputMonitorWin::StartKeyboardMonitoring() {
    278   ui_task_runner_->PostTask(
    279       FROM_HERE,
    280       base::Bind(&UserInputMonitorWinCore::StartMonitor,
    281                  core_->AsWeakPtr(),
    282                  UserInputMonitorWinCore::KEYBOARD_EVENT_MASK));
    283 }
    284 
    285 void UserInputMonitorWin::StopKeyboardMonitoring() {
    286   ui_task_runner_->PostTask(
    287       FROM_HERE,
    288       base::Bind(&UserInputMonitorWinCore::StopMonitor,
    289                  core_->AsWeakPtr(),
    290                  UserInputMonitorWinCore::KEYBOARD_EVENT_MASK));
    291 }
    292 
    293 void UserInputMonitorWin::StartMouseMonitoring() {
    294   ui_task_runner_->PostTask(
    295       FROM_HERE,
    296       base::Bind(&UserInputMonitorWinCore::StartMonitor,
    297                  core_->AsWeakPtr(),
    298                  UserInputMonitorWinCore::MOUSE_EVENT_MASK));
    299 }
    300 
    301 void UserInputMonitorWin::StopMouseMonitoring() {
    302   ui_task_runner_->PostTask(
    303       FROM_HERE,
    304       base::Bind(&UserInputMonitorWinCore::StopMonitor,
    305                  core_->AsWeakPtr(),
    306                  UserInputMonitorWinCore::MOUSE_EVENT_MASK));
    307 }
    308 
    309 }  // namespace
    310 
    311 scoped_ptr<UserInputMonitor> UserInputMonitor::Create(
    312     const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
    313     const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
    314   return scoped_ptr<UserInputMonitor>(new UserInputMonitorWin(ui_task_runner));
    315 }
    316 
    317 }  // namespace media
    318