input_injector_mac.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/clipboard.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/proto/internal.pb.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/protocol/message_decoder.h" 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" 22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/webrtc/modules/desktop_capture/mac/desktop_configuration.h" 23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/events/keycodes/dom4/keycode_converter.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SetOrClearBit(uint64_t &value, uint64_t bit, bool set_bit) { 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) value = set_bit ? (value | bit) : (value & ~bit); 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This value is not defined. Give it the obvious name so that if it is ever 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// added there will be a handy compilation error to remind us to remove this 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// definition. 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kVK_RightCommand = 0x36; 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using protocol::ClipboardEvent; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using protocol::KeyEvent; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using protocol::MouseEvent; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A class to generate events on Mac. 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class InputInjectorMac : public InputInjector { 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) explicit InputInjectorMac( 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<base::SingleThreadTaskRunner> task_runner); 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual ~InputInjectorMac(); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ClipboardStub interface. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void InjectClipboardEvent(const ClipboardEvent& event) OVERRIDE; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // InputStub interface. 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void InjectKeyEvent(const KeyEvent& event) OVERRIDE; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void InjectMouseEvent(const MouseEvent& event) OVERRIDE; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // InputInjector interface. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void Start( 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The actual implementation resides in InputInjectorMac::Core class. 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) class Core : public base::RefCountedThreadSafe<Core> { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit Core(scoped_refptr<base::SingleThreadTaskRunner> task_runner); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Mirrors the ClipboardStub interface. 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void InjectClipboardEvent(const ClipboardEvent& event); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Mirrors the InputStub interface. 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void InjectKeyEvent(const KeyEvent& event); 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void InjectMouseEvent(const MouseEvent& event); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Mirrors the InputInjector interface. 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void Start(scoped_ptr<protocol::ClipboardStub> client_clipboard); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Stop(); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend class base::RefCountedThreadSafe<Core>; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~Core(); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) webrtc::DesktopVector mouse_pos_; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 mouse_button_state_; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<Clipboard> clipboard_; 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CGEventFlags left_modifiers_; 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CGEventFlags right_modifiers_; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(Core); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<Core> core_; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(InputInjectorMac); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InputInjectorMac::InputInjectorMac( 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<base::SingleThreadTaskRunner> task_runner) { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) core_ = new Core(task_runner); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InputInjectorMac::~InputInjectorMac() { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) core_->Stop(); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputInjectorMac::InjectClipboardEvent(const ClipboardEvent& event) { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) core_->InjectClipboardEvent(event); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputInjectorMac::InjectKeyEvent(const KeyEvent& event) { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) core_->InjectKeyEvent(event); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputInjectorMac::InjectMouseEvent(const MouseEvent& event) { 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) core_->InjectMouseEvent(event); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputInjectorMac::Start( 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<protocol::ClipboardStub> client_clipboard) { 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) core_->Start(client_clipboard.Pass()); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InputInjectorMac::Core::Core( 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<base::SingleThreadTaskRunner> task_runner) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : task_runner_(task_runner), 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mouse_button_state_(0), 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) clipboard_(Clipboard::Create()), 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) left_modifiers_(0), 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) right_modifiers_(0) { 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ensure that local hardware events are not suppressed after injecting 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // input events. This allows LocalInputMonitor to detect if the local mouse 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is being moved whilst a remote user is connected. 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This API is deprecated, but it is needed when using the deprecated 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // injection APIs. 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the non-deprecated injection APIs were used instead, the equivalent of 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // this line would not be needed, as OS X defaults to _not_ suppressing local 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // inputs in that case. 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma clang diagnostic push 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma clang diagnostic ignored "-Wdeprecated-declarations" 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CGSetLocalEventsSuppressionInterval(0.0); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma clang diagnostic pop 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputInjectorMac::Core::InjectClipboardEvent(const ClipboardEvent& event) { 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!task_runner_->BelongsToCurrentThread()) { 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) task_runner_->PostTask( 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, base::Bind(&Core::InjectClipboardEvent, this, event)); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // |clipboard_| will ignore unknown MIME-types, and verify the data's format. 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clipboard_->InjectClipboardEvent(event); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputInjectorMac::Core::InjectKeyEvent(const KeyEvent& event) { 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // HostEventDispatcher should filter events missing the pressed field. 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!event.has_pressed() || !event.has_usb_keycode()) 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) ui::KeycodeConverter* key_converter = ui::KeycodeConverter::GetInstance(); 16168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) int keycode = key_converter->UsbKeycodeToNativeKeycode(event.usb_keycode()); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(3) << "Converting USB keycode: " << std::hex << event.usb_keycode() 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " to keycode: " << keycode << std::dec; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we couldn't determine the Mac virtual key code then ignore the event. 16768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (keycode == key_converter->InvalidNativeKeycode()) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // If this is a modifier key, remember its new state so that it can be 1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // correctly applied to subsequent events. 1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (keycode == kVK_Command) { 1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetOrClearBit(left_modifiers_, kCGEventFlagMaskCommand, event.pressed()); 1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (keycode == kVK_Shift) { 1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetOrClearBit(left_modifiers_, kCGEventFlagMaskShift, event.pressed()); 1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (keycode == kVK_Control) { 1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetOrClearBit(left_modifiers_, kCGEventFlagMaskControl, event.pressed()); 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (keycode == kVK_Option) { 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetOrClearBit(left_modifiers_, kCGEventFlagMaskAlternate, event.pressed()); 1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (keycode == kVK_RightCommand) { 1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetOrClearBit(right_modifiers_, kCGEventFlagMaskCommand, event.pressed()); 1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (keycode == kVK_RightShift) { 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetOrClearBit(right_modifiers_, kCGEventFlagMaskShift, event.pressed()); 1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (keycode == kVK_RightControl) { 1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetOrClearBit(right_modifiers_, kCGEventFlagMaskControl, event.pressed()); 1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (keycode == kVK_RightOption) { 1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetOrClearBit(right_modifiers_, kCGEventFlagMaskAlternate, event.pressed()); 1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<CGEventRef> eventRef( 191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CGEventCreateKeyboardEvent(NULL, keycode, event.pressed())); 192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (eventRef) { 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // In addition to the modifier keys pressed right now, we also need to set 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // AlphaShift if caps lock was active at the client (Mac ignores NumLock). 1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) uint64_t flags = left_modifiers_ | right_modifiers_; 197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (event.lock_states() & protocol::KeyEvent::LOCK_STATES_CAPSLOCK) 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) flags |= kCGEventFlagMaskAlphaShift; 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CGEventSetFlags(eventRef, flags); 200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Post the event to the current session. 202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CGEventPost(kCGSessionEventTap, eventRef); 203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputInjectorMac::Core::InjectMouseEvent(const MouseEvent& event) { 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event.has_x() && event.has_y()) { 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // On multi-monitor systems (0,0) refers to the top-left of the "main" 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // display, whereas our coordinate scheme places (0,0) at the top-left of 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the bounding rectangle around all the displays, so we need to translate 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // accordingly. 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set the mouse position assuming single-monitor. 2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mouse_pos_.set(event.x(), event.y()); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Fetch the desktop configuration. 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(wez): Optimize this out, or at least only enumerate displays in 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // response to display-changed events. VideoFrameCapturer's VideoFrames 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // could be augmented to include native cursor coordinates for use by 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // MouseClampingFilter, removing the need for translation here. 221868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) webrtc::MacDesktopConfiguration desktop_config = 222868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) webrtc::MacDesktopConfiguration::GetCurrent( 223868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) webrtc::MacDesktopConfiguration::TopLeftOrigin); 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Translate the mouse position into desktop coordinates. 2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mouse_pos_.add(webrtc::DesktopVector(desktop_config.pixel_bounds.left(), 2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) desktop_config.pixel_bounds.top())); 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Constrain the mouse position to the desktop coordinates. 2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mouse_pos_.set( 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::max(desktop_config.pixel_bounds.left(), 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::min(desktop_config.pixel_bounds.right(), mouse_pos_.x())), 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::max(desktop_config.pixel_bounds.top(), 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::min(desktop_config.pixel_bounds.bottom(), mouse_pos_.y()))); 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Convert from pixel to Density Independent Pixel coordinates. 2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mouse_pos_.set(mouse_pos_.x() / desktop_config.dip_to_pixel_scale, 2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mouse_pos_.y() / desktop_config.dip_to_pixel_scale); 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) VLOG(3) << "Moving mouse to " << mouse_pos_.x() << "," << mouse_pos_.y(); 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event.has_button() && event.has_button_down()) { 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event.button() >= 1 && event.button() <= 3) { 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(2) << "Button " << event.button() 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << (event.button_down() ? " down" : " up"); 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int button_change = 1 << (event.button() - 1); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event.button_down()) 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mouse_button_state_ |= button_change; 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mouse_button_state_ &= ~button_change; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "Unknown mouse button: " << event.button(); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We use the deprecated CGPostMouseEvent API because we receive low-level 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mouse events, whereas CGEventCreateMouseEvent is for injecting higher-level 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // events. For example, the deprecated APIs will detect double-clicks or drags 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in a way that is consistent with how they would be generated using a local 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mouse, whereas the new APIs expect us to inject these higher-level events 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // directly. 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CGPoint position = CGPointMake(mouse_pos_.x(), mouse_pos_.y()); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum { 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LeftBit = 1 << (MouseEvent::BUTTON_LEFT - 1), 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MiddleBit = 1 << (MouseEvent::BUTTON_MIDDLE - 1), 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RightBit = 1 << (MouseEvent::BUTTON_RIGHT - 1) 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma clang diagnostic push 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma clang diagnostic ignored "-Wdeprecated-declarations" 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CGError error = CGPostMouseEvent(position, true, 3, 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (mouse_button_state_ & LeftBit) != 0, 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (mouse_button_state_ & RightBit) != 0, 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (mouse_button_state_ & MiddleBit) != 0); 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma clang diagnostic pop 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (error != kCGErrorSuccess) 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(WARNING) << "CGPostMouseEvent error " << error; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event.has_wheel_delta_x() && event.has_wheel_delta_y()) { 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int delta_x = static_cast<int>(event.wheel_delta_x()); 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int delta_y = static_cast<int>(event.wheel_delta_y()); 280eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<CGEventRef> event(CGEventCreateScrollWheelEvent( 281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch NULL, kCGScrollEventUnitPixel, 2, delta_y, delta_x)); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event) 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CGEventPost(kCGSessionEventTap, event); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputInjectorMac::Core::Start( 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<protocol::ClipboardStub> client_clipboard) { 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!task_runner_->BelongsToCurrentThread()) { 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) task_runner_->PostTask( 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&Core::Start, this, base::Passed(&client_clipboard))); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clipboard_->Start(client_clipboard.Pass()); 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputInjectorMac::Core::Stop() { 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!task_runner_->BelongsToCurrentThread()) { 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) task_runner_->PostTask(FROM_HERE, base::Bind(&Core::Stop, this)); 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clipboard_->Stop(); 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InputInjectorMac::Core::~Core() { 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<InputInjector> InputInjector::Create( 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return scoped_ptr<InputInjector>(new InputInjectorMac(main_task_runner)); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace remoting 320