Index: ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc |
diff --git a/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc b/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..503155a7c4396e7fb6801b0c4131a3cfd638b25a |
--- /dev/null |
+++ b/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc |
@@ -0,0 +1,266 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.h" |
+ |
+#include <gestures/gestures.h> |
+#include <libevdev/libevdev.h> |
+ |
+#include "base/strings/stringprintf.h" |
+#include "base/timer/timer.h" |
+#include "ui/events/event.h" |
+#include "ui/events/ozone/evdev/cursor_delegate_evdev.h" |
+#include "ui/events/ozone/evdev/event_modifiers_evdev.h" |
+#include "ui/events/ozone/evdev/libgestures_glue/gesture_timer_provider.h" |
+#include "ui/gfx/geometry/point_f.h" |
+ |
+namespace ui { |
+ |
+namespace { |
+ |
+// Convert libevdev device class to libgestures device class. |
+GestureInterpreterDeviceClass GestureDeviceClass(Evdev* evdev) { |
+ switch (evdev->info.evdev_class) { |
+ case EvdevClassMouse: |
+ return GESTURES_DEVCLASS_MOUSE; |
+ case EvdevClassMultitouchMouse: |
+ return GESTURES_DEVCLASS_MULTITOUCH_MOUSE; |
+ case EvdevClassTouchpad: |
+ return GESTURES_DEVCLASS_TOUCHPAD; |
+ case EvdevClassTouchscreen: |
+ return GESTURES_DEVCLASS_TOUCHSCREEN; |
+ default: |
+ return GESTURES_DEVCLASS_UNKNOWN; |
+ } |
+} |
+ |
+// Convert libevdev state to libgestures hardware properties. |
+HardwareProperties GestureHardwareProperties(Evdev* evdev) { |
+ HardwareProperties hwprops; |
+ hwprops.left = Event_Get_Left(evdev); |
+ hwprops.top = Event_Get_Top(evdev); |
+ hwprops.right = Event_Get_Right(evdev); |
+ hwprops.bottom = Event_Get_Bottom(evdev); |
+ hwprops.res_x = Event_Get_Res_X(evdev); |
+ hwprops.res_y = Event_Get_Res_Y(evdev); |
+ hwprops.screen_x_dpi = 133; |
+ hwprops.screen_y_dpi = 133; |
+ hwprops.orientation_minimum = Event_Get_Orientation_Minimum(evdev); |
+ hwprops.orientation_maximum = Event_Get_Orientation_Maximum(evdev); |
+ hwprops.max_finger_cnt = Event_Get_Slot_Count(evdev); |
+ hwprops.max_touch_cnt = Event_Get_Touch_Count_Max(evdev); |
+ hwprops.supports_t5r2 = Event_Get_T5R2(evdev); |
+ hwprops.support_semi_mt = Event_Get_Semi_MT(evdev); |
+ /* buttonpad means a physical button under the touch surface */ |
+ hwprops.is_button_pad = Event_Get_Button_Pad(evdev); |
+ return hwprops; |
+} |
+ |
+// Callback from libgestures when a gesture is ready. |
+void OnGestureReadyHelper(void* client_data, const Gesture* gesture) { |
+ GestureInterpreterLibevdevCros* interpreter = |
+ static_cast<GestureInterpreterLibevdevCros*>(client_data); |
+ interpreter->OnGestureReady(gesture); |
+} |
+ |
+// Convert gestures timestamp (stime_t) to ui::Event timestamp. |
+base::TimeDelta StimeToTimedelta(stime_t timestamp) { |
+ return base::TimeDelta::FromMicroseconds(timestamp * |
+ base::Time::kMicrosecondsPerSecond); |
+} |
+ |
+// Number of fingers for scroll gestures. |
+const int kGestureScrollFingerCount = 2; |
+ |
+} // namespace |
+ |
+GestureInterpreterLibevdevCros::GestureInterpreterLibevdevCros( |
+ EventModifiersEvdev* modifiers, |
+ CursorDelegateEvdev* cursor, |
+ const EventDispatchCallback& callback) |
+ : modifiers_(modifiers), |
+ cursor_(cursor), |
+ dispatch_callback_(callback), |
+ interpreter_(NULL) {} |
+ |
+GestureInterpreterLibevdevCros::~GestureInterpreterLibevdevCros() { |
+ if (interpreter_) { |
+ DeleteGestureInterpreter(interpreter_); |
+ interpreter_ = NULL; |
+ } |
+} |
+ |
+void GestureInterpreterLibevdevCros::OnLibEvdevCrosOpen( |
+ Evdev* evdev, |
+ EventStateRec* evstate) { |
+ CHECK(evdev->info.is_monotonic) << "libevdev must use monotonic timestamps"; |
+ VLOG(9) << "HACK DO NOT REMOVE OR LINK WILL FAIL" << (void*)gestures_log; |
+ |
+ HardwareProperties hwprops = GestureHardwareProperties(evdev); |
+ GestureInterpreterDeviceClass devclass = GestureDeviceClass(evdev); |
+ |
+ // Create & initialize GestureInterpreter. |
+ CHECK(!interpreter_); |
+ interpreter_ = NewGestureInterpreter(); |
+ GestureInterpreterInitialize(interpreter_, devclass); |
+ GestureInterpreterSetHardwareProperties(interpreter_, &hwprops); |
+ GestureInterpreterSetTimerProvider( |
+ interpreter_, |
+ const_cast<GesturesTimerProvider*>(&kGestureTimerProvider), |
+ this); |
+ GestureInterpreterSetCallback(interpreter_, OnGestureReadyHelper, this); |
+} |
+ |
+void GestureInterpreterLibevdevCros::OnLibEvdevCrosEvent(Evdev* evdev, |
+ EventStateRec* evstate, |
+ const timeval& time) { |
+ HardwareState hwstate; |
+ memset(&hwstate, 0, sizeof(hwstate)); |
+ hwstate.timestamp = StimeFromTimeval(&time); |
+ |
+ // Mouse. |
+ hwstate.rel_x = evstate->rel_x; |
+ hwstate.rel_y = evstate->rel_y; |
+ hwstate.rel_wheel = evstate->rel_wheel; |
+ hwstate.rel_hwheel = evstate->rel_hwheel; |
+ |
+ // Touch. |
+ FingerState fingers[Event_Get_Slot_Count(evdev)]; |
+ memset(&fingers, 0, sizeof(fingers)); |
+ int current_finger = 0; |
+ for (int i = 0; i < evstate->slot_count; i++) { |
+ MtSlotPtr slot = &evstate->slots[i]; |
+ if (slot->tracking_id == -1) |
+ continue; |
+ fingers[current_finger].touch_major = slot->touch_major; |
+ fingers[current_finger].touch_minor = slot->touch_minor; |
+ fingers[current_finger].width_major = slot->width_major; |
+ fingers[current_finger].width_minor = slot->width_minor; |
+ fingers[current_finger].pressure = slot->pressure; |
+ fingers[current_finger].orientation = slot->orientation; |
+ fingers[current_finger].position_x = slot->position_x; |
+ fingers[current_finger].position_y = slot->position_y; |
+ fingers[current_finger].tracking_id = slot->tracking_id; |
+ current_finger++; |
+ } |
+ hwstate.touch_cnt = Event_Get_Touch_Count(evdev); |
+ hwstate.finger_cnt = current_finger; |
+ hwstate.fingers = fingers; |
+ |
+ // Buttons. |
+ if (Event_Get_Button_Left(evdev)) |
+ hwstate.buttons_down |= GESTURES_BUTTON_LEFT; |
+ if (Event_Get_Button_Middle(evdev)) |
+ hwstate.buttons_down |= GESTURES_BUTTON_MIDDLE; |
+ if (Event_Get_Button_Right(evdev)) |
+ hwstate.buttons_down |= GESTURES_BUTTON_RIGHT; |
+ |
+ GestureInterpreterPushHardwareState(interpreter_, &hwstate); |
+} |
+ |
+void GestureInterpreterLibevdevCros::OnGestureReady(const Gesture* gesture) { |
+ switch (gesture->type) { |
+ case kGestureTypeMove: |
+ OnGestureMove(gesture, &gesture->details.move); |
+ break; |
+ case kGestureTypeScroll: |
+ OnGestureScroll(gesture, &gesture->details.scroll); |
+ break; |
+ case kGestureTypeButtonsChange: |
+ OnGestureButtonsChange(gesture, &gesture->details.buttons); |
+ break; |
+ case kGestureTypeContactInitiated: |
+ case kGestureTypeFling: |
+ case kGestureTypeSwipe: |
+ case kGestureTypeSwipeLift: |
+ case kGestureTypePinch: |
+ case kGestureTypeMetrics: |
+ // TODO(spang): Support remaining gestures. |
+ NOTIMPLEMENTED(); |
+ break; |
+ default: |
+ LOG(WARNING) << base::StringPrintf("Unrecognized gesture type (%u)", |
+ gesture->type); |
+ break; |
+ } |
+} |
+ |
+void GestureInterpreterLibevdevCros::OnGestureMove(const Gesture* gesture, |
+ const GestureMove* move) { |
+ DVLOG(3) << base::StringPrintf("Gesture Move: (%f, %f) [%f, %f]", |
+ move->dx, |
+ move->dy, |
+ move->ordinal_dx, |
+ move->ordinal_dy); |
+ if (!cursor_) |
+ return; // No cursor! |
+ cursor_->MoveCursor(gfx::Vector2dF(move->dx, move->dy)); |
+ // TODO(spang): Use move->ordinal_dx, move->ordinal_dy |
+ // TODO(spang): Use move->start_time, move->end_time |
+ MouseEvent event(ET_MOUSE_MOVED, |
+ cursor_->location(), |
+ cursor_->location(), |
+ modifiers_->GetModifierFlags(), |
+ /* changed_button_flags */ 0); |
+ Dispatch(&event); |
+} |
+ |
+void GestureInterpreterLibevdevCros::OnGestureScroll( |
+ const Gesture* gesture, |
+ const GestureScroll* scroll) { |
+ DVLOG(3) << base::StringPrintf("Gesture Scroll: (%f, %f) [%f, %f]", |
+ scroll->dx, |
+ scroll->dy, |
+ scroll->ordinal_dx, |
+ scroll->ordinal_dy); |
+ // TODO(spang): Support SetNaturalScroll |
+ // TODO(spang): Use scroll->start_time |
+ ScrollEvent event(ET_SCROLL, |
+ cursor_->location(), |
+ StimeToTimedelta(gesture->end_time), |
+ modifiers_->GetModifierFlags(), |
+ scroll->dx, |
+ scroll->dy, |
+ scroll->ordinal_dx, |
+ scroll->ordinal_dy, |
+ kGestureScrollFingerCount); |
+ Dispatch(&event); |
+} |
+ |
+void GestureInterpreterLibevdevCros::OnGestureButtonsChange( |
+ const Gesture* gesture, |
+ const GestureButtonsChange* buttons) { |
+ DVLOG(3) << base::StringPrintf("Gesture Button Change: down=0x%02x up=0x%02x", |
+ buttons->down, |
+ buttons->up); |
+ // TODO(spang): Use buttons->start_time, buttons->end_time |
+ if (buttons->down & GESTURES_BUTTON_LEFT) |
+ DispatchMouseButton(EVDEV_MODIFIER_LEFT_MOUSE_BUTTON, true); |
+ if (buttons->down & GESTURES_BUTTON_MIDDLE) |
+ DispatchMouseButton(EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON, true); |
+ if (buttons->down & GESTURES_BUTTON_RIGHT) |
+ DispatchMouseButton(EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON, true); |
+ if (buttons->up & GESTURES_BUTTON_LEFT) |
+ DispatchMouseButton(EVDEV_MODIFIER_LEFT_MOUSE_BUTTON, false); |
+ if (buttons->up & GESTURES_BUTTON_MIDDLE) |
+ DispatchMouseButton(EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON, false); |
+ if (buttons->up & GESTURES_BUTTON_RIGHT) |
+ DispatchMouseButton(EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON, false); |
+} |
+ |
+void GestureInterpreterLibevdevCros::Dispatch(Event* event) { |
+ dispatch_callback_.Run(event); |
+} |
+ |
+void GestureInterpreterLibevdevCros::DispatchMouseButton(unsigned int modifier, |
+ bool down) { |
+ const gfx::PointF& loc = cursor_->location(); |
+ int flag = modifiers_->GetEventFlagFromModifier(modifier); |
+ EventType type = (down ? ET_MOUSE_PRESSED : ET_MOUSE_RELEASED); |
+ modifiers_->UpdateModifier(modifier, down); |
+ MouseEvent event(type, loc, loc, modifiers_->GetModifierFlags() | flag, flag); |
+ Dispatch(&event); |
+} |
+ |
+} // namespace ui |