Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(554)

Side by Side Diff: media/base/user_input_monitor_mac.mm

Issue 22801007: Adds the UserInputMonitor implementation for Mac. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/base/user_input_monitor.cc ('k') | media/media.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
OLDNEW
« no previous file with comments | « media/base/user_input_monitor.cc ('k') | media/media.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698