15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "remoting/host/input_injector.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <ApplicationServices/ApplicationServices.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <Carbon/Carbon.h> 9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include <algorithm> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/location.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/scoped_cftyperef.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/single_thread_task_runner.h" 18effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/strings/utf_string_conversions.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/clipboard.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/proto/internal.pb.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/protocol/message_decoder.h" 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" 23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/webrtc/modules/desktop_capture/mac/desktop_configuration.h" 24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/events/keycodes/dom4/keycode_converter.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SetOrClearBit(uint64_t &value, uint64_t bit, bool set_bit) { 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) value = set_bit ? (value | bit) : (value & ~bit); 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 34effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid CreateAndPostKeyEvent(int keycode, 35effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch bool pressed, 36effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch int flags, 37effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const base::string16& unicode) { 38effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::ScopedCFTypeRef<CGEventRef> eventRef( 39effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch CGEventCreateKeyboardEvent(NULL, keycode, pressed)); 40effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (eventRef) { 41effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch CGEventSetFlags(eventRef, flags); 42effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (!unicode.empty()) 43effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch CGEventKeyboardSetUnicodeString(eventRef, unicode.size(), &(unicode[0])); 44effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch CGEventPost(kCGSessionEventTap, eventRef); 45effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 46effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 47effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This value is not defined. Give it the obvious name so that if it is ever 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// added there will be a handy compilation error to remind us to remove this 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// definition. 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kVK_RightCommand = 0x36; 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using protocol::ClipboardEvent; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using protocol::KeyEvent; 55effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochusing protocol::TextEvent; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using protocol::MouseEvent; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A class to generate events on Mac. 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class InputInjectorMac : public InputInjector { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) explicit InputInjectorMac( 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<base::SingleThreadTaskRunner> task_runner); 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual ~InputInjectorMac(); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ClipboardStub interface. 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void InjectClipboardEvent(const ClipboardEvent& event) OVERRIDE; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // InputStub interface. 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void InjectKeyEvent(const KeyEvent& event) OVERRIDE; 70effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch virtual void InjectTextEvent(const TextEvent& event) OVERRIDE; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void InjectMouseEvent(const MouseEvent& event) OVERRIDE; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // InputInjector interface. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void Start( 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The actual implementation resides in InputInjectorMac::Core class. 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) class Core : public base::RefCountedThreadSafe<Core> { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit Core(scoped_refptr<base::SingleThreadTaskRunner> task_runner); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Mirrors the ClipboardStub interface. 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void InjectClipboardEvent(const ClipboardEvent& event); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Mirrors the InputStub interface. 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void InjectKeyEvent(const KeyEvent& event); 88effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch void InjectTextEvent(const TextEvent& event); 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void InjectMouseEvent(const MouseEvent& event); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Mirrors the InputInjector interface. 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void Start(scoped_ptr<protocol::ClipboardStub> client_clipboard); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Stop(); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend class base::RefCountedThreadSafe<Core>; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~Core(); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) webrtc::DesktopVector mouse_pos_; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 mouse_button_state_; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<Clipboard> clipboard_; 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CGEventFlags left_modifiers_; 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CGEventFlags right_modifiers_; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(Core); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<Core> core_; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(InputInjectorMac); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InputInjectorMac::InputInjectorMac( 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<base::SingleThreadTaskRunner> task_runner) { 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) core_ = new Core(task_runner); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InputInjectorMac::~InputInjectorMac() { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) core_->Stop(); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputInjectorMac::InjectClipboardEvent(const ClipboardEvent& event) { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) core_->InjectClipboardEvent(event); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputInjectorMac::InjectKeyEvent(const KeyEvent& event) { 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) core_->InjectKeyEvent(event); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 132effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid InputInjectorMac::InjectTextEvent(const TextEvent& event) { 133effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch core_->InjectTextEvent(event); 134effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 135effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputInjectorMac::InjectMouseEvent(const MouseEvent& event) { 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) core_->InjectMouseEvent(event); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputInjectorMac::Start( 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<protocol::ClipboardStub> client_clipboard) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) core_->Start(client_clipboard.Pass()); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InputInjectorMac::Core::Core( 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<base::SingleThreadTaskRunner> task_runner) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : task_runner_(task_runner), 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mouse_button_state_(0), 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) clipboard_(Clipboard::Create()), 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) left_modifiers_(0), 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) right_modifiers_(0) { 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ensure that local hardware events are not suppressed after injecting 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // input events. This allows LocalInputMonitor to detect if the local mouse 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is being moved whilst a remote user is connected. 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This API is deprecated, but it is needed when using the deprecated 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // injection APIs. 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the non-deprecated injection APIs were used instead, the equivalent of 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // this line would not be needed, as OS X defaults to _not_ suppressing local 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // inputs in that case. 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma clang diagnostic push 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma clang diagnostic ignored "-Wdeprecated-declarations" 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CGSetLocalEventsSuppressionInterval(0.0); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma clang diagnostic pop 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputInjectorMac::Core::InjectClipboardEvent(const ClipboardEvent& event) { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!task_runner_->BelongsToCurrentThread()) { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) task_runner_->PostTask( 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, base::Bind(&Core::InjectClipboardEvent, this, event)); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // |clipboard_| will ignore unknown MIME-types, and verify the data's format. 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clipboard_->InjectClipboardEvent(event); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputInjectorMac::Core::InjectKeyEvent(const KeyEvent& event) { 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // HostEventDispatcher should filter events missing the pressed field. 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!event.has_pressed() || !event.has_usb_keycode()) 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int keycode = 1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ui::KeycodeConverter::UsbKeycodeToNativeKeycode(event.usb_keycode()); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(3) << "Converting USB keycode: " << std::hex << event.usb_keycode() 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " to keycode: " << keycode << std::dec; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we couldn't determine the Mac virtual key code then ignore the event. 1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (keycode == ui::KeycodeConverter::InvalidNativeKeycode()) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // If this is a modifier key, remember its new state so that it can be 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // correctly applied to subsequent events. 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (keycode == kVK_Command) { 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetOrClearBit(left_modifiers_, kCGEventFlagMaskCommand, event.pressed()); 1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (keycode == kVK_Shift) { 1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetOrClearBit(left_modifiers_, kCGEventFlagMaskShift, event.pressed()); 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (keycode == kVK_Control) { 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetOrClearBit(left_modifiers_, kCGEventFlagMaskControl, event.pressed()); 2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (keycode == kVK_Option) { 2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetOrClearBit(left_modifiers_, kCGEventFlagMaskAlternate, event.pressed()); 2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (keycode == kVK_RightCommand) { 2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetOrClearBit(right_modifiers_, kCGEventFlagMaskCommand, event.pressed()); 2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (keycode == kVK_RightShift) { 2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetOrClearBit(right_modifiers_, kCGEventFlagMaskShift, event.pressed()); 2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (keycode == kVK_RightControl) { 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetOrClearBit(right_modifiers_, kCGEventFlagMaskControl, event.pressed()); 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (keycode == kVK_RightOption) { 2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetOrClearBit(right_modifiers_, kCGEventFlagMaskAlternate, event.pressed()); 2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 212effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // In addition to the modifier keys pressed right now, we also need to set 213effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // AlphaShift if caps lock was active at the client (Mac ignores NumLock). 214effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch uint64_t flags = left_modifiers_ | right_modifiers_; 215effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (event.lock_states() & protocol::KeyEvent::LOCK_STATES_CAPSLOCK) 216effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch flags |= kCGEventFlagMaskAlphaShift; 217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 218effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch CreateAndPostKeyEvent(keycode, event.pressed(), flags, base::string16()); 219effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 221effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid InputInjectorMac::Core::InjectTextEvent(const TextEvent& event) { 222effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK(event.has_text()); 223effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::string16 text = base::UTF8ToUTF16(event.text()); 224effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 225effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Applications that ignore UnicodeString field will see the text event as 226effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Space key. 227effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch CreateAndPostKeyEvent(kVK_Space, true, 0, text); 228effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch CreateAndPostKeyEvent(kVK_Space, false, 0, text); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputInjectorMac::Core::InjectMouseEvent(const MouseEvent& event) { 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event.has_x() && event.has_y()) { 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // On multi-monitor systems (0,0) refers to the top-left of the "main" 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // display, whereas our coordinate scheme places (0,0) at the top-left of 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the bounding rectangle around all the displays, so we need to translate 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // accordingly. 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set the mouse position assuming single-monitor. 2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mouse_pos_.set(event.x(), event.y()); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Fetch the desktop configuration. 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(wez): Optimize this out, or at least only enumerate displays in 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // response to display-changed events. VideoFrameCapturer's VideoFrames 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // could be augmented to include native cursor coordinates for use by 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // MouseClampingFilter, removing the need for translation here. 246868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) webrtc::MacDesktopConfiguration desktop_config = 247868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) webrtc::MacDesktopConfiguration::GetCurrent( 248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) webrtc::MacDesktopConfiguration::TopLeftOrigin); 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Translate the mouse position into desktop coordinates. 2510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch mouse_pos_ = mouse_pos_.add( 2520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch webrtc::DesktopVector(desktop_config.pixel_bounds.left(), 2530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch desktop_config.pixel_bounds.top())); 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Constrain the mouse position to the desktop coordinates. 2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mouse_pos_.set( 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::max(desktop_config.pixel_bounds.left(), 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::min(desktop_config.pixel_bounds.right(), mouse_pos_.x())), 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::max(desktop_config.pixel_bounds.top(), 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::min(desktop_config.pixel_bounds.bottom(), mouse_pos_.y()))); 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Convert from pixel to Density Independent Pixel coordinates. 2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mouse_pos_.set(mouse_pos_.x() / desktop_config.dip_to_pixel_scale, 2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mouse_pos_.y() / desktop_config.dip_to_pixel_scale); 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) VLOG(3) << "Moving mouse to " << mouse_pos_.x() << "," << mouse_pos_.y(); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event.has_button() && event.has_button_down()) { 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event.button() >= 1 && event.button() <= 3) { 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(2) << "Button " << event.button() 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << (event.button_down() ? " down" : " up"); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int button_change = 1 << (event.button() - 1); 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event.button_down()) 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mouse_button_state_ |= button_change; 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mouse_button_state_ &= ~button_change; 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "Unknown mouse button: " << event.button(); 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We use the deprecated CGPostMouseEvent API because we receive low-level 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mouse events, whereas CGEventCreateMouseEvent is for injecting higher-level 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // events. For example, the deprecated APIs will detect double-clicks or drags 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in a way that is consistent with how they would be generated using a local 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mouse, whereas the new APIs expect us to inject these higher-level events 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // directly. 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CGPoint position = CGPointMake(mouse_pos_.x(), mouse_pos_.y()); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum { 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LeftBit = 1 << (MouseEvent::BUTTON_LEFT - 1), 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MiddleBit = 1 << (MouseEvent::BUTTON_MIDDLE - 1), 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RightBit = 1 << (MouseEvent::BUTTON_RIGHT - 1) 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma clang diagnostic push 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma clang diagnostic ignored "-Wdeprecated-declarations" 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CGError error = CGPostMouseEvent(position, true, 3, 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (mouse_button_state_ & LeftBit) != 0, 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (mouse_button_state_ & RightBit) != 0, 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (mouse_button_state_ & MiddleBit) != 0); 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma clang diagnostic pop 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (error != kCGErrorSuccess) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(WARNING) << "CGPostMouseEvent error " << error; 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event.has_wheel_delta_x() && event.has_wheel_delta_y()) { 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int delta_x = static_cast<int>(event.wheel_delta_x()); 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int delta_y = static_cast<int>(event.wheel_delta_y()); 306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<CGEventRef> event(CGEventCreateScrollWheelEvent( 307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch NULL, kCGScrollEventUnitPixel, 2, delta_y, delta_x)); 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event) 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CGEventPost(kCGSessionEventTap, event); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputInjectorMac::Core::Start( 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<protocol::ClipboardStub> client_clipboard) { 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!task_runner_->BelongsToCurrentThread()) { 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) task_runner_->PostTask( 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&Core::Start, this, base::Passed(&client_clipboard))); 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clipboard_->Start(client_clipboard.Pass()); 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputInjectorMac::Core::Stop() { 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!task_runner_->BelongsToCurrentThread()) { 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) task_runner_->PostTask(FROM_HERE, base::Bind(&Core::Stop, this)); 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clipboard_->Stop(); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 334effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochInputInjectorMac::Core::~Core() {} 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<InputInjector> InputInjector::Create( 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return scoped_ptr<InputInjector>(new InputInjectorMac(main_task_runner)); 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace remoting 345