| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/host/local_input_monitor.h" | 5 #include "remoting/host/local_input_monitor.h" |
| 6 | 6 |
| 7 #import <AppKit/AppKit.h> | 7 #import <AppKit/AppKit.h> |
| 8 #include <set> | 8 #include <set> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/compiler_specific.h" | 11 #include "base/compiler_specific.h" |
| 12 #include "base/lazy_instance.h" | 12 #include "base/lazy_instance.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/mac/scoped_cftyperef.h" | 14 #include "base/mac/scoped_cftyperef.h" |
| 15 #include "base/memory/ref_counted.h" | 15 #include "base/memory/ref_counted.h" |
| 16 #include "base/synchronization/lock.h" | 16 #include "base/synchronization/lock.h" |
| 17 #include "remoting/host/chromoting_host.h" | 17 #include "remoting/host/mouse_move_observer.h" |
| 18 #include "third_party/skia/include/core/SkPoint.h" |
| 18 #import "third_party/GTM/AppKit/GTMCarbonEvent.h" | 19 #import "third_party/GTM/AppKit/GTMCarbonEvent.h" |
| 19 | 20 |
| 20 // Esc Key Code is 53. | 21 // Esc Key Code is 53. |
| 21 // http://boredzo.org/blog/wp-content/uploads/2007/05/IMTx-virtual-keycodes.pdf | 22 // http://boredzo.org/blog/wp-content/uploads/2007/05/IMTx-virtual-keycodes.pdf |
| 22 static const NSUInteger kEscKeyCode = 53; | 23 static const NSUInteger kEscKeyCode = 53; |
| 23 | 24 |
| 25 namespace remoting { |
| 26 |
| 24 namespace { | 27 namespace { |
| 25 typedef std::set<scoped_refptr<remoting::ChromotingHost> > Hosts; | |
| 26 } | |
| 27 | 28 |
| 28 @interface LocalInputMonitorImpl : NSObject { | 29 class LocalInputMonitorMac : public LocalInputMonitor { |
| 30 public: |
| 31 LocalInputMonitorMac() : mouse_move_observer_(NULL) {} |
| 32 virtual ~LocalInputMonitorMac(); |
| 33 virtual void Start(MouseMoveObserver* mouse_move_observer, |
| 34 const base::Closure& disconnect_callback) OVERRIDE; |
| 35 virtual void Stop() OVERRIDE; |
| 36 |
| 37 void OnLocalMouseMoved(const SkIPoint& new_pos); |
| 38 void OnDisconnectShortcut(); |
| 39 |
| 40 private: |
| 41 MouseMoveObserver* mouse_move_observer_; |
| 42 base::Closure disconnect_callback_; |
| 43 DISALLOW_COPY_AND_ASSIGN(LocalInputMonitorMac); |
| 44 }; |
| 45 |
| 46 typedef std::set<remoting::LocalInputMonitorMac*> LocalInputMonitors; |
| 47 |
| 48 } // namespace |
| 49 |
| 50 } // namespace remoting |
| 51 |
| 52 @interface LocalInputMonitorManager : NSObject { |
| 29 @private | 53 @private |
| 30 GTMCarbonHotKey* hotKey_; | 54 GTMCarbonHotKey* hotKey_; |
| 31 CFRunLoopSourceRef mouseRunLoopSource_; | 55 CFRunLoopSourceRef mouseRunLoopSource_; |
| 32 base::mac::ScopedCFTypeRef<CFMachPortRef> mouseMachPort_; | 56 base::mac::ScopedCFTypeRef<CFMachPortRef> mouseMachPort_; |
| 33 base::Lock hostsLock_; | 57 base::Lock lock_; |
| 34 Hosts hosts_; | 58 remoting::LocalInputMonitors monitors_; |
| 35 } | 59 } |
| 36 | 60 |
| 37 // Called when the hotKey is hit. | 61 // Called when the hotKey is hit. |
| 38 - (void)hotKeyHit:(GTMCarbonHotKey*)hotKey; | 62 - (void)hotKeyHit:(GTMCarbonHotKey*)hotKey; |
| 39 | 63 |
| 40 // Called when the local mouse moves | 64 // Called when the local mouse moves |
| 41 - (void)localMouseMoved:(const SkIPoint&)mousePos; | 65 - (void)localMouseMoved:(const SkIPoint&)mousePos; |
| 42 | 66 |
| 43 // Must be called when the LocalInputMonitorImpl is no longer to be used. | 67 // Must be called when the LocalInputMonitorManager is no longer to be used. |
| 44 // Similar to NSTimer in that more than a simple release is required. | 68 // Similar to NSTimer in that more than a simple release is required. |
| 45 - (void)invalidate; | 69 - (void)invalidate; |
| 46 | 70 |
| 47 // Called to add a host to the list of those to be Shutdown() when the hotkey | 71 // Called to add a monitor. |
| 48 // is pressed. | 72 - (void)addMonitor:(remoting::LocalInputMonitorMac*)monitor; |
| 49 - (void)addHost:(remoting::ChromotingHost*)host; | |
| 50 | 73 |
| 51 // Called to remove a host. Returns true if it was the last host being | 74 // Called to remove a monitor. Returns true if it was the last |
| 52 // monitored, in which case the object should be destroyed. | 75 // monitor, in which case the object should be destroyed. |
| 53 - (bool)removeHost:(remoting::ChromotingHost*)host; | 76 - (bool)removeMonitor:(remoting::LocalInputMonitorMac*)monitor; |
| 54 | |
| 55 // Disabled disconnection keyboard shortcut. | |
| 56 - (void)disableShortcut; | |
| 57 | 77 |
| 58 @end | 78 @end |
| 59 | 79 |
| 60 static CGEventRef LocalMouseMoved(CGEventTapProxy proxy, CGEventType type, | 80 static CGEventRef LocalMouseMoved(CGEventTapProxy proxy, CGEventType type, |
| 61 CGEventRef event, void* context) { | 81 CGEventRef event, void* context) { |
| 62 int64_t pid = CGEventGetIntegerValueField(event, kCGEventSourceUnixProcessID); | 82 int64_t pid = CGEventGetIntegerValueField(event, kCGEventSourceUnixProcessID); |
| 63 if (pid == 0) { | 83 if (pid == 0) { |
| 64 CGPoint cgMousePos = CGEventGetLocation(event); | 84 CGPoint cgMousePos = CGEventGetLocation(event); |
| 65 SkIPoint mousePos = SkIPoint::Make(cgMousePos.x, cgMousePos.y); | 85 SkIPoint mousePos = SkIPoint::Make(cgMousePos.x, cgMousePos.y); |
| 66 [static_cast<LocalInputMonitorImpl*>(context) localMouseMoved:mousePos]; | 86 [static_cast<LocalInputMonitorManager*>(context) localMouseMoved:mousePos]; |
| 67 } | 87 } |
| 68 return NULL; | 88 return NULL; |
| 69 } | 89 } |
| 70 | 90 |
| 71 @implementation LocalInputMonitorImpl | 91 @implementation LocalInputMonitorManager |
| 72 | 92 |
| 73 - (id)init { | 93 - (id)init { |
| 74 if ((self = [super init])) { | 94 if ((self = [super init])) { |
| 75 GTMCarbonEventDispatcherHandler* handler = | 95 GTMCarbonEventDispatcherHandler* handler = |
| 76 [GTMCarbonEventDispatcherHandler sharedEventDispatcherHandler]; | 96 [GTMCarbonEventDispatcherHandler sharedEventDispatcherHandler]; |
| 77 hotKey_ = [handler registerHotKey:kEscKeyCode | 97 hotKey_ = [handler registerHotKey:kEscKeyCode |
| 78 modifiers:(NSAlternateKeyMask | NSControlKeyMask) | 98 modifiers:(NSAlternateKeyMask | NSControlKeyMask) |
| 79 target:self | 99 target:self |
| 80 action:@selector(hotKeyHit:) | 100 action:@selector(hotKeyHit:) |
| 81 userInfo:nil | 101 userInfo:nil |
| (...skipping 14 matching lines...) Expand all Loading... |
| 96 } | 116 } |
| 97 if (!hotKey_ && !mouseMachPort_) { | 117 if (!hotKey_ && !mouseMachPort_) { |
| 98 [self release]; | 118 [self release]; |
| 99 return nil; | 119 return nil; |
| 100 } | 120 } |
| 101 } | 121 } |
| 102 return self; | 122 return self; |
| 103 } | 123 } |
| 104 | 124 |
| 105 - (void)hotKeyHit:(GTMCarbonHotKey*)hotKey { | 125 - (void)hotKeyHit:(GTMCarbonHotKey*)hotKey { |
| 106 base::AutoLock lock(hostsLock_); | 126 base::AutoLock lock(lock_); |
| 107 for (Hosts::const_iterator i = hosts_.begin(); i != hosts_.end(); ++i) { | 127 for (remoting::LocalInputMonitors::const_iterator i = monitors_.begin(); |
| 108 (*i)->Shutdown(base::Closure()); | 128 i != monitors_.end(); ++i) { |
| 129 (*i)->OnDisconnectShortcut(); |
| 109 } | 130 } |
| 110 } | 131 } |
| 111 | 132 |
| 112 - (void)localMouseMoved:(const SkIPoint&)mousePos { | 133 - (void)localMouseMoved:(const SkIPoint&)mousePos { |
| 113 base::AutoLock lock(hostsLock_); | 134 base::AutoLock lock(lock_); |
| 114 for (Hosts::const_iterator i = hosts_.begin(); i != hosts_.end(); ++i) { | 135 for (remoting::LocalInputMonitors::const_iterator i = monitors_.begin(); |
| 115 (*i)->LocalMouseMoved(mousePos); | 136 i != monitors_.end(); ++i) { |
| 137 (*i)->OnLocalMouseMoved(mousePos); |
| 116 } | 138 } |
| 117 } | 139 } |
| 118 | 140 |
| 119 - (void)invalidate { | 141 - (void)invalidate { |
| 120 if (hotKey_) { | 142 if (hotKey_) { |
| 121 GTMCarbonEventDispatcherHandler* handler = | 143 GTMCarbonEventDispatcherHandler* handler = |
| 122 [GTMCarbonEventDispatcherHandler sharedEventDispatcherHandler]; | 144 [GTMCarbonEventDispatcherHandler sharedEventDispatcherHandler]; |
| 123 [handler unregisterHotKey:hotKey_]; | 145 [handler unregisterHotKey:hotKey_]; |
| 124 hotKey_ = NULL; | 146 hotKey_ = NULL; |
| 125 } | 147 } |
| 126 if (mouseRunLoopSource_) { | 148 if (mouseRunLoopSource_) { |
| 127 CFMachPortInvalidate(mouseMachPort_); | 149 CFMachPortInvalidate(mouseMachPort_); |
| 128 CFRunLoopRemoveSource( | 150 CFRunLoopRemoveSource( |
| 129 CFRunLoopGetMain(), mouseRunLoopSource_, kCFRunLoopCommonModes); | 151 CFRunLoopGetMain(), mouseRunLoopSource_, kCFRunLoopCommonModes); |
| 130 CFRelease(mouseRunLoopSource_); | 152 CFRelease(mouseRunLoopSource_); |
| 131 mouseMachPort_.reset(0); | 153 mouseMachPort_.reset(0); |
| 132 mouseRunLoopSource_ = NULL; | 154 mouseRunLoopSource_ = NULL; |
| 133 } | 155 } |
| 134 } | 156 } |
| 135 | 157 |
| 136 - (void)addHost:(remoting::ChromotingHost*)host { | 158 - (void)addMonitor:(remoting::LocalInputMonitorMac*)monitor { |
| 137 base::AutoLock lock(hostsLock_); | 159 base::AutoLock lock(lock_); |
| 138 hosts_.insert(host); | 160 monitors_.insert(monitor); |
| 139 } | 161 } |
| 140 | 162 |
| 141 - (bool)removeHost:(remoting::ChromotingHost*)host { | 163 - (bool)removeMonitor:(remoting::LocalInputMonitorMac*)monitor { |
| 142 base::AutoLock lock(hostsLock_); | 164 base::AutoLock lock(lock_); |
| 143 hosts_.erase(host); | 165 monitors_.erase(monitor); |
| 144 return hosts_.empty(); | 166 return monitors_.empty(); |
| 145 } | |
| 146 | |
| 147 - (void)disableShortcut { | |
| 148 if (hotKey_) { | |
| 149 GTMCarbonEventDispatcherHandler* handler = | |
| 150 [GTMCarbonEventDispatcherHandler sharedEventDispatcherHandler]; | |
| 151 [handler unregisterHotKey:hotKey_]; | |
| 152 hotKey_ = NULL; | |
| 153 } | |
| 154 } | 167 } |
| 155 | 168 |
| 156 @end | 169 @end |
| 157 | 170 |
| 158 namespace remoting { | 171 namespace remoting { |
| 159 | 172 |
| 160 namespace { | 173 namespace { |
| 161 | 174 |
| 162 class LocalInputMonitorMac : public LocalInputMonitor { | 175 base::LazyInstance<base::Lock>::Leaky g_monitor_lock = |
| 163 public: | 176 LAZY_INSTANCE_INITIALIZER; |
| 164 LocalInputMonitorMac() : host_(NULL) {} | 177 LocalInputMonitorManager* g_local_input_monitor_manager = NULL; |
| 165 virtual ~LocalInputMonitorMac(); | |
| 166 virtual void Start(ChromotingHost* host) OVERRIDE; | |
| 167 virtual void Stop() OVERRIDE; | |
| 168 virtual void DisableShortcutOnMac() OVERRIDE; | |
| 169 | |
| 170 private: | |
| 171 ChromotingHost* host_; | |
| 172 DISALLOW_COPY_AND_ASSIGN(LocalInputMonitorMac); | |
| 173 }; | |
| 174 | |
| 175 base::LazyInstance<base::Lock>::Leaky monitor_lock = LAZY_INSTANCE_INITIALIZER; | |
| 176 LocalInputMonitorImpl* local_input_monitor = NULL; | |
| 177 | |
| 178 } // namespace | |
| 179 | 178 |
| 180 LocalInputMonitorMac::~LocalInputMonitorMac() { | 179 LocalInputMonitorMac::~LocalInputMonitorMac() { |
| 181 Stop(); | 180 Stop(); |
| 182 } | 181 } |
| 183 | 182 |
| 184 void LocalInputMonitorMac::Start(ChromotingHost* host) { | 183 void LocalInputMonitorMac::Start(MouseMoveObserver* mouse_move_observer, |
| 185 base::AutoLock lock(monitor_lock.Get()); | 184 const base::Closure& disconnect_callback) { |
| 186 if (!local_input_monitor) | 185 base::AutoLock lock(g_monitor_lock.Get()); |
| 187 local_input_monitor = [[LocalInputMonitorImpl alloc] init]; | 186 if (!g_local_input_monitor_manager) |
| 188 CHECK(local_input_monitor); | 187 g_local_input_monitor_manager = [[LocalInputMonitorManager alloc] init]; |
| 189 [local_input_monitor addHost:host]; | 188 CHECK(g_local_input_monitor_manager); |
| 190 host_ = host; | 189 mouse_move_observer_ = mouse_move_observer; |
| 190 disconnect_callback_ = disconnect_callback; |
| 191 [g_local_input_monitor_manager addMonitor:this]; |
| 191 } | 192 } |
| 192 | 193 |
| 193 void LocalInputMonitorMac::Stop() { | 194 void LocalInputMonitorMac::Stop() { |
| 194 base::AutoLock lock(monitor_lock.Get()); | 195 base::AutoLock lock(g_monitor_lock.Get()); |
| 195 if ([local_input_monitor removeHost:host_]) { | 196 if ([g_local_input_monitor_manager removeMonitor:this]) { |
| 196 [local_input_monitor invalidate]; | 197 [g_local_input_monitor_manager invalidate]; |
| 197 [local_input_monitor release]; | 198 [g_local_input_monitor_manager release]; |
| 198 local_input_monitor = nil; | 199 g_local_input_monitor_manager = nil; |
| 199 } | 200 } |
| 200 } | 201 } |
| 201 | 202 |
| 202 void LocalInputMonitorMac::DisableShortcutOnMac() { | 203 void LocalInputMonitorMac::OnLocalMouseMoved(const SkIPoint& new_pos) { |
| 203 [local_input_monitor disableShortcut]; | 204 mouse_move_observer_->OnLocalMouseMoved(new_pos); |
| 204 } | 205 } |
| 205 | 206 |
| 207 void LocalInputMonitorMac::OnDisconnectShortcut() { |
| 208 disconnect_callback_.Run(); |
| 209 } |
| 210 |
| 211 } // namespace |
| 212 |
| 206 scoped_ptr<LocalInputMonitor> LocalInputMonitor::Create() { | 213 scoped_ptr<LocalInputMonitor> LocalInputMonitor::Create() { |
| 207 return scoped_ptr<LocalInputMonitor>(new LocalInputMonitorMac()); | 214 return scoped_ptr<LocalInputMonitor>(new LocalInputMonitorMac()); |
| 208 } | 215 } |
| 209 | 216 |
| 210 } // namespace remoting | 217 } // namespace remoting |
| OLD | NEW |