summaryrefslogtreecommitdiff
path: root/include/lookahead_filter_interpreter.h
blob: 31aefe45178f799695c4d9fde9da19fcee6ef159 (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
// 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.

#include <algorithm>
#include <list>
#include <map>
#include <memory>
#include <vector>

#include <gtest/gtest.h>  // For FRIEND_TEST

#include "include/filter_interpreter.h"
#include "include/finger_metrics.h"
#include "include/gestures.h"
#include "include/prop_registry.h"
#include "include/tracer.h"

#ifndef GESTURES_LOOKAHEAD_FILTER_INTERPRETER_H_
#define GESTURES_LOOKAHEAD_FILTER_INTERPRETER_H_

namespace gestures {

class LookaheadFilterInterpreter : public FilterInterpreter {
  FRIEND_TEST(LookaheadFilterInterpreterTest, CyapaQuickTwoFingerMoveTest);
  FRIEND_TEST(LookaheadFilterInterpreterTest, DrumrollTest);
  FRIEND_TEST(LookaheadFilterInterpreterTest, InterpolateHwStateTest);
  FRIEND_TEST(LookaheadFilterInterpreterTest, InterpolateTest);
  FRIEND_TEST(LookaheadFilterInterpreterTest, InterpolationOverdueTest);
  FRIEND_TEST(LookaheadFilterInterpreterTest, NoTapSetTest);
  FRIEND_TEST(LookaheadFilterInterpreterTest, QuickMoveTest);
  FRIEND_TEST(LookaheadFilterInterpreterTest, QuickSwipeTest);
  FRIEND_TEST(LookaheadFilterInterpreterTest, SemiMtNoTrackingIdAssignmentTest);
  FRIEND_TEST(LookaheadFilterInterpreterTest, SimpleTest);
  FRIEND_TEST(LookaheadFilterInterpreterTest, SpuriousCallbackTest);
  FRIEND_TEST(LookaheadFilterInterpreterTest, VariableDelayTest);
  FRIEND_TEST(LookaheadFilterInterpreterTest, QStateListTest);

 public:
  LookaheadFilterInterpreter(PropRegistry* prop_reg, Interpreter* next,
                             Tracer* tracer);
  virtual ~LookaheadFilterInterpreter() {}

 protected:
  virtual void SyncInterpretImpl(HardwareState* hwstate,
                                 stime_t* timeout);

  virtual void HandleTimerImpl(stime_t now, stime_t* timeout);

  virtual void Initialize(const HardwareProperties* hwprops,
                          Metrics* metrics, MetricsProperties* mprops,
                          GestureConsumer* consumer);

 private:
  struct QState {
    QState();
    explicit QState(unsigned short max_fingers);

    // Deep copy of new_state to state_
    void set_state(const HardwareState& new_state);

    HardwareState state_;
    unsigned short max_fingers_;
    std::unique_ptr<FingerState[]> fs_;
    std::map<short, short> output_ids_;  // input tracking ids -> output

    stime_t due_;
    bool completed_;

    QState* next_;
    QState* prev_;
  };

  void LogVectors();

  // Produces a tapdown fling gesture if we just got a new hardware state
  // with a finger missing from the previous, or a null gesture otherwise.
  void TapDownOccurringGesture(stime_t now);

  // Looks at the most recent 2 states in the queue (one of which may have
  // already completed), and if they are separated by split_min_period_ time,
  // tries to insert an interpolated event in the middle.
  void AttemptInterpolation();

  // Reassigns tracking IDs, assigning them in such a way to avoid problems
  // of drumroll.
  void AssignTrackingIds();

  // For drumroll. Edits a QState node's fingerstate to have a new tracking id.
  void SeparateFinger(QState* node, FingerState* fs, short input_id);

  // Looks for a finger possibly lifting off the pad. If found, returns true.
  bool LiftoffJumpStarting(const HardwareState& hs,
                           const HardwareState& prev_hs,
                           const HardwareState& prev2_hs) const;

  // Returns a new tracking id for a contact.
  short NextTrackingId();

  // Interpolates first and second, storing the result into out.
  // first and second must have the same the same number of fingers and
  // have the same tracking_ids for all fingers.
  static void Interpolate(const HardwareState& first,
                          const HardwareState& second,
                          HardwareState* out);

  void UpdateInterpreterDue(stime_t new_interpreter_due,
                            stime_t now,
                            stime_t* timeout);
  void ConsumeGesture(const Gesture& gesture);

  stime_t ExtraVariableDelay() const;

  class QStateList : public std::list<QState*> {
  public:
    QState* at(int offset);
  } queue_;

  std::vector<QState*> free_list_;

  // The last id assigned to a contact (part of drumroll suppression)
  short last_id_;

  unsigned short max_fingers_per_hwstate_;

  stime_t interpreter_due_;

  // We want to present time to next_ in a monotonically increasing manner,
  // so this keeps track of the most recent timestamp we've given next_.
  stime_t last_interpreted_time_;

  Gesture result_;

  DoubleProperty min_nonsuppress_speed_;
  DoubleProperty min_delay_;
  // On some platforms, min_delay_ is very small, and sometimes we would like
  // temporary extra delay to avoid problems, so we can in those cases add
  // a delay specified by max_delay_. It's okay for max_delay_ to be less
  // than min_delay_. In that case, it simply has no effect.
  DoubleProperty max_delay_;
  // If this much time passes between consecutive events, interpolate.
  DoubleProperty split_min_period_;
  // If set to false, tracking IDs are not reassigned
  BoolProperty drumroll_suppression_enable_;
  // If a contact appears to move faster than this, the drumroll detector may
  // consider it a new contact.
  DoubleProperty drumroll_speed_thresh_;
  // If one contact's speed is more than drumroll_max_speed_ratio_ times the
  // previous speed, the drumroll detector may consider it a new contact.
  DoubleProperty drumroll_max_speed_ratio_;
  // If during 3 consecutive HardwareState, one contact moves more than
  // quick_move_thresh_ distance along the same direction on either x or y
  // axis, both between the 1st and 2nd HardwareState, and the 2nd and 3rd
  // HardwareState, it is considered to be a quick move and the tracking ID
  // reassignment due to drumroll detection may get corrected.
  DoubleProperty quick_move_thresh_;
  // If we're going to drumroll-suppress a finger that is moving too much,
  // we abort said suppression if it's moving less than co_move_ratio_ *
  // distance of another non-drumroll-suppressed finger.
  DoubleProperty co_move_ratio_;
  // Temporary property to turn on/off the generation of TapDown gestures
  // (i.e., stop flinging gestures).
  BoolProperty suppress_immediate_tapdown_;
  // If we should add extra delay when we think a finger may be lifting off.
  BoolProperty delay_on_possible_liftoff_;
  // If looking for a possible liftoff-move, the speed a finger is moving
  // relative to the previous speed, such that it's a possible leave.
  DoubleProperty liftoff_speed_increase_threshold_;
};

}  // namespace gestures

#endif  // GESTURES_LOOKAHEAD_FILTER_INTERPRETER_H_