summaryrefslogtreecommitdiff
path: root/src/click_wiggle_filter_interpreter.cc
blob: e4f9b104c6e53af0b2b91fdf4d7fa9aab03c1ac9 (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
// 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 "include/click_wiggle_filter_interpreter.h"

#include "include/gestures.h"
#include "include/interpreter.h"
#include "include/logging.h"
#include "include/tracer.h"
#include "include/util.h"

namespace gestures {

// Takes ownership of |next|:
ClickWiggleFilterInterpreter::ClickWiggleFilterInterpreter(
    PropRegistry* prop_reg, Interpreter* next, Tracer* tracer)
    : FilterInterpreter(nullptr, next, tracer, false),
      button_edge_occurred_(-1.0),
      prev_buttons_(0),
      wiggle_max_dist_(prop_reg, "Wiggle Max Distance", 5.5),
      wiggle_suppress_timeout_(prop_reg, "Wiggle Timeout", 0.075),
      wiggle_button_down_timeout_(prop_reg,
                                  "Wiggle Button Down Timeout",
                                  0.75),
      one_finger_click_wiggle_timeout_(prop_reg,
                                       "One Finger Click Wiggle Timeout",
                                       0.2) {
  InitName();
}

void ClickWiggleFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate,
                                                     stime_t* timeout) {
  const char name[] = "ClickWiggleFilterInterpreter::SyncInterpretImpl";
  LogHardwareStatePre(name, hwstate);

  UpdateClickWiggle(hwstate);
  SetWarpFlags(hwstate);

  // Update previous state
  prev_buttons_ = hwstate.buttons_down;
  RemoveMissingIdsFromMap(&prev_pressure_, hwstate);
  for (size_t i = 0; i < hwstate.finger_cnt; i++) {
    const FingerState& fs = hwstate.fingers[i];
    prev_pressure_[fs.tracking_id] = fs.pressure;
  }

  LogHardwareStatePost(name, hwstate);
  next_->SyncInterpret(hwstate, timeout);
}

void ClickWiggleFilterInterpreter::UpdateClickWiggle(
    const HardwareState& hwstate) {
  // Removed outdated fingers from wiggle_recs_
  RemoveMissingIdsFromMap(&wiggle_recs_, hwstate);

  // Check if clock changed backwards
  if (hwstate.timestamp < button_edge_occurred_)
    button_edge_occurred_ = -1.0;

  const bool button_down = hwstate.buttons_down & GESTURES_BUTTON_LEFT;
  const bool prev_button_down = prev_buttons_ & GESTURES_BUTTON_LEFT;
  const bool button_down_edge = button_down && !prev_button_down;
  const bool button_up_edge = !button_down && prev_button_down;

  if (button_down_edge || button_up_edge) {
    button_edge_occurred_ = hwstate.timestamp;
    size_t non_palm_count = 0;
    for (size_t i = 0; i < hwstate.finger_cnt; i++)
      if (!(hwstate.fingers[i].flags & (GESTURES_FINGER_PALM |
                                        GESTURES_FINGER_POSSIBLE_PALM)))
        non_palm_count++;
    button_edge_with_one_finger_ = (non_palm_count < 2);
  }

  // Update wiggle_recs_ for each current finger
  for (size_t i = 0; i < hwstate.finger_cnt; i++) {
    const FingerState& fs = hwstate.fingers[i];
    std::map<short, ClickWiggleRec>::iterator it =
        wiggle_recs_.find(fs.tracking_id);
    const bool new_finger = it == wiggle_recs_.end();

    if (button_down_edge || button_up_edge || new_finger) {
      stime_t timeout = button_down_edge ?
          wiggle_button_down_timeout_.val_ : wiggle_suppress_timeout_.val_;
      ClickWiggleRec rec = {
        fs.position_x,  // button down x
        fs.position_y,  // button down y
        hwstate.timestamp + timeout,  // unused during click down
        true  // suppress
      };
      wiggle_recs_[fs.tracking_id] = rec;
      continue;
    }

    // We have an existing finger
    ClickWiggleRec* rec = &(*it).second;

    if (!rec->suppress_)
      continue;  // It's already broken out of wiggle suppression

    float dx = fs.position_x - rec->x_;
    float dy = fs.position_y - rec->y_;
    if (dx * dx + dy * dy > wiggle_max_dist_.val_ * wiggle_max_dist_.val_) {
      // It's moved too much to be considered wiggle
      rec->suppress_ = false;
      continue;
    }

    if (hwstate.timestamp >= rec->began_press_suppression_) {
      // Too much time has passed to consider this wiggle
      rec->suppress_ = false;
      continue;
    }
  }
}

void ClickWiggleFilterInterpreter::SetWarpFlags(HardwareState& hwstate) const {
  if (button_edge_occurred_ != -1.0 &&
      button_edge_occurred_ < hwstate.timestamp &&
      button_edge_occurred_ + one_finger_click_wiggle_timeout_.val_ >
      hwstate.timestamp && button_edge_with_one_finger_) {
    for (size_t i = 0; i < hwstate.finger_cnt; i++)
      hwstate.fingers[i].flags |=
          (GESTURES_FINGER_WARP_X | GESTURES_FINGER_WARP_Y);
    // May as well return b/c already set warp on the only finger there is.
    return;
  }

  for (size_t i = 0; i < hwstate.finger_cnt; i++) {
    FingerState& fs = hwstate.fingers[i];
    if (!MapContainsKey(wiggle_recs_, fs.tracking_id)) {
      Err("Missing finger in wiggle recs.");
      continue;
    }
    if (wiggle_recs_.at(fs.tracking_id).suppress_)
      fs.flags |= (GESTURES_FINGER_WARP_X | GESTURES_FINGER_WARP_Y);
  }
}

}  // namespace gestures