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