146d0adf8256a42416584765625852b6e48497c90Mike Lockwood// Copyright 2013 The Chromium Authors. All rights reserved.
246d0adf8256a42416584765625852b6e48497c90Mike Lockwood// Use of this source code is governed by a BSD-style license that can be
346d0adf8256a42416584765625852b6e48497c90Mike Lockwood// found in the LICENSE file.
446d0adf8256a42416584765625852b6e48497c90Mike Lockwood
546d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include "media/base/user_input_monitor.h"
646d0adf8256a42416584765625852b6e48497c90Mike Lockwood
746d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include <sys/select.h>
846d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include <unistd.h>
946d0adf8256a42416584765625852b6e48497c90Mike Lockwood#define XK_MISCELLANY
1046d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include <X11/keysymdef.h>
1146d0adf8256a42416584765625852b6e48497c90Mike Lockwood
1246d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include "base/basictypes.h"
1346d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include "base/bind.h"
1446d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include "base/callback.h"
1546d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include "base/compiler_specific.h"
1646d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include "base/location.h"
1746d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include "base/logging.h"
1846d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include "base/message_loop/message_loop.h"
1946d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include "base/message_loop/message_pump_libevent.h"
2046d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include "base/single_thread_task_runner.h"
2146d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include "base/synchronization/lock.h"
2246d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include "media/base/keyboard_event_counter.h"
2346d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include "third_party/skia/include/core/SkPoint.h"
2446d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include "ui/events/keycodes/keyboard_code_conversion_x.h"
2546d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include "ui/gfx/x/x11_types.h"
2646d0adf8256a42416584765625852b6e48497c90Mike Lockwood
2746d0adf8256a42416584765625852b6e48497c90Mike Lockwood// These includes need to be later than dictated by the style guide due to
2846d0adf8256a42416584765625852b6e48497c90Mike Lockwood// Xlib header pollution, specifically the min, max, and Status macros.
2946d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include <X11/XKBlib.h>
3046d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include <X11/Xlibint.h>
3146d0adf8256a42416584765625852b6e48497c90Mike Lockwood#include <X11/extensions/record.h>
3246d0adf8256a42416584765625852b6e48497c90Mike Lockwood
3346d0adf8256a42416584765625852b6e48497c90Mike Lockwoodnamespace media {
3446d0adf8256a42416584765625852b6e48497c90Mike Lockwoodnamespace {
3546d0adf8256a42416584765625852b6e48497c90Mike Lockwood
3646d0adf8256a42416584765625852b6e48497c90Mike Lockwood// This is the actual implementation of event monitoring. It's separated from
3746d0adf8256a42416584765625852b6e48497c90Mike Lockwood// UserInputMonitorLinux since it needs to be deleted on the IO thread.
3846d0adf8256a42416584765625852b6e48497c90Mike Lockwoodclass UserInputMonitorLinuxCore
3946d0adf8256a42416584765625852b6e48497c90Mike Lockwood    : public base::MessagePumpLibevent::Watcher,
4046d0adf8256a42416584765625852b6e48497c90Mike Lockwood      public base::SupportsWeakPtr<UserInputMonitorLinuxCore>,
4146d0adf8256a42416584765625852b6e48497c90Mike Lockwood      public base::MessageLoop::DestructionObserver {
4246d0adf8256a42416584765625852b6e48497c90Mike Lockwood public:
4346d0adf8256a42416584765625852b6e48497c90Mike Lockwood  enum EventType {
4446d0adf8256a42416584765625852b6e48497c90Mike Lockwood    MOUSE_EVENT,
4546d0adf8256a42416584765625852b6e48497c90Mike Lockwood    KEYBOARD_EVENT
4646d0adf8256a42416584765625852b6e48497c90Mike Lockwood  };
4746d0adf8256a42416584765625852b6e48497c90Mike Lockwood
4846d0adf8256a42416584765625852b6e48497c90Mike Lockwood  explicit UserInputMonitorLinuxCore(
4946d0adf8256a42416584765625852b6e48497c90Mike Lockwood      const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
5046d0adf8256a42416584765625852b6e48497c90Mike Lockwood      const scoped_refptr<UserInputMonitor::MouseListenerList>&
5146d0adf8256a42416584765625852b6e48497c90Mike Lockwood          mouse_listeners);
5246d0adf8256a42416584765625852b6e48497c90Mike Lockwood  virtual ~UserInputMonitorLinuxCore();
5346d0adf8256a42416584765625852b6e48497c90Mike Lockwood
5446d0adf8256a42416584765625852b6e48497c90Mike Lockwood  // DestructionObserver overrides.
5546d0adf8256a42416584765625852b6e48497c90Mike Lockwood  virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
5646d0adf8256a42416584765625852b6e48497c90Mike Lockwood
5746d0adf8256a42416584765625852b6e48497c90Mike Lockwood  size_t GetKeyPressCount() const;
5846d0adf8256a42416584765625852b6e48497c90Mike Lockwood  void StartMonitor(EventType type);
5946d0adf8256a42416584765625852b6e48497c90Mike Lockwood  void StopMonitor(EventType type);
6046d0adf8256a42416584765625852b6e48497c90Mike Lockwood
6146d0adf8256a42416584765625852b6e48497c90Mike Lockwood private:
6246d0adf8256a42416584765625852b6e48497c90Mike Lockwood  // base::MessagePumpLibevent::Watcher interface.
6346d0adf8256a42416584765625852b6e48497c90Mike Lockwood  virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
6446d0adf8256a42416584765625852b6e48497c90Mike Lockwood  virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
6546d0adf8256a42416584765625852b6e48497c90Mike Lockwood
6646d0adf8256a42416584765625852b6e48497c90Mike Lockwood  // Processes key and mouse events.
6746d0adf8256a42416584765625852b6e48497c90Mike Lockwood  void ProcessXEvent(xEvent* event);
6846d0adf8256a42416584765625852b6e48497c90Mike Lockwood  static void ProcessReply(XPointer self, XRecordInterceptData* data);
6946d0adf8256a42416584765625852b6e48497c90Mike Lockwood
7046d0adf8256a42416584765625852b6e48497c90Mike Lockwood  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
7146d0adf8256a42416584765625852b6e48497c90Mike Lockwood  scoped_refptr<ObserverListThreadSafe<UserInputMonitor::MouseEventListener> >
7246d0adf8256a42416584765625852b6e48497c90Mike Lockwood      mouse_listeners_;
7346d0adf8256a42416584765625852b6e48497c90Mike Lockwood
7446d0adf8256a42416584765625852b6e48497c90Mike Lockwood  //
7546d0adf8256a42416584765625852b6e48497c90Mike Lockwood  // The following members should only be accessed on the IO thread.
7646d0adf8256a42416584765625852b6e48497c90Mike Lockwood  //
7746d0adf8256a42416584765625852b6e48497c90Mike Lockwood  base::MessagePumpLibevent::FileDescriptorWatcher controller_;
7846d0adf8256a42416584765625852b6e48497c90Mike Lockwood  Display* x_control_display_;
7946d0adf8256a42416584765625852b6e48497c90Mike Lockwood  Display* x_record_display_;
8046d0adf8256a42416584765625852b6e48497c90Mike Lockwood  XRecordRange* x_record_range_[2];
8146d0adf8256a42416584765625852b6e48497c90Mike Lockwood  XRecordContext x_record_context_;
8246d0adf8256a42416584765625852b6e48497c90Mike Lockwood  KeyboardEventCounter counter_;
8346d0adf8256a42416584765625852b6e48497c90Mike Lockwood
8446d0adf8256a42416584765625852b6e48497c90Mike Lockwood  DISALLOW_COPY_AND_ASSIGN(UserInputMonitorLinuxCore);
8546d0adf8256a42416584765625852b6e48497c90Mike Lockwood};
8646d0adf8256a42416584765625852b6e48497c90Mike Lockwood
8746d0adf8256a42416584765625852b6e48497c90Mike Lockwoodclass UserInputMonitorLinux : public UserInputMonitor {
8846d0adf8256a42416584765625852b6e48497c90Mike Lockwood public:
8946d0adf8256a42416584765625852b6e48497c90Mike Lockwood  explicit UserInputMonitorLinux(
9046d0adf8256a42416584765625852b6e48497c90Mike Lockwood      const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
9146d0adf8256a42416584765625852b6e48497c90Mike Lockwood  virtual ~UserInputMonitorLinux();
9246d0adf8256a42416584765625852b6e48497c90Mike Lockwood
9346d0adf8256a42416584765625852b6e48497c90Mike Lockwood  // Public UserInputMonitor overrides.
9446d0adf8256a42416584765625852b6e48497c90Mike Lockwood  virtual size_t GetKeyPressCount() const OVERRIDE;
9546d0adf8256a42416584765625852b6e48497c90Mike Lockwood
9646d0adf8256a42416584765625852b6e48497c90Mike Lockwood private:
9746d0adf8256a42416584765625852b6e48497c90Mike Lockwood  // Private UserInputMonitor overrides.
9846d0adf8256a42416584765625852b6e48497c90Mike Lockwood  virtual void StartKeyboardMonitoring() OVERRIDE;
9946d0adf8256a42416584765625852b6e48497c90Mike Lockwood  virtual void StopKeyboardMonitoring() OVERRIDE;
10046d0adf8256a42416584765625852b6e48497c90Mike Lockwood  virtual void StartMouseMonitoring() OVERRIDE;
10146d0adf8256a42416584765625852b6e48497c90Mike Lockwood  virtual void StopMouseMonitoring() OVERRIDE;
102d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood
103d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
104d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood  UserInputMonitorLinuxCore* core_;
105d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood
106d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood  DISALLOW_COPY_AND_ASSIGN(UserInputMonitorLinux);
107d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood};
108d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood
109d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike LockwoodUserInputMonitorLinuxCore::UserInputMonitorLinuxCore(
110d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood    const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
111d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood    const scoped_refptr<UserInputMonitor::MouseListenerList>& mouse_listeners)
112d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood    : io_task_runner_(io_task_runner),
113d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood      mouse_listeners_(mouse_listeners),
114d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood      x_control_display_(NULL),
11546d0adf8256a42416584765625852b6e48497c90Mike Lockwood      x_record_display_(NULL),
11646d0adf8256a42416584765625852b6e48497c90Mike Lockwood      x_record_context_(0) {
11746d0adf8256a42416584765625852b6e48497c90Mike Lockwood  x_record_range_[0] = NULL;
11846d0adf8256a42416584765625852b6e48497c90Mike Lockwood  x_record_range_[1] = NULL;
11946d0adf8256a42416584765625852b6e48497c90Mike Lockwood}
120d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood
121d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike LockwoodUserInputMonitorLinuxCore::~UserInputMonitorLinuxCore() {
12246d0adf8256a42416584765625852b6e48497c90Mike Lockwood  DCHECK(!x_control_display_);
12346d0adf8256a42416584765625852b6e48497c90Mike Lockwood  DCHECK(!x_record_display_);
12446d0adf8256a42416584765625852b6e48497c90Mike Lockwood  DCHECK(!x_record_range_[0]);
12546d0adf8256a42416584765625852b6e48497c90Mike Lockwood  DCHECK(!x_record_range_[1]);
12646d0adf8256a42416584765625852b6e48497c90Mike Lockwood  DCHECK(!x_record_context_);
12746d0adf8256a42416584765625852b6e48497c90Mike Lockwood}
12846d0adf8256a42416584765625852b6e48497c90Mike Lockwood
12946d0adf8256a42416584765625852b6e48497c90Mike Lockwoodvoid UserInputMonitorLinuxCore::WillDestroyCurrentMessageLoop() {
13046d0adf8256a42416584765625852b6e48497c90Mike Lockwood  DCHECK(io_task_runner_->BelongsToCurrentThread());
13146d0adf8256a42416584765625852b6e48497c90Mike Lockwood  StopMonitor(MOUSE_EVENT);
13246d0adf8256a42416584765625852b6e48497c90Mike Lockwood  StopMonitor(KEYBOARD_EVENT);
13346d0adf8256a42416584765625852b6e48497c90Mike Lockwood}
13446d0adf8256a42416584765625852b6e48497c90Mike Lockwood
13546d0adf8256a42416584765625852b6e48497c90Mike Lockwoodsize_t UserInputMonitorLinuxCore::GetKeyPressCount() const {
13646d0adf8256a42416584765625852b6e48497c90Mike Lockwood  return counter_.GetKeyPressCount();
13746d0adf8256a42416584765625852b6e48497c90Mike Lockwood}
13846d0adf8256a42416584765625852b6e48497c90Mike Lockwood
13946d0adf8256a42416584765625852b6e48497c90Mike Lockwoodvoid UserInputMonitorLinuxCore::StartMonitor(EventType type) {
14046d0adf8256a42416584765625852b6e48497c90Mike Lockwood  DCHECK(io_task_runner_->BelongsToCurrentThread());
14146d0adf8256a42416584765625852b6e48497c90Mike Lockwood
14246d0adf8256a42416584765625852b6e48497c90Mike Lockwood  if (type == KEYBOARD_EVENT)
14346d0adf8256a42416584765625852b6e48497c90Mike Lockwood    counter_.Reset();
144
145  // TODO(jamiewalch): We should pass the display in. At that point, since
146  // XRecord needs a private connection to the X Server for its data channel
147  // and both channels are used from a separate thread, we'll need to duplicate
148  // them with something like the following:
149  //   XOpenDisplay(DisplayString(display));
150  if (!x_control_display_)
151    x_control_display_ = gfx::OpenNewXDisplay();
152
153  if (!x_record_display_)
154    x_record_display_ = gfx::OpenNewXDisplay();
155
156  if (!x_control_display_ || !x_record_display_) {
157    LOG(ERROR) << "Couldn't open X display";
158    StopMonitor(type);
159    return;
160  }
161
162  int xr_opcode, xr_event, xr_error;
163  if (!XQueryExtension(
164           x_control_display_, "RECORD", &xr_opcode, &xr_event, &xr_error)) {
165    LOG(ERROR) << "X Record extension not available.";
166    StopMonitor(type);
167    return;
168  }
169
170  if (!x_record_range_[type])
171    x_record_range_[type] = XRecordAllocRange();
172
173  if (!x_record_range_[type]) {
174    LOG(ERROR) << "XRecordAllocRange failed.";
175    StopMonitor(type);
176    return;
177  }
178
179  if (type == MOUSE_EVENT) {
180    x_record_range_[type]->device_events.first = MotionNotify;
181    x_record_range_[type]->device_events.last = MotionNotify;
182  } else {
183    DCHECK_EQ(KEYBOARD_EVENT, type);
184    x_record_range_[type]->device_events.first = KeyPress;
185    x_record_range_[type]->device_events.last = KeyRelease;
186  }
187
188  if (x_record_context_) {
189    XRecordDisableContext(x_control_display_, x_record_context_);
190    XFlush(x_control_display_);
191    XRecordFreeContext(x_record_display_, x_record_context_);
192    x_record_context_ = 0;
193  }
194  XRecordRange** record_range_to_use =
195      (x_record_range_[0] && x_record_range_[1]) ? x_record_range_
196                                                 : &x_record_range_[type];
197  int number_of_ranges = (x_record_range_[0] && x_record_range_[1]) ? 2 : 1;
198
199  XRecordClientSpec client_spec = XRecordAllClients;
200  x_record_context_ = XRecordCreateContext(x_record_display_,
201                                           0,
202                                           &client_spec,
203                                           1,
204                                           record_range_to_use,
205                                           number_of_ranges);
206  if (!x_record_context_) {
207    LOG(ERROR) << "XRecordCreateContext failed.";
208    StopMonitor(type);
209    return;
210  }
211
212  if (!XRecordEnableContextAsync(x_record_display_,
213                                 x_record_context_,
214                                 &UserInputMonitorLinuxCore::ProcessReply,
215                                 reinterpret_cast<XPointer>(this))) {
216    LOG(ERROR) << "XRecordEnableContextAsync failed.";
217    StopMonitor(type);
218    return;
219  }
220
221  if (!x_record_range_[0] || !x_record_range_[1]) {
222    // Register OnFileCanReadWithoutBlocking() to be called every time there is
223    // something to read from |x_record_display_|.
224    base::MessageLoopForIO* message_loop = base::MessageLoopForIO::current();
225    int result =
226        message_loop->WatchFileDescriptor(ConnectionNumber(x_record_display_),
227                                          true,
228                                          base::MessageLoopForIO::WATCH_READ,
229                                          &controller_,
230                                          this);
231    if (!result) {
232      LOG(ERROR) << "Failed to create X record task.";
233      StopMonitor(type);
234      return;
235    }
236
237    // Start observing message loop destruction if we start monitoring the first
238    // event.
239    base::MessageLoop::current()->AddDestructionObserver(this);
240  }
241
242  // Fetch pending events if any.
243  OnFileCanReadWithoutBlocking(ConnectionNumber(x_record_display_));
244}
245
246void UserInputMonitorLinuxCore::StopMonitor(EventType type) {
247  DCHECK(io_task_runner_->BelongsToCurrentThread());
248
249  if (x_record_range_[type]) {
250    XFree(x_record_range_[type]);
251    x_record_range_[type] = NULL;
252  }
253  if (x_record_range_[0] || x_record_range_[1])
254    return;
255
256  // Context must be disabled via the control channel because we can't send
257  // any X protocol traffic over the data channel while it's recording.
258  if (x_record_context_) {
259    XRecordDisableContext(x_control_display_, x_record_context_);
260    XFlush(x_control_display_);
261    XRecordFreeContext(x_record_display_, x_record_context_);
262    x_record_context_ = 0;
263
264    controller_.StopWatchingFileDescriptor();
265  }
266  if (x_record_display_) {
267    XCloseDisplay(x_record_display_);
268    x_record_display_ = NULL;
269  }
270  if (x_control_display_) {
271    XCloseDisplay(x_control_display_);
272    x_control_display_ = NULL;
273  }
274  // Stop observing message loop destruction if no event is being monitored.
275  base::MessageLoop::current()->RemoveDestructionObserver(this);
276}
277
278void UserInputMonitorLinuxCore::OnFileCanReadWithoutBlocking(int fd) {
279  DCHECK(io_task_runner_->BelongsToCurrentThread());
280  XEvent event;
281  // Fetch pending events if any.
282  while (XPending(x_record_display_)) {
283    XNextEvent(x_record_display_, &event);
284  }
285}
286
287void UserInputMonitorLinuxCore::OnFileCanWriteWithoutBlocking(int fd) {
288  NOTREACHED();
289}
290
291void UserInputMonitorLinuxCore::ProcessXEvent(xEvent* event) {
292  DCHECK(io_task_runner_->BelongsToCurrentThread());
293  if (event->u.u.type == MotionNotify) {
294    SkIPoint position(SkIPoint::Make(event->u.keyButtonPointer.rootX,
295                                     event->u.keyButtonPointer.rootY));
296    mouse_listeners_->Notify(
297        &UserInputMonitor::MouseEventListener::OnMouseMoved, position);
298  } else {
299    ui::EventType type;
300    if (event->u.u.type == KeyPress) {
301      type = ui::ET_KEY_PRESSED;
302    } else if (event->u.u.type == KeyRelease) {
303      type = ui::ET_KEY_RELEASED;
304    } else {
305      NOTREACHED();
306      return;
307    }
308
309    KeySym key_sym =
310        XkbKeycodeToKeysym(x_control_display_, event->u.u.detail, 0, 0);
311    ui::KeyboardCode key_code = ui::KeyboardCodeFromXKeysym(key_sym);
312    counter_.OnKeyboardEvent(type, key_code);
313  }
314}
315
316// static
317void UserInputMonitorLinuxCore::ProcessReply(XPointer self,
318                                             XRecordInterceptData* data) {
319  if (data->category == XRecordFromServer) {
320    xEvent* event = reinterpret_cast<xEvent*>(data->data);
321    reinterpret_cast<UserInputMonitorLinuxCore*>(self)->ProcessXEvent(event);
322  }
323  XRecordFreeData(data);
324}
325
326//
327// Implementation of UserInputMonitorLinux.
328//
329
330UserInputMonitorLinux::UserInputMonitorLinux(
331    const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
332    : io_task_runner_(io_task_runner),
333      core_(new UserInputMonitorLinuxCore(io_task_runner, mouse_listeners())) {}
334
335UserInputMonitorLinux::~UserInputMonitorLinux() {
336  if (!io_task_runner_->DeleteSoon(FROM_HERE, core_))
337    delete core_;
338}
339
340size_t UserInputMonitorLinux::GetKeyPressCount() const {
341  return core_->GetKeyPressCount();
342}
343
344void UserInputMonitorLinux::StartKeyboardMonitoring() {
345  io_task_runner_->PostTask(
346      FROM_HERE,
347      base::Bind(&UserInputMonitorLinuxCore::StartMonitor,
348                 core_->AsWeakPtr(),
349                 UserInputMonitorLinuxCore::KEYBOARD_EVENT));
350}
351
352void UserInputMonitorLinux::StopKeyboardMonitoring() {
353  io_task_runner_->PostTask(
354      FROM_HERE,
355      base::Bind(&UserInputMonitorLinuxCore::StopMonitor,
356                 core_->AsWeakPtr(),
357                 UserInputMonitorLinuxCore::KEYBOARD_EVENT));
358}
359
360void UserInputMonitorLinux::StartMouseMonitoring() {
361  io_task_runner_->PostTask(FROM_HERE,
362                            base::Bind(&UserInputMonitorLinuxCore::StartMonitor,
363                                       core_->AsWeakPtr(),
364                                       UserInputMonitorLinuxCore::MOUSE_EVENT));
365}
366
367void UserInputMonitorLinux::StopMouseMonitoring() {
368  io_task_runner_->PostTask(FROM_HERE,
369                            base::Bind(&UserInputMonitorLinuxCore::StopMonitor,
370                                       core_->AsWeakPtr(),
371                                       UserInputMonitorLinuxCore::MOUSE_EVENT));
372}
373
374}  // namespace
375
376scoped_ptr<UserInputMonitor> UserInputMonitor::Create(
377    const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
378    const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
379  return scoped_ptr<UserInputMonitor>(
380      new UserInputMonitorLinux(io_task_runner));
381}
382
383}  // namespace media
384