Chromium Code Reviews| 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 |