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

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

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/base/user_input_monitor_mac.mm » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "media/base/user_input_monitor.h"
6
7 #include <ApplicationServices/ApplicationServices.h>
8
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/mac/scoped_cftyperef.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/time/time.h"
15 #include "base/timer/timer.h"
16 #include "third_party/skia/include/core/SkPoint.h"
17
18 namespace media {
19 namespace {
20
21 class UserInputMonitorMacCore;
22
23 class UserInputMonitorMac : public UserInputMonitor {
24 public:
25 typedef const base::Callback<void(const SkIPoint&)> MouseCallback;
26
27 UserInputMonitorMac(
28 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
29
30 virtual ~UserInputMonitorMac();
31
32 private:
33 virtual void StartMouseMonitoring() OVERRIDE;
34 virtual void StopMouseMonitoring() OVERRIDE;
35 virtual void StartKeyboardMonitoring() OVERRIDE;
36 virtual void StopKeyboardMonitoring() OVERRIDE;
37
38 void OnMouseMoved(const SkIPoint& position);
39 void OnKeyStroke();
40
41 // Task runner on which input events are received.
42 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
43
44 scoped_ptr<UserInputMonitorMacCore> core_;
45
46 DISALLOW_COPY_AND_ASSIGN(UserInputMonitorMac);
47 };
48
49 // The class implements the event listening. Must be called on the UI thread.
50 class UserInputMonitorMacCore {
51 public:
52 UserInputMonitorMacCore(
53 const UserInputMonitorMac::MouseCallback& mouse_callback,
54 const base::Closure& key_stroke_callback);
55 ~UserInputMonitorMacCore();
56
57 void StartMonitoringMouse();
58 void StopMonitoringMouse();
59 void StartPollingKeyState();
60 void StopPollingKeyState();
61
62 void OnMouseMoved(const SkIPoint& position);
63
64 base::WeakPtr<UserInputMonitorMacCore> GetAsWeakPtr();
65
66 private:
67 static CGEventRef MouseMoved(CGEventTapProxy proxy,
68 CGEventType type,
69 CGEventRef event,
70 void* context);
71 void PollKeyState();
72
73 UserInputMonitorMac::MouseCallback mouse_callback_;
74 base::Closure key_stroke_callback_;
75
76 base::ScopedCFTypeRef<CFRunLoopSourceRef> input_run_loop_source_;
77 base::ScopedCFTypeRef<CFMachPortRef> input_mach_port_;
78
79 base::Timer polling_timer_;
80 // 0x5c is key "9", after that comes function keys.
81 bool prev_key_state_[0x5d];
82
83 base::WeakPtrFactory<UserInputMonitorMacCore> weak_factory_;
84
85 DISALLOW_COPY_AND_ASSIGN(UserInputMonitorMacCore);
86 };
87
88 UserInputMonitorMac::UserInputMonitorMac(
89 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
90 : ui_task_runner_(ui_task_runner),
91 core_(new UserInputMonitorMacCore(
92 base::Bind(&UserInputMonitorMac::OnMouseMoved,
93 base::Unretained(this)),
94 base::Bind(&UserInputMonitorMac::OnKeyStroke,
95 base::Unretained(this)))) {}
96
97 UserInputMonitorMac::~UserInputMonitorMac() {
98 ui_task_runner_->DeleteSoon(FROM_HERE, core_.release());
99 }
100
101 void UserInputMonitorMac::StartMouseMonitoring() {
102 if (!ui_task_runner_->BelongsToCurrentThread()) {
103 ui_task_runner_->PostTask(
104 FROM_HERE,
105 base::Bind(&UserInputMonitorMacCore::StartMonitoringMouse,
106 core_->GetAsWeakPtr()));
107 return;
108 }
109 core_->StartMonitoringMouse();
110 }
111
112 void UserInputMonitorMac::StopMouseMonitoring() {
113 if (!ui_task_runner_->BelongsToCurrentThread()) {
114 ui_task_runner_->PostTask(
115 FROM_HERE,
116 base::Bind(&UserInputMonitorMacCore::StopMonitoringMouse,
117 core_->GetAsWeakPtr()));
118 return;
119 }
120 core_->StopMonitoringMouse();
121 }
122
123 void UserInputMonitorMac::StartKeyboardMonitoring() {
124 if (!ui_task_runner_->BelongsToCurrentThread()) {
125 ui_task_runner_->PostTask(
126 FROM_HERE,
127 base::Bind(&UserInputMonitorMacCore::StartPollingKeyState,
128 core_->GetAsWeakPtr()));
129 return;
130 }
131 core_->StartPollingKeyState();
132 }
133
134 void UserInputMonitorMac::StopKeyboardMonitoring() {
135 if (!ui_task_runner_->BelongsToCurrentThread()) {
136 ui_task_runner_->PostTask(
137 FROM_HERE,
138 base::Bind(&UserInputMonitorMacCore::StopPollingKeyState,
139 core_->GetAsWeakPtr()));
140 return;
141 }
142 core_->StopPollingKeyState();
143 }
144
145 void UserInputMonitorMac::OnMouseMoved(const SkIPoint& position) {
146 UserInputMonitor::OnMouseEvent(position);
147 }
148
149 void UserInputMonitorMac::OnKeyStroke() {
150 UserInputMonitor::OnKeyboardEvent(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN);
151 }
152
153 UserInputMonitorMacCore::UserInputMonitorMacCore(
154 const UserInputMonitorMac::MouseCallback& mouse_callback,
155 const base::Closure& key_stroke_callback)
156 : mouse_callback_(mouse_callback),
157 key_stroke_callback_(key_stroke_callback),
158 polling_timer_(false, true),
159 weak_factory_(this) {}
160
161 UserInputMonitorMacCore::~UserInputMonitorMacCore() {
162 DCHECK(!input_mach_port_);
163 DCHECK(!input_run_loop_source_);
164 DCHECK(!polling_timer_.IsRunning());
165 }
166
167 void UserInputMonitorMacCore::StartMonitoringMouse() {
168 DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type());
169
170 input_mach_port_.reset(CGEventTapCreate(kCGSessionEventTap,
171 kCGHeadInsertEventTap,
172 kCGEventTapOptionListenOnly,
173 CGEventMaskBit(kCGEventMouseMoved),
174 MouseMoved,
175 this));
176 if (input_mach_port_) {
177 input_run_loop_source_.reset(
178 CFMachPortCreateRunLoopSource(NULL, input_mach_port_, 0));
179 CFRunLoopAddSource(
180 CFRunLoopGetMain(), input_run_loop_source_, kCFRunLoopCommonModes);
181 } else {
182 LOG(ERROR) << "CGEventTapCreate failed.";
183 }
184 }
185
186 void UserInputMonitorMacCore::StopMonitoringMouse() {
187 DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type());
188
189 if (input_run_loop_source_) {
190 CFMachPortInvalidate(input_mach_port_);
191 CFRunLoopRemoveSource(
192 CFRunLoopGetMain(), input_run_loop_source_, kCFRunLoopCommonModes);
193 input_run_loop_source_.reset();
194 input_mach_port_.reset();
195 }
196 }
197
198 void UserInputMonitorMacCore::StartPollingKeyState() {
199 DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type());
200
201 polling_timer_.Start(
202 FROM_HERE,
203 base::TimeDelta::FromMilliseconds(30),
204 base::Bind(&UserInputMonitorMacCore::PollKeyState, GetAsWeakPtr()));
205 }
206
207 void UserInputMonitorMacCore::StopPollingKeyState() {
208 DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type());
209
210 polling_timer_.Stop();
211 }
212
213 base::WeakPtr<UserInputMonitorMacCore> UserInputMonitorMacCore::GetAsWeakPtr() {
214 return weak_factory_.GetWeakPtr();
215 }
216
217 void UserInputMonitorMacCore::OnMouseMoved(const SkIPoint& position) {
218 DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type());
219
220 mouse_callback_.Run(position);
221 }
222
223 CGEventRef UserInputMonitorMacCore::MouseMoved(CGEventTapProxy proxy,
224 CGEventType type,
225 CGEventRef event,
226 void* context) {
227 DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type());
228
229 int64_t pid = CGEventGetIntegerValueField(event, kCGEventSourceUnixProcessID);
230 // |pid| 0 means the event is generated by hardware.
231 if (pid == 0) {
232 DCHECK_EQ(kCGEventMouseMoved, type);
233 CGPoint cg_mouse_pos = CGEventGetLocation(event);
234 SkIPoint mouse_pos = SkIPoint::Make(cg_mouse_pos.x, cg_mouse_pos.y);
235 static_cast<UserInputMonitorMacCore*>(context)->OnMouseMoved(mouse_pos);
236 }
237 return NULL;
238 }
239
240 void UserInputMonitorMacCore::PollKeyState() {
241 DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type());
242
243 bool key_pressed = false;
244 for (CGKeyCode key_index = 0; key_index < arraysize(prev_key_state_);
245 ++key_index) {
246 bool key_state =
247 CGEventSourceKeyState(kCGEventSourceStateHIDSystemState, key_index);
Wez 2013/08/21 22:41:57 This should be *SessionState, not *SystemState, I
jiayl 2013/08/21 22:58:23 The webrtc impl uses *SystemState: https://code.go
Wez 2013/08/21 23:19:53 Monitoring session events is correct in terms of s
jiayl 2013/08/21 23:32:59 I'm not sure. What's the state of audio capturing
248 // A false -> true change in keymap means a key is pressed.
249 key_pressed |= (key_state && !prev_key_state_[key_index]);
250 // Save current state.
251 prev_key_state_[key_index] = key_state;
252 }
253
254 if (key_pressed)
255 key_stroke_callback_.Run();
256 }
257
258 } // namespace
259
260 scoped_ptr<UserInputMonitor> UserInputMonitor::Create(
261 const scoped_refptr<base::SingleThreadTaskRunner>& input_task_runner,
262 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
263 return scoped_ptr<UserInputMonitor>(new UserInputMonitorMac(ui_task_runner));
264 }
265
266 } // namespace media
OLDNEW
« no previous file with comments | « media/base/user_input_monitor.cc ('k') | media/base/user_input_monitor_mac.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698