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