| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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 "ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cr
os.h" | |
| 6 | |
| 7 #include <gestures/gestures.h> | |
| 8 #include <libevdev/libevdev.h> | |
| 9 | |
| 10 #include "base/strings/stringprintf.h" | |
| 11 #include "base/timer/timer.h" | |
| 12 #include "ui/events/event.h" | |
| 13 #include "ui/events/ozone/evdev/cursor_delegate_evdev.h" | |
| 14 #include "ui/events/ozone/evdev/event_device_util.h" | |
| 15 #include "ui/events/ozone/evdev/event_modifiers_evdev.h" | |
| 16 #include "ui/events/ozone/evdev/keyboard_evdev.h" | |
| 17 #include "ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h" | |
| 18 #include "ui/events/ozone/evdev/libgestures_glue/gesture_timer_provider.h" | |
| 19 #include "ui/gfx/geometry/point_f.h" | |
| 20 | |
| 21 namespace ui { | |
| 22 | |
| 23 namespace { | |
| 24 | |
| 25 // Convert libevdev device class to libgestures device class. | |
| 26 GestureInterpreterDeviceClass GestureDeviceClass(Evdev* evdev) { | |
| 27 switch (evdev->info.evdev_class) { | |
| 28 case EvdevClassMouse: | |
| 29 return GESTURES_DEVCLASS_MOUSE; | |
| 30 case EvdevClassMultitouchMouse: | |
| 31 return GESTURES_DEVCLASS_MULTITOUCH_MOUSE; | |
| 32 case EvdevClassTouchpad: | |
| 33 return GESTURES_DEVCLASS_TOUCHPAD; | |
| 34 case EvdevClassTouchscreen: | |
| 35 return GESTURES_DEVCLASS_TOUCHSCREEN; | |
| 36 default: | |
| 37 return GESTURES_DEVCLASS_UNKNOWN; | |
| 38 } | |
| 39 } | |
| 40 | |
| 41 // Convert libevdev state to libgestures hardware properties. | |
| 42 HardwareProperties GestureHardwareProperties( | |
| 43 Evdev* evdev, | |
| 44 const GestureDeviceProperties* props) { | |
| 45 HardwareProperties hwprops; | |
| 46 hwprops.left = props->area_left; | |
| 47 hwprops.top = props->area_top; | |
| 48 hwprops.right = props->area_right; | |
| 49 hwprops.bottom = props->area_bottom; | |
| 50 hwprops.res_x = props->res_x; | |
| 51 hwprops.res_y = props->res_y; | |
| 52 hwprops.screen_x_dpi = 133; | |
| 53 hwprops.screen_y_dpi = 133; | |
| 54 hwprops.orientation_minimum = props->orientation_minimum; | |
| 55 hwprops.orientation_maximum = props->orientation_maximum; | |
| 56 hwprops.max_finger_cnt = Event_Get_Slot_Count(evdev); | |
| 57 hwprops.max_touch_cnt = Event_Get_Touch_Count_Max(evdev); | |
| 58 hwprops.supports_t5r2 = Event_Get_T5R2(evdev); | |
| 59 hwprops.support_semi_mt = Event_Get_Semi_MT(evdev); | |
| 60 /* buttonpad means a physical button under the touch surface */ | |
| 61 hwprops.is_button_pad = Event_Get_Button_Pad(evdev); | |
| 62 return hwprops; | |
| 63 } | |
| 64 | |
| 65 // Callback from libgestures when a gesture is ready. | |
| 66 void OnGestureReadyHelper(void* client_data, const Gesture* gesture) { | |
| 67 GestureInterpreterLibevdevCros* interpreter = | |
| 68 static_cast<GestureInterpreterLibevdevCros*>(client_data); | |
| 69 interpreter->OnGestureReady(gesture); | |
| 70 } | |
| 71 | |
| 72 // Convert gestures timestamp (stime_t) to ui::Event timestamp. | |
| 73 base::TimeDelta StimeToTimedelta(stime_t timestamp) { | |
| 74 return base::TimeDelta::FromMicroseconds(timestamp * | |
| 75 base::Time::kMicrosecondsPerSecond); | |
| 76 } | |
| 77 | |
| 78 // Number of fingers for scroll gestures. | |
| 79 const int kGestureScrollFingerCount = 2; | |
| 80 | |
| 81 // Number of fingers for swipe gestures. | |
| 82 const int kGestureSwipeFingerCount = 3; | |
| 83 | |
| 84 } // namespace | |
| 85 | |
| 86 GestureInterpreterLibevdevCros::GestureInterpreterLibevdevCros( | |
| 87 int id, | |
| 88 EventModifiersEvdev* modifiers, | |
| 89 CursorDelegateEvdev* cursor, | |
| 90 KeyboardEvdev* keyboard, | |
| 91 GesturePropertyProvider* property_provider, | |
| 92 const EventDispatchCallback& callback) | |
| 93 : id_(id), | |
| 94 modifiers_(modifiers), | |
| 95 cursor_(cursor), | |
| 96 keyboard_(keyboard), | |
| 97 property_provider_(property_provider), | |
| 98 dispatch_callback_(callback), | |
| 99 interpreter_(NULL), | |
| 100 evdev_(NULL), | |
| 101 device_properties_(new GestureDeviceProperties) { | |
| 102 memset(&prev_key_state_, 0, sizeof(prev_key_state_)); | |
| 103 } | |
| 104 | |
| 105 GestureInterpreterLibevdevCros::~GestureInterpreterLibevdevCros() { | |
| 106 // Note that this destructor got called after the evdev device node has been | |
| 107 // closed. Therefore, all clean-up codes here shouldn't depend on the device | |
| 108 // information (except for the pointer address itself). | |
| 109 | |
| 110 // Clean-up if the gesture interpreter has been successfully created. | |
| 111 if (interpreter_) { | |
| 112 // Unset callbacks. | |
| 113 GestureInterpreterSetCallback(interpreter_, NULL, NULL); | |
| 114 GestureInterpreterSetPropProvider(interpreter_, NULL, NULL); | |
| 115 GestureInterpreterSetTimerProvider(interpreter_, NULL, NULL); | |
| 116 DeleteGestureInterpreter(interpreter_); | |
| 117 interpreter_ = NULL; | |
| 118 } | |
| 119 | |
| 120 // Unregister device from the gesture property provider. | |
| 121 GesturesPropFunctionsWrapper::UnregisterDevice(this); | |
| 122 } | |
| 123 | |
| 124 void GestureInterpreterLibevdevCros::OnLibEvdevCrosOpen( | |
| 125 Evdev* evdev, | |
| 126 EventStateRec* evstate) { | |
| 127 DCHECK(evdev->info.is_monotonic) << "libevdev must use monotonic timestamps"; | |
| 128 VLOG(9) << "HACK DO NOT REMOVE OR LINK WILL FAIL" << (void*)gestures_log; | |
| 129 | |
| 130 // Set device pointer and initialize properties. | |
| 131 evdev_ = evdev; | |
| 132 GesturesPropFunctionsWrapper::InitializeDeviceProperties( | |
| 133 this, device_properties_.get()); | |
| 134 HardwareProperties hwprops = | |
| 135 GestureHardwareProperties(evdev, device_properties_.get()); | |
| 136 GestureInterpreterDeviceClass devclass = GestureDeviceClass(evdev); | |
| 137 | |
| 138 // Create & initialize GestureInterpreter. | |
| 139 DCHECK(!interpreter_); | |
| 140 interpreter_ = NewGestureInterpreter(); | |
| 141 GestureInterpreterSetPropProvider( | |
| 142 interpreter_, | |
| 143 const_cast<GesturesPropProvider*>(&kGesturePropProvider), | |
| 144 this); | |
| 145 GestureInterpreterInitialize(interpreter_, devclass); | |
| 146 GestureInterpreterSetHardwareProperties(interpreter_, &hwprops); | |
| 147 GestureInterpreterSetTimerProvider( | |
| 148 interpreter_, | |
| 149 const_cast<GesturesTimerProvider*>(&kGestureTimerProvider), | |
| 150 this); | |
| 151 GestureInterpreterSetCallback(interpreter_, OnGestureReadyHelper, this); | |
| 152 } | |
| 153 | |
| 154 void GestureInterpreterLibevdevCros::OnLibEvdevCrosEvent(Evdev* evdev, | |
| 155 EventStateRec* evstate, | |
| 156 const timeval& time) { | |
| 157 // If the device has keys no it, dispatch any presses/release. | |
| 158 DispatchChangedKeys(evdev, time); | |
| 159 | |
| 160 HardwareState hwstate; | |
| 161 memset(&hwstate, 0, sizeof(hwstate)); | |
| 162 hwstate.timestamp = StimeFromTimeval(&time); | |
| 163 | |
| 164 // Mouse. | |
| 165 hwstate.rel_x = evstate->rel_x; | |
| 166 hwstate.rel_y = evstate->rel_y; | |
| 167 hwstate.rel_wheel = evstate->rel_wheel; | |
| 168 hwstate.rel_hwheel = evstate->rel_hwheel; | |
| 169 | |
| 170 // Touch. | |
| 171 FingerState fingers[Event_Get_Slot_Count(evdev)]; | |
| 172 memset(&fingers, 0, sizeof(fingers)); | |
| 173 int current_finger = 0; | |
| 174 for (int i = 0; i < evstate->slot_count; i++) { | |
| 175 MtSlotPtr slot = &evstate->slots[i]; | |
| 176 if (slot->tracking_id == -1) | |
| 177 continue; | |
| 178 fingers[current_finger].touch_major = slot->touch_major; | |
| 179 fingers[current_finger].touch_minor = slot->touch_minor; | |
| 180 fingers[current_finger].width_major = slot->width_major; | |
| 181 fingers[current_finger].width_minor = slot->width_minor; | |
| 182 fingers[current_finger].pressure = slot->pressure; | |
| 183 fingers[current_finger].orientation = slot->orientation; | |
| 184 fingers[current_finger].position_x = slot->position_x; | |
| 185 fingers[current_finger].position_y = slot->position_y; | |
| 186 fingers[current_finger].tracking_id = slot->tracking_id; | |
| 187 current_finger++; | |
| 188 } | |
| 189 hwstate.touch_cnt = Event_Get_Touch_Count(evdev); | |
| 190 hwstate.finger_cnt = current_finger; | |
| 191 hwstate.fingers = fingers; | |
| 192 | |
| 193 // Buttons. | |
| 194 if (Event_Get_Button_Left(evdev)) | |
| 195 hwstate.buttons_down |= GESTURES_BUTTON_LEFT; | |
| 196 if (Event_Get_Button_Middle(evdev)) | |
| 197 hwstate.buttons_down |= GESTURES_BUTTON_MIDDLE; | |
| 198 if (Event_Get_Button_Right(evdev)) | |
| 199 hwstate.buttons_down |= GESTURES_BUTTON_RIGHT; | |
| 200 | |
| 201 GestureInterpreterPushHardwareState(interpreter_, &hwstate); | |
| 202 } | |
| 203 | |
| 204 void GestureInterpreterLibevdevCros::OnGestureReady(const Gesture* gesture) { | |
| 205 switch (gesture->type) { | |
| 206 case kGestureTypeMove: | |
| 207 OnGestureMove(gesture, &gesture->details.move); | |
| 208 break; | |
| 209 case kGestureTypeScroll: | |
| 210 OnGestureScroll(gesture, &gesture->details.scroll); | |
| 211 break; | |
| 212 case kGestureTypeButtonsChange: | |
| 213 OnGestureButtonsChange(gesture, &gesture->details.buttons); | |
| 214 break; | |
| 215 case kGestureTypeContactInitiated: | |
| 216 OnGestureContactInitiated(gesture); | |
| 217 break; | |
| 218 case kGestureTypeFling: | |
| 219 OnGestureFling(gesture, &gesture->details.fling); | |
| 220 break; | |
| 221 case kGestureTypeSwipe: | |
| 222 OnGestureSwipe(gesture, &gesture->details.swipe); | |
| 223 break; | |
| 224 case kGestureTypeSwipeLift: | |
| 225 OnGestureSwipeLift(gesture, &gesture->details.swipe_lift); | |
| 226 break; | |
| 227 case kGestureTypePinch: | |
| 228 OnGesturePinch(gesture, &gesture->details.pinch); | |
| 229 break; | |
| 230 case kGestureTypeMetrics: | |
| 231 OnGestureMetrics(gesture, &gesture->details.metrics); | |
| 232 break; | |
| 233 default: | |
| 234 LOG(WARNING) << base::StringPrintf("Unrecognized gesture type (%u)", | |
| 235 gesture->type); | |
| 236 break; | |
| 237 } | |
| 238 } | |
| 239 | |
| 240 void GestureInterpreterLibevdevCros::OnGestureMove(const Gesture* gesture, | |
| 241 const GestureMove* move) { | |
| 242 DVLOG(3) << base::StringPrintf("Gesture Move: (%f, %f) [%f, %f]", | |
| 243 move->dx, | |
| 244 move->dy, | |
| 245 move->ordinal_dx, | |
| 246 move->ordinal_dy); | |
| 247 if (!cursor_) | |
| 248 return; // No cursor! | |
| 249 | |
| 250 cursor_->MoveCursor(gfx::Vector2dF(move->dx, move->dy)); | |
| 251 // TODO(spang): Use move->ordinal_dx, move->ordinal_dy | |
| 252 // TODO(spang): Use move->start_time, move->end_time | |
| 253 Dispatch(make_scoped_ptr(new MouseEvent(ET_MOUSE_MOVED, | |
| 254 cursor_->location(), | |
| 255 cursor_->location(), | |
| 256 modifiers_->GetModifierFlags(), | |
| 257 /* changed_button_flags */ 0))); | |
| 258 } | |
| 259 | |
| 260 void GestureInterpreterLibevdevCros::OnGestureScroll( | |
| 261 const Gesture* gesture, | |
| 262 const GestureScroll* scroll) { | |
| 263 DVLOG(3) << base::StringPrintf("Gesture Scroll: (%f, %f) [%f, %f]", | |
| 264 scroll->dx, | |
| 265 scroll->dy, | |
| 266 scroll->ordinal_dx, | |
| 267 scroll->ordinal_dy); | |
| 268 if (!cursor_) | |
| 269 return; // No cursor! | |
| 270 | |
| 271 // TODO(spang): Support SetNaturalScroll | |
| 272 // TODO(spang): Use scroll->start_time | |
| 273 Dispatch(make_scoped_ptr(new ScrollEvent(ET_SCROLL, | |
| 274 cursor_->location(), | |
| 275 StimeToTimedelta(gesture->end_time), | |
| 276 modifiers_->GetModifierFlags(), | |
| 277 scroll->dx, | |
| 278 scroll->dy, | |
| 279 scroll->ordinal_dx, | |
| 280 scroll->ordinal_dy, | |
| 281 kGestureScrollFingerCount))); | |
| 282 } | |
| 283 | |
| 284 void GestureInterpreterLibevdevCros::OnGestureButtonsChange( | |
| 285 const Gesture* gesture, | |
| 286 const GestureButtonsChange* buttons) { | |
| 287 DVLOG(3) << base::StringPrintf("Gesture Button Change: down=0x%02x up=0x%02x", | |
| 288 buttons->down, | |
| 289 buttons->up); | |
| 290 | |
| 291 if (!cursor_) | |
| 292 return; // No cursor! | |
| 293 | |
| 294 // HACK for disabling TTC (actually, all clicks) on hidden cursor. | |
| 295 // This is normally plumbed via properties and can be removed soon. | |
| 296 // TODO(spang): Remove this. | |
| 297 if (buttons->down == GESTURES_BUTTON_LEFT && | |
| 298 buttons->up == GESTURES_BUTTON_LEFT && | |
| 299 !cursor_->IsCursorVisible()) | |
| 300 return; | |
| 301 | |
| 302 // TODO(spang): Use buttons->start_time, buttons->end_time | |
| 303 if (buttons->down & GESTURES_BUTTON_LEFT) | |
| 304 DispatchMouseButton(EVDEV_MODIFIER_LEFT_MOUSE_BUTTON, true); | |
| 305 if (buttons->down & GESTURES_BUTTON_MIDDLE) | |
| 306 DispatchMouseButton(EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON, true); | |
| 307 if (buttons->down & GESTURES_BUTTON_RIGHT) | |
| 308 DispatchMouseButton(EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON, true); | |
| 309 if (buttons->up & GESTURES_BUTTON_LEFT) | |
| 310 DispatchMouseButton(EVDEV_MODIFIER_LEFT_MOUSE_BUTTON, false); | |
| 311 if (buttons->up & GESTURES_BUTTON_MIDDLE) | |
| 312 DispatchMouseButton(EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON, false); | |
| 313 if (buttons->up & GESTURES_BUTTON_RIGHT) | |
| 314 DispatchMouseButton(EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON, false); | |
| 315 } | |
| 316 | |
| 317 void GestureInterpreterLibevdevCros::OnGestureContactInitiated( | |
| 318 const Gesture* gesture) { | |
| 319 // TODO(spang): handle contact initiated. | |
| 320 } | |
| 321 | |
| 322 void GestureInterpreterLibevdevCros::OnGestureFling(const Gesture* gesture, | |
| 323 const GestureFling* fling) { | |
| 324 DVLOG(3) << base::StringPrintf( | |
| 325 "Gesture Fling: (%f, %f) [%f, %f] fling_state=%d", | |
| 326 fling->vx, | |
| 327 fling->vy, | |
| 328 fling->ordinal_vx, | |
| 329 fling->ordinal_vy, | |
| 330 fling->fling_state); | |
| 331 | |
| 332 if (!cursor_) | |
| 333 return; // No cursor! | |
| 334 | |
| 335 EventType type = | |
| 336 (fling->fling_state == GESTURES_FLING_START ? ET_SCROLL_FLING_START | |
| 337 : ET_SCROLL_FLING_CANCEL); | |
| 338 | |
| 339 // Fling is like 2-finger scrolling but with velocity instead of displacement. | |
| 340 Dispatch(make_scoped_ptr(new ScrollEvent(type, | |
| 341 cursor_->location(), | |
| 342 StimeToTimedelta(gesture->end_time), | |
| 343 modifiers_->GetModifierFlags(), | |
| 344 fling->vx, | |
| 345 fling->vy, | |
| 346 fling->ordinal_vx, | |
| 347 fling->ordinal_vy, | |
| 348 kGestureScrollFingerCount))); | |
| 349 } | |
| 350 | |
| 351 void GestureInterpreterLibevdevCros::OnGestureSwipe(const Gesture* gesture, | |
| 352 const GestureSwipe* swipe) { | |
| 353 DVLOG(3) << base::StringPrintf("Gesture Swipe: (%f, %f) [%f, %f]", | |
| 354 swipe->dx, | |
| 355 swipe->dy, | |
| 356 swipe->ordinal_dx, | |
| 357 swipe->ordinal_dy); | |
| 358 | |
| 359 if (!cursor_) | |
| 360 return; // No cursor! | |
| 361 | |
| 362 // Swipe is 3-finger scrolling. | |
| 363 Dispatch(make_scoped_ptr(new ScrollEvent(ET_SCROLL, | |
| 364 cursor_->location(), | |
| 365 StimeToTimedelta(gesture->end_time), | |
| 366 modifiers_->GetModifierFlags(), | |
| 367 swipe->dx, | |
| 368 swipe->dy, | |
| 369 swipe->ordinal_dx, | |
| 370 swipe->ordinal_dy, | |
| 371 kGestureSwipeFingerCount))); | |
| 372 } | |
| 373 | |
| 374 void GestureInterpreterLibevdevCros::OnGestureSwipeLift( | |
| 375 const Gesture* gesture, | |
| 376 const GestureSwipeLift* swipelift) { | |
| 377 DVLOG(3) << base::StringPrintf("Gesture Swipe Lift"); | |
| 378 | |
| 379 if (!cursor_) | |
| 380 return; // No cursor! | |
| 381 | |
| 382 // Turn a swipe lift into a fling start. | |
| 383 // TODO(spang): Figure out why and put it in this comment. | |
| 384 | |
| 385 Dispatch(make_scoped_ptr(new ScrollEvent(ET_SCROLL_FLING_START, | |
| 386 cursor_->location(), | |
| 387 StimeToTimedelta(gesture->end_time), | |
| 388 modifiers_->GetModifierFlags(), | |
| 389 /* x_offset */ 0, | |
| 390 /* y_offset */ 0, | |
| 391 /* x_offset_ordinal */ 0, | |
| 392 /* y_offset_ordinal */ 0, | |
| 393 kGestureScrollFingerCount))); | |
| 394 } | |
| 395 | |
| 396 void GestureInterpreterLibevdevCros::OnGesturePinch(const Gesture* gesture, | |
| 397 const GesturePinch* pinch) { | |
| 398 DVLOG(3) << base::StringPrintf( | |
| 399 "Gesture Pinch: dz=%f [%f]", pinch->dz, pinch->ordinal_dz); | |
| 400 | |
| 401 if (!cursor_) | |
| 402 return; // No cursor! | |
| 403 | |
| 404 NOTIMPLEMENTED(); | |
| 405 } | |
| 406 | |
| 407 void GestureInterpreterLibevdevCros::OnGestureMetrics( | |
| 408 const Gesture* gesture, | |
| 409 const GestureMetrics* metrics) { | |
| 410 DVLOG(3) << base::StringPrintf("Gesture Metrics: [%f, %f] type=%d", | |
| 411 metrics->data[0], | |
| 412 metrics->data[1], | |
| 413 metrics->type); | |
| 414 NOTIMPLEMENTED(); | |
| 415 } | |
| 416 | |
| 417 void GestureInterpreterLibevdevCros::Dispatch(scoped_ptr<Event> event) { | |
| 418 dispatch_callback_.Run(event.Pass()); | |
| 419 } | |
| 420 | |
| 421 void GestureInterpreterLibevdevCros::DispatchMouseButton(unsigned int modifier, | |
| 422 bool down) { | |
| 423 const gfx::PointF& loc = cursor_->location(); | |
| 424 int flag = modifiers_->GetEventFlagFromModifier(modifier); | |
| 425 EventType type = (down ? ET_MOUSE_PRESSED : ET_MOUSE_RELEASED); | |
| 426 modifiers_->UpdateModifier(modifier, down); | |
| 427 Dispatch(make_scoped_ptr(new MouseEvent( | |
| 428 type, loc, loc, modifiers_->GetModifierFlags() | flag, flag))); | |
| 429 } | |
| 430 | |
| 431 void GestureInterpreterLibevdevCros::DispatchChangedKeys(Evdev* evdev, | |
| 432 const timeval& time) { | |
| 433 unsigned long key_state_diff[EVDEV_BITS_TO_LONGS(KEY_CNT)]; | |
| 434 | |
| 435 // Find changed keys. | |
| 436 for (unsigned long i = 0; i < arraysize(key_state_diff); ++i) | |
| 437 key_state_diff[i] = evdev->key_state_bitmask[i] ^ prev_key_state_[i]; | |
| 438 | |
| 439 // Dispatch events for changed keys. | |
| 440 for (unsigned long i = 0; i < KEY_CNT; ++i) { | |
| 441 if (EvdevBitIsSet(key_state_diff, i)) { | |
| 442 bool value = EvdevBitIsSet(evdev->key_state_bitmask, i); | |
| 443 keyboard_->OnKeyChange(i, value); | |
| 444 } | |
| 445 } | |
| 446 | |
| 447 // Update internal key state. | |
| 448 for (unsigned long i = 0; i < EVDEV_BITS_TO_LONGS(KEY_CNT); ++i) | |
| 449 prev_key_state_[i] = evdev->key_state_bitmask[i]; | |
| 450 } | |
| 451 | |
| 452 } // namespace ui | |
| OLD | NEW |