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

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 namespace {
9 // TODO(jiayl): add the implementation. 26
27 class UserInputMonitorMacCore;
28
29 class UserInputMonitorMac : public base::NonThreadSafe,
30 public UserInputMonitor {
31 public:
32 typedef const base::Callback<void(const SkIPoint&)> MouseCallback;
33
34 UserInputMonitorMac(
35 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
36
37 virtual ~UserInputMonitorMac();
38
39 private:
40 virtual void StartMouseMonitoring() OVERRIDE;
41 virtual void StopMouseMonitoring() OVERRIDE;
42 virtual void StartKeyboardMonitoring() OVERRIDE;
43 virtual void StopKeyboardMonitoring() OVERRIDE;
44
45 void OnMouseMoved(const SkIPoint& position);
46 void OnKeyStroke();
47
48 // Task runner on which X Window events are received.
49 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
50
51 scoped_refptr<UserInputMonitorMacCore> core_;
52
53 DISALLOW_COPY_AND_ASSIGN(UserInputMonitorMac);
54 };
55
56 // The class implements the event listening. Must be called on the UI thread.
57 class UserInputMonitorMacCore
58 : public base::RefCountedThreadSafe<UserInputMonitorMacCore> {
59 public:
60 UserInputMonitorMacCore(
61 const UserInputMonitorMac::MouseCallback& mouse_callback,
62 const base::Closure& key_stroke_callback);
63
64 void StartMonitoringMouse();
65 void StopMonitoringMouse();
66 void StartPollingKeyState();
67 void StopPollingKeyState();
68
69 void OnMouseMoved(const SkIPoint& position);
70
71 private:
72 friend class base::RefCountedThreadSafe<UserInputMonitorMacCore>;
73 virtual ~UserInputMonitorMacCore();
74
75 void PollKeyState();
76
77 UserInputMonitorMac::MouseCallback mouse_callback_;
78 base::Closure key_stroke_callback_;
79
80 CFRunLoopSourceRef input_run_loop_source_;
81 base::ScopedCFTypeRef<CFMachPortRef> input_mach_port_;
82
83 bool polling_key_state_;
84 // 0x5d is key "9", after that comes function keys.
85 bool prev_key_state_[0x5d];
86
87 DISALLOW_COPY_AND_ASSIGN(UserInputMonitorMacCore);
88 };
89
90 static CGEventRef inputEvent(CGEventTapProxy proxy,
Robert Sesek 2013/08/21 14:43:24 This should be a static member function.
91 CGEventType type,
92 CGEventRef event,
93 void* context) {
94 int64_t pid = CGEventGetIntegerValueField(event, kCGEventSourceUnixProcessID);
95 if (pid == 0) {
96 DCHECK(type == kCGEventMouseMoved);
97 CGPoint cg_mouse_pos = CGEventGetLocation(event);
98 SkIPoint mouse_pos = SkIPoint::Make(cg_mouse_pos.x, cg_mouse_pos.y);
99 static_cast<UserInputMonitorMacCore*>(context)->OnMouseMoved(mouse_pos);
100 }
101 return NULL;
102 }
103
104 UserInputMonitorMac::UserInputMonitorMac(
105 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
106 : ui_task_runner_(ui_task_runner),
107 core_(new UserInputMonitorMacCore(
108 base::Bind(&UserInputMonitorMac::OnMouseMoved,
109 base::Unretained(this)),
110 base::Bind(&UserInputMonitorMac::OnKeyStroke,
111 base::Unretained(this)))) {}
112
113 UserInputMonitorMac::~UserInputMonitorMac() {}
114
115 void UserInputMonitorMac::StartMouseMonitoring() {
Robert Sesek 2013/08/21 14:43:24 I'm wondering if this could be simplified s.t. rat
116 ui_task_runner_->PostTask(
117 FROM_HERE, base::Bind(&UserInputMonitorMacCore::StartMonitoringMouse,
118 core_.get()));
119 }
120
121 void UserInputMonitorMac::StopMouseMonitoring() {
122 ui_task_runner_->PostTask(
123 FROM_HERE, base::Bind(&UserInputMonitorMacCore::StopMonitoringMouse,
124 core_.get()));
125 }
126
127 void UserInputMonitorMac::StartKeyboardMonitoring() {
128 ui_task_runner_->PostTask(
129 FROM_HERE, base::Bind(&UserInputMonitorMacCore::StartPollingKeyState,
130 core_.get()));
131 }
132
133 void UserInputMonitorMac::StopKeyboardMonitoring() {
134 ui_task_runner_->PostTask(
135 FROM_HERE, base::Bind(&UserInputMonitorMacCore::StopPollingKeyState,
136 core_.get()));
137 }
138
139 void UserInputMonitorMac::OnMouseMoved(const SkIPoint& position) {
140 UserInputMonitor::OnMouseEvent(position);
141 }
142
143 void UserInputMonitorMac::OnKeyStroke() {
144 UserInputMonitor::OnKeyboardEvent(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN);
145 }
146
147 UserInputMonitorMacCore::UserInputMonitorMacCore(
148 const UserInputMonitorMac::MouseCallback& mouse_callback,
149 const base::Closure& key_stroke_callback)
150 : mouse_callback_(mouse_callback),
151 key_stroke_callback_(key_stroke_callback),
152 polling_key_state_(false) {}
153
154 void UserInputMonitorMacCore::StartMonitoringMouse() {
155 input_mach_port_.reset(CGEventTapCreate(
156 kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly,
157 CGEventMaskBit(kCGEventMouseMoved), inputEvent, this));
158 if (input_mach_port_) {
159 input_run_loop_source_ = CFMachPortCreateRunLoopSource(
160 NULL, input_mach_port_, 0);
161 CFRunLoopAddSource(
162 CFRunLoopGetMain(), input_run_loop_source_, kCFRunLoopCommonModes);
163 } else {
164 LOG(ERROR) << "CGEventTapCreate failed.";
165 }
166 }
167
168 void UserInputMonitorMacCore::StopMonitoringMouse() {
169 if (input_run_loop_source_) {
170 CFMachPortInvalidate(input_mach_port_);
171 CFRunLoopRemoveSource(
172 CFRunLoopGetMain(), input_run_loop_source_, kCFRunLoopCommonModes);
173 CFRelease(input_run_loop_source_);
174 input_mach_port_.reset();
175 input_run_loop_source_ = NULL;
176 }
177 }
178
179 void UserInputMonitorMacCore::StartPollingKeyState() {
180 polling_key_state_ = true;
181 base::MessageLoop::current()->PostDelayedTask(
182 FROM_HERE,
183 base::Bind(&UserInputMonitorMacCore::PollKeyState, this),
184 base::TimeDelta::FromMilliseconds(10));
185 }
186
187 void UserInputMonitorMacCore::StopPollingKeyState() {
188 polling_key_state_ = false;
189 }
190
191 UserInputMonitorMacCore::~UserInputMonitorMacCore() {
192 DCHECK(!input_mach_port_);
193 DCHECK(input_run_loop_source_);
194 DCHECK(!polling_key_state_);
195 }
196
197 void UserInputMonitorMacCore::OnMouseMoved(const SkIPoint& position) {
198 mouse_callback_.Run(position);
199 }
200
201 void UserInputMonitorMacCore::PollKeyState() {
202 if (!polling_key_state_)
203 return;
204
205 bool key_pressed = false;
206 for (uint key_index = 0;
207 key_index <= sizeof(prev_key_state_)/sizeof(prev_key_state_[0]);
208 ++key_index) {
209 bool key_state = CGEventSourceKeyState(kCGEventSourceStateHIDSystemState,
210 key_index);
211
212 // A false -> true change in keymap means a key is pressed.
213 key_pressed |= (key_state && !prev_key_state_[key_index]);
214 // Save current state.
215 prev_key_state_[key_index] = key_state;
216 }
217
218 if (key_pressed)
219 key_stroke_callback_.Run();
220
221 base::MessageLoop::current()->PostDelayedTask(
222 FROM_HERE,
223 base::Bind(&UserInputMonitorMacCore::PollKeyState, this),
224 base::TimeDelta::FromMilliseconds(10));
225 }
226
227 } // namespace
228
10 scoped_ptr<UserInputMonitor> UserInputMonitor::Create( 229 scoped_ptr<UserInputMonitor> UserInputMonitor::Create(
11 const scoped_refptr<base::SingleThreadTaskRunner>& input_task_runner, 230 const scoped_refptr<base::SingleThreadTaskRunner>& input_task_runner,
12 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) { 231 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
13 return scoped_ptr<UserInputMonitor>(); 232 return scoped_ptr<UserInputMonitor>(new UserInputMonitorMac(ui_task_runner));
14 } 233 }
15 234
16 } // namespace media 235 } // namespace media
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