| 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 | 
|  | 10 #include "base/logging.h" | 
|  | 11 #include "base/posix/eintr_wrapper.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/aura/env.h" | 
|  | 16 #include "ui/aura/env_observer.h" | 
|  | 17 #include "ui/aura/window.h" | 
|  | 18 #include "ui/aura/window_observer.h" | 
|  | 19 #include "ui/events/event.h" | 
|  | 20 #include "ui/events/event_handler.h" | 
|  | 21 #include "ui/events/event_utils.h" | 
|  | 22 #include "ui/events/keycodes/dom/keycode_converter.h" | 
|  | 23 #include "ui/events/ozone/evdev/keyboard_util_evdev.h" | 
|  | 24 | 
|  | 25 namespace { | 
|  | 26 | 
|  | 27 // input_event values for keyboard events. | 
|  | 28 const int kKeyReleased = 0; | 
|  | 29 const int kKeyPressed = 1; | 
|  | 30 const int kKeyRepeated = 2; | 
|  | 31 | 
|  | 32 // maximum number of supported multi-touch slots (simultaneous fingers). | 
|  | 33 const int kMaxSlots = 64; | 
|  | 34 | 
|  | 35 // tracking id of an empty slot. | 
|  | 36 const int kEmptySlot = -1; | 
|  | 37 | 
|  | 38 // maximum possible pressure as defined in EventHubARC. | 
|  | 39 // TODO(denniskempin): communicate maximum during initialization. | 
|  | 40 const int kMaxPressure = 65536; | 
|  | 41 | 
|  | 42 // speed of the scroll emulation. Scroll events are reported at about 100 times | 
|  | 43 // the speed of a scroll wheel. | 
|  | 44 const float kScrollEmulationSpeed = 100.0f; | 
|  | 45 | 
|  | 46 struct MouseButtonMapping { | 
|  | 47   int ui_flag; | 
|  | 48   int evdev_code; | 
|  | 49 } kMouseButtonMap[] = { | 
|  | 50     {ui::EF_LEFT_MOUSE_BUTTON, BTN_LEFT}, | 
|  | 51     {ui::EF_RIGHT_MOUSE_BUTTON, BTN_RIGHT}, | 
|  | 52     {ui::EF_MIDDLE_MOUSE_BUTTON, BTN_MIDDLE}, | 
|  | 53 }; | 
|  | 54 | 
|  | 55 }  // namespace | 
|  | 56 | 
|  | 57 namespace arc { | 
|  | 58 | 
|  | 59 ArcInputBridgeImpl::ArcInputBridgeImpl(ArcBridgeService* arc_bridge_service) | 
|  | 60     : arc_bridge_service_(arc_bridge_service), | 
|  | 61       offset_x_acc_(0.5f), | 
|  | 62       offset_y_acc_(0.5f), | 
|  | 63       current_slot_(-1), | 
|  | 64       current_slot_tracking_ids_(kMaxSlots, kEmptySlot), | 
|  | 65       origin_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 
|  | 66       weak_factory_(this) { | 
|  | 67   DCHECK(arc_bridge_service->state() == ArcBridgeService::State::STOPPED); | 
|  | 68   arc_bridge_service->AddObserver(this); | 
|  | 69 | 
|  | 70   DCHECK(aura::Env::GetInstance()); | 
|  | 71   aura::Env::GetInstance()->AddObserver(this); | 
|  | 72 } | 
|  | 73 | 
|  | 74 ArcInputBridgeImpl::~ArcInputBridgeImpl() { | 
|  | 75   DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | 
|  | 76   arc_bridge_service_->RemoveObserver(this); | 
|  | 77 } | 
|  | 78 | 
|  | 79 void ArcInputBridgeImpl::OnInstanceBootPhase(InstanceBootPhase phase) { | 
|  | 80   DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | 
|  | 81   if (phase != InstanceBootPhase::SYSTEM_SERVICES_READY) | 
|  | 82     return; | 
|  | 83 | 
|  | 84   keyboard_fd_ = CreateBridgeInputDevice("ChromeOS Keyboard", "keyboard"); | 
|  | 85   mouse_fd_ = CreateBridgeInputDevice("ChromeOS Mouse", "mouse"); | 
|  | 86   touchscreen_fd_ = | 
|  | 87       CreateBridgeInputDevice("ChromeOS Touchscreen", "touchscreen"); | 
|  | 88 } | 
|  | 89 | 
|  | 90 // Translates and sends a ui::Event to the appropriate bridge device of the | 
|  | 91 // ARC instance. If the devices have not yet been initialized, the event | 
|  | 92 // will be ignored. | 
|  | 93 void ArcInputBridgeImpl::OnEvent(ui::Event* event) { | 
|  | 94   DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | 
|  | 95   if (event->IsKeyEvent()) { | 
|  | 96     SendKeyEvent(static_cast<ui::KeyEvent*>(event)); | 
|  | 97   } else if (event->IsMouseEvent() || event->IsScrollEvent()) { | 
|  | 98     SendMouseEvent(static_cast<ui::MouseEvent*>(event)); | 
|  | 99   } else if (event->IsTouchEvent()) { | 
|  | 100     SendTouchEvent(static_cast<ui::TouchEvent*>(event)); | 
|  | 101   } | 
|  | 102 } | 
|  | 103 | 
|  | 104 // Attaches the input bridge to the window if it is marked as an ARC window. | 
|  | 105 void ArcInputBridgeImpl::OnWindowInitialized(aura::Window* new_window) { | 
|  | 106   if (new_window->name() == "ExoSurface") | 
|  | 107     new_window->AddPreTargetHandler(this); | 
|  | 108 } | 
|  | 109 | 
|  | 110 void ArcInputBridgeImpl::SendKeyEvent(ui::KeyEvent* event) { | 
|  | 111   if (keyboard_fd_.get() < 0) { | 
|  | 112     VLOG(2) << "No keyboard bridge device available."; | 
|  | 113     return; | 
|  | 114   } | 
|  | 115 | 
|  | 116   int native_code = ui::KeycodeConverter::DomCodeToNativeKeycode(event->code()); | 
|  | 117 | 
|  | 118   unsigned short evdev_code = ui::NativeCodeToEvdevCode(native_code); | 
|  | 119   int evdev_value; | 
|  | 120   if (event->type() == ui::ET_KEY_PRESSED) { | 
|  | 121     if (event->flags() & ui::EF_IS_REPEAT) { | 
|  | 122       evdev_value = kKeyRepeated; | 
|  | 123     } else { | 
|  | 124       evdev_value = kKeyPressed; | 
|  | 125     } | 
|  | 126   } else if (event->type() == ui::ET_KEY_RELEASED) { | 
|  | 127     evdev_value = kKeyReleased; | 
|  | 128   } | 
|  | 129 | 
|  | 130   base::TimeDelta time_stamp = event->time_stamp(); | 
|  | 131   SendKernelEvent(keyboard_fd_, time_stamp, EV_KEY, evdev_code, evdev_value); | 
|  | 132   SendSynReport(keyboard_fd_, time_stamp); | 
|  | 133 } | 
|  | 134 | 
|  | 135 void ArcInputBridgeImpl::SendTouchEvent(ui::TouchEvent* event) { | 
|  | 136   if (touchscreen_fd_.get() < 0) { | 
|  | 137     VLOG(2) << "No touchscreen bridge device available."; | 
|  | 138     return; | 
|  | 139   } | 
|  | 140 | 
|  | 141   ui::PointerDetails details = event->pointer_details(); | 
|  | 142   base::TimeDelta time_stamp = event->time_stamp(); | 
|  | 143 | 
|  | 144   // find or assing a slot for this tracking id | 
|  | 145   int slot_id = AcquireTouchSlot(event); | 
|  | 146   if (slot_id < 0) { | 
|  | 147     VLOG(1) << "Ran out of slot IDs."; | 
|  | 148     return; | 
|  | 149   } | 
|  | 150 | 
|  | 151   // we only need to send the slot ID when it has changed. | 
|  | 152   if (slot_id != current_slot_) { | 
|  | 153     current_slot_ = slot_id; | 
|  | 154     SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_SLOT, | 
|  | 155                     current_slot_); | 
|  | 156   } | 
|  | 157 | 
|  | 158   // update tracking id | 
|  | 159   if (event->type() == ui::ET_TOUCH_PRESSED) { | 
|  | 160     SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TRACKING_ID, | 
|  | 161                     event->touch_id()); | 
|  | 162   } else if (event->type() == ui::ET_TOUCH_RELEASED) { | 
|  | 163     SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TRACKING_ID, | 
|  | 164                     kEmptySlot); | 
|  | 165   } | 
|  | 166 | 
|  | 167   // update touch information | 
|  | 168   if (event->type() == ui::ET_TOUCH_MOVED || | 
|  | 169       event->type() == ui::ET_TOUCH_PRESSED) { | 
|  | 170     SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_POSITION_X, | 
|  | 171                     event->x()); | 
|  | 172     SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_POSITION_Y, | 
|  | 173                     event->y()); | 
|  | 174     SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TOUCH_MAJOR, | 
|  | 175                     details.radius_x()); | 
|  | 176     SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_TOUCH_MINOR, | 
|  | 177                     details.radius_y()); | 
|  | 178     SendKernelEvent(touchscreen_fd_, time_stamp, EV_ABS, ABS_MT_PRESSURE, | 
|  | 179                     details.force() * kMaxPressure); | 
|  | 180   } | 
|  | 181   SendSynReport(touchscreen_fd_, time_stamp); | 
|  | 182 } | 
|  | 183 | 
|  | 184 void ArcInputBridgeImpl::SendMouseEvent(ui::MouseEvent* event) { | 
|  | 185   if (mouse_fd_.get() < 0) { | 
|  | 186     VLOG(2) << "No mouse bridge device available."; | 
|  | 187     return; | 
|  | 188   } | 
|  | 189 | 
|  | 190   base::TimeDelta time_stamp = event->time_stamp(); | 
|  | 191 | 
|  | 192   // update location | 
|  | 193   if (event->type() == ui::ET_MOUSE_MOVED || | 
|  | 194       event->type() == ui::ET_MOUSE_DRAGGED) { | 
|  | 195     SendKernelEvent(mouse_fd_, time_stamp, EV_ABS, ABS_X, event->x()); | 
|  | 196     SendKernelEvent(mouse_fd_, time_stamp, EV_ABS, ABS_Y, event->y()); | 
|  | 197   } | 
|  | 198 | 
|  | 199   // update buttons | 
|  | 200   if (event->type() == ui::ET_MOUSE_PRESSED || | 
|  | 201       event->type() == ui::ET_MOUSE_RELEASED) { | 
|  | 202     int evdev_value = static_cast<int>(event->type() == ui::ET_MOUSE_PRESSED); | 
|  | 203     for (MouseButtonMapping mapping : kMouseButtonMap) { | 
|  | 204       if (event->changed_button_flags() & mapping.ui_flag) { | 
|  | 205         SendKernelEvent(mouse_fd_, time_stamp, EV_KEY, mapping.evdev_code, | 
|  | 206                         evdev_value); | 
|  | 207       } | 
|  | 208     } | 
|  | 209   } | 
|  | 210 | 
|  | 211   // update scroll wheel | 
|  | 212   if (event->type() == ui::ET_SCROLL) { | 
|  | 213     ui::ScrollEvent* scroll_event = static_cast<ui::ScrollEvent*>(event); | 
|  | 214     // accumulate floating point scroll offset since we can only send full | 
|  | 215     // integer | 
|  | 216     // wheel events. | 
|  | 217     offset_x_acc_ += scroll_event->x_offset_ordinal() / kScrollEmulationSpeed; | 
|  | 218     offset_y_acc_ += scroll_event->y_offset_ordinal() / kScrollEmulationSpeed; | 
|  | 219 | 
|  | 220     int wheel = floor(offset_y_acc_); | 
|  | 221     if (wheel != 0) { | 
|  | 222       SendKernelEvent(mouse_fd_, time_stamp, EV_REL, REL_WHEEL, wheel); | 
|  | 223       offset_y_acc_ -= static_cast<float>(wheel); | 
|  | 224     } | 
|  | 225 | 
|  | 226     int hwheel = floor(offset_x_acc_); | 
|  | 227     if (hwheel != 0) { | 
|  | 228       SendKernelEvent(mouse_fd_, time_stamp, EV_REL, REL_HWHEEL, hwheel); | 
|  | 229       offset_x_acc_ -= static_cast<float>(hwheel); | 
|  | 230     } | 
|  | 231   } | 
|  | 232 | 
|  | 233   SendSynReport(mouse_fd_, time_stamp); | 
|  | 234 } | 
|  | 235 | 
|  | 236 void ArcInputBridgeImpl::SendKernelEvent(const base::ScopedFD& fd, | 
|  | 237                                          base::TimeDelta time_stamp, | 
|  | 238                                          unsigned short type, | 
|  | 239                                          unsigned short code, | 
|  | 240                                          int value) { | 
|  | 241   DCHECK(fd.is_valid()); | 
|  | 242 | 
|  | 243   // Chrome does not always use the monotonic system time for event times. | 
|  | 244   // For now always force the event time to the current system time. | 
|  | 245   // TODO(denniskempin): To enable performance tracing of events we will want | 
|  | 246   // to use the kernel-provided monotonic time stamps of events. | 
|  | 247   time_stamp = ui::EventTimeForNow(); | 
|  | 248 | 
|  | 249   struct input_event event; | 
|  | 250   event.time.tv_sec = time_stamp.InSeconds(); | 
|  | 251   base::TimeDelta remainder = | 
|  | 252       time_stamp - base::TimeDelta::FromSeconds(event.time.tv_sec); | 
|  | 253   event.time.tv_usec = remainder.InMicroseconds(); | 
|  | 254   event.type = type; | 
|  | 255   event.code = code; | 
|  | 256   event.value = value; | 
|  | 257 | 
|  | 258   // Write event to file descriptor | 
|  | 259   size_t num_written = write(fd.get(), reinterpret_cast<void*>(&event), | 
|  | 260                              sizeof(struct input_event)); | 
|  | 261   DCHECK_EQ(num_written, sizeof(struct input_event)); | 
|  | 262 } | 
|  | 263 | 
|  | 264 void ArcInputBridgeImpl::SendSynReport(const base::ScopedFD& fd, | 
|  | 265                                        base::TimeDelta time) { | 
|  | 266   DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | 
|  | 267 | 
|  | 268   SendKernelEvent(fd, time, EV_SYN, SYN_REPORT, 0); | 
|  | 269 } | 
|  | 270 | 
|  | 271 int ArcInputBridgeImpl::AcquireTouchSlot(ui::TouchEvent* event) { | 
|  | 272   int slot_id; | 
|  | 273   if (event->type() == ui::ET_TOUCH_PRESSED) { | 
|  | 274     slot_id = FindTouchSlot(kEmptySlot); | 
|  | 275   } else { | 
|  | 276     slot_id = FindTouchSlot(event->touch_id()); | 
|  | 277   } | 
|  | 278   if (slot_id < 0) { | 
|  | 279     return -1; | 
|  | 280   } | 
|  | 281 | 
|  | 282   if (event->type() == ui::ET_TOUCH_RELEASED) { | 
|  | 283     current_slot_tracking_ids_[slot_id] = kEmptySlot; | 
|  | 284   } else if (event->type() == ui::ET_TOUCH_PRESSED) { | 
|  | 285     current_slot_tracking_ids_[slot_id] = event->touch_id(); | 
|  | 286   } | 
|  | 287   return slot_id; | 
|  | 288 } | 
|  | 289 | 
|  | 290 int ArcInputBridgeImpl::FindTouchSlot(int tracking_id) { | 
|  | 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 ArcInputBridgeImpl::CreateBridgeInputDevice( | 
|  | 300     const std::string& name, | 
|  | 301     const std::string& device_type) { | 
|  | 302   if (!arc_bridge_service_) { | 
|  | 303     VLOG(1) << "ArcBridgeService disappeared."; | 
|  | 304     return base::ScopedFD(); | 
|  | 305   } | 
|  | 306 | 
|  | 307   // Create file descriptor pair for communication | 
|  | 308   int fd[2]; | 
|  | 309   int res = HANDLE_EINTR(pipe(fd)); | 
|  | 310   if (res < 0) { | 
|  | 311     VPLOG(1) << "Cannot create pipe"; | 
|  | 312     return base::ScopedFD(); | 
|  | 313   } | 
|  | 314   base::ScopedFD read_fd(fd[0]); | 
|  | 315   base::ScopedFD write_fd(fd[1]); | 
|  | 316 | 
|  | 317   // The read end is sent to the instance, ownership of fd transfers. | 
|  | 318   if (!arc_bridge_service_->RegisterInputDevice(name, device_type, | 
|  | 319                                                 std::move(read_fd))) { | 
|  | 320     VLOG(1) << "Cannot create bridge input device"; | 
|  | 321     return base::ScopedFD(); | 
|  | 322   } | 
|  | 323 | 
|  | 324   // setup write end as non blocking | 
|  | 325   int flags = HANDLE_EINTR(fcntl(write_fd.get(), F_GETFL, 0)); | 
|  | 326   if (res < 0) { | 
|  | 327     VPLOG(1) << "Cannot get file descriptor flags"; | 
|  | 328     return base::ScopedFD(); | 
|  | 329   } | 
|  | 330 | 
|  | 331   res = HANDLE_EINTR(fcntl(write_fd.get(), F_SETFL, flags | O_NONBLOCK)); | 
|  | 332   if (res < 0) { | 
|  | 333     VPLOG(1) << "Cannot set file descriptor flags"; | 
|  | 334     return base::ScopedFD(); | 
|  | 335   } | 
|  | 336   return std::move(write_fd); | 
|  | 337 } | 
|  | 338 | 
|  | 339 scoped_ptr<ArcInputBridge> ArcInputBridge::Create( | 
|  | 340     ArcBridgeService* arc_bridge_service) { | 
|  | 341   return make_scoped_ptr(new ArcInputBridgeImpl(arc_bridge_service)); | 
|  | 342 } | 
|  | 343 | 
|  | 344 }  // namespace arc | 
| OLD | NEW | 
|---|