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

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: Moved IO to IO thread. Fixed style issues pointed out by jochen@ 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
« no previous file with comments | « components/arc/input/arc_input_bridge.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "base/logging.h"
10 #include "base/posix/eintr_wrapper.h"
11 #include "base/sequenced_task_runner.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "base/time/time.h"
14 #include "components/arc/arc_bridge_service.h"
15 #include "ui/events/event_utils.h"
16 #include "ui/events/keycodes/dom/keycode_converter.h"
17 #include "ui/events/ozone/evdev/keyboard_util_evdev.h"
18
19 namespace {
20
21 // input_event values for keyboard events
22 const int kKeyReleased = 0;
23 const int kKeyPressed = 1;
24 const int kKeyRepeated = 2;
25
26 // maximum number of supported multi-touch slots (simultaneous fingers)
27 const int kMaxSlots = 64;
28
29 // tracking id of an empty slot
30 const int kEmptySlot = -1;
31
32 // maximum possible pressure as defined in EventHubARC.
33 // todo(denniskempin): communicate maximum during initialization.
34 const int kMaxPressure = 65536;
35
36 struct MouseButtonMapping {
37 int ui_flag;
38 int evdev_code;
39 };
40
41 MouseButtonMapping kMouseButtonMap[] = {
42 {ui::EF_LEFT_MOUSE_BUTTON, BTN_LEFT},
43 {ui::EF_RIGHT_MOUSE_BUTTON, BTN_RIGHT},
44 {ui::EF_MIDDLE_MOUSE_BUTTON, BTN_MIDDLE},
45 };
46
47 // Weak pointer. This class is owned by ChromeBrowserMainPartsChromeos.
48 arc::ArcInputBridge* g_arc_input_bridge = nullptr;
49
50 } // namespace
51
52 namespace arc {
53
54 ArcInputBridge::ArcInputBridge(
55 base::WeakPtr<ArcBridgeService> arc_bridge_service,
56 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
57 : arc_bridge_service_(arc_bridge_service),
58 current_slot_(-1),
59 current_slot_tracking_ids_(kMaxSlots, kEmptySlot),
60 origin_task_runner_(base::ThreadTaskRunnerHandle::Get()),
61 io_task_runner_(io_task_runner),
62 weak_factory_(this) {
63 DCHECK(arc_bridge_service);
64 DCHECK(arc_bridge_service->state() == ArcBridgeService::State::STOPPED);
65 arc_bridge_service->AddObserver(this);
66 g_arc_input_bridge = this;
67 }
68
69 ArcInputBridge::~ArcInputBridge() {
70 if (arc_bridge_service_)
71 arc_bridge_service_->RemoveObserver(this);
72 }
73
74 // static
75 ArcInputBridge* ArcInputBridge::Get() {
76 DCHECK(g_arc_input_bridge);
77 DCHECK(g_arc_input_bridge->origin_task_runner_->RunsTasksOnCurrentThread());
78 return g_arc_input_bridge;
79 }
80
81 void ArcInputBridge::OnInstanceBootPhase(InstanceBootPhase phase) {
82 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
83 if (phase != InstanceBootPhase::SYSTEM_SERVICES_READY)
84 return;
85
86 keyboard_fd_ = CreateBridgeInputDevice("ChromeOS Keyboard", "keyboard");
87 mouse_fd_ = CreateBridgeInputDevice("ChromeOS Mouse", "mouse");
88 touchscreen_fd_ =
89 CreateBridgeInputDevice("ChromeOS Touchscreen", "touchscreen");
90 }
91
92 void ArcInputBridge::SendInputEvent(ui::Event* event) {
93 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
94 scoped_ptr<ui::Event> copy = ui::Event::Clone(*event);
95 io_task_runner_->PostTask(
96 FROM_HERE, base::Bind(&ArcInputBridge::SendInputEventIO,
elijahtaylor1 2015/12/03 06:35:19 just wondering if you know the average thread swit
denniskempin 2015/12/03 15:43:40 I don't feel too comfortable about this either. Ma
97 weak_factory_.GetWeakPtr(), base::Passed(&copy)));
98 }
99
100 void ArcInputBridge::SendInputEventIO(scoped_ptr<ui::Event> event) {
101 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
102
103 if (event->IsKeyEvent()) {
104 SendKeyEventIO(static_cast<ui::KeyEvent*>(event.get()));
105 } else if (event->IsMouseEvent()) {
106 SendMouseEventIO(static_cast<ui::MouseEvent*>(event.get()));
107 } else if (event->IsTouchEvent()) {
108 SendTouchEventIO(static_cast<ui::TouchEvent*>(event.get()));
109 }
110 }
111
112 void ArcInputBridge::SendKeyEventIO(ui::KeyEvent* event) {
113 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
114
115 if (keyboard_fd_.get() < 0) {
116 LOG(WARNING) << "No keyboard bridge device available.";
117 return;
118 }
119
120 int native_code = ui::KeycodeConverter::DomCodeToNativeKeycode(event->code());
121
122 unsigned short evdev_code = ui::NativeCodeToEvdevCode(native_code);
123 int evdev_value;
124 if (event->type() == ui::ET_KEY_PRESSED) {
125 if (event->flags() & ui::EF_IS_REPEAT) {
126 evdev_value = kKeyRepeated;
127 } else {
128 evdev_value = kKeyPressed;
129 }
130 } else if (event->type() == ui::ET_KEY_RELEASED) {
131 evdev_value = kKeyReleased;
132 }
133
134 base::TimeDelta time_stamp = event->time_stamp();
135 SendKernelEventIO(keyboard_fd_, time_stamp, EV_KEY, evdev_code, evdev_value);
136 SendSynReportIO(keyboard_fd_, time_stamp);
137 }
138
139 void ArcInputBridge::SendTouchEventIO(ui::TouchEvent* event) {
140 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
141
142 if (touchscreen_fd_.get() < 0) {
143 LOG(WARNING) << "No touchscreen bridge device available.";
144 return;
145 }
146
147 ui::PointerDetails details = event->pointer_details();
148 base::TimeDelta time_stamp = event->time_stamp();
149
150 // find or assing a slot for this tracking id
151 int slot_id = AcquireTouchSlotIO(event);
152 if (slot_id < 0) {
153 LOG(ERROR) << "Ran out of slot IDs.";
154 return;
155 }
156
157 // we only need to send the slot ID when it has changed.
158 if (slot_id != current_slot_) {
159 current_slot_ = slot_id;
160 SendKernelEventIO(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_SLOT,
161 current_slot_);
162 }
163
164 // update tracking id
165 if (event->type() == ui::ET_TOUCH_PRESSED) {
166 SendKernelEventIO(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TRACKING_ID,
167 event->touch_id());
168 } else if (event->type() == ui::ET_TOUCH_RELEASED) {
169 SendKernelEventIO(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TRACKING_ID,
170 kEmptySlot);
171 }
172
173 // update touch information
174 if (event->type() == ui::ET_TOUCH_MOVED ||
175 event->type() == ui::ET_TOUCH_PRESSED) {
176 SendKernelEventIO(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_POSITION_X,
177 event->x());
178 SendKernelEventIO(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_POSITION_Y,
179 event->y());
180 SendKernelEventIO(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TOUCH_MAJOR,
181 details.radius_x());
182 SendKernelEventIO(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TOUCH_MINOR,
183 details.radius_y());
184 SendKernelEventIO(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_PRESSURE,
185 details.force() * kMaxPressure);
186 }
187 SendSynReportIO(touchscreen_fd_, time_stamp);
188 }
189
190 void ArcInputBridge::SendMouseEventIO(ui::MouseEvent* event) {
191 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
192
193 if (mouse_fd_.get() < 0) {
194 LOG(WARNING) << "No mouse bridge device available.";
195 return;
196 }
197
198 base::TimeDelta time_stamp = event->time_stamp();
199
200 // update location
201 if (event->type() == ui::ET_MOUSE_MOVED) {
202 SendKernelEventIO(mouse_fd_, time_stamp, EV_ABS, ABS_X, event->x());
203 SendKernelEventIO(mouse_fd_, time_stamp, EV_ABS, ABS_Y, event->y());
204 }
205
206 // update buttons
207 if (event->type() == ui::ET_MOUSE_PRESSED ||
208 event->type() == ui::ET_MOUSE_RELEASED) {
209 int evdev_value = static_cast<int>(event->type() == ui::ET_MOUSE_PRESSED);
210 for (MouseButtonMapping mapping : kMouseButtonMap) {
211 if (event->changed_button_flags() & mapping.ui_flag) {
212 SendKernelEventIO(mouse_fd_, time_stamp, EV_KEY, mapping.evdev_code,
213 evdev_value);
214 }
215 }
216 }
217
218 // update scroll wheel
219 if (event->IsMouseWheelEvent()) {
220 ui::MouseWheelEvent* wheel_event = static_cast<ui::MouseWheelEvent*>(event);
221 SendKernelEventIO(mouse_fd_, time_stamp, EV_REL, REL_WHEEL,
222 wheel_event->y_offset());
223 SendKernelEventIO(mouse_fd_, time_stamp, EV_REL, REL_HWHEEL,
224 wheel_event->x_offset());
225 }
226
227 SendSynReportIO(mouse_fd_, time_stamp);
228 }
229
230 void ArcInputBridge::SendKernelEventIO(const base::ScopedFD& fd,
231 base::TimeDelta time_stamp,
232 unsigned short type,
233 unsigned short code,
234 int value) {
235 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
236 DCHECK_GE(fd.get(), 0);
237
238 // Chrome does not always use the monotonic system time for event times.
239 // For now always force the event time to the current system time.
240 // todo(denniskempin): To enable performance tracing of events we will want
241 // to use the kernel-provided monotonic time stamps of events.
242 time_stamp = ui::EventTimeForNow();
elijahtaylor1 2015/12/03 06:35:19 I wonder if this might cause problems because you'
denniskempin 2015/12/03 15:43:40 As far as I can tell from the low level stuff we d
243
244 struct input_event event;
245 event.time.tv_sec = time_stamp.InSeconds();
246 base::TimeDelta remainder =
247 time_stamp - base::TimeDelta::FromSeconds(event.time.tv_sec);
248 event.time.tv_usec = remainder.InMicroseconds();
249 event.type = type;
250 event.code = code;
251 event.value = value;
252
253 // Write event to file descriptor
254 int num_written = write(fd.get(), reinterpret_cast<void*>(&event),
255 sizeof(struct input_event));
256 if (num_written != sizeof(struct input_event))
257 LOG(ERROR) << "Can't write to file descriptor";
258 }
259
260 void ArcInputBridge::SendSynReportIO(const base::ScopedFD& fd,
261 base::TimeDelta time) {
262 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
263
264 SendKernelEventIO(fd, time, EV_SYN, SYN_REPORT, 0);
elijahtaylor1 2015/12/03 06:35:19 you should probably use ui::EventTimeForNow here t
denniskempin 2015/12/03 15:43:40 it is calling the method above, so it's using the
elijahtaylor1 2015/12/04 01:38:29 doh, code comprehension failure!
265 }
266
267 int ArcInputBridge::AcquireTouchSlotIO(ui::TouchEvent* event) {
268 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
269
270 int slot_id;
271 if (event->type() == ui::ET_TOUCH_PRESSED) {
272 slot_id = FindTouchSlotIO(kEmptySlot);
273 } else {
274 slot_id = FindTouchSlotIO(event->touch_id());
275 }
276 if (slot_id < 0) {
277 return -1;
278 }
279
280 if (event->type() == ui::ET_TOUCH_RELEASED) {
281 current_slot_tracking_ids_[slot_id] = kEmptySlot;
282 } else if (event->type() == ui::ET_TOUCH_PRESSED) {
283 current_slot_tracking_ids_[slot_id] = event->touch_id();
284 }
285 return slot_id;
286 }
287
288 int ArcInputBridge::FindTouchSlotIO(int tracking_id) {
289 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
290
291 for (int i = 0; i < kMaxSlots; ++i) {
292 if (current_slot_tracking_ids_[i] == tracking_id) {
293 return i;
294 }
295 }
296 return -1;
297 }
298
299 base::ScopedFD ArcInputBridge::CreateBridgeInputDevice(
300 const std::string& name,
301 const std::string& device_type) {
302 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
303
304 if (!arc_bridge_service_) {
305 LOG(ERROR) << "ArcBridgeService disappeared.";
306 return base::ScopedFD();
307 }
308
309 // Create file descriptor pair for communication
310 int fd[2];
311 int res = HANDLE_EINTR(pipe(fd));
312 if (res < 0)
313 PLOG(ERROR) << "Cannot create pipe";
314
315 // The read end is sent to the instance, ownership of fd transfers.
316 if (!arc_bridge_service_->RegisterInputDevice(name, device_type,
317 base::ScopedFD(fd[0]))) {
318 close(fd[1]); // close write end.
319 LOG(ERROR) << "Cannot create bridge input device";
320 return base::ScopedFD();
321 }
322
323 // return the write end
324 return base::ScopedFD(fd[1]).Pass();
325 }
326
327 } // namespace arc
OLDNEW
« no previous file with comments | « components/arc/input/arc_input_bridge.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698