| Index: remoting/host/input_injector_x11.cc
|
| diff --git a/remoting/host/input_injector_x11.cc b/remoting/host/input_injector_x11.cc
|
| deleted file mode 100644
|
| index 3b5d2b46922014716fd862676de4a6c3f9c6ebd2..0000000000000000000000000000000000000000
|
| --- a/remoting/host/input_injector_x11.cc
|
| +++ /dev/null
|
| @@ -1,613 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "remoting/host/input_injector.h"
|
| -
|
| -#include <X11/extensions/XInput.h>
|
| -#include <X11/extensions/XTest.h>
|
| -#include <X11/Xlib.h>
|
| -#include <X11/XKBlib.h>
|
| -
|
| -#include <set>
|
| -
|
| -#include "base/basictypes.h"
|
| -#include "base/bind.h"
|
| -#include "base/compiler_specific.h"
|
| -#include "base/location.h"
|
| -#include "base/single_thread_task_runner.h"
|
| -#include "base/strings/utf_string_conversion_utils.h"
|
| -#include "remoting/base/logging.h"
|
| -#include "remoting/host/clipboard.h"
|
| -#include "remoting/host/linux/unicode_to_keysym.h"
|
| -#include "remoting/proto/internal.pb.h"
|
| -#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
|
| -#include "ui/events/keycodes/dom4/keycode_converter.h"
|
| -
|
| -namespace remoting {
|
| -
|
| -namespace {
|
| -
|
| -using protocol::ClipboardEvent;
|
| -using protocol::KeyEvent;
|
| -using protocol::TextEvent;
|
| -using protocol::MouseEvent;
|
| -
|
| -bool FindKeycodeForKeySym(Display* display,
|
| - KeySym key_sym,
|
| - uint32_t* keycode,
|
| - uint32_t* modifiers) {
|
| - *keycode = XKeysymToKeycode(display, key_sym);
|
| -
|
| - const uint32_t kModifiersToTry[] = {
|
| - 0,
|
| - ShiftMask,
|
| - Mod2Mask,
|
| - Mod3Mask,
|
| - Mod4Mask,
|
| - ShiftMask | Mod2Mask,
|
| - ShiftMask | Mod3Mask,
|
| - ShiftMask | Mod4Mask,
|
| - };
|
| -
|
| - // TODO(sergeyu): Is there a better way to find modifiers state?
|
| - for (size_t i = 0; i < arraysize(kModifiersToTry); ++i) {
|
| - unsigned long key_sym_with_mods;
|
| - if (XkbLookupKeySym(
|
| - display, *keycode, kModifiersToTry[i], NULL, &key_sym_with_mods) &&
|
| - key_sym_with_mods == key_sym) {
|
| - *modifiers = kModifiersToTry[i];
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - return false;
|
| -}
|
| -
|
| -// Finds a keycode and set of modifiers that generate character with the
|
| -// specified |code_point|.
|
| -bool FindKeycodeForUnicode(Display* display,
|
| - uint32_t code_point,
|
| - uint32_t* keycode,
|
| - uint32_t* modifiers) {
|
| - std::vector<uint32_t> keysyms;
|
| - GetKeySymsForUnicode(code_point, &keysyms);
|
| -
|
| - for (std::vector<uint32_t>::iterator it = keysyms.begin();
|
| - it != keysyms.end(); ++it) {
|
| - if (FindKeycodeForKeySym(display, *it, keycode, modifiers)) {
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - return false;
|
| -}
|
| -
|
| -// Pixel-to-wheel-ticks conversion ratio used by GTK.
|
| -// From third_party/WebKit/Source/web/gtk/WebInputEventFactory.cpp .
|
| -const float kWheelTicksPerPixel = 3.0f / 160.0f;
|
| -
|
| -// A class to generate events on X11.
|
| -class InputInjectorX11 : public InputInjector {
|
| - public:
|
| - explicit InputInjectorX11(
|
| - scoped_refptr<base::SingleThreadTaskRunner> task_runner);
|
| - ~InputInjectorX11() override;
|
| -
|
| - bool Init();
|
| -
|
| - // Clipboard stub interface.
|
| - void InjectClipboardEvent(const ClipboardEvent& event) override;
|
| -
|
| - // InputStub interface.
|
| - void InjectKeyEvent(const KeyEvent& event) override;
|
| - void InjectTextEvent(const TextEvent& event) override;
|
| - void InjectMouseEvent(const MouseEvent& event) override;
|
| -
|
| - // InputInjector interface.
|
| - void Start(scoped_ptr<protocol::ClipboardStub> client_clipboard) override;
|
| -
|
| - private:
|
| - // The actual implementation resides in InputInjectorX11::Core class.
|
| - class Core : public base::RefCountedThreadSafe<Core> {
|
| - public:
|
| - explicit Core(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
|
| -
|
| - bool Init();
|
| -
|
| - // Mirrors the ClipboardStub interface.
|
| - void InjectClipboardEvent(const ClipboardEvent& event);
|
| -
|
| - // Mirrors the InputStub interface.
|
| - void InjectKeyEvent(const KeyEvent& event);
|
| - void InjectTextEvent(const TextEvent& event);
|
| - void InjectMouseEvent(const MouseEvent& event);
|
| -
|
| - // Mirrors the InputInjector interface.
|
| - void Start(scoped_ptr<protocol::ClipboardStub> client_clipboard);
|
| -
|
| - void Stop();
|
| -
|
| - private:
|
| - friend class base::RefCountedThreadSafe<Core>;
|
| - virtual ~Core();
|
| -
|
| - void InitClipboard();
|
| -
|
| - // Queries whether keyboard auto-repeat is globally enabled. This is used
|
| - // to decide whether to temporarily disable then restore this setting. If
|
| - // auto-repeat has already been disabled, this class should leave it
|
| - // untouched.
|
| - bool IsAutoRepeatEnabled();
|
| -
|
| - // Enables or disables keyboard auto-repeat globally.
|
| - void SetAutoRepeatEnabled(bool enabled);
|
| -
|
| - void InjectScrollWheelClicks(int button, int count);
|
| - // Compensates for global button mappings and resets the XTest device
|
| - // mapping.
|
| - void InitMouseButtonMap();
|
| - int MouseButtonToX11ButtonNumber(MouseEvent::MouseButton button);
|
| - int HorizontalScrollWheelToX11ButtonNumber(int dx);
|
| - int VerticalScrollWheelToX11ButtonNumber(int dy);
|
| -
|
| - scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
|
| -
|
| - std::set<int> pressed_keys_;
|
| - webrtc::DesktopVector latest_mouse_position_;
|
| - float wheel_ticks_x_;
|
| - float wheel_ticks_y_;
|
| -
|
| - // X11 graphics context.
|
| - Display* display_;
|
| - Window root_window_;
|
| -
|
| - int test_event_base_;
|
| - int test_error_base_;
|
| -
|
| - // Number of buttons we support.
|
| - // Left, Right, Middle, VScroll Up/Down, HScroll Left/Right.
|
| - static const int kNumPointerButtons = 7;
|
| -
|
| - int pointer_button_map_[kNumPointerButtons];
|
| -
|
| - scoped_ptr<Clipboard> clipboard_;
|
| -
|
| - bool saved_auto_repeat_enabled_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(Core);
|
| - };
|
| -
|
| - scoped_refptr<Core> core_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(InputInjectorX11);
|
| -};
|
| -
|
| -InputInjectorX11::InputInjectorX11(
|
| - scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
|
| - core_ = new Core(task_runner);
|
| -}
|
| -
|
| -InputInjectorX11::~InputInjectorX11() {
|
| - core_->Stop();
|
| -}
|
| -
|
| -bool InputInjectorX11::Init() {
|
| - return core_->Init();
|
| -}
|
| -
|
| -void InputInjectorX11::InjectClipboardEvent(const ClipboardEvent& event) {
|
| - core_->InjectClipboardEvent(event);
|
| -}
|
| -
|
| -void InputInjectorX11::InjectKeyEvent(const KeyEvent& event) {
|
| - core_->InjectKeyEvent(event);
|
| -}
|
| -
|
| -void InputInjectorX11::InjectTextEvent(const TextEvent& event) {
|
| - core_->InjectTextEvent(event);
|
| -}
|
| -
|
| -void InputInjectorX11::InjectMouseEvent(const MouseEvent& event) {
|
| - core_->InjectMouseEvent(event);
|
| -}
|
| -
|
| -void InputInjectorX11::Start(
|
| - scoped_ptr<protocol::ClipboardStub> client_clipboard) {
|
| - core_->Start(client_clipboard.Pass());
|
| -}
|
| -
|
| -InputInjectorX11::Core::Core(
|
| - scoped_refptr<base::SingleThreadTaskRunner> task_runner)
|
| - : task_runner_(task_runner),
|
| - latest_mouse_position_(-1, -1),
|
| - wheel_ticks_x_(0.0f),
|
| - wheel_ticks_y_(0.0f),
|
| - display_(XOpenDisplay(NULL)),
|
| - root_window_(BadValue),
|
| - saved_auto_repeat_enabled_(false) {
|
| -}
|
| -
|
| -bool InputInjectorX11::Core::Init() {
|
| - CHECK(display_);
|
| -
|
| - if (!task_runner_->BelongsToCurrentThread())
|
| - task_runner_->PostTask(FROM_HERE, base::Bind(&Core::InitClipboard, this));
|
| -
|
| - root_window_ = RootWindow(display_, DefaultScreen(display_));
|
| - if (root_window_ == BadValue) {
|
| - LOG(ERROR) << "Unable to get the root window";
|
| - return false;
|
| - }
|
| -
|
| - // TODO(ajwong): Do we want to check the major/minor version at all for XTest?
|
| - int major = 0;
|
| - int minor = 0;
|
| - if (!XTestQueryExtension(display_, &test_event_base_, &test_error_base_,
|
| - &major, &minor)) {
|
| - LOG(ERROR) << "Server does not support XTest.";
|
| - return false;
|
| - }
|
| - InitMouseButtonMap();
|
| - return true;
|
| -}
|
| -
|
| -void InputInjectorX11::Core::InjectClipboardEvent(
|
| - const ClipboardEvent& event) {
|
| - if (!task_runner_->BelongsToCurrentThread()) {
|
| - task_runner_->PostTask(
|
| - FROM_HERE, base::Bind(&Core::InjectClipboardEvent, this, event));
|
| - return;
|
| - }
|
| -
|
| - // |clipboard_| will ignore unknown MIME-types, and verify the data's format.
|
| - clipboard_->InjectClipboardEvent(event);
|
| -}
|
| -
|
| -void InputInjectorX11::Core::InjectKeyEvent(const KeyEvent& event) {
|
| - // HostEventDispatcher should filter events missing the pressed field.
|
| - if (!event.has_pressed() || !event.has_usb_keycode())
|
| - return;
|
| -
|
| - if (!task_runner_->BelongsToCurrentThread()) {
|
| - task_runner_->PostTask(FROM_HERE,
|
| - base::Bind(&Core::InjectKeyEvent, this, event));
|
| - return;
|
| - }
|
| -
|
| - int keycode =
|
| - ui::KeycodeConverter::UsbKeycodeToNativeKeycode(event.usb_keycode());
|
| -
|
| - VLOG(3) << "Converting USB keycode: " << std::hex << event.usb_keycode()
|
| - << " to keycode: " << keycode << std::dec;
|
| -
|
| - // Ignore events which can't be mapped.
|
| - if (keycode == ui::KeycodeConverter::InvalidNativeKeycode())
|
| - return;
|
| -
|
| - if (event.pressed()) {
|
| - if (pressed_keys_.find(keycode) != pressed_keys_.end()) {
|
| - // Key is already held down, so lift the key up to ensure this repeated
|
| - // press takes effect.
|
| - XTestFakeKeyEvent(display_, keycode, False, CurrentTime);
|
| - }
|
| -
|
| - if (pressed_keys_.empty()) {
|
| - // Disable auto-repeat, if necessary, to avoid triggering auto-repeat
|
| - // if network congestion delays the key-up event from the client.
|
| - saved_auto_repeat_enabled_ = IsAutoRepeatEnabled();
|
| - if (saved_auto_repeat_enabled_)
|
| - SetAutoRepeatEnabled(false);
|
| - }
|
| - pressed_keys_.insert(keycode);
|
| - } else {
|
| - pressed_keys_.erase(keycode);
|
| - if (pressed_keys_.empty()) {
|
| - // Re-enable auto-repeat, if necessary, when all keys are released.
|
| - if (saved_auto_repeat_enabled_)
|
| - SetAutoRepeatEnabled(true);
|
| - }
|
| - }
|
| -
|
| - XTestFakeKeyEvent(display_, keycode, event.pressed(), CurrentTime);
|
| - XFlush(display_);
|
| -}
|
| -
|
| -void InputInjectorX11::Core::InjectTextEvent(const TextEvent& event) {
|
| - if (!task_runner_->BelongsToCurrentThread()) {
|
| - task_runner_->PostTask(FROM_HERE,
|
| - base::Bind(&Core::InjectTextEvent, this, event));
|
| - return;
|
| - }
|
| -
|
| - const std::string text = event.text();
|
| - for (int32 index = 0; index < static_cast<int32>(text.size()); ++index) {
|
| - uint32_t code_point;
|
| - if (!base::ReadUnicodeCharacter(
|
| - text.c_str(), text.size(), &index, &code_point)) {
|
| - continue;
|
| - }
|
| -
|
| - uint32_t keycode;
|
| - uint32_t modifiers;
|
| - if (!FindKeycodeForUnicode(display_, code_point, &keycode, &modifiers))
|
| - continue;
|
| -
|
| - XkbLockModifiers(display_, XkbUseCoreKbd, modifiers, modifiers);
|
| -
|
| - XTestFakeKeyEvent(display_, keycode, True, CurrentTime);
|
| - XTestFakeKeyEvent(display_, keycode, False, CurrentTime);
|
| -
|
| - XkbLockModifiers(display_, XkbUseCoreKbd, modifiers, 0);
|
| - }
|
| -
|
| - XFlush(display_);
|
| -}
|
| -
|
| -InputInjectorX11::Core::~Core() {
|
| - CHECK(pressed_keys_.empty());
|
| -}
|
| -
|
| -void InputInjectorX11::Core::InitClipboard() {
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - clipboard_ = Clipboard::Create();
|
| -}
|
| -
|
| -bool InputInjectorX11::Core::IsAutoRepeatEnabled() {
|
| - XKeyboardState state;
|
| - if (!XGetKeyboardControl(display_, &state)) {
|
| - LOG(ERROR) << "Failed to get keyboard auto-repeat status, assuming ON.";
|
| - return true;
|
| - }
|
| - return state.global_auto_repeat == AutoRepeatModeOn;
|
| -}
|
| -
|
| -void InputInjectorX11::Core::SetAutoRepeatEnabled(bool mode) {
|
| - XKeyboardControl control;
|
| - control.auto_repeat_mode = mode ? AutoRepeatModeOn : AutoRepeatModeOff;
|
| - XChangeKeyboardControl(display_, KBAutoRepeatMode, &control);
|
| -}
|
| -
|
| -void InputInjectorX11::Core::InjectScrollWheelClicks(int button, int count) {
|
| - if (button < 0) {
|
| - LOG(WARNING) << "Ignoring unmapped scroll wheel button";
|
| - return;
|
| - }
|
| - for (int i = 0; i < count; i++) {
|
| - // Generate a button-down and a button-up to simulate a wheel click.
|
| - XTestFakeButtonEvent(display_, button, true, CurrentTime);
|
| - XTestFakeButtonEvent(display_, button, false, CurrentTime);
|
| - }
|
| -}
|
| -
|
| -void InputInjectorX11::Core::InjectMouseEvent(const MouseEvent& event) {
|
| - if (!task_runner_->BelongsToCurrentThread()) {
|
| - task_runner_->PostTask(FROM_HERE,
|
| - base::Bind(&Core::InjectMouseEvent, this, event));
|
| - return;
|
| - }
|
| -
|
| - if (event.has_delta_x() &&
|
| - event.has_delta_y() &&
|
| - (event.delta_x() != 0 || event.delta_y() != 0)) {
|
| - latest_mouse_position_.set(-1, -1);
|
| - VLOG(3) << "Moving mouse by " << event.delta_x() << "," << event.delta_y();
|
| - XTestFakeRelativeMotionEvent(display_,
|
| - event.delta_x(), event.delta_y(),
|
| - CurrentTime);
|
| -
|
| - } else if (event.has_x() && event.has_y()) {
|
| - // Injecting a motion event immediately before a button release results in
|
| - // a MotionNotify even if the mouse position hasn't changed, which confuses
|
| - // apps which assume MotionNotify implies movement. See crbug.com/138075.
|
| - bool inject_motion = true;
|
| - webrtc::DesktopVector new_mouse_position(
|
| - webrtc::DesktopVector(event.x(), event.y()));
|
| - if (event.has_button() && event.has_button_down() && !event.button_down()) {
|
| - if (new_mouse_position.equals(latest_mouse_position_))
|
| - inject_motion = false;
|
| - }
|
| -
|
| - if (inject_motion) {
|
| - latest_mouse_position_.set(std::max(0, new_mouse_position.x()),
|
| - std::max(0, new_mouse_position.y()));
|
| -
|
| - VLOG(3) << "Moving mouse to " << latest_mouse_position_.x()
|
| - << "," << latest_mouse_position_.y();
|
| - XTestFakeMotionEvent(display_, DefaultScreen(display_),
|
| - latest_mouse_position_.x(),
|
| - latest_mouse_position_.y(),
|
| - CurrentTime);
|
| - }
|
| - }
|
| -
|
| - if (event.has_button() && event.has_button_down()) {
|
| - int button_number = MouseButtonToX11ButtonNumber(event.button());
|
| -
|
| - if (button_number < 0) {
|
| - LOG(WARNING) << "Ignoring unknown button type: " << event.button();
|
| - return;
|
| - }
|
| -
|
| - VLOG(3) << "Button " << event.button()
|
| - << " received, sending "
|
| - << (event.button_down() ? "down " : "up ")
|
| - << button_number;
|
| - XTestFakeButtonEvent(display_, button_number, event.button_down(),
|
| - CurrentTime);
|
| - }
|
| -
|
| - // Older client plugins always send scroll events in pixels, which
|
| - // must be accumulated host-side. Recent client plugins send both
|
| - // pixels and ticks with every scroll event, allowing the host to
|
| - // choose the best model on a per-platform basis. Since we can only
|
| - // inject ticks on Linux, use them if available.
|
| - int ticks_y = 0;
|
| - if (event.has_wheel_ticks_y()) {
|
| - ticks_y = event.wheel_ticks_y();
|
| - } else if (event.has_wheel_delta_y()) {
|
| - wheel_ticks_y_ += event.wheel_delta_y() * kWheelTicksPerPixel;
|
| - ticks_y = static_cast<int>(wheel_ticks_y_);
|
| - wheel_ticks_y_ -= ticks_y;
|
| - }
|
| - if (ticks_y != 0) {
|
| - InjectScrollWheelClicks(VerticalScrollWheelToX11ButtonNumber(ticks_y),
|
| - abs(ticks_y));
|
| - }
|
| -
|
| - int ticks_x = 0;
|
| - if (event.has_wheel_ticks_x()) {
|
| - ticks_x = event.wheel_ticks_x();
|
| - } else if (event.has_wheel_delta_x()) {
|
| - wheel_ticks_x_ += event.wheel_delta_x() * kWheelTicksPerPixel;
|
| - ticks_x = static_cast<int>(wheel_ticks_x_);
|
| - wheel_ticks_x_ -= ticks_x;
|
| - }
|
| - if (ticks_x != 0) {
|
| - InjectScrollWheelClicks(HorizontalScrollWheelToX11ButtonNumber(ticks_x),
|
| - abs(ticks_x));
|
| - }
|
| -
|
| - XFlush(display_);
|
| -}
|
| -
|
| -void InputInjectorX11::Core::InitMouseButtonMap() {
|
| - // TODO(rmsousa): Run this on global/device mapping change events.
|
| -
|
| - // Do not touch global pointer mapping, since this may affect the local user.
|
| - // Instead, try to work around it by reversing the mapping.
|
| - // Note that if a user has a global mapping that completely disables a button
|
| - // (by assigning 0 to it), we won't be able to inject it.
|
| - int num_buttons = XGetPointerMapping(display_, NULL, 0);
|
| - scoped_ptr<unsigned char[]> pointer_mapping(new unsigned char[num_buttons]);
|
| - num_buttons = XGetPointerMapping(display_, pointer_mapping.get(),
|
| - num_buttons);
|
| - for (int i = 0; i < kNumPointerButtons; i++) {
|
| - pointer_button_map_[i] = -1;
|
| - }
|
| - for (int i = 0; i < num_buttons; i++) {
|
| - // Reverse the mapping.
|
| - if (pointer_mapping[i] > 0 && pointer_mapping[i] <= kNumPointerButtons)
|
| - pointer_button_map_[pointer_mapping[i] - 1] = i + 1;
|
| - }
|
| - for (int i = 0; i < kNumPointerButtons; i++) {
|
| - if (pointer_button_map_[i] == -1)
|
| - LOG(ERROR) << "Global pointer mapping does not support button " << i + 1;
|
| - }
|
| -
|
| - int opcode, event, error;
|
| - if (!XQueryExtension(display_, "XInputExtension", &opcode, &event, &error)) {
|
| - // If XInput is not available, we're done. But it would be very unusual to
|
| - // have a server that supports XTest but not XInput, so log it as an error.
|
| - LOG(ERROR) << "X Input extension not available: " << error;
|
| - return;
|
| - }
|
| -
|
| - // Make sure the XTEST XInput pointer device mapping is trivial. It should be
|
| - // safe to reset this mapping, as it won't affect the user's local devices.
|
| - // In fact, the reason why we do this is because an old gnome-settings-daemon
|
| - // may have mistakenly applied left-handed preferences to the XTEST device.
|
| - XID device_id = 0;
|
| - bool device_found = false;
|
| - int num_devices;
|
| - XDeviceInfo* devices;
|
| - devices = XListInputDevices(display_, &num_devices);
|
| - for (int i = 0; i < num_devices; i++) {
|
| - XDeviceInfo* device_info = &devices[i];
|
| - if (device_info->use == IsXExtensionPointer &&
|
| - strcmp(device_info->name, "Virtual core XTEST pointer") == 0) {
|
| - device_id = device_info->id;
|
| - device_found = true;
|
| - break;
|
| - }
|
| - }
|
| - XFreeDeviceList(devices);
|
| -
|
| - if (!device_found) {
|
| - HOST_LOG << "Cannot find XTest device.";
|
| - return;
|
| - }
|
| -
|
| - XDevice* device = XOpenDevice(display_, device_id);
|
| - if (!device) {
|
| - LOG(ERROR) << "Cannot open XTest device.";
|
| - return;
|
| - }
|
| -
|
| - int num_device_buttons = XGetDeviceButtonMapping(display_, device, NULL, 0);
|
| - scoped_ptr<unsigned char[]> button_mapping(new unsigned char[num_buttons]);
|
| - for (int i = 0; i < num_device_buttons; i++) {
|
| - button_mapping[i] = i + 1;
|
| - }
|
| - error = XSetDeviceButtonMapping(display_, device, button_mapping.get(),
|
| - num_device_buttons);
|
| - if (error != Success)
|
| - LOG(ERROR) << "Failed to set XTest device button mapping: " << error;
|
| -
|
| - XCloseDevice(display_, device);
|
| -}
|
| -
|
| -int InputInjectorX11::Core::MouseButtonToX11ButtonNumber(
|
| - MouseEvent::MouseButton button) {
|
| - switch (button) {
|
| - case MouseEvent::BUTTON_LEFT:
|
| - return pointer_button_map_[0];
|
| -
|
| - case MouseEvent::BUTTON_RIGHT:
|
| - return pointer_button_map_[2];
|
| -
|
| - case MouseEvent::BUTTON_MIDDLE:
|
| - return pointer_button_map_[1];
|
| -
|
| - case MouseEvent::BUTTON_UNDEFINED:
|
| - default:
|
| - return -1;
|
| - }
|
| -}
|
| -
|
| -int InputInjectorX11::Core::HorizontalScrollWheelToX11ButtonNumber(int dx) {
|
| - return (dx > 0 ? pointer_button_map_[5] : pointer_button_map_[6]);
|
| -}
|
| -
|
| -int InputInjectorX11::Core::VerticalScrollWheelToX11ButtonNumber(int dy) {
|
| - // Positive y-values are wheel scroll-up events (button 4), negative y-values
|
| - // are wheel scroll-down events (button 5).
|
| - return (dy > 0 ? pointer_button_map_[3] : pointer_button_map_[4]);
|
| -}
|
| -
|
| -void InputInjectorX11::Core::Start(
|
| - scoped_ptr<protocol::ClipboardStub> client_clipboard) {
|
| - if (!task_runner_->BelongsToCurrentThread()) {
|
| - task_runner_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&Core::Start, this, base::Passed(&client_clipboard)));
|
| - return;
|
| - }
|
| -
|
| - InitMouseButtonMap();
|
| -
|
| - clipboard_->Start(client_clipboard.Pass());
|
| -}
|
| -
|
| -void InputInjectorX11::Core::Stop() {
|
| - if (!task_runner_->BelongsToCurrentThread()) {
|
| - task_runner_->PostTask(FROM_HERE, base::Bind(&Core::Stop, this));
|
| - return;
|
| - }
|
| -
|
| - clipboard_->Stop();
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -scoped_ptr<InputInjector> InputInjector::Create(
|
| - scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
|
| - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
|
| - scoped_ptr<InputInjectorX11> injector(
|
| - new InputInjectorX11(main_task_runner));
|
| - if (!injector->Init())
|
| - return nullptr;
|
| - return injector.Pass();
|
| -}
|
| -
|
| -} // namespace remoting
|
|
|