Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(420)

Unified Diff: media/base/user_input_monitor_mac.mm

Issue 22801007: Adds the UserInputMonitor implementation for Mac. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/base/user_input_monitor.cc ('k') | media/media.gyp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/base/user_input_monitor_mac.mm
diff --git a/media/base/user_input_monitor_mac.mm b/media/base/user_input_monitor_mac.mm
index 4ffad42a72d9b479d1611e4a10fea96ae41e0e5d..1aebd86b1f7128425d41a29b2004237f497e9bf3 100644
--- a/media/base/user_input_monitor_mac.mm
+++ b/media/base/user_input_monitor_mac.mm
@@ -4,13 +4,273 @@
#include "media/base/user_input_monitor.h"
+#import <AppKit/AppKit.h>
+
+#include <ApplicationServices/ApplicationServices.h>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/time/time.h"
+#include "third_party/skia/include/core/SkPoint.h"
+#import "third_party/GTM/AppKit/GTMCarbonEvent.h"
+
+namespace media {
+class UserInputMonitorMacCore;
+} // namespace media
+
+@interface UserInputMonitorMacHelper : NSObject {
Robert Sesek 2013/08/21 00:19:31 This ObjC class is unnecessary. You should be able
+ @private
+ CFRunLoopSourceRef inputRunLoopSource_;
+ base::ScopedCFTypeRef<CFMachPortRef> inputMachPort_;
+ media::UserInputMonitorMacCore* monitor_;
+}
+
+- (id)initWithMonitor:(media::UserInputMonitorMacCore*)monitor;
+
+// Called when the local mouse moves.
+- (void)mouseMoved:(const SkIPoint&)mousePos;
+
+// Must be called when the UserInputMonitorMacHelper is no longer to be used.
+// Similar to NSTimer in that more than a simple release is required.
+- (void)invalidate;
+
+@end
+
namespace media {
-// TODO(jiayl): add the implementation.
+class UserInputMonitorMac : public base::NonThreadSafe,
+ public UserInputMonitor {
+ public:
+ typedef const base::Callback<void(const SkIPoint&)> MouseCallback;
+
+ UserInputMonitorMac(
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
+
+ virtual ~UserInputMonitorMac();
+
+ private:
+ virtual void StartMouseMonitoring() OVERRIDE;
+ virtual void StopMouseMonitoring() OVERRIDE;
+ virtual void StartKeyboardMonitoring() OVERRIDE;
+ virtual void StopKeyboardMonitoring() OVERRIDE;
+
+ void OnMouseMoved(const SkIPoint& position);
+ void OnKeyStroke();
+
+ // Task runner on which X Window events are received.
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
+
+ scoped_refptr<UserInputMonitorMacCore> core_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserInputMonitorMac);
+};
+
+// The class implements the event listening. Must be called on the UI thread.
+class UserInputMonitorMacCore
+ : public base::RefCountedThreadSafe<UserInputMonitorMacCore> {
+ public:
+ UserInputMonitorMacCore(
+ const UserInputMonitorMac::MouseCallback& mouse_callback,
+ const base::Closure& key_stroke_callback);
+
+ void StartMonitoringMouse();
+ void StopMonitoringMouse();
+ void StartPollingKeyState();
+ void StopPollingKeyState();
+
+ void OnMouseMoved(const SkIPoint& position);
+
+ private:
+ friend class base::RefCountedThreadSafe<UserInputMonitorMacCore>;
+ virtual ~UserInputMonitorMacCore();
+
+ void PollKeyState();
+
+ UserInputMonitorMac::MouseCallback mouse_callback_;
+ base::Closure key_stroke_callback_;
+ UserInputMonitorMacHelper* helper_;
+
+ bool polling_key_state_;
+ // 0x5d is key "9", after that comes function keys.
+ bool prev_key_state_[0x5d];
+
+ DISALLOW_COPY_AND_ASSIGN(UserInputMonitorMacCore);
+};
+
+UserInputMonitorMac::UserInputMonitorMac(
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
+ : ui_task_runner_(ui_task_runner),
+ core_(new UserInputMonitorMacCore(
+ base::Bind(&UserInputMonitorMac::OnMouseMoved,
+ base::Unretained(this)),
+ base::Bind(&UserInputMonitorMac::OnKeyStroke,
+ base::Unretained(this)))) {}
+
+UserInputMonitorMac::~UserInputMonitorMac() {}
+
+void UserInputMonitorMac::StartMouseMonitoring() {
+ ui_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&UserInputMonitorMacCore::StartMonitoringMouse,
+ core_.get()));
+}
+
+void UserInputMonitorMac::StopMouseMonitoring() {
+ ui_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&UserInputMonitorMacCore::StopMonitoringMouse,
+ core_.get()));
+}
+
+void UserInputMonitorMac::StartKeyboardMonitoring() {
+ ui_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&UserInputMonitorMacCore::StartPollingKeyState,
+ core_.get()));
+}
+
+void UserInputMonitorMac::StopKeyboardMonitoring() {
+ ui_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&UserInputMonitorMacCore::StopPollingKeyState,
+ core_.get()));
+}
+
+void UserInputMonitorMac::OnMouseMoved(const SkIPoint& position) {
+ UserInputMonitor::OnMouseEvent(position);
+}
+
+void UserInputMonitorMac::OnKeyStroke() {
+ UserInputMonitor::OnKeyboardEvent(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN);
+}
+
+UserInputMonitorMacCore::UserInputMonitorMacCore(
+ const UserInputMonitorMac::MouseCallback& mouse_callback,
+ const base::Closure& key_stroke_callback)
+ : mouse_callback_(mouse_callback),
+ key_stroke_callback_(key_stroke_callback),
+ helper_(nil),
+ polling_key_state_(false) {}
+
+void UserInputMonitorMacCore::StartMonitoringMouse() {
+ helper_ = [[UserInputMonitorMacHelper alloc] initWithMonitor:this];
+}
+
+void UserInputMonitorMacCore::StopMonitoringMouse() {
+ [helper_ invalidate];
+ [helper_ release];
+ helper_ = nil;
+}
+
+void UserInputMonitorMacCore::StartPollingKeyState() {
+ polling_key_state_ = true;
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&UserInputMonitorMacCore::PollKeyState, this),
+ base::TimeDelta::FromMilliseconds(10));
+}
+
+void UserInputMonitorMacCore::StopPollingKeyState() {
+ polling_key_state_ = false;
+}
+
+UserInputMonitorMacCore::~UserInputMonitorMacCore() {
+ DCHECK(helper_ == nil);
+ DCHECK(!polling_key_state_);
+}
+
+void UserInputMonitorMacCore::OnMouseMoved(const SkIPoint& position) {
+ mouse_callback_.Run(position);
+}
+
+void UserInputMonitorMacCore::PollKeyState() {
+ if (!polling_key_state_)
+ return;
+
+ bool key_pressed = false;
+ for (uint key_index = 0;
+ key_index <= sizeof(prev_key_state_)/sizeof(prev_key_state_[0]);
+ ++key_index) {
+ bool key_state = CGEventSourceKeyState(kCGEventSourceStateHIDSystemState,
+ key_index);
+
+ // A false -> true change in keymap means a key is pressed.
+ key_pressed |= (key_state && !prev_key_state_[key_index]);
+ // Save current state.
+ prev_key_state_[key_index] = key_state;
+ }
+
+ if (key_pressed)
+ key_stroke_callback_.Run();
+
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&UserInputMonitorMacCore::PollKeyState, this),
+ base::TimeDelta::FromMilliseconds(10));
+}
+
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>();
+ return scoped_ptr<UserInputMonitor>(new UserInputMonitorMac(ui_task_runner));
}
} // namespace media
+
+static CGEventRef inputEvent(CGEventTapProxy proxy,
+ CGEventType type,
+ CGEventRef event,
+ void* context) {
+ int64_t pid = CGEventGetIntegerValueField(event, kCGEventSourceUnixProcessID);
+ if (pid == 0) {
+ DCHECK(type == kCGEventMouseMoved);
+ CGPoint cgMousePos = CGEventGetLocation(event);
+ SkIPoint mousePos = SkIPoint::Make(cgMousePos.x, cgMousePos.y);
+ [static_cast<UserInputMonitorMacHelper*>(context) mouseMoved:mousePos];
+ }
+ return NULL;
+}
+
+@implementation UserInputMonitorMacHelper
+
+- (id)initWithMonitor:(media::UserInputMonitorMacCore*)monitor {
+ if ((self = [super init])) {
+ monitor_ = monitor;
+ inputMachPort_.reset(CGEventTapCreate(
+ kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly,
+ CGEventMaskBit(kCGEventMouseMoved), inputEvent, self));
+ if (inputMachPort_) {
+ inputRunLoopSource_ = CFMachPortCreateRunLoopSource(
+ NULL, inputMachPort_, 0);
+ CFRunLoopAddSource(
+ CFRunLoopGetMain(), inputRunLoopSource_, kCFRunLoopCommonModes);
+ } else {
+ LOG(ERROR) << "CGEventTapCreate failed.";
+ }
+ if (!inputMachPort_) {
+ [self release];
+ return nil;
+ }
+ }
+ return self;
+}
+
+- (void)mouseMoved:(const SkIPoint&)mousePos {
+ monitor_->OnMouseMoved(mousePos);
+}
+
+- (void)invalidate {
+ if (inputRunLoopSource_) {
+ CFMachPortInvalidate(inputMachPort_);
+ CFRunLoopRemoveSource(
+ CFRunLoopGetMain(), inputRunLoopSource_, kCFRunLoopCommonModes);
+ CFRelease(inputRunLoopSource_);
+ inputMachPort_.reset();
+ inputRunLoopSource_ = NULL;
+ }
+}
+
+@end
« no previous file with comments | « media/base/user_input_monitor.cc ('k') | media/media.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698