diff options
author | kelvinp <kelvinp@chromium.org> | 2014-11-10 19:18:04 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-11-11 03:18:31 +0000 |
commit | a7aa648b4726884717287ac12b284cfd6054e49f (patch) | |
tree | 1ba0b4481d17bf859cfeaacd3f25a57e7fd5f65a /remoting/host/input_injector_x11.cc | |
parent | 1d3fbc02ea36d1054ed570bdf2fdb2d46e88e9ba (diff) | |
download | chromium_src-a7aa648b4726884717287ac12b284cfd6054e49f.zip chromium_src-a7aa648b4726884717287ac12b284cfd6054e49f.tar.gz chromium_src-a7aa648b4726884717287ac12b284cfd6054e49f.tar.bz2 |
Revert of Remote assistance on Chrome OS Part VIII - Compile on Ozone
This reverts commit 1d3fbc02ea36d1054ed570bdf2fdb2d46e88e9ba.
Reason for revert:
Build failure on
http://build.chromium.org/p/chromium.chromiumos/builders/Linux%20ChromiumOS%20GN/builds/877/steps/steps/logs/stdio
TBR=kelvinp
NOTREECHECKS=true
NOTRY=true
Review URL: https://codereview.chromium.org/703143004
Cr-Commit-Position: refs/heads/master@{#303579}
Diffstat (limited to 'remoting/host/input_injector_x11.cc')
-rw-r--r-- | remoting/host/input_injector_x11.cc | 613 |
1 files changed, 0 insertions, 613 deletions
diff --git a/remoting/host/input_injector_x11.cc b/remoting/host/input_injector_x11.cc deleted file mode 100644 index 3b5d2b4..0000000 --- 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 |