blob: 1e89587005ba9ce48659874ef56eac2d38ebcb45 [file] [log] [blame]
[email protected]67f92bc32012-01-26 01:56:191// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]eccefee2011-08-02 15:31:402// 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]9895e5792011-10-08 01:57:068#include <set>
[email protected]eccefee2011-08-02 15:31:409
[email protected]1e1cb3b2011-11-10 02:07:4110#include "base/bind.h"
[email protected]eccefee2011-08-02 15:31:4011#include "base/compiler_specific.h"
[email protected]ceffbde2013-03-14 14:54:3912#include "base/location.h"
[email protected]eccefee2011-08-02 15:31:4013#include "base/logging.h"
[email protected]3d2a9042011-10-18 20:30:4114#include "base/mac/scoped_cftyperef.h"
[email protected]0059eb96d2011-12-02 19:39:4115#include "base/memory/ref_counted.h"
[email protected]ceffbde2013-03-14 14:54:3916#include "base/single_thread_task_runner.h"
[email protected]9895e5792011-10-08 01:57:0617#include "base/synchronization/lock.h"
[email protected]b167a7b2013-03-25 18:34:4018#include "base/threading/non_thread_safe.h"
19#include "remoting/host/client_session_control.h"
[email protected]a023dca2013-12-18 03:58:3620#import "third_party/google_toolbox_for_mac/src/AppKit/GTMCarbonEvent.h"
[email protected]8c83a71c2013-12-16 18:02:5821#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
[email protected]eccefee2011-08-02 15:31:4022
23// Esc Key Code is 53.
24// http://boredzo.org/blog/wp-content/uploads/2007/05/IMTx-virtual-keycodes.pdf
25static const NSUInteger kEscKeyCode = 53;
26
[email protected]42dcc6732012-05-29 20:35:2327namespace remoting {
[email protected]42dcc6732012-05-29 20:35:2328namespace {
29
[email protected]b167a7b2013-03-25 18:34:4030class LocalInputMonitorMac : public base::NonThreadSafe,
31 public LocalInputMonitor {
[email protected]42dcc6732012-05-29 20:35:2332 public:
[email protected]ceffbde2013-03-14 14:54:3933 // Invoked by LocalInputMonitorManager.
34 class EventHandler {
35 public:
36 virtual ~EventHandler() {}
37
[email protected]8c83a71c2013-12-16 18:02:5838 virtual void OnLocalMouseMoved(const webrtc::DesktopVector& position) = 0;
[email protected]ceffbde2013-03-14 14:54:3939 virtual void OnDisconnectShortcut() = 0;
40 };
41
42 LocalInputMonitorMac(
43 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
[email protected]b167a7b2013-03-25 18:34:4044 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
45 base::WeakPtr<ClientSessionControl> client_session_control);
[email protected]42dcc6732012-05-29 20:35:2346 virtual ~LocalInputMonitorMac();
[email protected]ceffbde2013-03-14 14:54:3947
[email protected]42dcc6732012-05-29 20:35:2348 private:
[email protected]ceffbde2013-03-14 14:54:3949 // The actual implementation resides in LocalInputMonitorMac::Core class.
50 class Core;
51 scoped_refptr<Core> core_;
52
[email protected]42dcc6732012-05-29 20:35:2353 DISALLOW_COPY_AND_ASSIGN(LocalInputMonitorMac);
54};
55
[email protected]42dcc6732012-05-29 20:35:2356} // namespace
[email protected]42dcc6732012-05-29 20:35:2357} // namespace remoting
58
59@interface LocalInputMonitorManager : NSObject {
[email protected]eccefee2011-08-02 15:31:4060 @private
[email protected]3d2a9042011-10-18 20:30:4161 GTMCarbonHotKey* hotKey_;
62 CFRunLoopSourceRef mouseRunLoopSource_;
[email protected]3df79f42013-06-24 18:49:0563 base::ScopedCFTypeRef<CFMachPortRef> mouseMachPort_;
[email protected]ceffbde2013-03-14 14:54:3964 remoting::LocalInputMonitorMac::EventHandler* monitor_;
[email protected]eccefee2011-08-02 15:31:4065}
66
[email protected]ceffbde2013-03-14 14:54:3967- (id)initWithMonitor:(remoting::LocalInputMonitorMac::EventHandler*)monitor;
68
[email protected]eccefee2011-08-02 15:31:4069// Called when the hotKey is hit.
70- (void)hotKeyHit:(GTMCarbonHotKey*)hotKey;
71
[email protected]3d2a9042011-10-18 20:30:4172// Called when the local mouse moves
[email protected]8c83a71c2013-12-16 18:02:5873- (void)localMouseMoved:(const webrtc::DesktopVector&)mousePos;
[email protected]3d2a9042011-10-18 20:30:4174
[email protected]42dcc6732012-05-29 20:35:2375// Must be called when the LocalInputMonitorManager is no longer to be used.
[email protected]eccefee2011-08-02 15:31:4076// Similar to NSTimer in that more than a simple release is required.
77- (void)invalidate;
78
79@end
80
[email protected]3d2a9042011-10-18 20:30:4181static CGEventRef LocalMouseMoved(CGEventTapProxy proxy, CGEventType type,
82 CGEventRef event, void* context) {
[email protected]06b393152011-10-21 03:02:4183 int64_t pid = CGEventGetIntegerValueField(event, kCGEventSourceUnixProcessID);
84 if (pid == 0) {
85 CGPoint cgMousePos = CGEventGetLocation(event);
[email protected]8c83a71c2013-12-16 18:02:5886 webrtc::DesktopVector mousePos(cgMousePos.x, cgMousePos.y);
[email protected]42dcc6732012-05-29 20:35:2387 [static_cast<LocalInputMonitorManager*>(context) localMouseMoved:mousePos];
[email protected]06b393152011-10-21 03:02:4188 }
[email protected]3d2a9042011-10-18 20:30:4189 return NULL;
90}
91
[email protected]42dcc6732012-05-29 20:35:2392@implementation LocalInputMonitorManager
[email protected]eccefee2011-08-02 15:31:4093
[email protected]ceffbde2013-03-14 14:54:3994- (id)initWithMonitor:(remoting::LocalInputMonitorMac::EventHandler*)monitor {
[email protected]eccefee2011-08-02 15:31:4095 if ((self = [super init])) {
[email protected]ceffbde2013-03-14 14:54:3996 monitor_ = monitor;
97
[email protected]eccefee2011-08-02 15:31:4098 GTMCarbonEventDispatcherHandler* handler =
99 [GTMCarbonEventDispatcherHandler sharedEventDispatcherHandler];
[email protected]3d2a9042011-10-18 20:30:41100 hotKey_ = [handler registerHotKey:kEscKeyCode
[email protected]f67e2a52011-10-07 18:45:37101 modifiers:(NSAlternateKeyMask | NSControlKeyMask)
[email protected]eccefee2011-08-02 15:31:40102 target:self
103 action:@selector(hotKeyHit:)
104 userInfo:nil
105 whenPressed:YES];
[email protected]3d2a9042011-10-18 20:30:41106 if (!hotKey_) {
107 LOG(ERROR) << "registerHotKey failed.";
108 }
[email protected]f1e981882011-11-23 23:33:42109 mouseMachPort_.reset(CGEventTapCreate(
[email protected]3d2a9042011-10-18 20:30:41110 kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly,
111 1 << kCGEventMouseMoved, LocalMouseMoved, self));
[email protected]f1e981882011-11-23 23:33:42112 if (mouseMachPort_) {
[email protected]3d2a9042011-10-18 20:30:41113 mouseRunLoopSource_ = CFMachPortCreateRunLoopSource(
[email protected]f1e981882011-11-23 23:33:42114 NULL, mouseMachPort_, 0);
[email protected]3d2a9042011-10-18 20:30:41115 CFRunLoopAddSource(
116 CFRunLoopGetMain(), mouseRunLoopSource_, kCFRunLoopCommonModes);
117 } else {
118 LOG(ERROR) << "CGEventTapCreate failed.";
119 }
[email protected]f1e981882011-11-23 23:33:42120 if (!hotKey_ && !mouseMachPort_) {
[email protected]eccefee2011-08-02 15:31:40121 [self release];
122 return nil;
123 }
124 }
125 return self;
126}
127
128- (void)hotKeyHit:(GTMCarbonHotKey*)hotKey {
[email protected]ceffbde2013-03-14 14:54:39129 monitor_->OnDisconnectShortcut();
[email protected]eccefee2011-08-02 15:31:40130}
131
[email protected]8c83a71c2013-12-16 18:02:58132- (void)localMouseMoved:(const webrtc::DesktopVector&)mousePos {
[email protected]ceffbde2013-03-14 14:54:39133 monitor_->OnLocalMouseMoved(mousePos);
[email protected]3d2a9042011-10-18 20:30:41134}
135
[email protected]eccefee2011-08-02 15:31:40136- (void)invalidate {
[email protected]3d2a9042011-10-18 20:30:41137 if (hotKey_) {
138 GTMCarbonEventDispatcherHandler* handler =
139 [GTMCarbonEventDispatcherHandler sharedEventDispatcherHandler];
140 [handler unregisterHotKey:hotKey_];
141 hotKey_ = NULL;
142 }
143 if (mouseRunLoopSource_) {
[email protected]f1e981882011-11-23 23:33:42144 CFMachPortInvalidate(mouseMachPort_);
[email protected]3d2a9042011-10-18 20:30:41145 CFRunLoopRemoveSource(
146 CFRunLoopGetMain(), mouseRunLoopSource_, kCFRunLoopCommonModes);
147 CFRelease(mouseRunLoopSource_);
[email protected]f1e981882011-11-23 23:33:42148 mouseMachPort_.reset(0);
[email protected]3d2a9042011-10-18 20:30:41149 mouseRunLoopSource_ = NULL;
150 }
[email protected]eccefee2011-08-02 15:31:40151}
152
153@end
154
[email protected]3361e1f2012-03-20 20:31:44155namespace remoting {
[email protected]eccefee2011-08-02 15:31:40156namespace {
157
[email protected]ceffbde2013-03-14 14:54:39158class LocalInputMonitorMac::Core
159 : public base::RefCountedThreadSafe<Core>,
160 public EventHandler {
161 public:
162 Core(scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
[email protected]b167a7b2013-03-25 18:34:40163 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
164 base::WeakPtr<ClientSessionControl> client_session_control);
[email protected]ceffbde2013-03-14 14:54:39165
[email protected]b167a7b2013-03-25 18:34:40166 void Start();
[email protected]ceffbde2013-03-14 14:54:39167 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]8c83a71c2013-12-16 18:02:58177 virtual void OnLocalMouseMoved(
178 const webrtc::DesktopVector& position) OVERRIDE;
[email protected]ceffbde2013-03-14 14:54:39179 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]b167a7b2013-03-25 18:34:40189 // 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]ceffbde2013-03-14 14:54:39192
193 DISALLOW_COPY_AND_ASSIGN(Core);
194};
195
196LocalInputMonitorMac::LocalInputMonitorMac(
197 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
[email protected]b167a7b2013-03-25 18:34:40198 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]ceffbde2013-03-14 14:54:39204}
[email protected]eccefee2011-08-02 15:31:40205
206LocalInputMonitorMac::~LocalInputMonitorMac() {
[email protected]ceffbde2013-03-14 14:54:39207 core_->Stop();
208}
209
210LocalInputMonitorMac::Core::Core(
211 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
[email protected]b167a7b2013-03-25 18:34:40212 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
213 base::WeakPtr<ClientSessionControl> client_session_control)
[email protected]ceffbde2013-03-14 14:54:39214 : caller_task_runner_(caller_task_runner),
215 ui_task_runner_(ui_task_runner),
216 manager_(nil),
[email protected]b167a7b2013-03-25 18:34:40217 client_session_control_(client_session_control) {
[email protected]fd7d3792013-06-07 08:43:27218 DCHECK(client_session_control_);
[email protected]ceffbde2013-03-14 14:54:39219}
220
[email protected]b167a7b2013-03-25 18:34:40221void LocalInputMonitorMac::Core::Start() {
[email protected]ceffbde2013-03-14 14:54:39222 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]ceffbde2013-03-14 14:54:39223
[email protected]ceffbde2013-03-14 14:54:39224 ui_task_runner_->PostTask(FROM_HERE,
225 base::Bind(&Core::StartOnUiThread, this));
226}
227
228void LocalInputMonitorMac::Core::Stop() {
229 DCHECK(caller_task_runner_->BelongsToCurrentThread());
230
[email protected]ceffbde2013-03-14 14:54:39231 ui_task_runner_->PostTask(FROM_HERE, base::Bind(&Core::StopOnUiThread, this));
232}
233
234LocalInputMonitorMac::Core::~Core() {
235 DCHECK(manager_ == nil);
[email protected]ceffbde2013-03-14 14:54:39236}
237
238void LocalInputMonitorMac::Core::StartOnUiThread() {
239 DCHECK(ui_task_runner_->BelongsToCurrentThread());
240
241 manager_ = [[LocalInputMonitorManager alloc] initWithMonitor:this];
242}
243
244void LocalInputMonitorMac::Core::StopOnUiThread() {
245 DCHECK(ui_task_runner_->BelongsToCurrentThread());
246
247 [manager_ invalidate];
248 [manager_ release];
249 manager_ = nil;
250}
251
[email protected]8c83a71c2013-12-16 18:02:58252void LocalInputMonitorMac::Core::OnLocalMouseMoved(
253 const webrtc::DesktopVector& position) {
[email protected]b167a7b2013-03-25 18:34:40254 caller_task_runner_->PostTask(
255 FROM_HERE, base::Bind(&ClientSessionControl::OnLocalMouseMoved,
256 client_session_control_,
257 position));
[email protected]eccefee2011-08-02 15:31:40258}
259
[email protected]ceffbde2013-03-14 14:54:39260void LocalInputMonitorMac::Core::OnDisconnectShortcut() {
[email protected]b167a7b2013-03-25 18:34:40261 caller_task_runner_->PostTask(
262 FROM_HERE, base::Bind(&ClientSessionControl::DisconnectSession,
263 client_session_control_));
[email protected]42dcc6732012-05-29 20:35:23264}
265
266} // namespace
267
[email protected]ceffbde2013-03-14 14:54:39268scoped_ptr<LocalInputMonitor> LocalInputMonitor::Create(
269 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
270 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
[email protected]b167a7b2013-03-25 18:34:40271 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
272 base::WeakPtr<ClientSessionControl> client_session_control) {
[email protected]ceffbde2013-03-14 14:54:39273 return scoped_ptr<LocalInputMonitor>(
[email protected]b167a7b2013-03-25 18:34:40274 new LocalInputMonitorMac(caller_task_runner,
275 ui_task_runner,
276 client_session_control));
[email protected]eccefee2011-08-02 15:31:40277}
[email protected]3361e1f2012-03-20 20:31:44278
279} // namespace remoting