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 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |