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..98ec79271db2b993138c7250c2d82920a420cf58 100644 |
--- a/media/base/user_input_monitor_mac.mm |
+++ b/media/base/user_input_monitor_mac.mm |
@@ -4,13 +4,207 @@ |
#include "media/base/user_input_monitor.h" |
+#import <AppKit/AppKit.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/single_thread_task_runner.h" |
+#include "base/threading/non_thread_safe.h" |
+#include "third_party/skia/include/core/SkPoint.h" |
+#import "third_party/GTM/AppKit/GTMCarbonEvent.h" |
+ |
+namespace media { |
+namespace { |
+ |
+class UserInputMonitorMac : public base::NonThreadSafe, |
+ public UserInputMonitor { |
+ public: |
+ // Invoked by UserInputMonitorManager. |
+ class EventHandler { |
Sergey Ulanov
2013/08/20 00:55:41
Do you need this interface? Can you just reference
jiayl
2013/08/20 23:49:05
I rearranged the code to get rid of the interface.
|
+ public: |
+ virtual ~EventHandler() {} |
+ |
+ virtual void OnMouseMoved(const SkIPoint& position) = 0; |
+ }; |
+ |
+ UserInputMonitorMac( |
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner); |
+ |
+ virtual ~UserInputMonitorMac(); |
+ |
+ private: |
+ // The actual implementation resides in UserInputMonitorMac::Core class. |
+ // Only called on the UI task runner. |
+ class Core; |
+ typedef const base::Callback<void(const SkIPoint&)> MouseCallback; |
+ |
+ virtual void StartMouseMonitoring() OVERRIDE; |
+ virtual void StopMouseMonitoring() OVERRIDE; |
+ virtual void StartKeyboardMonitoring() OVERRIDE { NOTREACHED(); } |
+ virtual void StopKeyboardMonitoring() OVERRIDE { NOTREACHED(); } |
+ |
+ void OnMouseMoved(const SkIPoint& position); |
+ |
+ // Task runner on which X Window events are received. |
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; |
+ |
+ scoped_refptr<Core> core_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(UserInputMonitorMac); |
+}; |
+ |
+} // namespace |
+} // namespace media |
+ |
+@interface UserInputMonitorManager : NSObject { |
+ @private |
+ CFRunLoopSourceRef inputRunLoopSource_; |
+ base::ScopedCFTypeRef<CFMachPortRef> inputMachPort_; |
+ media::UserInputMonitorMac::EventHandler* monitor_; |
+} |
+ |
+- (id)initWithMonitor:(media::UserInputMonitorMac::EventHandler*)monitor; |
+ |
+// Called when the local mouse moves. |
+- (void)mouseMoved:(const SkIPoint&)mousePos; |
+ |
+// Must be called when the UserInputMonitorManager is no longer to be used. |
DaleCurtis
2013/08/19 23:49:00
UserInputMonitorManager?
jiayl
2013/08/20 00:21:15
Renamed
|
+// Similar to NSTimer in that more than a simple release is required. |
+- (void)invalidate; |
+ |
+@end |
+ |
+static CGEventRef inputEvent(CGEventTapProxy proxy, CGEventType type, |
Sergey Ulanov
2013/08/20 00:55:41
nit: one argument per line please.
jiayl
2013/08/20 23:49:05
Done.
|
+ CGEventRef event, void* context) { |
Sergey Ulanov
2013/08/20 00:55:41
why is it void*?
jiayl
2013/08/20 23:49:05
This is required by the CGEventTapCreate API.
|
+ 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<UserInputMonitorManager*>(context) mouseMoved:mousePos]; |
+ } |
+ return NULL; |
+} |
+ |
+@implementation UserInputMonitorManager |
+ |
+- (id)initWithMonitor:(media::UserInputMonitorMac::EventHandler*)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(0); |
Sergey Ulanov
2013/08/20 00:55:41
remove 0 - it's default.
jiayl
2013/08/20 23:49:05
Done.
|
+ inputRunLoopSource_ = NULL; |
+ } |
+} |
+ |
+@end |
+ |
namespace media { |
+namespace { |
+ |
+class UserInputMonitorMac::Core |
+ : public base::RefCountedThreadSafe<Core>, |
+ public EventHandler { |
+ public: |
+ Core(const MouseCallback& callback); |
+ |
+ void Start(); |
+ void Stop(); |
+ |
+ private: |
+ friend class base::RefCountedThreadSafe<Core>; |
+ virtual ~Core(); |
+ |
+ // EventHandler interface. |
+ virtual void OnMouseMoved(const SkIPoint& position) OVERRIDE; |
+ |
+ MouseCallback callback_; |
+ UserInputMonitorManager* manager_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(Core); |
+}; |
+ |
+UserInputMonitorMac::UserInputMonitorMac( |
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) |
+ : ui_task_runner_(ui_task_runner), |
+ core_(new Core(base::Bind(&UserInputMonitorMac::OnMouseMoved, |
+ base::Unretained(this)))) {} |
+ |
+UserInputMonitorMac::~UserInputMonitorMac() {} |
+ |
+void UserInputMonitorMac::StartMouseMonitoring() { |
+ ui_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&Core::Start, core_.get())); |
+} |
+ |
+void UserInputMonitorMac::StopMouseMonitoring() { |
+ ui_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&Core::Stop, core_.get())); |
+} |
+ |
+void UserInputMonitorMac::OnMouseMoved(const SkIPoint& position) { |
+ UserInputMonitor::OnMouseEvent(position); |
+} |
+ |
+UserInputMonitorMac::Core::Core(const MouseCallback& callback) |
+ : callback_(callback), manager_(nil) {} |
+ |
+void UserInputMonitorMac::Core::Start() { |
+ manager_ = [[UserInputMonitorManager alloc] initWithMonitor:this]; |
+} |
+ |
+void UserInputMonitorMac::Core::Stop() { |
+ [manager_ invalidate]; |
+ [manager_ release]; |
+ manager_ = nil; |
+} |
+ |
+UserInputMonitorMac::Core::~Core() { |
+ DCHECK(manager_ == nil); |
+} |
+ |
+void UserInputMonitorMac::Core::OnMouseMoved(const SkIPoint& position) { |
+ callback_.Run(position); |
+} |
+ |
+} // namespace |
-// 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>(); |
+ return scoped_ptr<UserInputMonitor>(new UserInputMonitorMac(ui_task_runner)); |
} |
} // namespace media |