xref: /aosp_15_r20/external/libchrome-gestures/src/stationary_wiggle_filter_interpreter.cc (revision aed3e5085e770be5b69ce25295ecf6ddf906af95)
1 // Copyright 2013 The ChromiumOS Authors
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 <map>
6 
7 #include "include/stationary_wiggle_filter_interpreter.h"
8 
9 #include "include/gestures.h"
10 #include "include/interpreter.h"
11 #include "include/tracer.h"
12 #include "include/util.h"
13 
14 namespace gestures {
15 
PushFingerState(const FingerState & fs,const stime_t timestamp)16 void FingerEnergyHistory::PushFingerState(const FingerState &fs,
17                                           const stime_t timestamp) {
18 
19   // Reset the history if there is no finger state received longer than
20   // time interval 'idle_time_'.
21   if (moving_ && timestamp - prev_ > idle_time_) {
22     moving_ = false;
23     head_ = size_ = 0;
24   }
25 
26   // Insert current finger position into the queue
27   head_ = (head_ + max_size_ - 1) % max_size_;
28   history_[head_].x = fs.position_x;
29   history_[head_].y = fs.position_y;
30   size_ = std::min(size_ + 1, max_size_);
31 
32   // Calculate average of original signal set, the average of original signal
33   // is considered as the offset.
34   float sum_x = 0.0;
35   float sum_y = 0.0;
36   for (size_t i = 0; i < size_; ++i) {
37     const FingerEnergy& fe = Get(i);
38     sum_x += fe.x;
39     sum_y += fe.y;
40   }
41   // Obtain the mixed signal strength
42   history_[head_].mixed_x = fs.position_x - sum_x / size_;
43   history_[head_].mixed_y = fs.position_y - sum_y / size_;
44 
45 
46   // Calculate the average of the mixed signal set, the average of mixed signal
47   // is considered as pure signal strength.
48   float psx = 0.0;
49   float psy = 0.0;
50   for (size_t i = 0; i < size_; ++i) {
51     const FingerEnergy& fe = Get(i);
52     psx += fe.mixed_x;
53     psy += fe.mixed_y;
54   }
55   psx /= size_;
56   psy /= size_;
57   // Calculate current pure signal energy
58   history_[head_].energy_x = psx * psx;
59   history_[head_].energy_y = psy * psy;
60 
61   prev_ = timestamp;
62 }
63 
Get(size_t offset) const64 const FingerEnergy& FingerEnergyHistory::Get(size_t offset) const {
65   if (offset >= size_) {
66     Err("Out of bounds access!");
67     // avoid returning null pointer
68     static FingerEnergy dummy_event = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
69     return dummy_event;
70   }
71   return history_[(head_ + offset) % max_size_];
72 }
73 
IsFingerMoving(float threshold)74 bool FingerEnergyHistory::IsFingerMoving(float threshold) {
75   if (size_ < max_size_)
76     return false;
77 
78   float sum_energy_x = 0.0;
79   float sum_energy_y = 0.0;
80   for (size_t i = 0; i < size_; i++) {
81     const FingerEnergy& fe = history_[i];
82     sum_energy_x += fe.energy_x;
83     sum_energy_y += fe.energy_y;
84   }
85   moving_ = (sum_energy_x > threshold || sum_energy_y > threshold);
86   return moving_;
87 }
88 
operator ==(const FingerEnergyHistory & that) const89 bool FingerEnergyHistory::operator==(const FingerEnergyHistory& that) const {
90   for (size_t i = 0; i < size_; i++)
91     if (history_[i] != that.history_[i])
92       return false;
93   if (size_ != that.size_ || head_ != that.head_ || moving_ != that.moving_)
94     return false;
95   return true;
96 }
97 
operator !=(const FingerEnergyHistory & that) const98 bool FingerEnergyHistory::operator!=(const FingerEnergyHistory& that) const {
99   return !(*this == that);
100 }
101 
StationaryWiggleFilterInterpreter(PropRegistry * prop_reg,Interpreter * next,Tracer * tracer)102 StationaryWiggleFilterInterpreter::StationaryWiggleFilterInterpreter(
103     PropRegistry* prop_reg, Interpreter* next, Tracer* tracer)
104     : FilterInterpreter(nullptr, next, tracer, false),
105       enabled_(prop_reg, "Stationary Wiggle Filter Enabled", false),
106       threshold_(prop_reg, "Finger Moving Energy", 0.012),
107       hysteresis_(prop_reg, "Finger Moving Hysteresis", 0.006) {
108   InitName();
109 }
110 
SyncInterpretImpl(HardwareState & hwstate,stime_t * timeout)111 void StationaryWiggleFilterInterpreter::SyncInterpretImpl(
112     HardwareState& hwstate, stime_t* timeout) {
113   const char name[] = "StationaryWiggleFilterInterpreter::SyncInterpretImpl";
114   LogHardwareStatePre(name, hwstate);
115 
116   if (enabled_.val_)
117     UpdateStationaryFlags(hwstate);
118 
119   LogHardwareStatePost(name, hwstate);
120   next_->SyncInterpret(hwstate, timeout);
121 }
122 
UpdateStationaryFlags(HardwareState & hwstate)123 void StationaryWiggleFilterInterpreter::UpdateStationaryFlags(
124     HardwareState& hwstate) {
125 
126   RemoveMissingIdsFromMap(&histories_, hwstate);
127 
128   for (int i = 0; i < hwstate.finger_cnt; ++i) {
129     FingerState *fs = &hwstate.fingers[i];
130 
131     // Create a new entry if it is a new finger
132     if (!MapContainsKey(histories_, fs->tracking_id)) {
133       histories_[fs->tracking_id] = FingerEnergyHistory();
134       histories_[fs->tracking_id].PushFingerState(*fs, hwstate.timestamp);
135       continue;
136     }
137 
138     // Update the energy history and check if the finger is moving
139     FingerEnergyHistory& feh = histories_[fs->tracking_id];
140     feh.PushFingerState(*fs, hwstate.timestamp);
141     if (feh.HasEnoughSamples()) {
142       float threshold = feh.moving() ? hysteresis_.val_ : threshold_.val_;
143       if (!feh.IsFingerMoving(threshold))
144         fs->flags |= (GESTURES_FINGER_WARP_X | GESTURES_FINGER_WARP_Y);
145       else
146         fs->flags |= GESTURES_FINGER_INSTANTANEOUS_MOVING;
147     }
148   }
149 }
150 
151 }  // namespace gestures
152