OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 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/single_window_input_injector.h" |
| 6 |
| 7 #include <ApplicationServices/ApplicationServices.h> |
| 8 #include <Carbon/Carbon.h> |
| 9 |
| 10 #include "base/mac/foundation_util.h" |
| 11 #include "base/mac/scoped_cftyperef.h" |
| 12 #include "remoting/proto/event.pb.h" |
| 13 #include "third_party/webrtc/modules/desktop_capture/mac/desktop_configuration.h
" |
| 14 |
| 15 namespace remoting { |
| 16 |
| 17 using protocol::ClipboardEvent; |
| 18 using protocol::KeyEvent; |
| 19 using protocol::TextEvent; |
| 20 using protocol::MouseEvent; |
| 21 |
| 22 class SingleWindowInputInjectorMac : public SingleWindowInputInjector { |
| 23 public: |
| 24 SingleWindowInputInjectorMac( |
| 25 webrtc::WindowId window_id, |
| 26 scoped_ptr<InputInjector> input_injector); |
| 27 virtual ~SingleWindowInputInjectorMac(); |
| 28 |
| 29 // InputInjector interface. |
| 30 virtual void Start( |
| 31 scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE; |
| 32 virtual void InjectKeyEvent(const KeyEvent& event) OVERRIDE; |
| 33 virtual void InjectTextEvent(const TextEvent& event) OVERRIDE; |
| 34 virtual void InjectMouseEvent(const MouseEvent& event) OVERRIDE; |
| 35 virtual void InjectClipboardEvent(const ClipboardEvent& event) OVERRIDE; |
| 36 |
| 37 private: |
| 38 CGRect FindCGRectOfWindow(); |
| 39 |
| 40 CGWindowID window_id_; |
| 41 scoped_ptr<InputInjector> input_injector_; |
| 42 |
| 43 DISALLOW_COPY_AND_ASSIGN(SingleWindowInputInjectorMac); |
| 44 }; |
| 45 |
| 46 SingleWindowInputInjectorMac::SingleWindowInputInjectorMac( |
| 47 webrtc::WindowId window_id, |
| 48 scoped_ptr<InputInjector> input_injector) |
| 49 : window_id_(static_cast<CGWindowID>(window_id)), |
| 50 input_injector_(input_injector.Pass()) { |
| 51 } |
| 52 |
| 53 SingleWindowInputInjectorMac::~SingleWindowInputInjectorMac() { |
| 54 } |
| 55 |
| 56 void SingleWindowInputInjectorMac::Start( |
| 57 scoped_ptr<protocol::ClipboardStub> client_clipboard) { |
| 58 input_injector_->Start(client_clipboard.Pass()); |
| 59 } |
| 60 |
| 61 void SingleWindowInputInjectorMac::InjectKeyEvent(const KeyEvent& event) { |
| 62 input_injector_->InjectKeyEvent(event); |
| 63 } |
| 64 |
| 65 void SingleWindowInputInjectorMac::InjectTextEvent(const TextEvent& event) { |
| 66 input_injector_->InjectTextEvent(event); |
| 67 } |
| 68 |
| 69 void SingleWindowInputInjectorMac::InjectMouseEvent(const MouseEvent& event) { |
| 70 if (event.has_x() && event.has_y()) { |
| 71 CGRect window_rect = FindCGRectOfWindow(); |
| 72 if (CGRectIsNull(window_rect)) { |
| 73 LOG(ERROR) << "Window rect is null, so forwarding unmodified MouseEvent"; |
| 74 input_injector_->InjectMouseEvent(event); |
| 75 return; |
| 76 } |
| 77 |
| 78 webrtc::MacDesktopConfiguration desktop_config = |
| 79 webrtc::MacDesktopConfiguration::GetCurrent( |
| 80 webrtc::MacDesktopConfiguration::TopLeftOrigin); |
| 81 |
| 82 // Create a vector that has the origin of the window. |
| 83 webrtc::DesktopVector window_pos(window_rect.origin.x, |
| 84 window_rect.origin.y); |
| 85 |
| 86 // The underlying InputInjector expects coordinates relative to the |
| 87 // top-left of the top-left-most monitor, so translate the window origin |
| 88 // to that coordinate scheme. |
| 89 window_pos.subtract( |
| 90 webrtc::DesktopVector(desktop_config.pixel_bounds.left(), |
| 91 desktop_config.pixel_bounds.top())); |
| 92 |
| 93 // We must make sure we are taking into account the fact that when we |
| 94 // find the window on the host it returns its coordinates in Density |
| 95 // Independent coordinates. We have to convert to Density Dependent |
| 96 // because InputInjector assumes Density Dependent coordinates in the |
| 97 // MouseEvent. |
| 98 window_pos.set(window_pos.x() * desktop_config.dip_to_pixel_scale, |
| 99 window_pos.y() * desktop_config.dip_to_pixel_scale); |
| 100 |
| 101 // Create a new event with coordinates that are in respect to the window. |
| 102 MouseEvent modified_event(event); |
| 103 modified_event.set_x(event.x() + window_pos.x()); |
| 104 modified_event.set_y(event.y() + window_pos.y()); |
| 105 input_injector_->InjectMouseEvent(modified_event); |
| 106 } else { |
| 107 input_injector_->InjectMouseEvent(event); |
| 108 } |
| 109 } |
| 110 |
| 111 void SingleWindowInputInjectorMac::InjectClipboardEvent( |
| 112 const ClipboardEvent& event) { |
| 113 input_injector_->InjectClipboardEvent(event); |
| 114 } |
| 115 |
| 116 // This method finds the rectangle of the window we are streaming using |
| 117 // |window_id_|. The InputInjector can then use this rectangle |
| 118 // to translate the input event to coordinates of the window rather |
| 119 // than the screen. |
| 120 CGRect SingleWindowInputInjectorMac::FindCGRectOfWindow() { |
| 121 CGRect rect; |
| 122 CGWindowID ids[1] = {window_id_}; |
| 123 base::ScopedCFTypeRef<CFArrayRef> window_id_array( |
| 124 CFArrayCreate(NULL, reinterpret_cast<const void **>(&ids), 1, NULL)); |
| 125 |
| 126 base::ScopedCFTypeRef<CFArrayRef> window_array( |
| 127 CGWindowListCreateDescriptionFromArray(window_id_array)); |
| 128 |
| 129 if (window_array == NULL || CFArrayGetCount(window_array) == 0) { |
| 130 // Could not find the window. It might have been closed. |
| 131 LOG(ERROR) << "Specified window to stream not found for id: " |
| 132 << window_id_; |
| 133 return CGRectNull; |
| 134 } |
| 135 |
| 136 // We don't use ScopedCFTypeRef for |window_array| because the |
| 137 // CFDictionaryRef returned by CFArrayGetValueAtIndex is owned by |
| 138 // window_array. The same is true of the |bounds|. |
| 139 CFDictionaryRef window = |
| 140 base::mac::CFCast<CFDictionaryRef>( |
| 141 CFArrayGetValueAtIndex(window_array, 0)); |
| 142 |
| 143 if (CFDictionaryContainsKey(window, kCGWindowBounds)) { |
| 144 CFDictionaryRef bounds = |
| 145 base::mac::GetValueFromDictionary<CFDictionaryRef>( |
| 146 window, kCGWindowBounds); |
| 147 |
| 148 if (bounds) { |
| 149 if (CGRectMakeWithDictionaryRepresentation(bounds, &rect)) { |
| 150 return rect; |
| 151 } |
| 152 } |
| 153 } |
| 154 |
| 155 return CGRectNull; |
| 156 } |
| 157 |
| 158 scoped_ptr<InputInjector> SingleWindowInputInjector::CreateForWindow( |
| 159 webrtc::WindowId window_id, |
| 160 scoped_ptr<InputInjector> input_injector) { |
| 161 scoped_ptr<SingleWindowInputInjectorMac> injector( |
| 162 new SingleWindowInputInjectorMac(window_id, input_injector.Pass())); |
| 163 return injector.PassAs<InputInjector>(); |
| 164 } |
| 165 |
| 166 } // namespace remoting |
OLD | NEW |