summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjiayl@chromium.org <jiayl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-28 03:43:16 +0000
committerjiayl@chromium.org <jiayl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-28 03:43:16 +0000
commit2354f76ddf3fbb0ccfa88c611d1d7ad19ada3941 (patch)
tree6d7d8f1d0cdb3803a0e6db45e1ff5c2797519582
parentd45dac89d8166feec63932c9b9c91ca967a4e18b (diff)
downloadchromium_src-2354f76ddf3fbb0ccfa88c611d1d7ad19ada3941.zip
chromium_src-2354f76ddf3fbb0ccfa88c611d1d7ad19ada3941.tar.gz
chromium_src-2354f76ddf3fbb0ccfa88c611d1d7ad19ada3941.tar.bz2
Adds key press detection for Mac by detecting the increase of key down event count in audio callback.
CGEventSourceCounterForEventType does not count auto-repeated key presses, so we get exactly the same behavior as the webrtc impl. The CGEventSourceCounterForEventType call takes 2-3 microseconds on a Macbook Pro. BUG=274623 Review URL: https://chromiumcodereview.appspot.com/22801007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@219896 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--media/audio/audio_input_controller.cc33
-rw-r--r--media/audio/audio_input_controller.h12
-rw-r--r--media/base/keyboard_event_counter.cc41
-rw-r--r--media/base/keyboard_event_counter.h48
-rw-r--r--media/base/user_input_monitor.cc45
-rw-r--r--media/base/user_input_monitor.h44
-rw-r--r--media/base/user_input_monitor_linux.cc202
-rw-r--r--media/base/user_input_monitor_mac.cc57
-rw-r--r--media/base/user_input_monitor_mac.mm16
-rw-r--r--media/media.gyp6
10 files changed, 307 insertions, 197 deletions
diff --git a/media/audio/audio_input_controller.cc b/media/audio/audio_input_controller.cc
index f7747b9..d701337 100644
--- a/media/audio/audio_input_controller.cc
+++ b/media/audio/audio_input_controller.cc
@@ -8,6 +8,7 @@
#include "base/threading/thread_restrictions.h"
#include "media/base/limits.h"
#include "media/base/scoped_histogram_timer.h"
+#include "media/base/user_input_monitor.h"
namespace {
const int kMaxInputChannels = 2;
@@ -46,7 +47,7 @@ AudioInputController::AudioInputController(EventHandler* handler,
sync_writer_(sync_writer),
max_volume_(0.0),
user_input_monitor_(user_input_monitor),
- key_pressed_(false) {
+ prev_key_down_count_(0) {
DCHECK(creator_loop_.get());
}
@@ -218,6 +219,11 @@ void AudioInputController::DoCreateForStream(
state_ = kCreated;
handler_->OnCreated(this);
+
+ if (user_input_monitor_) {
+ user_input_monitor_->EnableKeyPressMonitoring();
+ prev_key_down_count_ = user_input_monitor_->GetKeyPressCount();
+ }
}
void AudioInputController::DoRecord() {
@@ -240,9 +246,6 @@ void AudioInputController::DoRecord() {
stream_->Start(this);
handler_->OnRecording(this);
-
- if (user_input_monitor_)
- user_input_monitor_->AddKeyStrokeListener(this);
}
void AudioInputController::DoClose() {
@@ -263,7 +266,7 @@ void AudioInputController::DoClose() {
state_ = kClosed;
if (user_input_monitor_)
- user_input_monitor_->RemoveKeyStrokeListener(this);
+ user_input_monitor_->DisableKeyPressMonitoring();
}
}
@@ -330,16 +333,23 @@ void AudioInputController::DoCheckForNoData() {
base::Unretained(this)));
}
-void AudioInputController::OnData(AudioInputStream* stream, const uint8* data,
- uint32 size, uint32 hardware_delay_bytes,
+void AudioInputController::OnData(AudioInputStream* stream,
+ const uint8* data,
+ uint32 size,
+ uint32 hardware_delay_bytes,
double volume) {
- bool key_pressed = false;
{
base::AutoLock auto_lock(lock_);
if (state_ != kRecording)
return;
+ }
- std::swap(key_pressed, key_pressed_);
+ bool key_pressed = false;
+ if (user_input_monitor_) {
+ size_t current_count = user_input_monitor_->GetKeyPressCount();
+ key_pressed = current_count != prev_key_down_count_;
+ prev_key_down_count_ = current_count;
+ DVLOG_IF(6, key_pressed) << "Detected keypress.";
}
// Mark data as active to ensure that the periodic calls to
@@ -369,11 +379,6 @@ void AudioInputController::OnError(AudioInputStream* stream) {
&AudioInputController::DoReportError, this));
}
-void AudioInputController::OnKeyStroke() {
- base::AutoLock auto_lock(lock_);
- key_pressed_ = true;
-}
-
void AudioInputController::DoStopCloseAndClearStream(
base::WaitableEvent* done) {
DCHECK(message_loop_->BelongsToCurrentThread());
diff --git a/media/audio/audio_input_controller.h b/media/audio/audio_input_controller.h
index 6be4821..6b40459 100644
--- a/media/audio/audio_input_controller.h
+++ b/media/audio/audio_input_controller.h
@@ -16,7 +16,6 @@
#include "base/timer/timer.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_manager_base.h"
-#include "media/base/user_input_monitor.h"
// An AudioInputController controls an AudioInputStream and records data
// from this input stream. The two main methods are Record() and Close() and
@@ -73,10 +72,11 @@
//
namespace media {
+class UserInputMonitor;
+
class MEDIA_EXPORT AudioInputController
: public base::RefCountedThreadSafe<AudioInputController>,
- public AudioInputStream::AudioInputCallback,
- public UserInputMonitor::KeyStrokeListener {
+ public AudioInputStream::AudioInputCallback {
public:
// An event handler that receives events from the AudioInputController. The
// following methods are all called on the audio thread.
@@ -203,9 +203,6 @@ class MEDIA_EXPORT AudioInputController
bool LowLatencyMode() const { return sync_writer_ != NULL; }
- // Impl of KeyStrokeListener.
- virtual void OnKeyStroke() OVERRIDE;
-
protected:
friend class base::RefCountedThreadSafe<AudioInputController>;
@@ -287,8 +284,7 @@ class MEDIA_EXPORT AudioInputController
UserInputMonitor* user_input_monitor_;
- // True if any key has been pressed after the last OnData call.
- bool key_pressed_;
+ size_t prev_key_down_count_;
DISALLOW_COPY_AND_ASSIGN(AudioInputController);
};
diff --git a/media/base/keyboard_event_counter.cc b/media/base/keyboard_event_counter.cc
new file mode 100644
index 0000000..a4ae109
--- /dev/null
+++ b/media/base/keyboard_event_counter.cc
@@ -0,0 +1,41 @@
+// 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/keyboard_event_counter.h"
+
+#include "base/atomicops.h"
+#include "base/logging.h"
+
+namespace media {
+
+KeyboardEventCounter::KeyboardEventCounter() : total_key_presses_(0) {}
+
+KeyboardEventCounter::~KeyboardEventCounter() {}
+
+void KeyboardEventCounter::Reset() {
+ pressed_keys_.clear();
+ total_key_presses_ = 0;
+}
+
+void KeyboardEventCounter::OnKeyboardEvent(ui::EventType event,
+ ui::KeyboardCode key_code) {
+ // Updates the pressed keys and the total count of key presses.
+ if (event == ui::ET_KEY_PRESSED) {
+ if (pressed_keys_.find(key_code) != pressed_keys_.end())
+ return;
+ pressed_keys_.insert(key_code);
+ base::subtle::NoBarrier_AtomicIncrement(
+ reinterpret_cast<base::subtle::AtomicWord*>(&total_key_presses_), 1);
+ } else {
+ DCHECK_EQ(ui::ET_KEY_RELEASED, event);
+ pressed_keys_.erase(key_code);
+ }
+}
+
+size_t KeyboardEventCounter::GetKeyPressCount() const {
+ return base::subtle::NoBarrier_Load(
+ reinterpret_cast<const base::subtle::AtomicWord*>(&total_key_presses_));
+}
+
+} // namespace media
diff --git a/media/base/keyboard_event_counter.h b/media/base/keyboard_event_counter.h
new file mode 100644
index 0000000..c82ca59
--- /dev/null
+++ b/media/base/keyboard_event_counter.h
@@ -0,0 +1,48 @@
+// 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.
+
+#ifndef MEDIA_BASE_KEYBOARD_EVENT_COUNTER_H_
+#define MEDIA_BASE_KEYBOARD_EVENT_COUNTER_H_
+
+#include <set>
+
+#include "base/synchronization/lock.h"
+#include "ui/base/events/event_constants.h"
+#include "ui/base/keycodes/keyboard_codes.h"
+
+namespace media {
+
+// This class tracks the total number of keypresses based on the OnKeyboardEvent
+// calls it receives from the client.
+// Multiple key down events for the same key are counted as one keypress until
+// the same key is released.
+class KeyboardEventCounter {
+ public:
+ KeyboardEventCounter();
+ ~KeyboardEventCounter();
+
+ // Resets the count to 0. Must be called on the same thread as
+ // OnKeyboardEvent.
+ void Reset();
+
+ // Returns the total number of keypresses since its creation or last Reset()
+ // call. Can be called on any thread.
+ size_t GetKeyPressCount() const;
+
+ // The client should call this method on key down or key up events.
+ // Must be called on a single thread.
+ void OnKeyboardEvent(ui::EventType event, ui::KeyboardCode key_code);
+
+ private:
+ // The set of keys currently held down.
+ std::set<ui::KeyboardCode> pressed_keys_;
+
+ size_t total_key_presses_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeyboardEventCounter);
+};
+
+} // namespace media
+
+#endif // MEDIA_BASE_KEYBOARD_EVENT_COUNTER_H_
diff --git a/media/base/user_input_monitor.cc b/media/base/user_input_monitor.cc
index 8a1f1da..34e07d8 100644
--- a/media/base/user_input_monitor.cc
+++ b/media/base/user_input_monitor.cc
@@ -16,9 +16,12 @@ scoped_ptr<UserInputMonitor> UserInputMonitor::Create(
}
#endif // DISABLE_USER_INPUT_MONITOR
+UserInputMonitor::UserInputMonitor()
+ : monitoring_mouse_(false), key_press_counter_references_(0) {}
+
UserInputMonitor::~UserInputMonitor() {
DCHECK(!monitoring_mouse_);
- DCHECK(!monitoring_keyboard_);
+ DCHECK(!key_press_counter_references_);
}
void UserInputMonitor::AddMouseListener(MouseEventListener* listener) {
@@ -30,6 +33,7 @@ void UserInputMonitor::AddMouseListener(MouseEventListener* listener) {
DVLOG(2) << "Started mouse monitoring.";
}
}
+
void UserInputMonitor::RemoveMouseListener(MouseEventListener* listener) {
base::AutoLock auto_lock(lock_);
mouse_listeners_.RemoveObserver(listener);
@@ -39,49 +43,32 @@ void UserInputMonitor::RemoveMouseListener(MouseEventListener* listener) {
DVLOG(2) << "Stopped mouse monitoring.";
}
}
-void UserInputMonitor::AddKeyStrokeListener(KeyStrokeListener* listener) {
+
+void UserInputMonitor::EnableKeyPressMonitoring() {
base::AutoLock auto_lock(lock_);
- key_stroke_listeners_.AddObserver(listener);
- if (!monitoring_keyboard_) {
+ ++key_press_counter_references_;
+ if (key_press_counter_references_ == 1) {
StartKeyboardMonitoring();
- monitoring_keyboard_ = true;
DVLOG(2) << "Started keyboard monitoring.";
}
}
-void UserInputMonitor::RemoveKeyStrokeListener(KeyStrokeListener* listener) {
+
+void UserInputMonitor::DisableKeyPressMonitoring() {
base::AutoLock auto_lock(lock_);
- key_stroke_listeners_.RemoveObserver(listener);
- if (!key_stroke_listeners_.might_have_observers()) {
+ DCHECK_NE(key_press_counter_references_, 0u);
+ --key_press_counter_references_;
+ if (key_press_counter_references_ == 0) {
StopKeyboardMonitoring();
- monitoring_keyboard_ = false;
DVLOG(2) << "Stopped keyboard monitoring.";
}
}
-UserInputMonitor::UserInputMonitor()
- : monitoring_mouse_(false), monitoring_keyboard_(false) {}
-
void UserInputMonitor::OnMouseEvent(const SkIPoint& position) {
base::AutoLock auto_lock(lock_);
+ if (!monitoring_mouse_)
+ return;
FOR_EACH_OBSERVER(
MouseEventListener, mouse_listeners_, OnMouseMoved(position));
}
-void UserInputMonitor::OnKeyboardEvent(ui::EventType event,
- ui::KeyboardCode key_code) {
- base::AutoLock auto_lock(lock_);
- // Updates the pressed keys and maybe notifies the key_stroke_listeners_.
- if (event == ui::ET_KEY_PRESSED) {
- if (pressed_keys_.find(key_code) != pressed_keys_.end())
- return;
- pressed_keys_.insert(key_code);
- DVLOG(6) << "Key stroke detected.";
- FOR_EACH_OBSERVER(KeyStrokeListener, key_stroke_listeners_, OnKeyStroke());
- } else {
- DCHECK_EQ(ui::ET_KEY_RELEASED, event);
- DCHECK(pressed_keys_.find(key_code) != pressed_keys_.end());
- pressed_keys_.erase(key_code);
- }
-}
-
} // namespace media
diff --git a/media/base/user_input_monitor.h b/media/base/user_input_monitor.h
index 9eb82f3..567907c 100644
--- a/media/base/user_input_monitor.h
+++ b/media/base/user_input_monitor.h
@@ -5,16 +5,10 @@
#ifndef MEDIA_BASE_USER_INPUT_MONITOR_H_
#define MEDIA_BASE_USER_INPUT_MONITOR_H_
-#include <set>
-
-#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/synchronization/lock.h"
#include "media/base/media_export.h"
-#include "ui/base/events/event_constants.h"
-#include "ui/base/keycodes/keyboard_codes.h"
struct SkIPoint;
@@ -28,6 +22,8 @@ namespace media {
// Thread safe. The thread on which the listenters are called is not guaranteed.
// The callers should not perform expensive/blocking tasks in the callback since
// it might be called on the browser UI/IO threads.
+// The object must outlive the browser UI/IO threads to make sure the callbacks
+// will not access a deleted object.
class MEDIA_EXPORT UserInputMonitor {
public:
// The interface to receive mouse movement events.
@@ -39,18 +35,8 @@ class MEDIA_EXPORT UserInputMonitor {
protected:
virtual ~MouseEventListener() {}
};
- // The interface to receive key stroke events.
- class MEDIA_EXPORT KeyStrokeListener {
- public:
- // Called when any key is pressed. Called only once until the key is
- // released, i.e. holding down a key for a long period will generate one
- // callback just when the key is pressed down.
- virtual void OnKeyStroke() = 0;
-
- protected:
- virtual ~KeyStrokeListener() {}
- };
+ UserInputMonitor();
virtual ~UserInputMonitor();
// Creates a platform-specific instance of UserInputMonitor.
@@ -65,16 +51,24 @@ class MEDIA_EXPORT UserInputMonitor {
// destroyed.
void AddMouseListener(MouseEventListener* listener);
void RemoveMouseListener(MouseEventListener* listener);
- void AddKeyStrokeListener(KeyStrokeListener* listener);
- void RemoveKeyStrokeListener(KeyStrokeListener* listener);
- protected:
- UserInputMonitor();
+ // A caller must call EnableKeyPressMonitoring and
+ // DisableKeyPressMonitoring in pair.
+ void EnableKeyPressMonitoring();
+ void DisableKeyPressMonitoring();
+ // Returns the number of keypresses. The starting point from when it is
+ // counted is not guaranteed, but consistent within the pair of calls of
+ // EnableKeyPressMonitoring and DisableKeyPressMonitoring. So a caller can
+ // use the difference between the values returned at two times to get the
+ // number of keypresses happened within that time period, but should not make
+ // any assumption on the initial value.
+ virtual size_t GetKeyPressCount() const = 0;
+
+ protected:
// Called by the platform-specific sub-classes to propagate the events to the
// listeners.
void OnMouseEvent(const SkIPoint& position);
- void OnKeyboardEvent(ui::EventType event, ui::KeyboardCode key_code);
private:
virtual void StartMouseMonitoring() = 0;
@@ -84,12 +78,8 @@ class MEDIA_EXPORT UserInputMonitor {
base::Lock lock_;
ObserverList<MouseEventListener, true> mouse_listeners_;
- ObserverList<KeyStrokeListener, true> key_stroke_listeners_;
bool monitoring_mouse_;
- bool monitoring_keyboard_;
- // The set of keys currently held down. Used for convering raw keyboard events
- // into KeyStrokeListener callbacks.
- std::set<ui::KeyboardCode> pressed_keys_;
+ size_t key_press_counter_references_;
DISALLOW_COPY_AND_ASSIGN(UserInputMonitor);
};
diff --git a/media/base/user_input_monitor_linux.cc b/media/base/user_input_monitor_linux.cc
index ee1b774..196b4e7 100644
--- a/media/base/user_input_monitor_linux.cc
+++ b/media/base/user_input_monitor_linux.cc
@@ -15,12 +15,11 @@
#include "base/compiler_specific.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_pump_libevent.h"
#include "base/posix/eintr_wrapper.h"
#include "base/single_thread_task_runner.h"
-#include "base/threading/non_thread_safe.h"
+#include "media/base/keyboard_event_counter.h"
#include "third_party/skia/include/core/SkPoint.h"
#include "ui/base/keycodes/keyboard_code_conversion_x.h"
@@ -31,73 +30,54 @@
#include <X11/extensions/record.h>
namespace media {
-
namespace {
-class UserInputMonitorLinux : public base::NonThreadSafe,
- public UserInputMonitor {
+class UserInputMonitorLinux : public UserInputMonitor ,
+ public base::MessagePumpLibevent::Watcher {
public:
- UserInputMonitorLinux(
+ explicit UserInputMonitorLinux(
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
virtual ~UserInputMonitorLinux();
+ virtual size_t GetKeyPressCount() const OVERRIDE;
+
private:
enum EventType {
MOUSE_EVENT,
KEYBOARD_EVENT
};
- // The actual implementation resides in UserInputMonitorLinux::Core class.
- // Must be called on the io_task_runner thread.
- class Core : public base::RefCountedThreadSafe<Core>,
- public base::MessagePumpLibevent::Watcher {
- public:
- typedef const base::Callback<void(const SkIPoint&)> MouseCallback;
- typedef base::Callback<void(ui::EventType event, ui::KeyboardCode key_code)>
- KeyboardCallback;
- Core(const MouseCallback& mouse_callback,
- const KeyboardCallback& keyboard_callback);
-
- void StartMonitor(EventType type);
- void StopMonitor(EventType type);
-
- private:
- friend class base::RefCountedThreadSafe<Core>;
- virtual ~Core();
-
- // base::MessagePumpLibevent::Watcher interface.
- virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
- virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
-
- // Processes key and mouse events.
- void ProcessXEvent(xEvent* event);
- static void ProcessReply(XPointer self, XRecordInterceptData* data);
-
- // Used to receive base::MessagePumpLibevent::Watcher events.
- base::MessagePumpLibevent::FileDescriptorWatcher controller_;
-
- Display* display_;
- Display* x_record_display_;
- XRecordRange* x_record_range_[2];
- XRecordContext x_record_context_;
- base::Callback<void(const SkIPoint&)> mouse_callback_;
- base::Callback<void(ui::EventType event, ui::KeyboardCode key_code)>
- keyboard_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(Core);
- };
-
virtual void StartMouseMonitoring() OVERRIDE;
virtual void StopMouseMonitoring() OVERRIDE;
virtual void StartKeyboardMonitoring() OVERRIDE;
virtual void StopKeyboardMonitoring() OVERRIDE;
- void OnMouseEvent(const SkIPoint& position);
- void OnKeyboardEvent(ui::EventType event, ui::KeyboardCode key_code);
+ //
+ // The following methods must be called on the IO thread.
+ //
+ void StartMonitor(EventType type);
+ void StopMonitor(EventType type);
+
+ // base::MessagePumpLibevent::Watcher interface.
+ virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
+ virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
+
+ // Processes key and mouse events.
+ void ProcessXEvent(xEvent* event);
+ static void ProcessReply(XPointer self, XRecordInterceptData* data);
// Task runner on which X Window events are received.
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
- scoped_refptr<Core> core_;
+
+ //
+ // The following members should only be accessed on the IO thread.
+ //
+ base::MessagePumpLibevent::FileDescriptorWatcher controller_;
+ Display* display_;
+ Display* x_record_display_;
+ XRecordRange* x_record_range_[2];
+ XRecordContext x_record_context_;
+ KeyboardEventCounter counter_;
DISALLOW_COPY_AND_ASSIGN(UserInputMonitorLinux);
};
@@ -105,63 +85,79 @@ class UserInputMonitorLinux : public base::NonThreadSafe,
UserInputMonitorLinux::UserInputMonitorLinux(
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
: io_task_runner_(io_task_runner),
- core_(new Core(base::Bind(&UserInputMonitorLinux::OnMouseEvent,
- base::Unretained(this)),
- base::Bind(&UserInputMonitorLinux::OnKeyboardEvent,
- base::Unretained(this)))) {}
+ display_(NULL),
+ x_record_display_(NULL),
+ x_record_context_(0) {
+ x_record_range_[0] = NULL;
+ x_record_range_[1] = NULL;
+}
-UserInputMonitorLinux::~UserInputMonitorLinux() {}
+UserInputMonitorLinux::~UserInputMonitorLinux() {
+ DCHECK(!display_);
+ DCHECK(!x_record_display_);
+ DCHECK(!x_record_range_[0]);
+ DCHECK(!x_record_range_[1]);
+ DCHECK(!x_record_context_);
+}
+
+size_t UserInputMonitorLinux::GetKeyPressCount() const {
+ return counter_.GetKeyPressCount();
+}
void UserInputMonitorLinux::StartMouseMonitoring() {
- io_task_runner_->PostTask(
- FROM_HERE, base::Bind(&Core::StartMonitor, core_.get(), MOUSE_EVENT));
+ if (!io_task_runner_->BelongsToCurrentThread()) {
+ io_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UserInputMonitorLinux::StartMonitor,
+ base::Unretained(this),
+ MOUSE_EVENT));
+ return;
+ }
+ StartMonitor(MOUSE_EVENT);
}
void UserInputMonitorLinux::StopMouseMonitoring() {
- io_task_runner_->PostTask(
- FROM_HERE, base::Bind(&Core::StopMonitor, core_.get(), MOUSE_EVENT));
+ if (!io_task_runner_->BelongsToCurrentThread()) {
+ io_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UserInputMonitorLinux::StopMonitor,
+ base::Unretained(this),
+ MOUSE_EVENT));
+ return;
+ }
+ StopMonitor(MOUSE_EVENT);
}
void UserInputMonitorLinux::StartKeyboardMonitoring() {
- io_task_runner_->PostTask(
- FROM_HERE, base::Bind(&Core::StartMonitor, core_.get(), KEYBOARD_EVENT));
+ if (!io_task_runner_->BelongsToCurrentThread()) {
+ io_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UserInputMonitorLinux::StartMonitor,
+ base::Unretained(this),
+ KEYBOARD_EVENT));
+ return;
+ }
+ StartMonitor(KEYBOARD_EVENT);
}
void UserInputMonitorLinux::StopKeyboardMonitoring() {
- io_task_runner_->PostTask(
- FROM_HERE, base::Bind(&Core::StopMonitor, core_.get(), KEYBOARD_EVENT));
+ if (!io_task_runner_->BelongsToCurrentThread()) {
+ io_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UserInputMonitorLinux::StopMonitor,
+ base::Unretained(this),
+ KEYBOARD_EVENT));
+ return;
+ }
+ StopMonitor(KEYBOARD_EVENT);
}
-void UserInputMonitorLinux::OnMouseEvent(const SkIPoint& position) {
- UserInputMonitor::OnMouseEvent(position);
-}
+void UserInputMonitorLinux::StartMonitor(EventType type) {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
-void UserInputMonitorLinux::OnKeyboardEvent(ui::EventType event,
- ui::KeyboardCode key_code) {
- UserInputMonitor::OnKeyboardEvent(event, key_code);
-}
+ if (type == KEYBOARD_EVENT)
+ counter_.Reset();
-UserInputMonitorLinux::Core::Core(const MouseCallback& mouse_callback,
- const KeyboardCallback& keyboard_callback)
- : display_(NULL),
- x_record_display_(NULL),
- x_record_context_(0),
- mouse_callback_(mouse_callback),
- keyboard_callback_(keyboard_callback) {
- x_record_range_[0] = NULL;
- x_record_range_[1] = NULL;
-}
-
-UserInputMonitorLinux::Core::~Core() {
- DCHECK(!display_);
- DCHECK(!x_record_display_);
- DCHECK(!x_record_range_[0]);
- DCHECK(!x_record_range_[1]);
- DCHECK(!x_record_context_);
-}
-
-void UserInputMonitorLinux::Core::StartMonitor(EventType type) {
- DCHECK(base::MessageLoopForIO::current());
// TODO(jamiewalch): We should pass the display in. At that point, since
// XRecord needs a private connection to the X Server for its data channel
// and both channels are used from a separate thread, we'll need to duplicate
@@ -226,7 +222,7 @@ void UserInputMonitorLinux::Core::StartMonitor(EventType type) {
if (!XRecordEnableContextAsync(x_record_display_,
x_record_context_,
- &Core::ProcessReply,
+ &UserInputMonitorLinux::ProcessReply,
reinterpret_cast<XPointer>(this))) {
LOG(ERROR) << "XRecordEnableContextAsync failed.";
return;
@@ -252,8 +248,8 @@ void UserInputMonitorLinux::Core::StartMonitor(EventType type) {
OnFileCanReadWithoutBlocking(ConnectionNumber(x_record_display_));
}
-void UserInputMonitorLinux::Core::StopMonitor(EventType type) {
- DCHECK(base::MessageLoopForIO::current());
+void UserInputMonitorLinux::StopMonitor(EventType type) {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
if (x_record_range_[type]) {
XFree(x_record_range_[type]);
@@ -282,8 +278,8 @@ void UserInputMonitorLinux::Core::StopMonitor(EventType type) {
}
}
-void UserInputMonitorLinux::Core::OnFileCanReadWithoutBlocking(int fd) {
- DCHECK(base::MessageLoopForIO::current());
+void UserInputMonitorLinux::OnFileCanReadWithoutBlocking(int fd) {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
XEvent event;
// Fetch pending events if any.
while (XPending(x_record_display_)) {
@@ -291,15 +287,16 @@ void UserInputMonitorLinux::Core::OnFileCanReadWithoutBlocking(int fd) {
}
}
-void UserInputMonitorLinux::Core::OnFileCanWriteWithoutBlocking(int fd) {
+void UserInputMonitorLinux::OnFileCanWriteWithoutBlocking(int fd) {
NOTREACHED();
}
-void UserInputMonitorLinux::Core::ProcessXEvent(xEvent* event) {
+void UserInputMonitorLinux::ProcessXEvent(xEvent* event) {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
if (event->u.u.type == MotionNotify) {
SkIPoint position(SkIPoint::Make(event->u.keyButtonPointer.rootX,
event->u.keyButtonPointer.rootY));
- mouse_callback_.Run(position);
+ OnMouseEvent(position);
} else {
ui::EventType type;
if (event->u.u.type == KeyPress) {
@@ -308,20 +305,21 @@ void UserInputMonitorLinux::Core::ProcessXEvent(xEvent* event) {
type = ui::ET_KEY_RELEASED;
} else {
NOTREACHED();
+ return;
}
KeySym key_sym = XkbKeycodeToKeysym(display_, event->u.u.detail, 0, 0);
ui::KeyboardCode key_code = ui::KeyboardCodeFromXKeysym(key_sym);
- keyboard_callback_.Run(type, key_code);
+ counter_.OnKeyboardEvent(type, key_code);
}
}
// static
-void UserInputMonitorLinux::Core::ProcessReply(XPointer self,
- XRecordInterceptData* data) {
+void UserInputMonitorLinux::ProcessReply(XPointer self,
+ XRecordInterceptData* data) {
if (data->category == XRecordFromServer) {
xEvent* event = reinterpret_cast<xEvent*>(data->data);
- reinterpret_cast<Core*>(self)->ProcessXEvent(event);
+ reinterpret_cast<UserInputMonitorLinux*>(self)->ProcessXEvent(event);
}
XRecordFreeData(data);
}
diff --git a/media/base/user_input_monitor_mac.cc b/media/base/user_input_monitor_mac.cc
new file mode 100644
index 0000000..3d19134
--- /dev/null
+++ b/media/base/user_input_monitor_mac.cc
@@ -0,0 +1,57 @@
+// 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 <ApplicationServices/ApplicationServices.h>
+
+namespace media {
+namespace {
+
+class UserInputMonitorMac : public UserInputMonitor {
+ public:
+ UserInputMonitorMac();
+ virtual ~UserInputMonitorMac();
+
+ virtual size_t GetKeyPressCount() const OVERRIDE;
+
+ private:
+ virtual void StartMouseMonitoring() OVERRIDE;
+ virtual void StopMouseMonitoring() OVERRIDE;
+ virtual void StartKeyboardMonitoring() OVERRIDE;
+ virtual void StopKeyboardMonitoring() OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(UserInputMonitorMac);
+};
+
+UserInputMonitorMac::UserInputMonitorMac() {}
+
+UserInputMonitorMac::~UserInputMonitorMac() {}
+
+size_t UserInputMonitorMac::GetKeyPressCount() const {
+ // Use |kCGEventSourceStateHIDSystemState| since we only want to count
+ // hardware generated events.
+ return CGEventSourceCounterForEventType(kCGEventSourceStateHIDSystemState,
+ kCGEventKeyDown);
+}
+
+// TODO(jiayl): add the impl.
+void UserInputMonitorMac::StartMouseMonitoring() { NOTIMPLEMENTED(); }
+
+// TODO(jiayl): add the impl.
+void UserInputMonitorMac::StopMouseMonitoring() { NOTIMPLEMENTED(); }
+
+void UserInputMonitorMac::StartKeyboardMonitoring() {}
+
+void UserInputMonitorMac::StopKeyboardMonitoring() {}
+
+} // namespace
+
+scoped_ptr<UserInputMonitor> UserInputMonitor::Create(
+ const scoped_refptr<base::SingleThreadTaskRunner>& input_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
+ return scoped_ptr<UserInputMonitor>(new UserInputMonitorMac());
+}
+
+} // namespace media
diff --git a/media/base/user_input_monitor_mac.mm b/media/base/user_input_monitor_mac.mm
deleted file mode 100644
index 4ffad42..0000000
--- a/media/base/user_input_monitor_mac.mm
+++ /dev/null
@@ -1,16 +0,0 @@
-// 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"
-
-namespace media {
-
-// TODO(jiayl): add the implementation.
-scoped_ptr<UserInputMonitor> UserInputMonitor::Create(
- const scoped_refptr<base::SingleThreadTaskRunner>& input_task_runner,
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
- return scoped_ptr<UserInputMonitor>();
-}
-
-} // namespace media
diff --git a/media/media.gyp b/media/media.gyp
index 6408f4b..5554a28 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -258,6 +258,8 @@
'base/djb2.h',
'base/filter_collection.cc',
'base/filter_collection.h',
+ 'base/keyboard_event_counter.cc',
+ 'base/keyboard_event_counter.h',
'base/media.cc',
'base/media.h',
'base/media_file_checker.cc',
@@ -304,7 +306,7 @@
'base/user_input_monitor.cc',
'base/user_input_monitor.h',
'base/user_input_monitor_linux.cc',
- 'base/user_input_monitor_mac.mm',
+ 'base/user_input_monitor_mac.cc',
'base/user_input_monitor_win.cc',
'base/video_decoder.cc',
'base/video_decoder.h',
@@ -687,6 +689,8 @@
'audio/cras/cras_input.h',
'audio/cras/cras_unified.cc',
'audio/cras/cras_unified.h',
+ 'base/keyboard_event_counter.cc',
+ 'base/keyboard_event_counter.h',
],
}],
['use_pulseaudio==1', {