[email protected] | 67f92bc3 | 2012-01-26 01:56:19 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "remoting/host/local_input_monitor.h" |
| 6 | |
| 7 | #import <AppKit/AppKit.h> |
[email protected] | 9895e579 | 2011-10-08 01:57:06 | [diff] [blame] | 8 | #include <set> |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 9 | |
[email protected] | 1e1cb3b | 2011-11-10 02:07:41 | [diff] [blame] | 10 | #include "base/bind.h" |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 11 | #include "base/compiler_specific.h" |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 12 | #include "base/location.h" |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 13 | #include "base/logging.h" |
[email protected] | 3d2a904 | 2011-10-18 20:30:41 | [diff] [blame] | 14 | #include "base/mac/scoped_cftyperef.h" |
[email protected] | 0059eb96d | 2011-12-02 19:39:41 | [diff] [blame] | 15 | #include "base/memory/ref_counted.h" |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 16 | #include "base/single_thread_task_runner.h" |
[email protected] | 9895e579 | 2011-10-08 01:57:06 | [diff] [blame] | 17 | #include "base/synchronization/lock.h" |
[email protected] | b167a7b | 2013-03-25 18:34:40 | [diff] [blame] | 18 | #include "base/threading/non_thread_safe.h" |
| 19 | #include "remoting/host/client_session_control.h" |
[email protected] | a023dca | 2013-12-18 03:58:36 | [diff] [blame] | 20 | #import "third_party/google_toolbox_for_mac/src/AppKit/GTMCarbonEvent.h" |
[email protected] | 8c83a71c | 2013-12-16 18:02:58 | [diff] [blame] | 21 | #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 22 | |
| 23 | // Esc Key Code is 53. |
| 24 | // http://boredzo.org/blog/wp-content/uploads/2007/05/IMTx-virtual-keycodes.pdf |
| 25 | static const NSUInteger kEscKeyCode = 53; |
| 26 | |
[email protected] | 42dcc673 | 2012-05-29 20:35:23 | [diff] [blame] | 27 | namespace remoting { |
[email protected] | 42dcc673 | 2012-05-29 20:35:23 | [diff] [blame] | 28 | namespace { |
| 29 | |
[email protected] | b167a7b | 2013-03-25 18:34:40 | [diff] [blame] | 30 | class LocalInputMonitorMac : public base::NonThreadSafe, |
| 31 | public LocalInputMonitor { |
[email protected] | 42dcc673 | 2012-05-29 20:35:23 | [diff] [blame] | 32 | public: |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 33 | // Invoked by LocalInputMonitorManager. |
| 34 | class EventHandler { |
| 35 | public: |
| 36 | virtual ~EventHandler() {} |
| 37 | |
[email protected] | 8c83a71c | 2013-12-16 18:02:58 | [diff] [blame] | 38 | virtual void OnLocalMouseMoved(const webrtc::DesktopVector& position) = 0; |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 39 | virtual void OnDisconnectShortcut() = 0; |
| 40 | }; |
| 41 | |
| 42 | LocalInputMonitorMac( |
| 43 | scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, |
[email protected] | b167a7b | 2013-03-25 18:34:40 | [diff] [blame] | 44 | scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, |
| 45 | base::WeakPtr<ClientSessionControl> client_session_control); |
[email protected] | 42dcc673 | 2012-05-29 20:35:23 | [diff] [blame] | 46 | virtual ~LocalInputMonitorMac(); |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 47 | |
[email protected] | 42dcc673 | 2012-05-29 20:35:23 | [diff] [blame] | 48 | private: |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 49 | // The actual implementation resides in LocalInputMonitorMac::Core class. |
| 50 | class Core; |
| 51 | scoped_refptr<Core> core_; |
| 52 | |
[email protected] | 42dcc673 | 2012-05-29 20:35:23 | [diff] [blame] | 53 | DISALLOW_COPY_AND_ASSIGN(LocalInputMonitorMac); |
| 54 | }; |
| 55 | |
[email protected] | 42dcc673 | 2012-05-29 20:35:23 | [diff] [blame] | 56 | } // namespace |
[email protected] | 42dcc673 | 2012-05-29 20:35:23 | [diff] [blame] | 57 | } // namespace remoting |
| 58 | |
| 59 | @interface LocalInputMonitorManager : NSObject { |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 60 | @private |
[email protected] | 3d2a904 | 2011-10-18 20:30:41 | [diff] [blame] | 61 | GTMCarbonHotKey* hotKey_; |
| 62 | CFRunLoopSourceRef mouseRunLoopSource_; |
[email protected] | 3df79f4 | 2013-06-24 18:49:05 | [diff] [blame] | 63 | base::ScopedCFTypeRef<CFMachPortRef> mouseMachPort_; |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 64 | remoting::LocalInputMonitorMac::EventHandler* monitor_; |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 65 | } |
| 66 | |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 67 | - (id)initWithMonitor:(remoting::LocalInputMonitorMac::EventHandler*)monitor; |
| 68 | |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 69 | // Called when the hotKey is hit. |
| 70 | - (void)hotKeyHit:(GTMCarbonHotKey*)hotKey; |
| 71 | |
[email protected] | 3d2a904 | 2011-10-18 20:30:41 | [diff] [blame] | 72 | // Called when the local mouse moves |
[email protected] | 8c83a71c | 2013-12-16 18:02:58 | [diff] [blame] | 73 | - (void)localMouseMoved:(const webrtc::DesktopVector&)mousePos; |
[email protected] | 3d2a904 | 2011-10-18 20:30:41 | [diff] [blame] | 74 | |
[email protected] | 42dcc673 | 2012-05-29 20:35:23 | [diff] [blame] | 75 | // Must be called when the LocalInputMonitorManager is no longer to be used. |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 76 | // Similar to NSTimer in that more than a simple release is required. |
| 77 | - (void)invalidate; |
| 78 | |
| 79 | @end |
| 80 | |
[email protected] | 3d2a904 | 2011-10-18 20:30:41 | [diff] [blame] | 81 | static CGEventRef LocalMouseMoved(CGEventTapProxy proxy, CGEventType type, |
| 82 | CGEventRef event, void* context) { |
[email protected] | 06b39315 | 2011-10-21 03:02:41 | [diff] [blame] | 83 | int64_t pid = CGEventGetIntegerValueField(event, kCGEventSourceUnixProcessID); |
| 84 | if (pid == 0) { |
| 85 | CGPoint cgMousePos = CGEventGetLocation(event); |
[email protected] | 8c83a71c | 2013-12-16 18:02:58 | [diff] [blame] | 86 | webrtc::DesktopVector mousePos(cgMousePos.x, cgMousePos.y); |
[email protected] | 42dcc673 | 2012-05-29 20:35:23 | [diff] [blame] | 87 | [static_cast<LocalInputMonitorManager*>(context) localMouseMoved:mousePos]; |
[email protected] | 06b39315 | 2011-10-21 03:02:41 | [diff] [blame] | 88 | } |
[email protected] | 3d2a904 | 2011-10-18 20:30:41 | [diff] [blame] | 89 | return NULL; |
| 90 | } |
| 91 | |
[email protected] | 42dcc673 | 2012-05-29 20:35:23 | [diff] [blame] | 92 | @implementation LocalInputMonitorManager |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 93 | |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 94 | - (id)initWithMonitor:(remoting::LocalInputMonitorMac::EventHandler*)monitor { |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 95 | if ((self = [super init])) { |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 96 | monitor_ = monitor; |
| 97 | |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 98 | GTMCarbonEventDispatcherHandler* handler = |
| 99 | [GTMCarbonEventDispatcherHandler sharedEventDispatcherHandler]; |
[email protected] | 3d2a904 | 2011-10-18 20:30:41 | [diff] [blame] | 100 | hotKey_ = [handler registerHotKey:kEscKeyCode |
[email protected] | f67e2a5 | 2011-10-07 18:45:37 | [diff] [blame] | 101 | modifiers:(NSAlternateKeyMask | NSControlKeyMask) |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 102 | target:self |
| 103 | action:@selector(hotKeyHit:) |
| 104 | userInfo:nil |
| 105 | whenPressed:YES]; |
[email protected] | 3d2a904 | 2011-10-18 20:30:41 | [diff] [blame] | 106 | if (!hotKey_) { |
| 107 | LOG(ERROR) << "registerHotKey failed."; |
| 108 | } |
[email protected] | f1e98188 | 2011-11-23 23:33:42 | [diff] [blame] | 109 | mouseMachPort_.reset(CGEventTapCreate( |
[email protected] | 3d2a904 | 2011-10-18 20:30:41 | [diff] [blame] | 110 | kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly, |
| 111 | 1 << kCGEventMouseMoved, LocalMouseMoved, self)); |
[email protected] | f1e98188 | 2011-11-23 23:33:42 | [diff] [blame] | 112 | if (mouseMachPort_) { |
[email protected] | 3d2a904 | 2011-10-18 20:30:41 | [diff] [blame] | 113 | mouseRunLoopSource_ = CFMachPortCreateRunLoopSource( |
[email protected] | f1e98188 | 2011-11-23 23:33:42 | [diff] [blame] | 114 | NULL, mouseMachPort_, 0); |
[email protected] | 3d2a904 | 2011-10-18 20:30:41 | [diff] [blame] | 115 | CFRunLoopAddSource( |
| 116 | CFRunLoopGetMain(), mouseRunLoopSource_, kCFRunLoopCommonModes); |
| 117 | } else { |
| 118 | LOG(ERROR) << "CGEventTapCreate failed."; |
| 119 | } |
[email protected] | f1e98188 | 2011-11-23 23:33:42 | [diff] [blame] | 120 | if (!hotKey_ && !mouseMachPort_) { |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 121 | [self release]; |
| 122 | return nil; |
| 123 | } |
| 124 | } |
| 125 | return self; |
| 126 | } |
| 127 | |
| 128 | - (void)hotKeyHit:(GTMCarbonHotKey*)hotKey { |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 129 | monitor_->OnDisconnectShortcut(); |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 130 | } |
| 131 | |
[email protected] | 8c83a71c | 2013-12-16 18:02:58 | [diff] [blame] | 132 | - (void)localMouseMoved:(const webrtc::DesktopVector&)mousePos { |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 133 | monitor_->OnLocalMouseMoved(mousePos); |
[email protected] | 3d2a904 | 2011-10-18 20:30:41 | [diff] [blame] | 134 | } |
| 135 | |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 136 | - (void)invalidate { |
[email protected] | 3d2a904 | 2011-10-18 20:30:41 | [diff] [blame] | 137 | if (hotKey_) { |
| 138 | GTMCarbonEventDispatcherHandler* handler = |
| 139 | [GTMCarbonEventDispatcherHandler sharedEventDispatcherHandler]; |
| 140 | [handler unregisterHotKey:hotKey_]; |
| 141 | hotKey_ = NULL; |
| 142 | } |
| 143 | if (mouseRunLoopSource_) { |
[email protected] | f1e98188 | 2011-11-23 23:33:42 | [diff] [blame] | 144 | CFMachPortInvalidate(mouseMachPort_); |
[email protected] | 3d2a904 | 2011-10-18 20:30:41 | [diff] [blame] | 145 | CFRunLoopRemoveSource( |
| 146 | CFRunLoopGetMain(), mouseRunLoopSource_, kCFRunLoopCommonModes); |
| 147 | CFRelease(mouseRunLoopSource_); |
[email protected] | f1e98188 | 2011-11-23 23:33:42 | [diff] [blame] | 148 | mouseMachPort_.reset(0); |
[email protected] | 3d2a904 | 2011-10-18 20:30:41 | [diff] [blame] | 149 | mouseRunLoopSource_ = NULL; |
| 150 | } |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 151 | } |
| 152 | |
| 153 | @end |
| 154 | |
[email protected] | 3361e1f | 2012-03-20 20:31:44 | [diff] [blame] | 155 | namespace remoting { |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 156 | namespace { |
| 157 | |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 158 | class LocalInputMonitorMac::Core |
| 159 | : public base::RefCountedThreadSafe<Core>, |
| 160 | public EventHandler { |
| 161 | public: |
| 162 | Core(scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, |
[email protected] | b167a7b | 2013-03-25 18:34:40 | [diff] [blame] | 163 | scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, |
| 164 | base::WeakPtr<ClientSessionControl> client_session_control); |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 165 | |
[email protected] | b167a7b | 2013-03-25 18:34:40 | [diff] [blame] | 166 | void Start(); |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 167 | void Stop(); |
| 168 | |
| 169 | private: |
| 170 | friend class base::RefCountedThreadSafe<Core>; |
| 171 | virtual ~Core(); |
| 172 | |
| 173 | void StartOnUiThread(); |
| 174 | void StopOnUiThread(); |
| 175 | |
| 176 | // EventHandler interface. |
[email protected] | 8c83a71c | 2013-12-16 18:02:58 | [diff] [blame] | 177 | virtual void OnLocalMouseMoved( |
| 178 | const webrtc::DesktopVector& position) OVERRIDE; |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 179 | virtual void OnDisconnectShortcut() OVERRIDE; |
| 180 | |
| 181 | // Task runner on which public methods of this class must be called. |
| 182 | scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_; |
| 183 | |
| 184 | // Task runner on which |window_| is created. |
| 185 | scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; |
| 186 | |
| 187 | LocalInputMonitorManager* manager_; |
| 188 | |
[email protected] | b167a7b | 2013-03-25 18:34:40 | [diff] [blame] | 189 | // Invoked in the |caller_task_runner_| thread to report local mouse events |
| 190 | // and session disconnect requests. |
| 191 | base::WeakPtr<ClientSessionControl> client_session_control_; |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 192 | |
| 193 | DISALLOW_COPY_AND_ASSIGN(Core); |
| 194 | }; |
| 195 | |
| 196 | LocalInputMonitorMac::LocalInputMonitorMac( |
| 197 | scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, |
[email protected] | b167a7b | 2013-03-25 18:34:40 | [diff] [blame] | 198 | scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, |
| 199 | base::WeakPtr<ClientSessionControl> client_session_control) |
| 200 | : core_(new Core(caller_task_runner, |
| 201 | ui_task_runner, |
| 202 | client_session_control)) { |
| 203 | core_->Start(); |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 204 | } |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 205 | |
| 206 | LocalInputMonitorMac::~LocalInputMonitorMac() { |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 207 | core_->Stop(); |
| 208 | } |
| 209 | |
| 210 | LocalInputMonitorMac::Core::Core( |
| 211 | scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, |
[email protected] | b167a7b | 2013-03-25 18:34:40 | [diff] [blame] | 212 | scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, |
| 213 | base::WeakPtr<ClientSessionControl> client_session_control) |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 214 | : caller_task_runner_(caller_task_runner), |
| 215 | ui_task_runner_(ui_task_runner), |
| 216 | manager_(nil), |
[email protected] | b167a7b | 2013-03-25 18:34:40 | [diff] [blame] | 217 | client_session_control_(client_session_control) { |
[email protected] | fd7d379 | 2013-06-07 08:43:27 | [diff] [blame] | 218 | DCHECK(client_session_control_); |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 219 | } |
| 220 | |
[email protected] | b167a7b | 2013-03-25 18:34:40 | [diff] [blame] | 221 | void LocalInputMonitorMac::Core::Start() { |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 222 | DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 223 | |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 224 | ui_task_runner_->PostTask(FROM_HERE, |
| 225 | base::Bind(&Core::StartOnUiThread, this)); |
| 226 | } |
| 227 | |
| 228 | void LocalInputMonitorMac::Core::Stop() { |
| 229 | DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 230 | |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 231 | ui_task_runner_->PostTask(FROM_HERE, base::Bind(&Core::StopOnUiThread, this)); |
| 232 | } |
| 233 | |
| 234 | LocalInputMonitorMac::Core::~Core() { |
| 235 | DCHECK(manager_ == nil); |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 236 | } |
| 237 | |
| 238 | void LocalInputMonitorMac::Core::StartOnUiThread() { |
| 239 | DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 240 | |
| 241 | manager_ = [[LocalInputMonitorManager alloc] initWithMonitor:this]; |
| 242 | } |
| 243 | |
| 244 | void LocalInputMonitorMac::Core::StopOnUiThread() { |
| 245 | DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 246 | |
| 247 | [manager_ invalidate]; |
| 248 | [manager_ release]; |
| 249 | manager_ = nil; |
| 250 | } |
| 251 | |
[email protected] | 8c83a71c | 2013-12-16 18:02:58 | [diff] [blame] | 252 | void LocalInputMonitorMac::Core::OnLocalMouseMoved( |
| 253 | const webrtc::DesktopVector& position) { |
[email protected] | b167a7b | 2013-03-25 18:34:40 | [diff] [blame] | 254 | caller_task_runner_->PostTask( |
| 255 | FROM_HERE, base::Bind(&ClientSessionControl::OnLocalMouseMoved, |
| 256 | client_session_control_, |
| 257 | position)); |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 258 | } |
| 259 | |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 260 | void LocalInputMonitorMac::Core::OnDisconnectShortcut() { |
[email protected] | b167a7b | 2013-03-25 18:34:40 | [diff] [blame] | 261 | caller_task_runner_->PostTask( |
| 262 | FROM_HERE, base::Bind(&ClientSessionControl::DisconnectSession, |
| 263 | client_session_control_)); |
[email protected] | 42dcc673 | 2012-05-29 20:35:23 | [diff] [blame] | 264 | } |
| 265 | |
| 266 | } // namespace |
| 267 | |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 268 | scoped_ptr<LocalInputMonitor> LocalInputMonitor::Create( |
| 269 | scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, |
| 270 | scoped_refptr<base::SingleThreadTaskRunner> input_task_runner, |
[email protected] | b167a7b | 2013-03-25 18:34:40 | [diff] [blame] | 271 | scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, |
| 272 | base::WeakPtr<ClientSessionControl> client_session_control) { |
[email protected] | ceffbde | 2013-03-14 14:54:39 | [diff] [blame] | 273 | return scoped_ptr<LocalInputMonitor>( |
[email protected] | b167a7b | 2013-03-25 18:34:40 | [diff] [blame] | 274 | new LocalInputMonitorMac(caller_task_runner, |
| 275 | ui_task_runner, |
| 276 | client_session_control)); |
[email protected] | eccefee | 2011-08-02 15:31:40 | [diff] [blame] | 277 | } |
[email protected] | 3361e1f | 2012-03-20 20:31:44 | [diff] [blame] | 278 | |
| 279 | } // namespace remoting |