Chromium Code Reviews| 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 |