blob: 961d7efda125e26c1a6f10a080ef6f64551bc65d [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>
avic5960f32015-12-22 22:49:488#include <stdint.h>
dcheng0765c492016-04-06 22:41:539
[email protected]9895e5792011-10-08 01:57:0610#include <set>
[email protected]eccefee2011-08-02 15:31:4011
[email protected]1e1cb3b2011-11-10 02:07:4112#include "base/bind.h"
[email protected]eccefee2011-08-02 15:31:4013#include "base/compiler_specific.h"
[email protected]ceffbde2013-03-14 14:54:3914#include "base/location.h"
[email protected]eccefee2011-08-02 15:31:4015#include "base/logging.h"
[email protected]3d2a9042011-10-18 20:30:4116#include "base/mac/scoped_cftyperef.h"
avic5960f32015-12-22 22:49:4817#include "base/macros.h"
dcheng0765c492016-04-06 22:41:5318#include "base/memory/ptr_util.h"
[email protected]0059eb96d2011-12-02 19:39:4119#include "base/memory/ref_counted.h"
[email protected]ceffbde2013-03-14 14:54:3920#include "base/single_thread_task_runner.h"
[email protected]9895e5792011-10-08 01:57:0621#include "base/synchronization/lock.h"
[email protected]b167a7b2013-03-25 18:34:4022#include "base/threading/non_thread_safe.h"
23#include "remoting/host/client_session_control.h"
[email protected]a023dca2013-12-18 03:58:3624#import "third_party/google_toolbox_for_mac/src/AppKit/GTMCarbonEvent.h"
[email protected]8c83a71c2013-12-16 18:02:5825#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
[email protected]eccefee2011-08-02 15:31:4026
27// Esc Key Code is 53.
28// http://boredzo.org/blog/wp-content/uploads/2007/05/IMTx-virtual-keycodes.pdf
29static const NSUInteger kEscKeyCode = 53;
30
[email protected]42dcc6732012-05-29 20:35:2331namespace remoting {
[email protected]42dcc6732012-05-29 20:35:2332namespace {
33
[email protected]b167a7b2013-03-25 18:34:4034class LocalInputMonitorMac : public base::NonThreadSafe,
35 public LocalInputMonitor {
[email protected]42dcc6732012-05-29 20:35:2336 public:
[email protected]ceffbde2013-03-14 14:54:3937 // Invoked by LocalInputMonitorManager.
38 class EventHandler {
39 public:
40 virtual ~EventHandler() {}
41
[email protected]8c83a71c2013-12-16 18:02:5842 virtual void OnLocalMouseMoved(const webrtc::DesktopVector& position) = 0;
[email protected]ceffbde2013-03-14 14:54:3943 virtual void OnDisconnectShortcut() = 0;
44 };
45
46 LocalInputMonitorMac(
47 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
[email protected]b167a7b2013-03-25 18:34:4048 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
49 base::WeakPtr<ClientSessionControl> client_session_control);
dcheng562aba52014-10-21 12:30:1450 ~LocalInputMonitorMac() override;
[email protected]ceffbde2013-03-14 14:54:3951
[email protected]42dcc6732012-05-29 20:35:2352 private:
[email protected]ceffbde2013-03-14 14:54:3953 // The actual implementation resides in LocalInputMonitorMac::Core class.
54 class Core;
55 scoped_refptr<Core> core_;
56
[email protected]42dcc6732012-05-29 20:35:2357 DISALLOW_COPY_AND_ASSIGN(LocalInputMonitorMac);
58};
59
[email protected]42dcc6732012-05-29 20:35:2360} // namespace
[email protected]42dcc6732012-05-29 20:35:2361} // namespace remoting
62
63@interface LocalInputMonitorManager : NSObject {
[email protected]eccefee2011-08-02 15:31:4064 @private
[email protected]3d2a9042011-10-18 20:30:4165 GTMCarbonHotKey* hotKey_;
66 CFRunLoopSourceRef mouseRunLoopSource_;
[email protected]3df79f42013-06-24 18:49:0567 base::ScopedCFTypeRef<CFMachPortRef> mouseMachPort_;
[email protected]ceffbde2013-03-14 14:54:3968 remoting::LocalInputMonitorMac::EventHandler* monitor_;
[email protected]eccefee2011-08-02 15:31:4069}
70
[email protected]ceffbde2013-03-14 14:54:3971- (id)initWithMonitor:(remoting::LocalInputMonitorMac::EventHandler*)monitor;
72
[email protected]eccefee2011-08-02 15:31:4073// Called when the hotKey is hit.
74- (void)hotKeyHit:(GTMCarbonHotKey*)hotKey;
75
[email protected]3d2a9042011-10-18 20:30:4176// Called when the local mouse moves
[email protected]8c83a71c2013-12-16 18:02:5877- (void)localMouseMoved:(const webrtc::DesktopVector&)mousePos;
[email protected]3d2a9042011-10-18 20:30:4178
[email protected]42dcc6732012-05-29 20:35:2379// Must be called when the LocalInputMonitorManager is no longer to be used.
[email protected]eccefee2011-08-02 15:31:4080// Similar to NSTimer in that more than a simple release is required.
81- (void)invalidate;
82
83@end
84
[email protected]3d2a9042011-10-18 20:30:4185static CGEventRef LocalMouseMoved(CGEventTapProxy proxy, CGEventType type,
86 CGEventRef event, void* context) {
[email protected]06b393152011-10-21 03:02:4187 int64_t pid = CGEventGetIntegerValueField(event, kCGEventSourceUnixProcessID);
88 if (pid == 0) {
89 CGPoint cgMousePos = CGEventGetLocation(event);
[email protected]8c83a71c2013-12-16 18:02:5890 webrtc::DesktopVector mousePos(cgMousePos.x, cgMousePos.y);
[email protected]42dcc6732012-05-29 20:35:2391 [static_cast<LocalInputMonitorManager*>(context) localMouseMoved:mousePos];
[email protected]06b393152011-10-21 03:02:4192 }
sergeyuc5f104b2015-01-09 19:33:2493 return nullptr;
[email protected]3d2a9042011-10-18 20:30:4194}
95
[email protected]42dcc6732012-05-29 20:35:2396@implementation LocalInputMonitorManager
[email protected]eccefee2011-08-02 15:31:4097
[email protected]ceffbde2013-03-14 14:54:3998- (id)initWithMonitor:(remoting::LocalInputMonitorMac::EventHandler*)monitor {
[email protected]eccefee2011-08-02 15:31:4099 if ((self = [super init])) {
[email protected]ceffbde2013-03-14 14:54:39100 monitor_ = monitor;
101
[email protected]eccefee2011-08-02 15:31:40102 GTMCarbonEventDispatcherHandler* handler =
103 [GTMCarbonEventDispatcherHandler sharedEventDispatcherHandler];
[email protected]3d2a9042011-10-18 20:30:41104 hotKey_ = [handler registerHotKey:kEscKeyCode
[email protected]f67e2a52011-10-07 18:45:37105 modifiers:(NSAlternateKeyMask | NSControlKeyMask)
[email protected]eccefee2011-08-02 15:31:40106 target:self
107 action:@selector(hotKeyHit:)
108 userInfo:nil
109 whenPressed:YES];
[email protected]3d2a9042011-10-18 20:30:41110 if (!hotKey_) {
111 LOG(ERROR) << "registerHotKey failed.";
112 }
[email protected]f1e981882011-11-23 23:33:42113 mouseMachPort_.reset(CGEventTapCreate(
[email protected]3d2a9042011-10-18 20:30:41114 kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly,
115 1 << kCGEventMouseMoved, LocalMouseMoved, self));
[email protected]f1e981882011-11-23 23:33:42116 if (mouseMachPort_) {
[email protected]3d2a9042011-10-18 20:30:41117 mouseRunLoopSource_ = CFMachPortCreateRunLoopSource(
sergeyuc5f104b2015-01-09 19:33:24118 nullptr, mouseMachPort_, 0);
[email protected]3d2a9042011-10-18 20:30:41119 CFRunLoopAddSource(
120 CFRunLoopGetMain(), mouseRunLoopSource_, kCFRunLoopCommonModes);
121 } else {
122 LOG(ERROR) << "CGEventTapCreate failed.";
123 }
[email protected]f1e981882011-11-23 23:33:42124 if (!hotKey_ && !mouseMachPort_) {
[email protected]eccefee2011-08-02 15:31:40125 [self release];
126 return nil;
127 }
128 }
129 return self;
130}
131
132- (void)hotKeyHit:(GTMCarbonHotKey*)hotKey {
[email protected]ceffbde2013-03-14 14:54:39133 monitor_->OnDisconnectShortcut();
[email protected]eccefee2011-08-02 15:31:40134}
135
[email protected]8c83a71c2013-12-16 18:02:58136- (void)localMouseMoved:(const webrtc::DesktopVector&)mousePos {
[email protected]ceffbde2013-03-14 14:54:39137 monitor_->OnLocalMouseMoved(mousePos);
[email protected]3d2a9042011-10-18 20:30:41138}
139
[email protected]eccefee2011-08-02 15:31:40140- (void)invalidate {
[email protected]3d2a9042011-10-18 20:30:41141 if (hotKey_) {
142 GTMCarbonEventDispatcherHandler* handler =
143 [GTMCarbonEventDispatcherHandler sharedEventDispatcherHandler];
144 [handler unregisterHotKey:hotKey_];
sergeyuc5f104b2015-01-09 19:33:24145 hotKey_ = nullptr;
[email protected]3d2a9042011-10-18 20:30:41146 }
147 if (mouseRunLoopSource_) {
[email protected]f1e981882011-11-23 23:33:42148 CFMachPortInvalidate(mouseMachPort_);
[email protected]3d2a9042011-10-18 20:30:41149 CFRunLoopRemoveSource(
150 CFRunLoopGetMain(), mouseRunLoopSource_, kCFRunLoopCommonModes);
151 CFRelease(mouseRunLoopSource_);
[email protected]f1e981882011-11-23 23:33:42152 mouseMachPort_.reset(0);
sergeyuc5f104b2015-01-09 19:33:24153 mouseRunLoopSource_ = nullptr;
[email protected]3d2a9042011-10-18 20:30:41154 }
[email protected]eccefee2011-08-02 15:31:40155}
156
157@end
158
[email protected]3361e1f2012-03-20 20:31:44159namespace remoting {
[email protected]eccefee2011-08-02 15:31:40160namespace {
161
[email protected]ceffbde2013-03-14 14:54:39162class LocalInputMonitorMac::Core
163 : public base::RefCountedThreadSafe<Core>,
164 public EventHandler {
165 public:
166 Core(scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
[email protected]b167a7b2013-03-25 18:34:40167 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
168 base::WeakPtr<ClientSessionControl> client_session_control);
[email protected]ceffbde2013-03-14 14:54:39169
[email protected]b167a7b2013-03-25 18:34:40170 void Start();
[email protected]ceffbde2013-03-14 14:54:39171 void Stop();
172
173 private:
174 friend class base::RefCountedThreadSafe<Core>;
dcheng562aba52014-10-21 12:30:14175 ~Core() override;
[email protected]ceffbde2013-03-14 14:54:39176
177 void StartOnUiThread();
178 void StopOnUiThread();
179
180 // EventHandler interface.
dcheng562aba52014-10-21 12:30:14181 void OnLocalMouseMoved(const webrtc::DesktopVector& position) override;
182 void OnDisconnectShortcut() override;
[email protected]ceffbde2013-03-14 14:54:39183
184 // Task runner on which public methods of this class must be called.
185 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
186
187 // Task runner on which |window_| is created.
188 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
189
190 LocalInputMonitorManager* manager_;
191
[email protected]b167a7b2013-03-25 18:34:40192 // Invoked in the |caller_task_runner_| thread to report local mouse events
193 // and session disconnect requests.
194 base::WeakPtr<ClientSessionControl> client_session_control_;
[email protected]ceffbde2013-03-14 14:54:39195
[email protected]1bed4a22014-04-12 01:32:51196 webrtc::DesktopVector mouse_position_;
197
[email protected]ceffbde2013-03-14 14:54:39198 DISALLOW_COPY_AND_ASSIGN(Core);
199};
200
201LocalInputMonitorMac::LocalInputMonitorMac(
202 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
[email protected]b167a7b2013-03-25 18:34:40203 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
204 base::WeakPtr<ClientSessionControl> client_session_control)
205 : core_(new Core(caller_task_runner,
206 ui_task_runner,
207 client_session_control)) {
208 core_->Start();
[email protected]ceffbde2013-03-14 14:54:39209}
[email protected]eccefee2011-08-02 15:31:40210
211LocalInputMonitorMac::~LocalInputMonitorMac() {
[email protected]ceffbde2013-03-14 14:54:39212 core_->Stop();
213}
214
215LocalInputMonitorMac::Core::Core(
216 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
[email protected]b167a7b2013-03-25 18:34:40217 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
218 base::WeakPtr<ClientSessionControl> client_session_control)
[email protected]ceffbde2013-03-14 14:54:39219 : caller_task_runner_(caller_task_runner),
220 ui_task_runner_(ui_task_runner),
221 manager_(nil),
[email protected]b167a7b2013-03-25 18:34:40222 client_session_control_(client_session_control) {
[email protected]fd7d3792013-06-07 08:43:27223 DCHECK(client_session_control_);
[email protected]ceffbde2013-03-14 14:54:39224}
225
[email protected]b167a7b2013-03-25 18:34:40226void LocalInputMonitorMac::Core::Start() {
[email protected]ceffbde2013-03-14 14:54:39227 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]ceffbde2013-03-14 14:54:39228
[email protected]ceffbde2013-03-14 14:54:39229 ui_task_runner_->PostTask(FROM_HERE,
230 base::Bind(&Core::StartOnUiThread, this));
231}
232
233void LocalInputMonitorMac::Core::Stop() {
234 DCHECK(caller_task_runner_->BelongsToCurrentThread());
235
[email protected]ceffbde2013-03-14 14:54:39236 ui_task_runner_->PostTask(FROM_HERE, base::Bind(&Core::StopOnUiThread, this));
237}
238
239LocalInputMonitorMac::Core::~Core() {
240 DCHECK(manager_ == nil);
[email protected]ceffbde2013-03-14 14:54:39241}
242
243void LocalInputMonitorMac::Core::StartOnUiThread() {
244 DCHECK(ui_task_runner_->BelongsToCurrentThread());
245
246 manager_ = [[LocalInputMonitorManager alloc] initWithMonitor:this];
247}
248
249void LocalInputMonitorMac::Core::StopOnUiThread() {
250 DCHECK(ui_task_runner_->BelongsToCurrentThread());
251
252 [manager_ invalidate];
253 [manager_ release];
254 manager_ = nil;
255}
256
[email protected]8c83a71c2013-12-16 18:02:58257void LocalInputMonitorMac::Core::OnLocalMouseMoved(
258 const webrtc::DesktopVector& position) {
[email protected]1bed4a22014-04-12 01:32:51259 // In some cases OS may emit bogus mouse-move events even when cursor is not
260 // actually moving. To handle this case properly verify that mouse position
261 // has changed. See crbug.com/360912 .
262 if (position.equals(mouse_position_)) {
263 return;
264 }
265
266 mouse_position_ = position;
267
[email protected]b167a7b2013-03-25 18:34:40268 caller_task_runner_->PostTask(
269 FROM_HERE, base::Bind(&ClientSessionControl::OnLocalMouseMoved,
270 client_session_control_,
271 position));
[email protected]eccefee2011-08-02 15:31:40272}
273
[email protected]ceffbde2013-03-14 14:54:39274void LocalInputMonitorMac::Core::OnDisconnectShortcut() {
[email protected]b167a7b2013-03-25 18:34:40275 caller_task_runner_->PostTask(
276 FROM_HERE, base::Bind(&ClientSessionControl::DisconnectSession,
sergeyuec77d8542015-11-03 22:31:00277 client_session_control_, protocol::OK));
[email protected]42dcc6732012-05-29 20:35:23278}
279
280} // namespace
281
dcheng0765c492016-04-06 22:41:53282std::unique_ptr<LocalInputMonitor> LocalInputMonitor::Create(
[email protected]ceffbde2013-03-14 14:54:39283 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
284 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
[email protected]b167a7b2013-03-25 18:34:40285 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
286 base::WeakPtr<ClientSessionControl> client_session_control) {
dcheng0765c492016-04-06 22:41:53287 return base::WrapUnique(new LocalInputMonitorMac(
sergeyu2d690882014-10-01 02:36:43288 caller_task_runner, ui_task_runner, client_session_control));
[email protected]eccefee2011-08-02 15:31:40289}
[email protected]3361e1f2012-03-20 20:31:44290
291} // namespace remoting