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

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

Issue 1408263006: chromeos: Add ArcInputBridge to components/arc (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@arcxx
Patch Set: integration with ArcServiceManager and ExoSurfaces Created 5 years 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.h"
6
7 #include <linux/input.h>
8
9 #include "ash/shell.h"
10 #include "base/logging.h"
11 #include "base/posix/eintr_wrapper.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/time/time.h"
15 #include "components/arc/arc_bridge_service.h"
16 #include "ui/aura/window.h"
17 #include "ui/events/event_utils.h"
18 #include "ui/events/keycodes/dom/keycode_converter.h"
19 #include "ui/events/ozone/evdev/keyboard_util_evdev.h"
20 #include "components/exo/shell_surface.h"
21
22 namespace {
23
24 // input_event values for keyboard events
reveman 2015/12/04 03:21:24 nit: missing punctuation
denniskempin 2015/12/04 22:35:29 Done.
25 const int kKeyReleased = 0;
26 const int kKeyPressed = 1;
27 const int kKeyRepeated = 2;
28
29 // maximum number of supported multi-touch slots (simultaneous fingers)
reveman 2015/12/04 03:21:24 nit: missing punctuation
denniskempin 2015/12/04 22:35:29 Done.
30 const int kMaxSlots = 64;
31
32 // tracking id of an empty slot
reveman 2015/12/04 03:21:23 nit: missing punctuation
denniskempin 2015/12/04 22:35:29 Done.
33 const int kEmptySlot = -1;
34
35 // maximum possible pressure as defined in EventHubARC.
36 // todo(denniskempin): communicate maximum during initialization.
reveman 2015/12/04 03:21:24 nit: s/todo/TODO
denniskempin 2015/12/04 22:35:29 Done.
37 const int kMaxPressure = 65536;
38
39 // speed of the scroll emulation. Scroll events are reported at about 100 times
40 // the speed of a scroll wheel.
41 const float kScrollEmulationSpeed = 100.0f;
42
43 struct MouseButtonMapping {
44 int ui_flag;
45 int evdev_code;
46 };
47
48 MouseButtonMapping kMouseButtonMap[] = {
reveman 2015/12/04 03:21:23 nit: we could save a few lines by: struct MouseBu
denniskempin 2015/12/04 22:35:29 Done.
49 {ui::EF_LEFT_MOUSE_BUTTON, BTN_LEFT},
50 {ui::EF_RIGHT_MOUSE_BUTTON, BTN_RIGHT},
51 {ui::EF_MIDDLE_MOUSE_BUTTON, BTN_MIDDLE},
52 };
53
54 } // namespace
55
56 namespace arc {
57
58 ArcInputBridge::ArcInputBridge(
59 ArcBridgeService* arc_bridge_service,
60 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
61 : arc_bridge_service_(arc_bridge_service),
62 offset_x_acc(0.5f),
63 offset_y_acc(0.5f),
64 current_slot_(-1),
65 current_slot_tracking_ids_(kMaxSlots, kEmptySlot),
66 origin_task_runner_(base::ThreadTaskRunnerHandle::Get()),
67 io_task_runner_(io_task_runner),
reveman 2015/12/04 03:21:23 what happens if origin_task_runner_ == io_task_run
denniskempin 2015/12/04 22:35:29 no longer necessary.
68 weak_factory_(this) {
69 DCHECK(arc_bridge_service->state() == ArcBridgeService::State::STOPPED);
70 arc_bridge_service->AddObserver(this);
71
72 origin_task_runner_->PostTask(
73 FROM_HERE, base::Bind(&ArcInputBridge::InitializeAuraObserver,
74 weak_factory_.GetWeakPtr()));
reveman 2015/12/04 03:21:23 why do we need to post a task for this if we're al
denniskempin 2015/12/04 22:35:29 aura::Env is created after this class is. Unfortun
reveman 2015/12/04 23:19:31 hm, calling aura::Env::GetInstance() here and havi
75 }
76
77 ArcInputBridge::~ArcInputBridge() {
78 if (arc_bridge_service_)
reveman 2015/12/04 03:21:23 I'm failing to see how arc_bridge_service_ can eve
denniskempin 2015/12/04 22:35:29 Yes, now that's guaranteed. done.
79 arc_bridge_service_->RemoveObserver(this);
80 }
81
82 void ArcInputBridge::InitializeAuraObserver() {
83 aura::Env::GetInstance()->AddObserver(this);
reveman 2015/12/04 03:21:24 where is the matching RemoveObserver call?
denniskempin 2015/12/04 22:35:29 I don't think we can. aura::Env is destroyed befor
84 }
85
86 void ArcInputBridge::OnInstanceBootPhase(InstanceBootPhase phase) {
87 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
88 if (phase != InstanceBootPhase::SYSTEM_SERVICES_READY)
89 return;
90
91 keyboard_fd_ = CreateBridgeInputDevice("ChromeOS Keyboard", "keyboard");
92 mouse_fd_ = CreateBridgeInputDevice("ChromeOS Mouse", "mouse");
93 touchscreen_fd_ =
94 CreateBridgeInputDevice("ChromeOS Touchscreen", "touchscreen");
reveman 2015/12/04 03:21:23 these "*_fd_" members seem to also be used on the
denniskempin 2015/12/04 22:35:29 Done.
95 }
96
97 void ArcInputBridge::OnEvent(ui::Event* event) {
98 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
99 scoped_ptr<ui::Event> copy = ui::Event::Clone(*event);
reveman 2015/12/04 03:21:23 Would it make sense to do more processing on the U
denniskempin 2015/12/04 22:35:30 Done.
100 io_task_runner_->PostTask(
101 FROM_HERE, base::Bind(&ArcInputBridge::SendInputEventIO,
102 weak_factory_.GetWeakPtr(), base::Passed(&copy)));
reveman 2015/12/04 03:21:24 This doesn't work as weak pointers are not thread
denniskempin 2015/12/04 22:35:29 Done.
103 }
104
105 void ArcInputBridge::OnWindowInitialized(aura::Window* new_window) {
106 if (new_window->name() == "ExoSurface")
107 new_window->AddPreTargetHandler(this);
reveman 2015/12/04 03:21:24 nit: call RemovePreTargetHandler before the window
denniskempin 2015/12/04 22:35:29 As we talked over in hangouts. It's common practic
108 }
109
110 void ArcInputBridge::SendInputEventIO(scoped_ptr<ui::Event> event) {
111 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
112
113 if (event->IsKeyEvent()) {
114 SendKeyEventIO(static_cast<ui::KeyEvent*>(event.get()));
115 } else if (event->IsMouseEvent() || event->IsScrollEvent()) {
116 SendMouseEventIO(static_cast<ui::MouseEvent*>(event.get()));
117 } else if (event->IsTouchEvent()) {
118 SendTouchEventIO(static_cast<ui::TouchEvent*>(event.get()));
119 }
jochen (gone - plz use gerrit) 2015/12/04 14:18:12 else { UNREACHABLE(); }?
denniskempin 2015/12/04 22:35:29 It is actually reachable if we are receiving an ui
120 }
121
122 void ArcInputBridge::SendKeyEventIO(ui::KeyEvent* event) {
123 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
124
125 if (keyboard_fd_.get() < 0) {
126 LOG(WARNING) << "No keyboard bridge device available.";
jochen (gone - plz use gerrit) 2015/12/04 14:18:11 please use VLOG/DVLOG for logging. note that logg
denniskempin 2015/12/04 22:35:29 Done. I searched the code for other occurrences an
127 return;
128 }
129
130 int native_code = ui::KeycodeConverter::DomCodeToNativeKeycode(event->code());
131
132 unsigned short evdev_code = ui::NativeCodeToEvdevCode(native_code);
133 int evdev_value;
134 if (event->type() == ui::ET_KEY_PRESSED) {
135 if (event->flags() & ui::EF_IS_REPEAT) {
136 evdev_value = kKeyRepeated;
137 } else {
138 evdev_value = kKeyPressed;
139 }
140 } else if (event->type() == ui::ET_KEY_RELEASED) {
141 evdev_value = kKeyReleased;
142 }
143
144 base::TimeDelta time_stamp = event->time_stamp();
145 SendKernelEventIO(keyboard_fd_, time_stamp, EV_KEY, evdev_code, evdev_value);
146 SendSynReportIO(keyboard_fd_, time_stamp);
147 }
148
149 void ArcInputBridge::SendTouchEventIO(ui::TouchEvent* event) {
150 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
151
152 if (touchscreen_fd_.get() < 0) {
153 LOG(WARNING) << "No touchscreen bridge device available.";
154 return;
155 }
156
157 ui::PointerDetails details = event->pointer_details();
158 base::TimeDelta time_stamp = event->time_stamp();
159
160 // find or assing a slot for this tracking id
161 int slot_id = AcquireTouchSlotIO(event);
162 if (slot_id < 0) {
163 LOG(ERROR) << "Ran out of slot IDs.";
164 return;
165 }
166
167 // we only need to send the slot ID when it has changed.
168 if (slot_id != current_slot_) {
169 current_slot_ = slot_id;
170 SendKernelEventIO(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_SLOT,
171 current_slot_);
172 }
173
174 // update tracking id
175 if (event->type() == ui::ET_TOUCH_PRESSED) {
176 SendKernelEventIO(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TRACKING_ID,
177 event->touch_id());
178 } else if (event->type() == ui::ET_TOUCH_RELEASED) {
179 SendKernelEventIO(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TRACKING_ID,
180 kEmptySlot);
181 }
182
183 // update touch information
184 if (event->type() == ui::ET_TOUCH_MOVED ||
185 event->type() == ui::ET_TOUCH_PRESSED) {
186 SendKernelEventIO(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_POSITION_X,
187 event->x());
188 SendKernelEventIO(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_POSITION_Y,
189 event->y());
190 SendKernelEventIO(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TOUCH_MAJOR,
191 details.radius_x());
192 SendKernelEventIO(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TOUCH_MINOR,
193 details.radius_y());
194 SendKernelEventIO(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_PRESSURE,
195 details.force() * kMaxPressure);
196 }
197 SendSynReportIO(touchscreen_fd_, time_stamp);
198 }
199
200 void ArcInputBridge::SendMouseEventIO(ui::MouseEvent* event) {
201 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
202
203 if (mouse_fd_.get() < 0) {
204 LOG(WARNING) << "No mouse bridge device available.";
jochen (gone - plz use gerrit) 2015/12/04 14:18:12 same here.
denniskempin 2015/12/04 22:35:29 Done.
205 return;
206 }
207
208 base::TimeDelta time_stamp = event->time_stamp();
209
210 // update location
211 if (event->type() == ui::ET_MOUSE_MOVED) {
212 SendKernelEventIO(mouse_fd_, time_stamp, EV_ABS, ABS_X, event->x());
213 SendKernelEventIO(mouse_fd_, time_stamp, EV_ABS, ABS_Y, event->y());
214 }
215
216 // update buttons
217 if (event->type() == ui::ET_MOUSE_PRESSED ||
218 event->type() == ui::ET_MOUSE_RELEASED) {
219 int evdev_value = static_cast<int>(event->type() == ui::ET_MOUSE_PRESSED);
220 for (MouseButtonMapping mapping : kMouseButtonMap) {
221 if (event->changed_button_flags() & mapping.ui_flag) {
222 SendKernelEventIO(mouse_fd_, time_stamp, EV_KEY, mapping.evdev_code,
223 evdev_value);
224 }
225 }
226 }
227
228 // update scroll wheel
229 if (event->type() == ui::ET_SCROLL) {
230 ui::ScrollEvent* scroll_event = static_cast<ui::ScrollEvent*>(event);
231 // accumulate floating point scroll offset since we can only send full
232 // integer
233 // wheel events.
234 offset_x_acc += scroll_event->x_offset_ordinal() / kScrollEmulationSpeed;
235 offset_y_acc += scroll_event->y_offset_ordinal() / kScrollEmulationSpeed;
236
237 int wheel = floor(offset_y_acc);
238 if (wheel != 0) {
239 SendKernelEventIO(mouse_fd_, time_stamp, EV_REL, REL_WHEEL, wheel);
240 offset_y_acc -= static_cast<float>(wheel);
241 }
242
243 int hwheel = floor(offset_x_acc);
244 if (hwheel != 0) {
245 SendKernelEventIO(mouse_fd_, time_stamp, EV_REL, REL_HWHEEL, hwheel);
246 offset_x_acc -= static_cast<float>(hwheel);
247 }
248 }
249
250 SendSynReportIO(mouse_fd_, time_stamp);
251 }
252
253 void ArcInputBridge::SendKernelEventIO(const base::ScopedFD& fd,
254 base::TimeDelta time_stamp,
255 unsigned short type,
256 unsigned short code,
257 int value) {
258 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
259 DCHECK_GE(fd.get(), 0);
260
261 // Chrome does not always use the monotonic system time for event times.
262 // For now always force the event time to the current system time.
263 // todo(denniskempin): To enable performance tracing of events we will want
reveman 2015/12/04 03:21:23 nit: s/todo/TODO/
denniskempin 2015/12/04 22:35:29 Done.
264 // to use the kernel-provided monotonic time stamps of events.
265 time_stamp = ui::EventTimeForNow();
266
267 struct input_event event;
268 event.time.tv_sec = time_stamp.InSeconds();
269 base::TimeDelta remainder =
270 time_stamp - base::TimeDelta::FromSeconds(event.time.tv_sec);
271 event.time.tv_usec = remainder.InMicroseconds();
272 event.type = type;
273 event.code = code;
274 event.value = value;
275
276 // Write event to file descriptor
277 int num_written = write(fd.get(), reinterpret_cast<void*>(&event),
278 sizeof(struct input_event));
279 if (num_written != sizeof(struct input_event))
reveman 2015/12/04 03:21:23 can this be a DCHECK?
denniskempin 2015/12/04 22:35:29 Done.
280 LOG(ERROR) << "Can't write to file descriptor";
281 }
282
283 void ArcInputBridge::SendSynReportIO(const base::ScopedFD& fd,
284 base::TimeDelta time) {
285 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
reveman 2015/12/04 03:21:24 origin_task_runner?
denniskempin 2015/12/04 22:35:30 Done.
286
287 SendKernelEventIO(fd, time, EV_SYN, SYN_REPORT, 0);
288 }
289
290 int ArcInputBridge::AcquireTouchSlotIO(ui::TouchEvent* event) {
291 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
292
293 int slot_id;
294 if (event->type() == ui::ET_TOUCH_PRESSED) {
295 slot_id = FindTouchSlotIO(kEmptySlot);
296 } else {
297 slot_id = FindTouchSlotIO(event->touch_id());
298 }
299 if (slot_id < 0) {
300 return -1;
301 }
302
303 if (event->type() == ui::ET_TOUCH_RELEASED) {
304 current_slot_tracking_ids_[slot_id] = kEmptySlot;
305 } else if (event->type() == ui::ET_TOUCH_PRESSED) {
306 current_slot_tracking_ids_[slot_id] = event->touch_id();
307 }
308 return slot_id;
309 }
310
311 int ArcInputBridge::FindTouchSlotIO(int tracking_id) {
312 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
313
314 for (int i = 0; i < kMaxSlots; ++i) {
315 if (current_slot_tracking_ids_[i] == tracking_id) {
316 return i;
317 }
318 }
319 return -1;
320 }
321
322 base::ScopedFD ArcInputBridge::CreateBridgeInputDevice(
323 const std::string& name,
324 const std::string& device_type) {
325 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
326
327 if (!arc_bridge_service_) {
328 LOG(ERROR) << "ArcBridgeService disappeared.";
329 return base::ScopedFD();
330 }
331
332 // Create file descriptor pair for communication
333 int fd[2];
334 int res = HANDLE_EINTR(pipe(fd));
335 if (res < 0)
336 PLOG(ERROR) << "Cannot create pipe";
337
338 // The read end is sent to the instance, ownership of fd transfers.
339 if (!arc_bridge_service_->RegisterInputDevice(name, device_type,
340 base::ScopedFD(fd[0]))) {
341 close(fd[1]); // close write end.
342 LOG(ERROR) << "Cannot create bridge input device";
343 return base::ScopedFD();
344 }
345
346 // return the write end
347 return base::ScopedFD(fd[1]).Pass();
348 }
349
350 } // namespace arc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698