Remove dependency on content from remoting_host.
[chromium-blink-merge.git] / remoting / host / input_injector_chromeos.cc
blob569119163b011d277edf97cc0ff2c1569d11dcec
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "remoting/host/input_injector_chromeos.h"
7 #include <set>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/location.h"
12 #include "remoting/host/chromeos/point_transformer.h"
13 #include "remoting/host/clipboard.h"
14 #include "remoting/proto/internal.pb.h"
15 #include "ui/events/keycodes/dom3/dom_code.h"
16 #include "ui/events/keycodes/dom4/keycode_converter.h"
17 #include "ui/ozone/public/input_controller.h"
18 #include "ui/ozone/public/ozone_platform.h"
19 #include "ui/ozone/public/system_input_injector.h"
21 namespace remoting {
23 using protocol::ClipboardEvent;
24 using protocol::KeyEvent;
25 using protocol::MouseEvent;
26 using protocol::TextEvent;
28 namespace {
30 ui::EventFlags MouseButtonToUIFlags(MouseEvent::MouseButton button) {
31 switch (button) {
32 case MouseEvent::BUTTON_LEFT:
33 return ui::EF_LEFT_MOUSE_BUTTON;
34 case MouseEvent::BUTTON_RIGHT:
35 return ui::EF_RIGHT_MOUSE_BUTTON;
36 case MouseEvent::BUTTON_MIDDLE:
37 return ui::EF_MIDDLE_MOUSE_BUTTON;
38 default:
39 NOTREACHED();
40 return ui::EF_NONE;
44 } // namespace
46 // This class is run exclusively on the UI thread of the browser process.
47 class InputInjectorChromeos::Core {
48 public:
49 Core(scoped_ptr<ui::SystemInputInjector> delegate_,
50 ui::InputController* input_controller);
52 // Mirrors the public InputInjectorChromeos interface.
53 void InjectClipboardEvent(const ClipboardEvent& event);
54 void InjectKeyEvent(const KeyEvent& event);
55 void InjectTextEvent(const TextEvent& event);
56 void InjectMouseEvent(const MouseEvent& event);
57 void Start(scoped_ptr<protocol::ClipboardStub> client_clipboard);
59 private:
60 void HandleAutoRepeat(ui::DomCode dom_code, bool pressed);
62 scoped_ptr<ui::SystemInputInjector> delegate_;
63 ui::InputController* input_controller_;
64 scoped_ptr<Clipboard> clipboard_;
66 // Used to rotate the input coordinates appropriately based on the current
67 // display rotation settings.
68 scoped_ptr<PointTransformer> point_transformer_;
70 // Used by HandleAutoRepeat().
71 std::set<ui::DomCode> pressed_keys_;
72 bool saved_auto_repeat_enabled_;
74 DISALLOW_COPY_AND_ASSIGN(Core);
77 InputInjectorChromeos::Core::Core(scoped_ptr<ui::SystemInputInjector> delegate,
78 ui::InputController* input_controller)
79 : delegate_(delegate.Pass()),
80 input_controller_(input_controller),
81 saved_auto_repeat_enabled_(false) {
82 DCHECK(delegate_);
83 DCHECK(input_controller_);
86 void InputInjectorChromeos::Core::InjectClipboardEvent(
87 const ClipboardEvent& event) {
88 clipboard_->InjectClipboardEvent(event);
91 void InputInjectorChromeos::Core::InjectKeyEvent(const KeyEvent& event) {
92 DCHECK(event.has_pressed());
93 DCHECK(event.has_usb_keycode());
95 ui::DomCode dom_code =
96 ui::KeycodeConverter::UsbKeycodeToDomCode(event.usb_keycode());
98 // Ignore events which can't be mapped.
99 if (dom_code != ui::DomCode::NONE) {
100 HandleAutoRepeat(dom_code, event.pressed());
101 delegate_->InjectKeyPress(dom_code, event.pressed());
105 // Disables auto-repeat as long as keys are pressed to avoid duplicated
106 // key-presses if network congestion delays the key-up event from the client.
107 void InputInjectorChromeos::Core::HandleAutoRepeat(ui::DomCode dom_code,
108 bool pressed) {
109 if (pressed) {
110 if (pressed_keys_.find(dom_code) != pressed_keys_.end()) {
111 // Key is already held down, so lift the key up to ensure this repeated
112 // press takes effect.
113 // TODO(kelvinp): Fix this code to inject auto-repeated key presses as
114 // the expected behavior of "down down down ... up" as opposed to current
115 // implementation "down up down ... up".
116 delegate_->InjectKeyPress(dom_code, false);
119 if (pressed_keys_.empty()) {
120 // Disable auto-repeat, if necessary, when any key is pressed.
121 saved_auto_repeat_enabled_ = input_controller_->IsAutoRepeatEnabled();
122 if (saved_auto_repeat_enabled_) {
123 input_controller_->SetAutoRepeatEnabled(false);
126 pressed_keys_.insert(dom_code);
127 } else {
128 pressed_keys_.erase(dom_code);
129 if (pressed_keys_.empty()) {
130 // Re-enable auto-repeat, if necessary, when all keys are released.
131 if (saved_auto_repeat_enabled_) {
132 input_controller_->SetAutoRepeatEnabled(true);
138 void InputInjectorChromeos::Core::InjectTextEvent(const TextEvent& event) {
139 // Chrome OS only supports It2Me, which is not supported on mobile clients, so
140 // we don't need to implement text events.
141 NOTIMPLEMENTED();
144 void InputInjectorChromeos::Core::InjectMouseEvent(const MouseEvent& event) {
145 if (event.has_button() && event.has_button_down()) {
146 delegate_->InjectMouseButton(MouseButtonToUIFlags(event.button()),
147 event.button_down());
148 } else if (event.has_wheel_delta_y() || event.has_wheel_delta_x()) {
149 delegate_->InjectMouseWheel(event.wheel_delta_x(), event.wheel_delta_y());
150 } else {
151 DCHECK(event.has_x() && event.has_y());
152 delegate_->MoveCursorTo(point_transformer_->ToScreenCoordinates(
153 gfx::PointF(event.x(), event.y())));
157 void InputInjectorChromeos::Core::Start(
158 scoped_ptr<protocol::ClipboardStub> client_clipboard) {
159 clipboard_.reset(Clipboard::Create());
160 clipboard_->Start(client_clipboard.Pass());
161 point_transformer_.reset(new PointTransformer());
164 InputInjectorChromeos::InputInjectorChromeos(
165 scoped_refptr<base::SingleThreadTaskRunner> task_runner)
166 : input_task_runner_(task_runner) {
167 ui::OzonePlatform* ozone_platform = ui::OzonePlatform::GetInstance();
168 core_.reset(new Core(ozone_platform->CreateSystemInputInjector(),
169 ozone_platform->GetInputController()));
172 InputInjectorChromeos::~InputInjectorChromeos() {
173 input_task_runner_->DeleteSoon(FROM_HERE, core_.release());
176 void InputInjectorChromeos::InjectClipboardEvent(const ClipboardEvent& event) {
177 input_task_runner_->PostTask(
178 FROM_HERE, base::Bind(&Core::InjectClipboardEvent,
179 base::Unretained(core_.get()), event));
182 void InputInjectorChromeos::InjectKeyEvent(const KeyEvent& event) {
183 input_task_runner_->PostTask(
184 FROM_HERE,
185 base::Bind(&Core::InjectKeyEvent, base::Unretained(core_.get()), event));
188 void InputInjectorChromeos::InjectTextEvent(const TextEvent& event) {
189 input_task_runner_->PostTask(
190 FROM_HERE,
191 base::Bind(&Core::InjectTextEvent, base::Unretained(core_.get()), event));
194 void InputInjectorChromeos::InjectMouseEvent(const MouseEvent& event) {
195 input_task_runner_->PostTask(
196 FROM_HERE, base::Bind(&Core::InjectMouseEvent,
197 base::Unretained(core_.get()), event));
200 void InputInjectorChromeos::Start(
201 scoped_ptr<protocol::ClipboardStub> client_clipboard) {
202 input_task_runner_->PostTask(
203 FROM_HERE, base::Bind(&Core::Start, base::Unretained(core_.get()),
204 base::Passed(&client_clipboard)));
207 // static
208 scoped_ptr<InputInjector> InputInjector::Create(
209 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
210 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
211 // The Ozone input injector must be called on the UI task runner of the
212 // browser process.
213 return make_scoped_ptr(new InputInjectorChromeos(ui_task_runner));
216 } // namespace remoting