summaryrefslogtreecommitdiff
path: root/include/gestures.h
blob: f21d531b6ea31e3d8f46c1721adfdb6d5ae60ecc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
// Copyright 2012 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef GESTURES_GESTURES_H__
#define GESTURES_GESTURES_H__

#include <stdint.h>
#include <sys/time.h>
#include <sys/types.h>

#ifdef __cplusplus
#include <string>

#include <memory>

extern "C" {
#endif

// C API:

// external logging interface
#define GESTURES_LOG_ERROR 0
#define GESTURES_LOG_INFO 1

// this function has to be provided by the user of the library.
void gestures_log(int verb, const char* format, ...)
    __attribute__((format(printf, 2, 3)));

typedef double stime_t;  // seconds

// Represents "unset" when stime_t is used for timeouts or deadlines.
#define NO_DEADLINE -1.0

enum GestureInterpreterDeviceClass {
  GESTURES_DEVCLASS_UNKNOWN,
  GESTURES_DEVCLASS_MOUSE,
  GESTURES_DEVCLASS_MULTITOUCH_MOUSE,
  GESTURES_DEVCLASS_TOUCHPAD,
  GESTURES_DEVCLASS_TOUCHSCREEN,
  GESTURES_DEVCLASS_POINTING_STICK,
};

stime_t StimeFromTimeval(const struct timeval*);
stime_t StimeFromTimespec(const struct timespec*);

// Describes the capabilities of a touchpad or mouse.
struct HardwareProperties {
  // Touch properties
  // The minimum X coordinate that the device can report.
  float left;
  // The minimum Y coordinate that the device can report.
  float top;
  // The maximum X coordinate that the device can report.
  float right;
  // The maximum Y coordinate that the device can report.
  float bottom;
  // The resolutions of the X and Y axes, in units per mm. Set to 0 if the
  // resolution is unknown.
  float res_x;
  float res_y;

  // Deprecated: these values are now ignored. Previously, they specified the
  // DPI of the screen to which gestures output by the library should be
  // scaled.
  float screen_x_dpi;
  float screen_y_dpi;

  // The minimum and maximum orientation values.
  float orientation_minimum;
  float orientation_maximum;

  // The maximum number of finger slots that the device can report in one
  // HardwareState struct.
  unsigned short max_finger_cnt;
  // The maximum number of contacts that the device can detect at once, whether
  // or not it can report their coordinates.
  unsigned short max_touch_cnt;

  // Whether this is a "Track 5, Report 2" touchpad, which can track up to five
  // fingers but only report the locations of two. (For more details, see
  // https://crrev.com/37cccb42e652b50f9e788d90e82252f78c78f1ed)
  unsigned supports_t5r2:1;

  // Whether this is a "Semi-Multitouch" touchpad, which can detect two separate
  // fingers but only report their bounding box, not individual locations.
  unsigned support_semi_mt:1;

  // Whether the touchpad has a button under its touch surface, allowing the
  // user to click by pressing (almost) anywhere on the pad, as opposed to
  // having one or more separate buttons for clicking.
  unsigned is_button_pad:1;

  // Mouse properties
  // Whether the mouse has a scroll wheel.
  unsigned has_wheel:1;
  // Whether the mouse's scroll wheel is high-resolution (reported through the
  // rel_wheel_hi_res field of the HardwareState struct).
  unsigned wheel_is_hi_res:1;

  // Whether the touchpad is haptic, meaning that it reports true pressure (not
  // just touch area) via the pressure axis, and can provide haptic feedback.
  unsigned is_haptic_pad:1;
#ifdef __cplusplus
  std::string String() const;
#endif  // __cplusplus
};

// position is the (x,y) cartesian coord of the finger on the trackpad.
// touch_major/minor are the large/small radii of the ellipse of the touching
// finger. width_major/minor are also radii, but of the finger itself,
// including a little bit that isn't touching. So, width* is generally a tad
// larger than touch*.
// tracking_id: If a finger is the same physical finger across two
// consecutive frames, it must have the same tracking id; if it's a different
// finger, it may (should) have a different tracking id.

// Warp: If a finger has the 'warp' flag set for an axis, it means that while
// the finger may have moved, it should not cause any motion in that direction.
// This may occur is some situations where we thought a finger was in one place,
// but then we realized later it was actually in another place.
// The *_WARP_X/Y_MOVE version is an indication for suppressing unwanted
// cursor movement, while the *_WARP_X/Y_NON_MOVE version is for unwanted
// non-cursor movement (e.g. scrolling)
#define GESTURES_FINGER_WARP_X_NON_MOVE        (1 << 0)
#define GESTURES_FINGER_WARP_Y_NON_MOVE        (1 << 1)
// If a finger has notap set, it shouldn't begin a tap gesture.
#define GESTURES_FINGER_NO_TAP        (1 << 2)
#define GESTURES_FINGER_POSSIBLE_PALM (1 << 3)
#define GESTURES_FINGER_PALM          (1 << 4)
#define GESTURES_FINGER_WARP_X_MOVE   (1 << 5)
#define GESTURES_FINGER_WARP_Y_MOVE   (1 << 6)
// If tap to click movement detection should warp:
#define GESTURES_FINGER_WARP_X_TAP_MOVE   (1 << 7)
#define GESTURES_FINGER_WARP_Y_TAP_MOVE   (1 << 8)
// If a finger is a merged finger or one of close fingers
#define GESTURES_FINGER_MERGE   (1 << 9)
// If a finger is showing a trend of moving (see the TrendClassifyingFilter).
#define GESTURES_FINGER_TREND_INC_X (1 << 10)
#define GESTURES_FINGER_TREND_DEC_X (1 << 11)
#define GESTURES_FINGER_TREND_INC_Y (1 << 12)
#define GESTURES_FINGER_TREND_DEC_Y (1 << 13)
#define GESTURES_FINGER_TREND_INC_PRESSURE (1 << 14)
#define GESTURES_FINGER_TREND_DEC_PRESSURE (1 << 15)
#define GESTURES_FINGER_TREND_INC_TOUCH_MAJOR (1 << 16)
#define GESTURES_FINGER_TREND_DEC_TOUCH_MAJOR (1 << 17)
// If a finger is non-stationary recently (see the StationaryWiggleFilter).
// Compared to the trend flags, this one takes the magnitude of movements
// into account so it might be more useful in some cases. However, it is also
// more prone to abrupt noisy jumps than the trend flags. It also looks at
// a shorter period of time than the trend ones so it may provide faster
// response and lower latency.
#define GESTURES_FINGER_INSTANTANEOUS_MOVING (1 << 18)
// We sometimes use the warp flags only because we want to suppress unwanted
// movements and not that we really have no good idea of the finger position.
// This poses additional difficulty for some classifying logics that relies
// much on the finger position. To maximize the use of any available data,
// we further mark a finger as GESTURES_FINGER_WARP_TELEPORTATION only if we
// indeed have no idea of its position (e.g. due to sensor jumps). For all
// other cases (e.g. click wiggle, plams suppression, stationary wiggle), we
// skip the flag so that we can have the option to use the not-that-accurate
// positions.
#define GESTURES_FINGER_WARP_TELEPORTATION (1 << 19)
#define GESTURES_FINGER_LARGE_PALM (1 << 20)

#define GESTURES_FINGER_WARP_X    (GESTURES_FINGER_WARP_X_NON_MOVE | \
                                   GESTURES_FINGER_WARP_X_MOVE)
#define GESTURES_FINGER_WARP_Y    (GESTURES_FINGER_WARP_Y_NON_MOVE | \
                                   GESTURES_FINGER_WARP_Y_MOVE)

// Describes a single contact on a touch surface. Unless otherwise noted, the
// fields have the same meaning as the equivalent ABS_MT_... axis in the Linux
// evdev protocol.
struct FingerState {
  float touch_major, touch_minor;
  float width_major, width_minor;
  float pressure;
  float orientation;
  float position_x;
  float position_y;
  short tracking_id;

  // A bit field of flags that are used internally by the library. (See the
  // GESTURES_FINGER_* constants.) Should be set to 0 on incoming FingerStates.
  unsigned flags;
#ifdef __cplusplus
  bool NonFlagsEquals(const FingerState& that) const {
    return touch_major == that.touch_major &&
        touch_minor == that.touch_minor &&
        width_major == that.width_major &&
        width_minor == that.width_minor &&
        pressure == that.pressure &&
        orientation == that.orientation &&
        position_x == that.position_x &&
        position_y == that.position_y &&
        tracking_id == that.tracking_id;
  }
  bool operator==(const FingerState& that) const {
    return NonFlagsEquals(that) && flags == that.flags;
  }
  bool operator!=(const FingerState& that) const { return !(*this == that); }
  static std::string FlagsString(unsigned flags);
  std::string String() const;
#endif
};

#define GESTURES_BUTTON_NONE 0
#define GESTURES_BUTTON_LEFT 1
#define GESTURES_BUTTON_MIDDLE 2
#define GESTURES_BUTTON_RIGHT 4
#define GESTURES_BUTTON_BACK 8
#define GESTURES_BUTTON_FORWARD 16

// Describes one frame of data from the input device.
struct HardwareState {
#ifdef __cplusplus
  FingerState* GetFingerState(short tracking_id);
  const FingerState* GetFingerState(short tracking_id) const;
  bool SameFingersAs(const HardwareState& that) const;
  std::string String() const;
  void DeepCopy(const HardwareState& that, unsigned short max_finger_cnt);
#endif  // __cplusplus
  // The time at which the event was received by the system.
  stime_t timestamp;
  // A bit field indicating which buttons are pressed. (See the
  // GESTURES_BUTTON_* constants.)
  int buttons_down;
  // The number of FingerState structs pointed to by the fingers field.
  unsigned short finger_cnt;
  // The number of fingers touching the pad, which may be more than finger_cnt.
  unsigned short touch_cnt;
  // A pointer to finger_cnt FingerState structs representing the contacts
  // currently being tracked.
  struct FingerState* fingers;

  // Mouse axes, which have the same meanings as the Linux evdev axes of the
  // same name.
  float rel_x;
  float rel_y;
  float rel_wheel;
  float rel_wheel_hi_res;
  float rel_hwheel;

  // The timestamp for the frame, as reported by the device's firmware. This may
  // be different from the timestamp field above, for example if events were
  // batched when being sent over Bluetooth. Set to 0.0 if no such timestamp is
  // available. (Named after the MSC_TIMESTAMP axis from evdev.)
  stime_t msc_timestamp;
};

#define GESTURES_FLING_START 0  // Scroll end/fling begin
#define GESTURES_FLING_TAP_DOWN 1  // Finger touched down/fling end

#define GESTURES_ZOOM_START 0  // Pinch zoom begin
#define GESTURES_ZOOM_UPDATE 1  // Zoom-in/Zoom-out update
#define GESTURES_ZOOM_END 2  // Pinch zoom end

// Gesture sub-structs

// Note about ordinal_* values: Sometimes, UI will want to use unaccelerated
// values for various gestures, so we expose the non-accelerated values in
// the ordinal_* fields.

typedef struct {
  // The movement in the X axis. Positive values indicate motion to the right.
  float dx;
  // The movement in the Y axis. Positive values indicate downwards motion.
  float dy;
  float ordinal_dx, ordinal_dy;
} GestureMove;

// Represents scroll gestures on a touch device.
typedef struct{
  // The scroll movement in the X axis. Unlike with move gestures, *negative*
  // values indicate the fingers moving to the right, unless the "Australian
  // Scrolling" or "Invert Scrolling" properties are set.
  float dx;
  // The scroll movement in the Y axis. Unlike with move gestures, *negative*
  // values indicate the fingers moving downwards, unless the "Australian
  // Scrolling" or "Invert Scrolling" properties are set.
  float dy;
  float ordinal_dx, ordinal_dy;
  // If set, stop_fling means that this scroll should stop flinging, thus
  // if an interpreter suppresses it for any reason (e.g., rounds the size
  // down to 0, thus making it a noop), it will replace it with a Fling
  // TAP_DOWN gesture
  unsigned stop_fling:1;
} GestureScroll;

// Represents mouse wheel movements.
typedef struct {
  // The amount to scroll by, after acceleration and scaling have been applied.
  float dx, dy;
  // The amount the wheel actually moved. A change of 120 represents moving the
  // wheel one whole tick (a.k.a. notch).
  int tick_120ths_dx, tick_120ths_dy;
} GestureMouseWheel;

typedef struct {
  // If a bit is set in both down and up, client should process down first
  unsigned down;  // bit field, use GESTURES_BUTTON_*
  unsigned up;  // bit field, use GESTURES_BUTTON_*
  bool is_tap; // was the gesture generated with tap-to-click?
} GestureButtonsChange;

typedef struct {
  // The fling velocity in the X axis, only valid when fling_state is
  // GESTURES_FLING_START. Unlike with move gestures, *negative* values indicate
  // the fingers moving to the right, unless the "Australian Scrolling" or
  // "Invert Scrolling" properties are set.
  float vx;
  // The fling velocity in the Y axis, only valid when fling_state is
  // GESTURES_FLING_START. Unlike with move gestures, *negative* values indicate
  // the fingers moving downwards, unless the "Australian Scrolling" or "Invert
  // Scrolling" properties are set.
  float vy;
  float ordinal_vx, ordinal_vy;
  unsigned fling_state:1;  // GESTURES_FLING_START or GESTURES_FLING_TAP_DOWN
} GestureFling;

typedef struct {
  // The swipe movement in the X axis. Positive values indicate motion to the
  // right.
  float dx;
  // The swipe movement in the Y axis. Unlike with move gestures, *negative*
  // values indicate downwards motion, unless the "Australian Scrolling"
  // property is set.
  float dy;
  float ordinal_dx, ordinal_dy;
} GestureSwipe;

typedef struct {
  // The swipe movement in the X axis. Positive values indicate motion to the
  // right.
  float dx;
  // The swipe movement in the Y axis. Unlike with move gestures, *negative*
  // values indicate downwards motion, unless the "Australian Scrolling"
  // property is set.
  float dy;
  float ordinal_dx, ordinal_dy;
} GestureFourFingerSwipe;

typedef struct {
  char __dummy;
  // Remove this when there is a member in this struct. http://crbug.com/341155
  // Currently no members
} GestureFourFingerSwipeLift;

typedef struct {
  char __dummy;
  // Remove this when there is a member in this struct. http://crbug.com/341155
  // Currently no members
} GestureSwipeLift;

typedef struct {
  // Relative pinch factor starting with 1.0 = no pinch
  // <1.0 for outwards pinch
  // >1.0 for inwards pinch
  float dz;
  float ordinal_dz;
  // GESTURES_ZOOM_START, GESTURES_ZOOM_UPDATE, or GESTURES_ZOOM_END
  unsigned zoom_state;
} GesturePinch;

// Metrics types that we care about
enum GestureMetricsType {
  kGestureMetricsTypeNoisyGround = 0,
  kGestureMetricsTypeMouseMovement,
  kGestureMetricsTypeUnknown,
};

typedef struct {
  enum GestureMetricsType type;
  // Optional values for the metrics. 2 are more than enough for now.
  float data[2];
} GestureMetrics;

// Describes the type of gesture that is being reported.
enum GestureType {
#ifdef GESTURES_INTERNAL
  kGestureTypeNull = -1,  // internal to Gestures library only
#endif  // GESTURES_INTERNAL
  // No longer used.
  kGestureTypeContactInitiated = 0,
  // For touchpads, a movement of a single finger on the pad. For mice, a
  // movement of the whole mouse.
  kGestureTypeMove,
  // A two-finger scroll gesture on a touchpad. (See kGestureTypeMouseWheel for
  // the mouse equivalent.)
  kGestureTypeScroll,
  // A change in the buttons that are currently pressed on the device.
  kGestureTypeButtonsChange,
  // The start or end of a fling motion, where scrolling should continue after
  // the user's fingers have left the touchpad.
  kGestureTypeFling,
  // A movement of three fingers on a touchpad.
  kGestureTypeSwipe,
  // A movement of two fingers on a touchpad that are primarily moving closer to
  // or further from each other.
  kGestureTypePinch,
  // The end of a movement of three fingers on a touchpad.
  kGestureTypeSwipeLift,
  // Used to report metrics to the client.
  kGestureTypeMetrics,
  // A movement of four fingers on a touchpad.
  kGestureTypeFourFingerSwipe,
  // The end of a movement of four fingers on a touchpad.
  kGestureTypeFourFingerSwipeLift,
  // The movement of a scroll wheel on a mouse.
  kGestureTypeMouseWheel,
};

#ifdef __cplusplus
// Pass these into Gesture() ctor as first arg
extern const GestureMove kGestureMove;
extern const GestureScroll kGestureScroll;
extern const GestureMouseWheel kGestureMouseWheel;
extern const GestureButtonsChange kGestureButtonsChange;
extern const GestureFling kGestureFling;
extern const GestureSwipe kGestureSwipe;
extern const GestureFourFingerSwipe kGestureFourFingerSwipe;
extern const GesturePinch kGesturePinch;
extern const GestureSwipeLift kGestureSwipeLift;
extern const GestureFourFingerSwipeLift kGestureFourFingerSwipeLift;
extern const GestureMetrics kGestureMetrics;
#endif  // __cplusplus

struct Gesture {
#ifdef __cplusplus
  // Create Move/Scroll gesture
#ifdef GESTURES_INTERNAL
  Gesture() : start_time(0), end_time(0), type(kGestureTypeNull) {}
  bool operator==(const Gesture& that) const;
  bool operator!=(const Gesture& that) const { return !(*this == that); };
#endif  // GESTURES_INTERNAL
  std::string String() const;
  Gesture(const GestureMove&, stime_t start, stime_t end, float dx, float dy)
      : start_time(start), end_time(end), type(kGestureTypeMove) {
    details.move.ordinal_dx = details.move.dx = dx;
    details.move.ordinal_dy = details.move.dy = dy;
  }
  Gesture(const GestureScroll&,
          stime_t start, stime_t end, float dx, float dy)
      : start_time(start), end_time(end), type(kGestureTypeScroll) {
    details.scroll.ordinal_dx = details.scroll.dx = dx;
    details.scroll.ordinal_dy = details.scroll.dy = dy;
    details.scroll.stop_fling = 0;
  }
  Gesture(const GestureMouseWheel&,
          stime_t start, stime_t end, float dx, float dy, int tick_120ths_dx,
          int tick_120ths_dy)
      : start_time(start), end_time(end), type(kGestureTypeMouseWheel) {
    details.wheel.dx = dx;
    details.wheel.dy = dy;
    details.wheel.tick_120ths_dx = tick_120ths_dx;
    details.wheel.tick_120ths_dy = tick_120ths_dy;
  }
  Gesture(const GestureButtonsChange&,
          stime_t start, stime_t end, unsigned down, unsigned up, bool is_tap)
      : start_time(start),
        end_time(end),
        type(kGestureTypeButtonsChange) {
    details.buttons.down = down;
    details.buttons.up = up;
    details.buttons.is_tap = is_tap;
  }
  Gesture(const GestureFling&,
          stime_t start, stime_t end, float vx, float vy, unsigned state)
      : start_time(start), end_time(end), type(kGestureTypeFling) {
    details.fling.ordinal_vx = details.fling.vx = vx;
    details.fling.ordinal_vy = details.fling.vy = vy;
    details.fling.fling_state = state;
  }
  Gesture(const GestureSwipe&,
          stime_t start, stime_t end, float dx, float dy)
      : start_time(start),
        end_time(end),
        type(kGestureTypeSwipe) {
    details.swipe.ordinal_dx = details.swipe.dx = dx;
    details.swipe.ordinal_dy = details.swipe.dy = dy;
  }
  Gesture(const GestureFourFingerSwipe&,
          stime_t start, stime_t end, float dx, float dy)
      : start_time(start),
        end_time(end),
        type(kGestureTypeFourFingerSwipe) {
    details.four_finger_swipe.ordinal_dx = details.four_finger_swipe.dx = dx;
    details.four_finger_swipe.ordinal_dy = details.four_finger_swipe.dy = dy;
  }
  Gesture(const GesturePinch&,
          stime_t start, stime_t end, float dz, unsigned state)
      : start_time(start),
        end_time(end),
        type(kGestureTypePinch) {
    details.pinch.ordinal_dz = details.pinch.dz = dz;
    details.pinch.zoom_state = state;
  }
  Gesture(const GestureSwipeLift&, stime_t start, stime_t end)
      : start_time(start),
        end_time(end),
        type(kGestureTypeSwipeLift) {}
  Gesture(const GestureFourFingerSwipeLift&, stime_t start, stime_t end)
      : start_time(start),
        end_time(end),
        type(kGestureTypeFourFingerSwipeLift) {}
  Gesture(const GestureMetrics&,
          stime_t start, stime_t end, GestureMetricsType m_type,
          float d1, float d2)
      : start_time(start),
        end_time(end),
        type(kGestureTypeMetrics) {
    details.metrics.type = m_type;
    details.metrics.data[0] = d1;
    details.metrics.data[1] = d2;
  }
#endif  // __cplusplus

  stime_t start_time, end_time;
  enum GestureType type;
  union {
    GestureMove move;
    GestureScroll scroll;
    GestureMouseWheel wheel;
    GestureButtonsChange buttons;
    GestureFling fling;
    GestureSwipe swipe;
    GesturePinch pinch;
    GestureSwipeLift swipe_lift;
    GestureMetrics metrics;
    GestureFourFingerSwipe four_finger_swipe;
    GestureFourFingerSwipeLift four_finger_swipe_lift;
  } details;
};

typedef void (*GestureReadyFunction)(void* client_data,
                                     const struct Gesture* gesture);

// Gestures Timer Provider Interface
struct GesturesTimer;
typedef struct GesturesTimer GesturesTimer;

// If this returns < 0, the timer should be freed. If it returns >= 0.0, it
// should be called again after that amount of delay.
typedef stime_t (*GesturesTimerCallback)(stime_t now,
                                         void* callback_data);
// Allocate and return a new timer, or NULL if error.
typedef GesturesTimer* (*GesturesTimerCreate)(void* data);
// Set a timer:
typedef void (*GesturesTimerSet)(void* data,
                                 GesturesTimer* timer,
                                 stime_t delay,
                                 GesturesTimerCallback callback,
                                 void* callback_data);
// Cancel a set timer:
typedef void (*GesturesTimerCancel)(void* data, GesturesTimer* timer);
// Free the timer. Will not be called from within a timer callback.
typedef void (*GesturesTimerFree)(void* data, GesturesTimer* timer);

typedef struct {
  GesturesTimerCreate create_fn;
  GesturesTimerSet set_fn;
  GesturesTimerCancel cancel_fn;
  GesturesTimerFree free_fn;
} GesturesTimerProvider;

// Gestures Property Provider Interface
struct GesturesProp;
typedef struct GesturesProp GesturesProp;

typedef unsigned char GesturesPropBool;

// These functions create a named property of given type.
//   data - data used by PropProvider
//   loc - location of a variable to be updated by PropProvider
//         (Chromium calls its own GesturesPropCreate... functions with loc set
//         to null to create read-only properties, but the Gestures library
//         itself doesn't, so other clients don't need to support them.)
//   init - initial value for the property.
//          If the PropProvider has an alternate configuration source, it may
//          override this initial value, in which case *loc returns the
//          value from the configuration source.
typedef GesturesProp* (*GesturesPropCreateInt)(void* data, const char* name,
                                               int* loc, size_t count,
                                               const int* init);

// Deprecated: the gestures library no longer uses short gesture properties.
typedef GesturesProp* (*GesturesPropCreateShort_Deprecated)(
    void*, const char*, short*, size_t, const short*);

typedef GesturesProp* (*GesturesPropCreateBool)(void* data, const char* name,
                                                GesturesPropBool* loc,
                                                size_t count,
                                                const GesturesPropBool* init);

typedef GesturesProp* (*GesturesPropCreateString)(void* data, const char* name,
                                                  const char** loc,
                                                  const char* const init);

typedef GesturesProp* (*GesturesPropCreateReal)(void* data, const char* name,
                                                double* loc, size_t count,
                                                const double* init);

// A function to call just before a property is to be read.
// |handler_data| is a local context pointer that can be used by the handler.
// Handler should return non-zero if it modifies the property's value.
typedef GesturesPropBool (*GesturesPropGetHandler)(void* handler_data);

// A function to call just after a property's value is updated.
// |handler_data| is a local context pointer that can be used by the handler.
typedef void (*GesturesPropSetHandler)(void* handler_data);

// Register handlers for the client to call when a GesturesProp is accessed.
//
// The get handler, if not NULL, should be called immediately before the
// property's value is to be read. This gives the library a chance to update its
// value.
//
// The set handler, if not NULL, should be called immediately after the
// property's value is updated. This can be used to create a property that is
// used to trigger an action, or to force an update to multiple properties
// atomically.
//
// Note: the handlers are called from non-signal/interrupt context
typedef void (*GesturesPropRegisterHandlers)(void* data, GesturesProp* prop,
                                             void* handler_data,
                                             GesturesPropGetHandler getter,
                                             GesturesPropSetHandler setter);

// Free a property.
typedef void (*GesturesPropFree)(void* data, GesturesProp* prop);

typedef struct GesturesPropProvider {
  GesturesPropCreateInt create_int_fn;
  // Deprecated: the library no longer uses short gesture properties, so this
  // function pointer should be null.
  GesturesPropCreateShort_Deprecated create_short_fn;
  GesturesPropCreateBool create_bool_fn;
  GesturesPropCreateString create_string_fn;
  GesturesPropCreateReal create_real_fn;
  GesturesPropRegisterHandlers register_handlers_fn;
  GesturesPropFree free_fn;
} GesturesPropProvider;

#ifdef __cplusplus
// C++ API:

namespace gestures {

class Interpreter;
class PropRegistry;
class LoggingFilterInterpreter;
class Tracer;
class GestureInterpreterConsumer;
class MetricsProperties;

#if __cplusplus >= 201103L

struct GestureInterpreter {
 public:
  explicit GestureInterpreter(int version);
  ~GestureInterpreter();
  void PushHardwareState(HardwareState* hwstate);

  void SetHardwareProperties(const HardwareProperties& hwprops);

  void TimerCallback(stime_t now, stime_t* timeout);

  void SetCallback(GestureReadyFunction callback, void* client_data);
  // Deprecated; use SetCallback instead.
  void set_callback(GestureReadyFunction callback,
                    void* client_data);
  void SetTimerProvider(GesturesTimerProvider* tp, void* data);
  void SetPropProvider(GesturesPropProvider* pp, void* data);

  // Initialize GestureInterpreter based on device configuration.  This must be
  // called after GesturesPropProvider is set and before it accepts any inputs.
  void Initialize(
      GestureInterpreterDeviceClass type=GESTURES_DEVCLASS_TOUCHPAD);

  Interpreter* interpreter() const { return interpreter_.get(); }
  PropRegistry* prop_reg() const { return prop_reg_.get(); }

  std::string EncodeActivityLog();
 private:
  void InitializeTouchpad(void);
  void InitializeTouchpad2(void);
  void InitializeMouse(GestureInterpreterDeviceClass cls);
  void InitializeMultitouchMouse(void);

  GestureReadyFunction callback_;
  void* callback_data_;

  std::unique_ptr<PropRegistry> prop_reg_;
  std::unique_ptr<Tracer> tracer_;
  std::unique_ptr<Interpreter> interpreter_;
  std::unique_ptr<MetricsProperties> mprops_;

  GesturesTimerProvider* timer_provider_;
  void* timer_provider_data_;
  GesturesTimer* interpret_timer_;

  LoggingFilterInterpreter* loggingFilter_;
  std::unique_ptr<GestureInterpreterConsumer> consumer_;
  HardwareProperties hwprops_;

  // Disallow copy & assign;
  GestureInterpreter(const GestureInterpreter&);
  void operator=(const GestureInterpreter&);
};

#else  // __cplusplus >= 201103L

// Must be opaque under C++03 builds, since it has unique_ptr members.
struct GestureInterpreter;

#endif  // __cplusplus >= 201103L


}  // namespace gestures

typedef gestures::GestureInterpreter GestureInterpreter;
#else
struct GestureInterpreter;
typedef struct GestureInterpreter GestureInterpreter;
#endif  // __cplusplus

#define GESTURES_VERSION 1
GestureInterpreter* NewGestureInterpreterImpl(int);
#define NewGestureInterpreter() NewGestureInterpreterImpl(GESTURES_VERSION)

void DeleteGestureInterpreter(GestureInterpreter*);

void GestureInterpreterSetHardwareProperties(GestureInterpreter*,
                                             const struct HardwareProperties*);

void GestureInterpreterPushHardwareState(GestureInterpreter*,
                                         struct HardwareState*);

void GestureInterpreterSetCallback(GestureInterpreter*,
                                   GestureReadyFunction,
                                   void*);

// Gestures will hold a reference to passed provider. Pass NULL to tell
// Gestures to stop holding a reference.
void GestureInterpreterSetTimerProvider(GestureInterpreter*,
                                        GesturesTimerProvider*,
                                        void*);

void GestureInterpreterSetPropProvider(GestureInterpreter*,
                                       GesturesPropProvider*,
                                       void*);

void GestureInterpreterInitialize(GestureInterpreter*,
                                  enum GestureInterpreterDeviceClass);

#ifdef __cplusplus
}
#endif

#endif  // GESTURES_GESTURES_H__