OLD | NEW |
---|---|
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 Loading... | |
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 // TODO(sidj, sskhandp) Remove these methods and use | |
78 // WindowInputInjectorMac instead. | |
79 virtual void SetWindowId(webrtc::WindowId windowId); | |
Lambros
2014/07/30 00:14:48
Do these need to be virtual?
ronakvora do not use
2014/07/30 20:55:36
Nope, changed.
| |
80 virtual void SetEnableWindowCapture(bool enable_window_capture); | |
Lambros
2014/07/30 00:14:48
Don't say "Capture" here. Maybe replace these meth
ronakvora do not use
2014/07/30 20:55:36
Done.
| |
76 | 81 |
77 private: | 82 private: |
83 // TODO(sidj, sskhandp) put these inside of WindowInputInjectorMac. | |
Lambros
2014/07/30 00:14:49
Remove TODO - I don't think it's worth defining a
ronakvora do not use
2014/07/30 20:55:36
Done.
| |
84 CGWindowID windowId_input_injector_mac_; | |
Lambros
2014/07/30 00:14:49
nit: window_id_
ronakvora do not use
2014/07/30 20:55:36
Done.
| |
85 bool enable_window_capture_injector_mac_; | |
Lambros
2014/07/30 00:14:48
nit: window_injection_enabled_ - don't use "captur
ronakvora do not use
2014/07/30 20:55:36
Done.
| |
78 // The actual implementation resides in InputInjectorMac::Core class. | 86 // The actual implementation resides in InputInjectorMac::Core class. |
79 class Core : public base::RefCountedThreadSafe<Core> { | 87 class Core : public base::RefCountedThreadSafe<Core> { |
80 public: | 88 public: |
81 explicit Core(scoped_refptr<base::SingleThreadTaskRunner> task_runner); | 89 explicit Core(scoped_refptr<base::SingleThreadTaskRunner> task_runner); |
82 | 90 |
83 // Mirrors the ClipboardStub interface. | 91 // Mirrors the ClipboardStub interface. |
84 void InjectClipboardEvent(const ClipboardEvent& event); | 92 void InjectClipboardEvent(const ClipboardEvent& event); |
85 | 93 |
86 // Mirrors the InputStub interface. | 94 // Mirrors the InputStub interface. |
87 void InjectKeyEvent(const KeyEvent& event); | 95 void InjectKeyEvent(const KeyEvent& event); |
88 void InjectTextEvent(const TextEvent& event); | 96 void InjectTextEvent(const TextEvent& event); |
89 void InjectMouseEvent(const MouseEvent& event); | 97 void InjectMouseEvent(const MouseEvent& event); |
90 | 98 |
91 // Mirrors the InputInjector interface. | 99 // Mirrors the InputInjector interface. |
92 void Start(scoped_ptr<protocol::ClipboardStub> client_clipboard); | 100 void Start(scoped_ptr<protocol::ClipboardStub> client_clipboard); |
93 | 101 |
102 // TODO(sidj, sskhandp) Remove these methods and use | |
Lambros
2014/07/30 00:14:48
Remove TODO.
ronakvora do not use
2014/07/30 20:55:36
Done.
| |
103 // WindowInputInjectorMac instead. | |
104 void SetWindowId(CGWindowID windowId); | |
105 void SetEnableWindowCapture(bool enable_window_capture); | |
106 | |
94 void Stop(); | 107 void Stop(); |
95 | 108 |
96 private: | 109 private: |
97 friend class base::RefCountedThreadSafe<Core>; | 110 friend class base::RefCountedThreadSafe<Core>; |
98 virtual ~Core(); | 111 virtual ~Core(); |
112 CGRect FindCGRectOfWindow(webrtc::MacDesktopConfiguration desktop_config); | |
99 | 113 |
100 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 114 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
101 webrtc::DesktopVector mouse_pos_; | 115 webrtc::DesktopVector mouse_pos_; |
102 uint32 mouse_button_state_; | 116 uint32 mouse_button_state_; |
103 scoped_ptr<Clipboard> clipboard_; | 117 scoped_ptr<Clipboard> clipboard_; |
104 CGEventFlags left_modifiers_; | 118 CGEventFlags left_modifiers_; |
105 CGEventFlags right_modifiers_; | 119 CGEventFlags right_modifiers_; |
120 // TODO(sidj, sskhandp) put these inside of WindowInputInjectorMac. | |
Lambros
2014/07/30 00:14:48
Remove TODO.
ronakvora do not use
2014/07/30 20:55:36
Done.
| |
121 CGWindowID windowId_core_; | |
122 bool enable_window_capture_core_; | |
106 | 123 |
107 DISALLOW_COPY_AND_ASSIGN(Core); | 124 DISALLOW_COPY_AND_ASSIGN(Core); |
108 }; | 125 }; |
109 | 126 |
110 scoped_refptr<Core> core_; | 127 scoped_refptr<Core> core_; |
111 | 128 |
112 DISALLOW_COPY_AND_ASSIGN(InputInjectorMac); | 129 DISALLOW_COPY_AND_ASSIGN(InputInjectorMac); |
113 }; | 130 }; |
114 | 131 |
115 InputInjectorMac::InputInjectorMac( | 132 InputInjectorMac::InputInjectorMac( |
(...skipping 19 matching lines...) Expand all Loading... | |
135 | 152 |
136 void InputInjectorMac::InjectMouseEvent(const MouseEvent& event) { | 153 void InputInjectorMac::InjectMouseEvent(const MouseEvent& event) { |
137 core_->InjectMouseEvent(event); | 154 core_->InjectMouseEvent(event); |
138 } | 155 } |
139 | 156 |
140 void InputInjectorMac::Start( | 157 void InputInjectorMac::Start( |
141 scoped_ptr<protocol::ClipboardStub> client_clipboard) { | 158 scoped_ptr<protocol::ClipboardStub> client_clipboard) { |
142 core_->Start(client_clipboard.Pass()); | 159 core_->Start(client_clipboard.Pass()); |
143 } | 160 } |
144 | 161 |
162 void InputInjectorMac::SetWindowId(webrtc::WindowId windowId) { | |
163 windowId_input_injector_mac_ = (CGWindowID) windowId; | |
164 core_->SetWindowId(windowId_input_injector_mac_); | |
165 } | |
166 | |
167 void InputInjectorMac::SetEnableWindowCapture(bool enable_window_capture) { | |
168 enable_window_capture_injector_mac_ = enable_window_capture; | |
169 core_->SetEnableWindowCapture(enable_window_capture_injector_mac_); | |
170 } | |
171 | |
145 InputInjectorMac::Core::Core( | 172 InputInjectorMac::Core::Core( |
146 scoped_refptr<base::SingleThreadTaskRunner> task_runner) | 173 scoped_refptr<base::SingleThreadTaskRunner> task_runner) |
147 : task_runner_(task_runner), | 174 : task_runner_(task_runner), |
148 mouse_button_state_(0), | 175 mouse_button_state_(0), |
149 clipboard_(Clipboard::Create()), | 176 clipboard_(Clipboard::Create()), |
150 left_modifiers_(0), | 177 left_modifiers_(0), |
151 right_modifiers_(0) { | 178 right_modifiers_(0) { |
152 // Ensure that local hardware events are not suppressed after injecting | 179 // Ensure that local hardware events are not suppressed after injecting |
153 // input events. This allows LocalInputMonitor to detect if the local mouse | 180 // input events. This allows LocalInputMonitor to detect if the local mouse |
154 // is being moved whilst a remote user is connected. | 181 // is being moved whilst a remote user is connected. |
155 // This API is deprecated, but it is needed when using the deprecated | 182 // This API is deprecated, but it is needed when using the deprecated |
156 // injection APIs. | 183 // injection APIs. |
157 // If the non-deprecated injection APIs were used instead, the equivalent of | 184 // 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 | 185 // this line would not be needed, as OS X defaults to _not_ suppressing local |
159 // inputs in that case. | 186 // inputs in that case. |
160 #pragma clang diagnostic push | 187 #pragma clang diagnostic push |
161 #pragma clang diagnostic ignored "-Wdeprecated-declarations" | 188 #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
162 CGSetLocalEventsSuppressionInterval(0.0); | 189 CGSetLocalEventsSuppressionInterval(0.0); |
163 #pragma clang diagnostic pop | 190 #pragma clang diagnostic pop |
164 } | 191 } |
165 | 192 |
193 void InputInjectorMac::Core::SetWindowId(CGWindowID windowId) { | |
194 windowId_core_ = windowId; | |
195 } | |
196 void InputInjectorMac::Core::SetEnableWindowCapture | |
197 (bool enable_window_capture) { | |
198 enable_window_capture_core_ = enable_window_capture; | |
199 } | |
166 void InputInjectorMac::Core::InjectClipboardEvent(const ClipboardEvent& event) { | 200 void InputInjectorMac::Core::InjectClipboardEvent(const ClipboardEvent& event) { |
167 if (!task_runner_->BelongsToCurrentThread()) { | 201 if (!task_runner_->BelongsToCurrentThread()) { |
168 task_runner_->PostTask( | 202 task_runner_->PostTask( |
169 FROM_HERE, base::Bind(&Core::InjectClipboardEvent, this, event)); | 203 FROM_HERE, base::Bind(&Core::InjectClipboardEvent, this, event)); |
170 return; | 204 return; |
171 } | 205 } |
172 | 206 |
173 // |clipboard_| will ignore unknown MIME-types, and verify the data's format. | 207 // |clipboard_| will ignore unknown MIME-types, and verify the data's format. |
174 clipboard_->InjectClipboardEvent(event); | 208 clipboard_->InjectClipboardEvent(event); |
175 } | 209 } |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
221 void InputInjectorMac::Core::InjectTextEvent(const TextEvent& event) { | 255 void InputInjectorMac::Core::InjectTextEvent(const TextEvent& event) { |
222 DCHECK(event.has_text()); | 256 DCHECK(event.has_text()); |
223 base::string16 text = base::UTF8ToUTF16(event.text()); | 257 base::string16 text = base::UTF8ToUTF16(event.text()); |
224 | 258 |
225 // Applications that ignore UnicodeString field will see the text event as | 259 // Applications that ignore UnicodeString field will see the text event as |
226 // Space key. | 260 // Space key. |
227 CreateAndPostKeyEvent(kVK_Space, true, 0, text); | 261 CreateAndPostKeyEvent(kVK_Space, true, 0, text); |
228 CreateAndPostKeyEvent(kVK_Space, false, 0, text); | 262 CreateAndPostKeyEvent(kVK_Space, false, 0, text); |
229 } | 263 } |
230 | 264 |
265 CGRect InputInjectorMac::Core::FindCGRectOfWindow( | |
266 webrtc::MacDesktopConfiguration desktop_config) { | |
267 CGRect rect; | |
268 CGWindowID ids[1] = {windowId_core_}; | |
269 CFArrayRef window_id_array = | |
270 CFArrayCreate(NULL, reinterpret_cast<const void **>(&ids), 1, NULL); | |
271 CFArrayRef window_array = | |
272 CGWindowListCreateDescriptionFromArray(window_id_array); | |
273 if (window_array == NULL || 0 == CFArrayGetCount(window_array)) { | |
274 // Could not find the window. It might have been closed. | |
275 LOG(ERROR) << "Specified window to stream not found for id: " | |
276 << windowId_core_; | |
277 CFRelease(window_id_array); | |
Lambros
2014/07/30 00:14:49
Use ScopedCFTypeRef from base/mac/scoped_cftyperef
ronakvora do not use
2014/07/30 20:55:36
I've been a bit confused on the scoped_X types. Do
| |
278 CFRelease(window_array); | |
279 return CGRectNull; | |
280 } | |
281 CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>( | |
282 CFArrayGetValueAtIndex(window_array, 0)); | |
283 | |
284 if (CFDictionaryContainsKey(window, kCGWindowBounds)) { | |
285 CFDictionaryRef bounds = | |
286 reinterpret_cast<CFDictionaryRef> | |
287 (CFDictionaryGetValue(window, kCGWindowBounds)); | |
288 if (bounds) { | |
289 CGRectMakeWithDictionaryRepresentation(bounds, &rect); | |
290 } | |
291 } | |
292 | |
293 CFRelease(window_id_array); | |
294 CFRelease(window_array); | |
295 return rect; | |
296 } | |
297 | |
231 void InputInjectorMac::Core::InjectMouseEvent(const MouseEvent& event) { | 298 void InputInjectorMac::Core::InjectMouseEvent(const MouseEvent& event) { |
232 if (event.has_x() && event.has_y()) { | 299 if (event.has_x() && event.has_y()) { |
233 // On multi-monitor systems (0,0) refers to the top-left of the "main" | 300 // 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 | 301 // 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 | 302 // the bounding rectangle around all the displays, so we need to translate |
236 // accordingly. | 303 // accordingly. |
237 | 304 |
238 // Set the mouse position assuming single-monitor. | 305 // Set the mouse position assuming single-monitor. |
239 mouse_pos_.set(event.x(), event.y()); | 306 mouse_pos_.set(event.x(), event.y()); |
240 | 307 |
(...skipping 15 matching lines...) Expand all Loading... | |
256 mouse_pos_.set( | 323 mouse_pos_.set( |
257 std::max(desktop_config.pixel_bounds.left(), | 324 std::max(desktop_config.pixel_bounds.left(), |
258 std::min(desktop_config.pixel_bounds.right(), mouse_pos_.x())), | 325 std::min(desktop_config.pixel_bounds.right(), mouse_pos_.x())), |
259 std::max(desktop_config.pixel_bounds.top(), | 326 std::max(desktop_config.pixel_bounds.top(), |
260 std::min(desktop_config.pixel_bounds.bottom(), mouse_pos_.y()))); | 327 std::min(desktop_config.pixel_bounds.bottom(), mouse_pos_.y()))); |
261 | 328 |
262 // Convert from pixel to Density Independent Pixel coordinates. | 329 // Convert from pixel to Density Independent Pixel coordinates. |
263 mouse_pos_.set(mouse_pos_.x() / desktop_config.dip_to_pixel_scale, | 330 mouse_pos_.set(mouse_pos_.x() / desktop_config.dip_to_pixel_scale, |
264 mouse_pos_.y() / desktop_config.dip_to_pixel_scale); | 331 mouse_pos_.y() / desktop_config.dip_to_pixel_scale); |
265 | 332 |
333 // Translate the mouse position into window coordinates. | |
334 // TODO(sskhandp, sidj) Remove this if clause and implement | |
335 // functionality in WindowInputInjectorMac. | |
336 if (enable_window_capture_core_) { | |
337 CGRect windowRect = FindCGRectOfWindow(desktop_config); | |
338 if (CGRectEqualToRect(windowRect, CGRectNull)) { | |
339 LOG(ERROR) << "Can't find rectangle of window."; | |
340 return; | |
341 } | |
342 mouse_pos_ = mouse_pos_.add( | |
343 webrtc::DesktopVector(CGRectGetMinX(windowRect), | |
344 CGRectGetMinY(windowRect))); | |
345 } | |
346 | |
266 VLOG(3) << "Moving mouse to " << mouse_pos_.x() << "," << mouse_pos_.y(); | 347 VLOG(3) << "Moving mouse to " << mouse_pos_.x() << "," << mouse_pos_.y(); |
267 } | 348 } |
268 if (event.has_button() && event.has_button_down()) { | 349 if (event.has_button() && event.has_button_down()) { |
269 if (event.button() >= 1 && event.button() <= 3) { | 350 if (event.button() >= 1 && event.button() <= 3) { |
270 VLOG(2) << "Button " << event.button() | 351 VLOG(2) << "Button " << event.button() |
271 << (event.button_down() ? " down" : " up"); | 352 << (event.button_down() ? " down" : " up"); |
272 int button_change = 1 << (event.button() - 1); | 353 int button_change = 1 << (event.button() - 1); |
273 if (event.button_down()) | 354 if (event.button_down()) |
274 mouse_button_state_ |= button_change; | 355 mouse_button_state_ |= button_change; |
275 else | 356 else |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
334 InputInjectorMac::Core::~Core() {} | 415 InputInjectorMac::Core::~Core() {} |
335 | 416 |
336 } // namespace | 417 } // namespace |
337 | 418 |
338 scoped_ptr<InputInjector> InputInjector::Create( | 419 scoped_ptr<InputInjector> InputInjector::Create( |
339 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, | 420 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, |
340 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { | 421 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { |
341 return scoped_ptr<InputInjector>(new InputInjectorMac(main_task_runner)); | 422 return scoped_ptr<InputInjector>(new InputInjectorMac(main_task_runner)); |
342 } | 423 } |
343 | 424 |
425 // TODO(sskhandp, sidj) remove this method and make WindowInputInjector | |
Lambros
2014/07/30 00:14:48
Remove TODO.
ronakvora do not use
2014/07/30 20:55:36
Done.
| |
426 scoped_ptr<InputInjector> InputInjector::Create( | |
427 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, | |
428 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, | |
429 webrtc::WindowId windowId, | |
430 bool enable_window_capture) { | |
431 InputInjectorMac* injector = new InputInjectorMac(main_task_runner); | |
Lambros
2014/07/30 00:14:49
nit: Declare |injector| as scoped_ptr instead of r
ronakvora do not use
2014/07/30 20:55:36
Done.
| |
432 injector->SetWindowId(windowId); | |
433 injector->SetEnableWindowCapture(enable_window_capture); | |
434 return scoped_ptr<InputInjector>(injector); | |
435 } | |
436 | |
344 } // namespace remoting | 437 } // namespace remoting |
OLD | NEW |