OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "media/base/user_input_monitor.h" | 5 #include "media/base/user_input_monitor.h" |
6 | 6 |
7 #import <AppKit/AppKit.h> | |
8 | |
9 #include <ApplicationServices/ApplicationServices.h> | |
10 | |
11 #include "base/bind.h" | |
12 #include "base/compiler_specific.h" | |
13 #include "base/location.h" | |
14 #include "base/logging.h" | |
15 #include "base/mac/scoped_cftyperef.h" | |
16 #include "base/memory/ref_counted.h" | |
17 #include "base/message_loop/message_loop.h" | |
18 #include "base/single_thread_task_runner.h" | |
19 #include "base/threading/non_thread_safe.h" | |
20 #include "base/time/time.h" | |
21 #include "third_party/skia/include/core/SkPoint.h" | |
22 #import "third_party/GTM/AppKit/GTMCarbonEvent.h" | |
23 | |
7 namespace media { | 24 namespace media { |
8 | 25 class UserInputMonitorMacCore; |
9 // TODO(jiayl): add the implementation. | 26 } // namespace media |
27 | |
28 @interface UserInputMonitorMacHelper : NSObject { | |
Robert Sesek
2013/08/21 00:19:31
This ObjC class is unnecessary. You should be able
| |
29 @private | |
30 CFRunLoopSourceRef inputRunLoopSource_; | |
31 base::ScopedCFTypeRef<CFMachPortRef> inputMachPort_; | |
32 media::UserInputMonitorMacCore* monitor_; | |
33 } | |
34 | |
35 - (id)initWithMonitor:(media::UserInputMonitorMacCore*)monitor; | |
36 | |
37 // Called when the local mouse moves. | |
38 - (void)mouseMoved:(const SkIPoint&)mousePos; | |
39 | |
40 // Must be called when the UserInputMonitorMacHelper is no longer to be used. | |
41 // Similar to NSTimer in that more than a simple release is required. | |
42 - (void)invalidate; | |
43 | |
44 @end | |
45 | |
46 namespace media { | |
47 | |
48 class UserInputMonitorMac : public base::NonThreadSafe, | |
49 public UserInputMonitor { | |
50 public: | |
51 typedef const base::Callback<void(const SkIPoint&)> MouseCallback; | |
52 | |
53 UserInputMonitorMac( | |
54 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner); | |
55 | |
56 virtual ~UserInputMonitorMac(); | |
57 | |
58 private: | |
59 virtual void StartMouseMonitoring() OVERRIDE; | |
60 virtual void StopMouseMonitoring() OVERRIDE; | |
61 virtual void StartKeyboardMonitoring() OVERRIDE; | |
62 virtual void StopKeyboardMonitoring() OVERRIDE; | |
63 | |
64 void OnMouseMoved(const SkIPoint& position); | |
65 void OnKeyStroke(); | |
66 | |
67 // Task runner on which X Window events are received. | |
68 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; | |
69 | |
70 scoped_refptr<UserInputMonitorMacCore> core_; | |
71 | |
72 DISALLOW_COPY_AND_ASSIGN(UserInputMonitorMac); | |
73 }; | |
74 | |
75 // The class implements the event listening. Must be called on the UI thread. | |
76 class UserInputMonitorMacCore | |
77 : public base::RefCountedThreadSafe<UserInputMonitorMacCore> { | |
78 public: | |
79 UserInputMonitorMacCore( | |
80 const UserInputMonitorMac::MouseCallback& mouse_callback, | |
81 const base::Closure& key_stroke_callback); | |
82 | |
83 void StartMonitoringMouse(); | |
84 void StopMonitoringMouse(); | |
85 void StartPollingKeyState(); | |
86 void StopPollingKeyState(); | |
87 | |
88 void OnMouseMoved(const SkIPoint& position); | |
89 | |
90 private: | |
91 friend class base::RefCountedThreadSafe<UserInputMonitorMacCore>; | |
92 virtual ~UserInputMonitorMacCore(); | |
93 | |
94 void PollKeyState(); | |
95 | |
96 UserInputMonitorMac::MouseCallback mouse_callback_; | |
97 base::Closure key_stroke_callback_; | |
98 UserInputMonitorMacHelper* helper_; | |
99 | |
100 bool polling_key_state_; | |
101 // 0x5d is key "9", after that comes function keys. | |
102 bool prev_key_state_[0x5d]; | |
103 | |
104 DISALLOW_COPY_AND_ASSIGN(UserInputMonitorMacCore); | |
105 }; | |
106 | |
107 UserInputMonitorMac::UserInputMonitorMac( | |
108 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) | |
109 : ui_task_runner_(ui_task_runner), | |
110 core_(new UserInputMonitorMacCore( | |
111 base::Bind(&UserInputMonitorMac::OnMouseMoved, | |
112 base::Unretained(this)), | |
113 base::Bind(&UserInputMonitorMac::OnKeyStroke, | |
114 base::Unretained(this)))) {} | |
115 | |
116 UserInputMonitorMac::~UserInputMonitorMac() {} | |
117 | |
118 void UserInputMonitorMac::StartMouseMonitoring() { | |
119 ui_task_runner_->PostTask( | |
120 FROM_HERE, base::Bind(&UserInputMonitorMacCore::StartMonitoringMouse, | |
121 core_.get())); | |
122 } | |
123 | |
124 void UserInputMonitorMac::StopMouseMonitoring() { | |
125 ui_task_runner_->PostTask( | |
126 FROM_HERE, base::Bind(&UserInputMonitorMacCore::StopMonitoringMouse, | |
127 core_.get())); | |
128 } | |
129 | |
130 void UserInputMonitorMac::StartKeyboardMonitoring() { | |
131 ui_task_runner_->PostTask( | |
132 FROM_HERE, base::Bind(&UserInputMonitorMacCore::StartPollingKeyState, | |
133 core_.get())); | |
134 } | |
135 | |
136 void UserInputMonitorMac::StopKeyboardMonitoring() { | |
137 ui_task_runner_->PostTask( | |
138 FROM_HERE, base::Bind(&UserInputMonitorMacCore::StopPollingKeyState, | |
139 core_.get())); | |
140 } | |
141 | |
142 void UserInputMonitorMac::OnMouseMoved(const SkIPoint& position) { | |
143 UserInputMonitor::OnMouseEvent(position); | |
144 } | |
145 | |
146 void UserInputMonitorMac::OnKeyStroke() { | |
147 UserInputMonitor::OnKeyboardEvent(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN); | |
148 } | |
149 | |
150 UserInputMonitorMacCore::UserInputMonitorMacCore( | |
151 const UserInputMonitorMac::MouseCallback& mouse_callback, | |
152 const base::Closure& key_stroke_callback) | |
153 : mouse_callback_(mouse_callback), | |
154 key_stroke_callback_(key_stroke_callback), | |
155 helper_(nil), | |
156 polling_key_state_(false) {} | |
157 | |
158 void UserInputMonitorMacCore::StartMonitoringMouse() { | |
159 helper_ = [[UserInputMonitorMacHelper alloc] initWithMonitor:this]; | |
160 } | |
161 | |
162 void UserInputMonitorMacCore::StopMonitoringMouse() { | |
163 [helper_ invalidate]; | |
164 [helper_ release]; | |
165 helper_ = nil; | |
166 } | |
167 | |
168 void UserInputMonitorMacCore::StartPollingKeyState() { | |
169 polling_key_state_ = true; | |
170 base::MessageLoop::current()->PostDelayedTask( | |
171 FROM_HERE, | |
172 base::Bind(&UserInputMonitorMacCore::PollKeyState, this), | |
173 base::TimeDelta::FromMilliseconds(10)); | |
174 } | |
175 | |
176 void UserInputMonitorMacCore::StopPollingKeyState() { | |
177 polling_key_state_ = false; | |
178 } | |
179 | |
180 UserInputMonitorMacCore::~UserInputMonitorMacCore() { | |
181 DCHECK(helper_ == nil); | |
182 DCHECK(!polling_key_state_); | |
183 } | |
184 | |
185 void UserInputMonitorMacCore::OnMouseMoved(const SkIPoint& position) { | |
186 mouse_callback_.Run(position); | |
187 } | |
188 | |
189 void UserInputMonitorMacCore::PollKeyState() { | |
190 if (!polling_key_state_) | |
191 return; | |
192 | |
193 bool key_pressed = false; | |
194 for (uint key_index = 0; | |
195 key_index <= sizeof(prev_key_state_)/sizeof(prev_key_state_[0]); | |
196 ++key_index) { | |
197 bool key_state = CGEventSourceKeyState(kCGEventSourceStateHIDSystemState, | |
198 key_index); | |
199 | |
200 // A false -> true change in keymap means a key is pressed. | |
201 key_pressed |= (key_state && !prev_key_state_[key_index]); | |
202 // Save current state. | |
203 prev_key_state_[key_index] = key_state; | |
204 } | |
205 | |
206 if (key_pressed) | |
207 key_stroke_callback_.Run(); | |
208 | |
209 base::MessageLoop::current()->PostDelayedTask( | |
210 FROM_HERE, | |
211 base::Bind(&UserInputMonitorMacCore::PollKeyState, this), | |
212 base::TimeDelta::FromMilliseconds(10)); | |
213 } | |
214 | |
10 scoped_ptr<UserInputMonitor> UserInputMonitor::Create( | 215 scoped_ptr<UserInputMonitor> UserInputMonitor::Create( |
11 const scoped_refptr<base::SingleThreadTaskRunner>& input_task_runner, | 216 const scoped_refptr<base::SingleThreadTaskRunner>& input_task_runner, |
12 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) { | 217 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) { |
13 return scoped_ptr<UserInputMonitor>(); | 218 return scoped_ptr<UserInputMonitor>(new UserInputMonitorMac(ui_task_runner)); |
14 } | 219 } |
15 | 220 |
16 } // namespace media | 221 } // namespace media |
222 | |
223 static CGEventRef inputEvent(CGEventTapProxy proxy, | |
224 CGEventType type, | |
225 CGEventRef event, | |
226 void* context) { | |
227 int64_t pid = CGEventGetIntegerValueField(event, kCGEventSourceUnixProcessID); | |
228 if (pid == 0) { | |
229 DCHECK(type == kCGEventMouseMoved); | |
230 CGPoint cgMousePos = CGEventGetLocation(event); | |
231 SkIPoint mousePos = SkIPoint::Make(cgMousePos.x, cgMousePos.y); | |
232 [static_cast<UserInputMonitorMacHelper*>(context) mouseMoved:mousePos]; | |
233 } | |
234 return NULL; | |
235 } | |
236 | |
237 @implementation UserInputMonitorMacHelper | |
238 | |
239 - (id)initWithMonitor:(media::UserInputMonitorMacCore*)monitor { | |
240 if ((self = [super init])) { | |
241 monitor_ = monitor; | |
242 inputMachPort_.reset(CGEventTapCreate( | |
243 kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly, | |
244 CGEventMaskBit(kCGEventMouseMoved), inputEvent, self)); | |
245 if (inputMachPort_) { | |
246 inputRunLoopSource_ = CFMachPortCreateRunLoopSource( | |
247 NULL, inputMachPort_, 0); | |
248 CFRunLoopAddSource( | |
249 CFRunLoopGetMain(), inputRunLoopSource_, kCFRunLoopCommonModes); | |
250 } else { | |
251 LOG(ERROR) << "CGEventTapCreate failed."; | |
252 } | |
253 if (!inputMachPort_) { | |
254 [self release]; | |
255 return nil; | |
256 } | |
257 } | |
258 return self; | |
259 } | |
260 | |
261 - (void)mouseMoved:(const SkIPoint&)mousePos { | |
262 monitor_->OnMouseMoved(mousePos); | |
263 } | |
264 | |
265 - (void)invalidate { | |
266 if (inputRunLoopSource_) { | |
267 CFMachPortInvalidate(inputMachPort_); | |
268 CFRunLoopRemoveSource( | |
269 CFRunLoopGetMain(), inputRunLoopSource_, kCFRunLoopCommonModes); | |
270 CFRelease(inputRunLoopSource_); | |
271 inputMachPort_.reset(); | |
272 inputRunLoopSource_ = NULL; | |
273 } | |
274 } | |
275 | |
276 @end | |
OLD | NEW |