Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(70)

Side by Side Diff: components/arc/input/arc_input_bridge_impl.cc

Issue 1596663002: arc-bridge: Introduce the ArcService class (Closed) Base URL: https://chromium.googlesource.com/a/chromium/src.git@master
Patch Set: Rebased + protected ArcService direct instantiation Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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.
4
5 #include "components/arc/input/arc_input_bridge_impl.h"
6
7 #include <linux/input.h>
8 #include <fcntl.h>
9 #include <stddef.h>
10
11 #include <string>
12
13 #include "base/logging.h"
14 #include "base/posix/eintr_wrapper.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "base/time/time.h"
17 #include "components/arc/arc_bridge_service.h"
18 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
19 #include "ui/aura/env.h"
20 #include "ui/aura/env_observer.h"
21 #include "ui/aura/window.h"
22 #include "ui/aura/window_observer.h"
23 #include "ui/events/event.h"
24 #include "ui/events/event_handler.h"
25 #include "ui/events/event_utils.h"
26 #include "ui/events/keycodes/dom/keycode_converter.h"
27
28 namespace {
29
30 // ARC runs as 32-bit in all platforms, so we need to make sure to send a
31 // struct input_event that is the same size it expects.
32 struct timeval32 {
33 int32_t tv_sec;
34 int32_t tv_usec;
35 };
36
37 struct input_event32 {
38 struct timeval32 time;
39 uint16_t type;
40 uint16_t code;
41 int32_t value;
42 };
43
44 // input_event values for keyboard events.
45 const int kKeyReleased = 0;
46 const int kKeyPressed = 1;
47 const int kKeyRepeated = 2;
48
49 // maximum number of supported multi-touch slots (simultaneous fingers).
50 const int kMaxSlots = 64;
51
52 // tracking id of an empty slot.
53 const int kEmptySlot = -1;
54
55 // maximum possible pressure as defined in EventHubARC.
56 // TODO(denniskempin): communicate maximum during initialization.
57 const int kMaxPressure = 65536;
58
59 // speed of the scroll emulation. Scroll events are reported at about 100 times
60 // the speed of a scroll wheel.
61 const float kScrollEmulationSpeed = 100.0f;
62
63 struct MouseButtonMapping {
64 int ui_flag;
65 int evdev_code;
66 } kMouseButtonMap[] = {
67 {ui::EF_LEFT_MOUSE_BUTTON, BTN_LEFT},
68 {ui::EF_RIGHT_MOUSE_BUTTON, BTN_RIGHT},
69 {ui::EF_MIDDLE_MOUSE_BUTTON, BTN_MIDDLE},
70 };
71
72 // Offset between evdev key codes and chrome native key codes
73 const int kXkbKeycodeOffset = 8;
74
75 } // namespace
76
77 namespace arc {
78
79 ArcInputBridgeImpl::ArcInputBridgeImpl(ArcBridgeService* arc_bridge_service)
80 : arc_bridge_service_(arc_bridge_service),
81 offset_x_acc_(0.5f),
82 offset_y_acc_(0.5f),
83 current_slot_(-1),
84 current_slot_tracking_ids_(kMaxSlots, kEmptySlot),
85 origin_task_runner_(base::ThreadTaskRunnerHandle::Get()),
86 weak_factory_(this) {
87 arc_bridge_service->AddObserver(this);
88 if (arc_bridge_service->input_instance())
89 OnInputInstanceReady();
90
91 aura::Env* env = aura::Env::GetInstanceDontCreate();
92 if (env)
93 env->AddObserver(this);
94 }
95
96 ArcInputBridgeImpl::~ArcInputBridgeImpl() {
97 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
98 arc_bridge_service_->RemoveObserver(this);
99
100 aura::Env* env = aura::Env::GetInstanceDontCreate();
101 if (env)
102 env->RemoveObserver(this);
103
104 for (aura::Window* window : arc_windows_.windows()) {
105 window->RemovePreTargetHandler(this);
106 }
107 }
108
109 void ArcInputBridgeImpl::OnInputInstanceReady() {
110 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
111
112 keyboard_fd_ = CreateBridgeInputDevice("ChromeOS Keyboard", "keyboard");
113 mouse_fd_ = CreateBridgeInputDevice("ChromeOS Mouse", "mouse");
114 touchscreen_fd_ =
115 CreateBridgeInputDevice("ChromeOS Touchscreen", "touchscreen");
116 }
117
118 // Translates and sends a ui::Event to the appropriate bridge device of the
119 // ARC instance. If the devices have not yet been initialized, the event
120 // will be ignored.
121 void ArcInputBridgeImpl::OnEvent(ui::Event* event) {
122 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
123 if (event->IsKeyEvent()) {
124 SendKeyEvent(static_cast<ui::KeyEvent*>(event));
125 } else if (event->IsMouseEvent() || event->IsScrollEvent()) {
126 SendMouseEvent(static_cast<ui::MouseEvent*>(event));
127 } else if (event->IsTouchEvent()) {
128 SendTouchEvent(static_cast<ui::TouchEvent*>(event));
129 }
130 }
131
132 // Attaches the input bridge to the window if it is marked as an ARC window.
133 void ArcInputBridgeImpl::OnWindowInitialized(aura::Window* new_window) {
134 if (new_window->name() == "ExoSurface") {
135 arc_windows_.Add(new_window);
136 new_window->AddPreTargetHandler(this);
137 }
138 }
139
140 void ArcInputBridgeImpl::SendKeyEvent(ui::KeyEvent* event) {
141 if (keyboard_fd_.get() < 0) {
142 VLOG(2) << "No keyboard bridge device available.";
143 return;
144 }
145
146 uint16_t evdev_code = DomCodeToEvdevCode(event->code());
147 int evdev_value = 0;
148 if (event->type() == ui::ET_KEY_PRESSED) {
149 if (event->flags() & ui::EF_IS_REPEAT) {
150 evdev_value = kKeyRepeated;
151 } else {
152 evdev_value = kKeyPressed;
153 }
154 } else if (event->type() == ui::ET_KEY_RELEASED) {
155 evdev_value = kKeyReleased;
156 } else {
157 NOTREACHED() << "Key should be either PRESSED or RELEASED.";
158 }
159
160 base::TimeDelta time_stamp = event->time_stamp();
161 SendKernelEvent(keyboard_fd_, time_stamp, EV_KEY, evdev_code, evdev_value);
162 SendSynReport(keyboard_fd_, time_stamp);
163 }
164
165 void ArcInputBridgeImpl::SendTouchEvent(ui::TouchEvent* event) {
166 if (touchscreen_fd_.get() < 0) {
167 VLOG(2) << "No touchscreen bridge device available.";
168 return;
169 }
170
171 ui::PointerDetails details = event->pointer_details();
172 base::TimeDelta time_stamp = event->time_stamp();
173
174 // find or assing a slot for this tracking id
175 int slot_id = AcquireTouchSlot(event);
176 if (slot_id < 0) {
177 VLOG(1) << "Ran out of slot IDs.";
178 return;
179 }
180
181 // we only need to send the slot ID when it has changed.
182 if (slot_id != current_slot_) {
183 current_slot_ = slot_id;
184 SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_SLOT,
185 current_slot_);
186 }
187
188 // update tracking id
189 if (event->type() == ui::ET_TOUCH_PRESSED) {
190 SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TRACKING_ID,
191 event->touch_id());
192 } else if (event->type() == ui::ET_TOUCH_RELEASED) {
193 SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TRACKING_ID,
194 kEmptySlot);
195 }
196
197 // update touch information
198 if (event->type() == ui::ET_TOUCH_MOVED ||
199 event->type() == ui::ET_TOUCH_PRESSED) {
200 SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_POSITION_X,
201 event->x());
202 SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_POSITION_Y,
203 event->y());
204 SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TOUCH_MAJOR,
205 details.radius_x());
206 SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TOUCH_MINOR,
207 details.radius_y());
208 SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_PRESSURE,
209 details.force() * kMaxPressure);
210 }
211 SendSynReport(touchscreen_fd_, time_stamp);
212 }
213
214 void ArcInputBridgeImpl::SendMouseEvent(ui::MouseEvent* event) {
215 if (mouse_fd_.get() < 0) {
216 VLOG(2) << "No mouse bridge device available.";
217 return;
218 }
219
220 base::TimeDelta time_stamp = event->time_stamp();
221
222 // update location
223 if (event->type() == ui::ET_MOUSE_MOVED ||
224 event->type() == ui::ET_MOUSE_DRAGGED) {
225 SendKernelEvent(mouse_fd_, time_stamp, EV_ABS, ABS_X, event->x());
226 SendKernelEvent(mouse_fd_, time_stamp, EV_ABS, ABS_Y, event->y());
227 }
228
229 // update buttons
230 if (event->type() == ui::ET_MOUSE_PRESSED ||
231 event->type() == ui::ET_MOUSE_RELEASED) {
232 int evdev_value = static_cast<int>(event->type() == ui::ET_MOUSE_PRESSED);
233 for (MouseButtonMapping mapping : kMouseButtonMap) {
234 if (event->changed_button_flags() & mapping.ui_flag) {
235 SendKernelEvent(mouse_fd_, time_stamp, EV_KEY, mapping.evdev_code,
236 evdev_value);
237 }
238 }
239 }
240
241 // update scroll wheel
242 if (event->type() == ui::ET_SCROLL) {
243 ui::ScrollEvent* scroll_event = static_cast<ui::ScrollEvent*>(event);
244 // accumulate floating point scroll offset since we can only send full
245 // integer
246 // wheel events.
247 offset_x_acc_ += scroll_event->x_offset_ordinal() / kScrollEmulationSpeed;
248 offset_y_acc_ += scroll_event->y_offset_ordinal() / kScrollEmulationSpeed;
249
250 int wheel = floor(offset_y_acc_);
251 if (wheel != 0) {
252 SendKernelEvent(mouse_fd_, time_stamp, EV_REL, REL_WHEEL, wheel);
253 offset_y_acc_ -= static_cast<float>(wheel);
254 }
255
256 int hwheel = floor(offset_x_acc_);
257 if (hwheel != 0) {
258 SendKernelEvent(mouse_fd_, time_stamp, EV_REL, REL_HWHEEL, hwheel);
259 offset_x_acc_ -= static_cast<float>(hwheel);
260 }
261 }
262
263 SendSynReport(mouse_fd_, time_stamp);
264 }
265
266 void ArcInputBridgeImpl::SendKernelEvent(const base::ScopedFD& fd,
267 base::TimeDelta time_stamp,
268 uint16_t type,
269 uint16_t code,
270 int value) {
271 DCHECK(fd.is_valid());
272
273 struct input_event32 event;
274 event.time.tv_sec = time_stamp.InSeconds();
275 base::TimeDelta remainder =
276 time_stamp - base::TimeDelta::FromSeconds(event.time.tv_sec);
277 event.time.tv_usec = remainder.InMicroseconds();
278 event.type = type;
279 event.code = code;
280 event.value = value;
281
282 // Write event to file descriptor
283 size_t num_written = write(fd.get(), reinterpret_cast<void*>(&event),
284 sizeof(struct input_event32));
285 DCHECK_EQ(num_written, sizeof(struct input_event32));
286 }
287
288 void ArcInputBridgeImpl::SendSynReport(const base::ScopedFD& fd,
289 base::TimeDelta time) {
290 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
291
292 SendKernelEvent(fd, time, EV_SYN, SYN_REPORT, 0);
293 }
294
295 int ArcInputBridgeImpl::AcquireTouchSlot(ui::TouchEvent* event) {
296 int slot_id;
297 if (event->type() == ui::ET_TOUCH_PRESSED) {
298 slot_id = FindTouchSlot(kEmptySlot);
299 } else {
300 slot_id = FindTouchSlot(event->touch_id());
301 }
302 if (slot_id < 0) {
303 return -1;
304 }
305
306 if (event->type() == ui::ET_TOUCH_RELEASED) {
307 current_slot_tracking_ids_[slot_id] = kEmptySlot;
308 } else if (event->type() == ui::ET_TOUCH_PRESSED) {
309 current_slot_tracking_ids_[slot_id] = event->touch_id();
310 }
311 return slot_id;
312 }
313
314 int ArcInputBridgeImpl::FindTouchSlot(int tracking_id) {
315 for (int i = 0; i < kMaxSlots; ++i) {
316 if (current_slot_tracking_ids_[i] == tracking_id) {
317 return i;
318 }
319 }
320 return -1;
321 }
322
323 uint16_t ArcInputBridgeImpl::DomCodeToEvdevCode(ui::DomCode dom_code) {
324 int native_code = ui::KeycodeConverter::DomCodeToNativeKeycode(dom_code);
325 if (native_code == ui::KeycodeConverter::InvalidNativeKeycode())
326 return KEY_RESERVED;
327
328 return native_code - kXkbKeycodeOffset;
329 }
330
331 base::ScopedFD ArcInputBridgeImpl::CreateBridgeInputDevice(
332 const std::string& name,
333 const std::string& device_type) {
334 if (!arc_bridge_service_) {
335 VLOG(1) << "ArcBridgeService disappeared.";
336 return base::ScopedFD();
337 }
338
339 // Create file descriptor pair for communication
340 int fd[2];
341 int res = HANDLE_EINTR(pipe(fd));
342 if (res < 0) {
343 VPLOG(1) << "Cannot create pipe";
344 return base::ScopedFD();
345 }
346 base::ScopedFD read_fd(fd[0]);
347 base::ScopedFD write_fd(fd[1]);
348
349 // The read end is sent to the instance, ownership of fd transfers.
350 InputInstance* input_instance = arc_bridge_service_->input_instance();
351 if (!input_instance) {
352 VLOG(1) << "ArcBridgeService InputInstance disappeared.";
353 return base::ScopedFD();
354 }
355 MojoHandle wrapped_handle;
356 MojoResult wrap_result = mojo::embedder::CreatePlatformHandleWrapper(
357 mojo::embedder::ScopedPlatformHandle(
358 mojo::embedder::PlatformHandle(read_fd.release())),
359 &wrapped_handle);
360 if (wrap_result != MOJO_RESULT_OK) {
361 LOG(WARNING) << "Pipe failed to wrap handles. Closing: " << wrap_result;
362 return base::ScopedFD();
363 }
364 input_instance->RegisterInputDevice(
365 name, device_type, mojo::ScopedHandle(mojo::Handle(wrapped_handle)));
366
367 // setup write end as non blocking
368 int flags = HANDLE_EINTR(fcntl(write_fd.get(), F_GETFL, 0));
369 if (res < 0) {
370 VPLOG(1) << "Cannot get file descriptor flags";
371 return base::ScopedFD();
372 }
373
374 res = HANDLE_EINTR(fcntl(write_fd.get(), F_SETFL, flags | O_NONBLOCK));
375 if (res < 0) {
376 VPLOG(1) << "Cannot set file descriptor flags";
377 return base::ScopedFD();
378 }
379 return write_fd;
380 }
381
382 scoped_ptr<ArcInputBridge> ArcInputBridge::Create(
383 ArcBridgeService* arc_bridge_service) {
384 return make_scoped_ptr(new ArcInputBridgeImpl(arc_bridge_service));
385 }
386
387 } // namespace arc
OLDNEW
« no previous file with comments | « components/arc/input/arc_input_bridge_impl.h ('k') | components/arc/intent_helper/arc_intent_helper_bridge.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698