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

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

Issue 422503004: Adding ability to stream windows and inject events to them (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: I updated the code with almost all of the comments Lambros had. The exceptions are the redesign of … Created 6 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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 "remoting/host/input_injector.h" 5 #include "remoting/host/input_injector.h"
6 6
7 #include <ApplicationServices/ApplicationServices.h> 7 #include <ApplicationServices/ApplicationServices.h>
8 #include <Carbon/Carbon.h> 8 #include <Carbon/Carbon.h>
9 #include <algorithm> 9 #include <algorithm>
10 10
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 using protocol::ClipboardEvent; 53 using protocol::ClipboardEvent;
54 using protocol::KeyEvent; 54 using protocol::KeyEvent;
55 using protocol::TextEvent; 55 using protocol::TextEvent;
56 using protocol::MouseEvent; 56 using protocol::MouseEvent;
57 57
58 // A class to generate events on Mac. 58 // A class to generate events on Mac.
59 class InputInjectorMac : public InputInjector { 59 class InputInjectorMac : public InputInjector {
60 public: 60 public:
61 explicit InputInjectorMac( 61 explicit InputInjectorMac(
62 scoped_refptr<base::SingleThreadTaskRunner> task_runner); 62 scoped_refptr<base::SingleThreadTaskRunner> task_runner);
63
63 virtual ~InputInjectorMac(); 64 virtual ~InputInjectorMac();
64 65
65 // ClipboardStub interface. 66 // ClipboardStub interface.
66 virtual void InjectClipboardEvent(const ClipboardEvent& event) OVERRIDE; 67 virtual void InjectClipboardEvent(const ClipboardEvent& event) OVERRIDE;
67 68
68 // InputStub interface. 69 // InputStub interface.
69 virtual void InjectKeyEvent(const KeyEvent& event) OVERRIDE; 70 virtual void InjectKeyEvent(const KeyEvent& event) OVERRIDE;
70 virtual void InjectTextEvent(const TextEvent& event) OVERRIDE; 71 virtual void InjectTextEvent(const TextEvent& event) OVERRIDE;
71 virtual void InjectMouseEvent(const MouseEvent& event) OVERRIDE; 72 virtual void InjectMouseEvent(const MouseEvent& event) OVERRIDE;
72 73
73 // InputInjector interface. 74 // InputInjector interface.
74 virtual void Start( 75 virtual void Start(
75 scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE; 76 scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE;
77 void EnableWindowInjection(webrtc::WindowId window_id);
76 78
77 private: 79 private:
80 CGWindowID window_id_input_injector_mac_;
Wez 2014/08/01 23:41:53 Members appear after type definitions (see style g
ronakvora do not use 2014/08/05 19:54:49 Got it. Removed anyhow since it was not needed, as
78 // The actual implementation resides in InputInjectorMac::Core class. 81 // The actual implementation resides in InputInjectorMac::Core class.
79 class Core : public base::RefCountedThreadSafe<Core> { 82 class Core : public base::RefCountedThreadSafe<Core> {
80 public: 83 public:
81 explicit Core(scoped_refptr<base::SingleThreadTaskRunner> task_runner); 84 explicit Core(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
82 85
83 // Mirrors the ClipboardStub interface. 86 // Mirrors the ClipboardStub interface.
84 void InjectClipboardEvent(const ClipboardEvent& event); 87 void InjectClipboardEvent(const ClipboardEvent& event);
85 88
86 // Mirrors the InputStub interface. 89 // Mirrors the InputStub interface.
87 void InjectKeyEvent(const KeyEvent& event); 90 void InjectKeyEvent(const KeyEvent& event);
88 void InjectTextEvent(const TextEvent& event); 91 void InjectTextEvent(const TextEvent& event);
89 void InjectMouseEvent(const MouseEvent& event); 92 void InjectMouseEvent(const MouseEvent& event);
90 93
91 // Mirrors the InputInjector interface. 94 // Mirrors the InputInjector interface.
92 void Start(scoped_ptr<protocol::ClipboardStub> client_clipboard); 95 void Start(scoped_ptr<protocol::ClipboardStub> client_clipboard);
96 void EnableWindowInjection(CGWindowID window_id);
93 97
94 void Stop(); 98 void Stop();
95 99
96 private: 100 private:
97 friend class base::RefCountedThreadSafe<Core>; 101 friend class base::RefCountedThreadSafe<Core>;
98 virtual ~Core(); 102 virtual ~Core();
103 CGRect FindCGRectOfWindow(webrtc::MacDesktopConfiguration desktop_config);
99 104
100 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 105 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
101 webrtc::DesktopVector mouse_pos_; 106 webrtc::DesktopVector mouse_pos_;
102 uint32 mouse_button_state_; 107 uint32 mouse_button_state_;
103 scoped_ptr<Clipboard> clipboard_; 108 scoped_ptr<Clipboard> clipboard_;
104 CGEventFlags left_modifiers_; 109 CGEventFlags left_modifiers_;
105 CGEventFlags right_modifiers_; 110 CGEventFlags right_modifiers_;
111 CGWindowID window_id_core_;
112 bool window_injection_enabled_;
106 113
107 DISALLOW_COPY_AND_ASSIGN(Core); 114 DISALLOW_COPY_AND_ASSIGN(Core);
108 }; 115 };
109 116
110 scoped_refptr<Core> core_; 117 scoped_refptr<Core> core_;
111 118
112 DISALLOW_COPY_AND_ASSIGN(InputInjectorMac); 119 DISALLOW_COPY_AND_ASSIGN(InputInjectorMac);
113 }; 120 };
114 121
115 InputInjectorMac::InputInjectorMac( 122 InputInjectorMac::InputInjectorMac(
(...skipping 19 matching lines...) Expand all
135 142
136 void InputInjectorMac::InjectMouseEvent(const MouseEvent& event) { 143 void InputInjectorMac::InjectMouseEvent(const MouseEvent& event) {
137 core_->InjectMouseEvent(event); 144 core_->InjectMouseEvent(event);
138 } 145 }
139 146
140 void InputInjectorMac::Start( 147 void InputInjectorMac::Start(
141 scoped_ptr<protocol::ClipboardStub> client_clipboard) { 148 scoped_ptr<protocol::ClipboardStub> client_clipboard) {
142 core_->Start(client_clipboard.Pass()); 149 core_->Start(client_clipboard.Pass());
143 } 150 }
144 151
152 void InputInjectorMac::EnableWindowInjection(webrtc::WindowId window_id) {
153 window_id_input_injector_mac_ = (CGWindowID) window_id;
Wez 2014/08/01 23:41:53 Why do you need to store this in the InputInjector
ronakvora do not use 2014/08/05 19:54:49 Don't. Removed!
154 core_->EnableWindowInjection(window_id_input_injector_mac_);
155 }
156
145 InputInjectorMac::Core::Core( 157 InputInjectorMac::Core::Core(
146 scoped_refptr<base::SingleThreadTaskRunner> task_runner) 158 scoped_refptr<base::SingleThreadTaskRunner> task_runner)
147 : task_runner_(task_runner), 159 : task_runner_(task_runner),
148 mouse_button_state_(0), 160 mouse_button_state_(0),
149 clipboard_(Clipboard::Create()), 161 clipboard_(Clipboard::Create()),
150 left_modifiers_(0), 162 left_modifiers_(0),
151 right_modifiers_(0) { 163 right_modifiers_(0) {
152 // Ensure that local hardware events are not suppressed after injecting 164 // Ensure that local hardware events are not suppressed after injecting
153 // input events. This allows LocalInputMonitor to detect if the local mouse 165 // input events. This allows LocalInputMonitor to detect if the local mouse
154 // is being moved whilst a remote user is connected. 166 // is being moved whilst a remote user is connected.
155 // This API is deprecated, but it is needed when using the deprecated 167 // This API is deprecated, but it is needed when using the deprecated
156 // injection APIs. 168 // injection APIs.
157 // If the non-deprecated injection APIs were used instead, the equivalent of 169 // If the non-deprecated injection APIs were used instead, the equivalent of
158 // this line would not be needed, as OS X defaults to _not_ suppressing local 170 // this line would not be needed, as OS X defaults to _not_ suppressing local
159 // inputs in that case. 171 // inputs in that case.
160 #pragma clang diagnostic push 172 #pragma clang diagnostic push
161 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 173 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
162 CGSetLocalEventsSuppressionInterval(0.0); 174 CGSetLocalEventsSuppressionInterval(0.0);
163 #pragma clang diagnostic pop 175 #pragma clang diagnostic pop
164 } 176 }
165 177
178 void InputInjectorMac::Core::EnableWindowInjection(CGWindowID window_id) {
179 window_id_core_ = window_id;
180 window_injection_enabled_ = true;
181 }
182
166 void InputInjectorMac::Core::InjectClipboardEvent(const ClipboardEvent& event) { 183 void InputInjectorMac::Core::InjectClipboardEvent(const ClipboardEvent& event) {
167 if (!task_runner_->BelongsToCurrentThread()) { 184 if (!task_runner_->BelongsToCurrentThread()) {
168 task_runner_->PostTask( 185 task_runner_->PostTask(
169 FROM_HERE, base::Bind(&Core::InjectClipboardEvent, this, event)); 186 FROM_HERE, base::Bind(&Core::InjectClipboardEvent, this, event));
170 return; 187 return;
171 } 188 }
172 189
173 // |clipboard_| will ignore unknown MIME-types, and verify the data's format. 190 // |clipboard_| will ignore unknown MIME-types, and verify the data's format.
174 clipboard_->InjectClipboardEvent(event); 191 clipboard_->InjectClipboardEvent(event);
175 } 192 }
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
221 void InputInjectorMac::Core::InjectTextEvent(const TextEvent& event) { 238 void InputInjectorMac::Core::InjectTextEvent(const TextEvent& event) {
222 DCHECK(event.has_text()); 239 DCHECK(event.has_text());
223 base::string16 text = base::UTF8ToUTF16(event.text()); 240 base::string16 text = base::UTF8ToUTF16(event.text());
224 241
225 // Applications that ignore UnicodeString field will see the text event as 242 // Applications that ignore UnicodeString field will see the text event as
226 // Space key. 243 // Space key.
227 CreateAndPostKeyEvent(kVK_Space, true, 0, text); 244 CreateAndPostKeyEvent(kVK_Space, true, 0, text);
228 CreateAndPostKeyEvent(kVK_Space, false, 0, text); 245 CreateAndPostKeyEvent(kVK_Space, false, 0, text);
229 } 246 }
230 247
248 // This method is used if we are capturing a window instead of a screen.
249 // It finds the rectangle of the window we are streaming using
250 // |window_id_core_|. The InputInjector can then use this rectangle
251 // to translate the input event to coordinates of the window rather
252 // than the screen.
253 CGRect InputInjectorMac::Core::FindCGRectOfWindow(
254 webrtc::MacDesktopConfiguration desktop_config) {
255 CGRect rect;
256 CGWindowID ids[1] = {window_id_core_};
257 CFArrayRef window_id_array =
258 CFArrayCreate(NULL, reinterpret_cast<const void **>(&ids), 1, NULL);
259 CFArrayRef window_array =
260 CGWindowListCreateDescriptionFromArray(window_id_array);
261 if (window_array == NULL || 0 == CFArrayGetCount(window_array)) {
262 // Could not find the window. It might have been closed.
263 LOG(ERROR) << "Specified window to stream not found for id: "
264 << window_id_core_;
265 CFRelease(window_id_array);
266 CFRelease(window_array);
267 return CGRectNull;
268 }
269 CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
270 CFArrayGetValueAtIndex(window_array, 0));
271
272 if (CFDictionaryContainsKey(window, kCGWindowBounds)) {
273 CFDictionaryRef bounds =
274 reinterpret_cast<CFDictionaryRef>
275 (CFDictionaryGetValue(window, kCGWindowBounds));
276 if (bounds) {
277 CGRectMakeWithDictionaryRepresentation(bounds, &rect);
278 }
279 }
280
281 CFRelease(window_id_array);
282 CFRelease(window_array);
283 return rect;
284 }
285
231 void InputInjectorMac::Core::InjectMouseEvent(const MouseEvent& event) { 286 void InputInjectorMac::Core::InjectMouseEvent(const MouseEvent& event) {
232 if (event.has_x() && event.has_y()) { 287 if (event.has_x() && event.has_y()) {
233 // On multi-monitor systems (0,0) refers to the top-left of the "main" 288 // On multi-monitor systems (0,0) refers to the top-left of the "main"
234 // display, whereas our coordinate scheme places (0,0) at the top-left of 289 // display, whereas our coordinate scheme places (0,0) at the top-left of
235 // the bounding rectangle around all the displays, so we need to translate 290 // the bounding rectangle around all the displays, so we need to translate
236 // accordingly. 291 // accordingly.
237 292
238 // Set the mouse position assuming single-monitor. 293 // Set the mouse position assuming single-monitor.
239 mouse_pos_.set(event.x(), event.y()); 294 mouse_pos_.set(event.x(), event.y());
240 295
(...skipping 15 matching lines...) Expand all
256 mouse_pos_.set( 311 mouse_pos_.set(
257 std::max(desktop_config.pixel_bounds.left(), 312 std::max(desktop_config.pixel_bounds.left(),
258 std::min(desktop_config.pixel_bounds.right(), mouse_pos_.x())), 313 std::min(desktop_config.pixel_bounds.right(), mouse_pos_.x())),
259 std::max(desktop_config.pixel_bounds.top(), 314 std::max(desktop_config.pixel_bounds.top(),
260 std::min(desktop_config.pixel_bounds.bottom(), mouse_pos_.y()))); 315 std::min(desktop_config.pixel_bounds.bottom(), mouse_pos_.y())));
261 316
262 // Convert from pixel to Density Independent Pixel coordinates. 317 // Convert from pixel to Density Independent Pixel coordinates.
263 mouse_pos_.set(mouse_pos_.x() / desktop_config.dip_to_pixel_scale, 318 mouse_pos_.set(mouse_pos_.x() / desktop_config.dip_to_pixel_scale,
264 mouse_pos_.y() / desktop_config.dip_to_pixel_scale); 319 mouse_pos_.y() / desktop_config.dip_to_pixel_scale);
265 320
321 if (window_injection_enabled_) {
322 CGRect windowRect = FindCGRectOfWindow(desktop_config);
323 if (CGRectEqualToRect(windowRect, CGRectNull)) {
324 LOG(ERROR) << "Can't find rectangle of window.";
325 return;
326 }
327 mouse_pos_ = mouse_pos_.add(
328 webrtc::DesktopVector(CGRectGetMinX(windowRect),
329 CGRectGetMinY(windowRect)));
Wez 2014/08/01 23:41:54 Do you mean to clamp input to the window width & h
ronakvora do not use 2014/08/05 19:54:49 I don't know what you mean by clamp input to windo
330 }
331
266 VLOG(3) << "Moving mouse to " << mouse_pos_.x() << "," << mouse_pos_.y(); 332 VLOG(3) << "Moving mouse to " << mouse_pos_.x() << "," << mouse_pos_.y();
267 } 333 }
268 if (event.has_button() && event.has_button_down()) { 334 if (event.has_button() && event.has_button_down()) {
269 if (event.button() >= 1 && event.button() <= 3) { 335 if (event.button() >= 1 && event.button() <= 3) {
270 VLOG(2) << "Button " << event.button() 336 VLOG(2) << "Button " << event.button()
271 << (event.button_down() ? " down" : " up"); 337 << (event.button_down() ? " down" : " up");
272 int button_change = 1 << (event.button() - 1); 338 int button_change = 1 << (event.button() - 1);
273 if (event.button_down()) 339 if (event.button_down())
274 mouse_button_state_ |= button_change; 340 mouse_button_state_ |= button_change;
275 else 341 else
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 InputInjectorMac::Core::~Core() {} 400 InputInjectorMac::Core::~Core() {}
335 401
336 } // namespace 402 } // namespace
337 403
338 scoped_ptr<InputInjector> InputInjector::Create( 404 scoped_ptr<InputInjector> InputInjector::Create(
339 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 405 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
340 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { 406 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
341 return scoped_ptr<InputInjector>(new InputInjectorMac(main_task_runner)); 407 return scoped_ptr<InputInjector>(new InputInjectorMac(main_task_runner));
342 } 408 }
343 409
410 scoped_ptr<InputInjector> InputInjector::CreateForWindow(
411 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
412 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
413 webrtc::WindowId window_id) {
414 scoped_ptr<InputInjectorMac>injector(new InputInjectorMac(main_task_runner));
415 injector->EnableWindowInjection(window_id);
416 return injector.PassAs<InputInjector>();
417 }
418
344 } // namespace remoting 419 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698