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

Side by Side Diff: remoting/host/event_executor_mac.cc

Issue 12760012: Rename EventExecutor to InputInjector. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Replace some missed occurrences and remove unused include. Created 7 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « remoting/host/event_executor_linux.cc ('k') | remoting/host/event_executor_win.cc » ('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 (c) 2012 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 "remoting/host/event_executor.h"
6
7 #include <algorithm>
8 #include <ApplicationServices/ApplicationServices.h>
9 #include <Carbon/Carbon.h>
10
11 #include "base/basictypes.h"
12 #include "base/bind.h"
13 #include "base/compiler_specific.h"
14 #include "base/location.h"
15 #include "base/mac/scoped_cftyperef.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/single_thread_task_runner.h"
18 #include "media/video/capture/screen/mac/desktop_configuration.h"
19 #include "remoting/host/clipboard.h"
20 #include "remoting/proto/internal.pb.h"
21 #include "remoting/protocol/message_decoder.h"
22 #include "skia/ext/skia_utils_mac.h"
23 #include "third_party/skia/include/core/SkPoint.h"
24 #include "third_party/skia/include/core/SkRect.h"
25
26 namespace remoting {
27
28 namespace {
29
30 using protocol::ClipboardEvent;
31 using protocol::KeyEvent;
32 using protocol::MouseEvent;
33
34 // USB to Mac keycode mapping table.
35 #define USB_KEYMAP(usb, xkb, win, mac) {usb, mac}
36 #include "ui/base/keycodes/usb_keycode_map.h"
37 #undef USB_KEYMAP
38
39 // skia/ext/skia_utils_mac.h only defines CGRectToSkRect().
40 SkIRect CGRectToSkIRect(const CGRect& rect) {
41 SkIRect result;
42 gfx::CGRectToSkRect(rect).round(&result);
43 return result;
44 }
45
46 // A class to generate events on Mac.
47 class EventExecutorMac : public EventExecutor {
48 public:
49 explicit EventExecutorMac(
50 scoped_refptr<base::SingleThreadTaskRunner> task_runner);
51 virtual ~EventExecutorMac();
52
53 // ClipboardStub interface.
54 virtual void InjectClipboardEvent(const ClipboardEvent& event) OVERRIDE;
55
56 // InputStub interface.
57 virtual void InjectKeyEvent(const KeyEvent& event) OVERRIDE;
58 virtual void InjectMouseEvent(const MouseEvent& event) OVERRIDE;
59
60 // EventExecutor interface.
61 virtual void Start(
62 scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE;
63
64 private:
65 // The actual implementation resides in EventExecutorMac::Core class.
66 class Core : public base::RefCountedThreadSafe<Core> {
67 public:
68 explicit Core(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
69
70 // Mirrors the ClipboardStub interface.
71 void InjectClipboardEvent(const ClipboardEvent& event);
72
73 // Mirrors the InputStub interface.
74 void InjectKeyEvent(const KeyEvent& event);
75 void InjectMouseEvent(const MouseEvent& event);
76
77 // Mirrors the EventExecutor interface.
78 void Start(scoped_ptr<protocol::ClipboardStub> client_clipboard);
79
80 void Stop();
81
82 private:
83 friend class base::RefCountedThreadSafe<Core>;
84 virtual ~Core();
85
86 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
87 SkIPoint mouse_pos_;
88 uint32 mouse_button_state_;
89 scoped_ptr<Clipboard> clipboard_;
90
91 DISALLOW_COPY_AND_ASSIGN(Core);
92 };
93
94 scoped_refptr<Core> core_;
95
96 DISALLOW_COPY_AND_ASSIGN(EventExecutorMac);
97 };
98
99 EventExecutorMac::EventExecutorMac(
100 scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
101 core_ = new Core(task_runner);
102 }
103
104 EventExecutorMac::~EventExecutorMac() {
105 core_->Stop();
106 }
107
108 void EventExecutorMac::InjectClipboardEvent(const ClipboardEvent& event) {
109 core_->InjectClipboardEvent(event);
110 }
111
112 void EventExecutorMac::InjectKeyEvent(const KeyEvent& event) {
113 core_->InjectKeyEvent(event);
114 }
115
116 void EventExecutorMac::InjectMouseEvent(const MouseEvent& event) {
117 core_->InjectMouseEvent(event);
118 }
119
120 void EventExecutorMac::Start(
121 scoped_ptr<protocol::ClipboardStub> client_clipboard) {
122 core_->Start(client_clipboard.Pass());
123 }
124
125 EventExecutorMac::Core::Core(
126 scoped_refptr<base::SingleThreadTaskRunner> task_runner)
127 : task_runner_(task_runner),
128 mouse_button_state_(0),
129 clipboard_(Clipboard::Create()) {
130 // Ensure that local hardware events are not suppressed after injecting
131 // input events. This allows LocalInputMonitor to detect if the local mouse
132 // is being moved whilst a remote user is connected.
133 // This API is deprecated, but it is needed when using the deprecated
134 // injection APIs.
135 // If the non-deprecated injection APIs were used instead, the equivalent of
136 // this line would not be needed, as OS X defaults to _not_ suppressing local
137 // inputs in that case.
138 #pragma clang diagnostic push
139 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
140 CGSetLocalEventsSuppressionInterval(0.0);
141 #pragma clang diagnostic pop
142 }
143
144 void EventExecutorMac::Core::InjectClipboardEvent(const ClipboardEvent& event) {
145 if (!task_runner_->BelongsToCurrentThread()) {
146 task_runner_->PostTask(
147 FROM_HERE, base::Bind(&Core::InjectClipboardEvent, this, event));
148 return;
149 }
150
151 // |clipboard_| will ignore unknown MIME-types, and verify the data's format.
152 clipboard_->InjectClipboardEvent(event);
153 }
154
155 void EventExecutorMac::Core::InjectKeyEvent(const KeyEvent& event) {
156 // HostEventDispatcher should filter events missing the pressed field.
157 if (!event.has_pressed() || !event.has_usb_keycode())
158 return;
159
160 int keycode = UsbKeycodeToNativeKeycode(event.usb_keycode());
161
162 VLOG(3) << "Converting USB keycode: " << std::hex << event.usb_keycode()
163 << " to keycode: " << keycode << std::dec;
164
165 // If we couldn't determine the Mac virtual key code then ignore the event.
166 if (keycode == InvalidNativeKeycode())
167 return;
168
169 // We use the deprecated event injection API because the new one doesn't
170 // work with switched-out sessions (curtain mode).
171 #pragma clang diagnostic push
172 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
173 CGError error = CGPostKeyboardEvent(0, keycode, event.pressed());
174 #pragma clang diagnostic pop
175 if (error != kCGErrorSuccess)
176 LOG(WARNING) << "CGPostKeyboardEvent error " << error;
177 }
178
179 void EventExecutorMac::Core::InjectMouseEvent(const MouseEvent& event) {
180 if (event.has_x() && event.has_y()) {
181 // On multi-monitor systems (0,0) refers to the top-left of the "main"
182 // display, whereas our coordinate scheme places (0,0) at the top-left of
183 // the bounding rectangle around all the displays, so we need to translate
184 // accordingly.
185
186 // Set the mouse position assuming single-monitor.
187 mouse_pos_ = SkIPoint::Make(event.x(), event.y());
188
189 // Fetch the desktop configuration.
190 // TODO(wez): Optimize this out, or at least only enumerate displays in
191 // response to display-changed events. VideoFrameCapturer's VideoFrames
192 // could be augmented to include native cursor coordinates for use by
193 // MouseClampingFilter, removing the need for translation here.
194 media::MacDesktopConfiguration desktop_config =
195 media::MacDesktopConfiguration::GetCurrent(
196 media::MacDesktopConfiguration::TopLeftOrigin);
197
198 // Translate the mouse position into desktop coordinates.
199 mouse_pos_ += SkIPoint::Make(desktop_config.pixel_bounds.left(),
200 desktop_config.pixel_bounds.top());
201
202 // Constrain the mouse position to the desktop coordinates.
203 mouse_pos_ = SkIPoint::Make(
204 std::max(desktop_config.pixel_bounds.left(),
205 std::min(desktop_config.pixel_bounds.right(), mouse_pos_.x())),
206 std::max(desktop_config.pixel_bounds.top(),
207 std::min(desktop_config.pixel_bounds.bottom(), mouse_pos_.y())));
208
209 // Convert from pixel to Density Independent Pixel coordinates.
210 mouse_pos_ = SkIPoint::Make(
211 SkScalarRound(mouse_pos_.x() / desktop_config.dip_to_pixel_scale),
212 SkScalarRound(mouse_pos_.y() / desktop_config.dip_to_pixel_scale));
213
214 VLOG(3) << "Moving mouse to " << mouse_pos_.x() << "," << mouse_pos_.y();
215 }
216 if (event.has_button() && event.has_button_down()) {
217 if (event.button() >= 1 && event.button() <= 3) {
218 VLOG(2) << "Button " << event.button()
219 << (event.button_down() ? " down" : " up");
220 int button_change = 1 << (event.button() - 1);
221 if (event.button_down())
222 mouse_button_state_ |= button_change;
223 else
224 mouse_button_state_ &= ~button_change;
225 } else {
226 VLOG(1) << "Unknown mouse button: " << event.button();
227 }
228 }
229 // We use the deprecated CGPostMouseEvent API because we receive low-level
230 // mouse events, whereas CGEventCreateMouseEvent is for injecting higher-level
231 // events. For example, the deprecated APIs will detect double-clicks or drags
232 // in a way that is consistent with how they would be generated using a local
233 // mouse, whereas the new APIs expect us to inject these higher-level events
234 // directly.
235 CGPoint position = CGPointMake(mouse_pos_.x(), mouse_pos_.y());
236 enum {
237 LeftBit = 1 << (MouseEvent::BUTTON_LEFT - 1),
238 MiddleBit = 1 << (MouseEvent::BUTTON_MIDDLE - 1),
239 RightBit = 1 << (MouseEvent::BUTTON_RIGHT - 1)
240 };
241 #pragma clang diagnostic push
242 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
243 CGError error = CGPostMouseEvent(position, true, 3,
244 (mouse_button_state_ & LeftBit) != 0,
245 (mouse_button_state_ & RightBit) != 0,
246 (mouse_button_state_ & MiddleBit) != 0);
247 #pragma clang diagnostic pop
248 if (error != kCGErrorSuccess)
249 LOG(WARNING) << "CGPostMouseEvent error " << error;
250
251 if (event.has_wheel_delta_x() && event.has_wheel_delta_y()) {
252 int delta_x = static_cast<int>(event.wheel_delta_x());
253 int delta_y = static_cast<int>(event.wheel_delta_y());
254 base::mac::ScopedCFTypeRef<CGEventRef> event(
255 CGEventCreateScrollWheelEvent(
256 NULL, kCGScrollEventUnitPixel, 2, delta_y, delta_x));
257 if (event)
258 CGEventPost(kCGSessionEventTap, event);
259 }
260 }
261
262 void EventExecutorMac::Core::Start(
263 scoped_ptr<protocol::ClipboardStub> client_clipboard) {
264 if (!task_runner_->BelongsToCurrentThread()) {
265 task_runner_->PostTask(
266 FROM_HERE,
267 base::Bind(&Core::Start, this, base::Passed(&client_clipboard)));
268 return;
269 }
270
271 clipboard_->Start(client_clipboard.Pass());
272 }
273
274 void EventExecutorMac::Core::Stop() {
275 if (!task_runner_->BelongsToCurrentThread()) {
276 task_runner_->PostTask(FROM_HERE, base::Bind(&Core::Stop, this));
277 return;
278 }
279
280 clipboard_->Stop();
281 }
282
283 EventExecutorMac::Core::~Core() {
284 }
285
286 } // namespace
287
288 scoped_ptr<EventExecutor> EventExecutor::Create(
289 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
290 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
291 return scoped_ptr<EventExecutor>(new EventExecutorMac(main_task_runner));
292 }
293
294 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/event_executor_linux.cc ('k') | remoting/host/event_executor_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698