OLD | NEW |
| (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 | |
OLD | NEW |