xref: /aosp_15_r20/external/libchrome-gestures/include/split_correcting_filter_interpreter.h (revision aed3e5085e770be5b69ce25295ecf6ddf906af95)
1 // Copyright 2012 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 <set>
6 #include <gtest/gtest.h>  // for FRIEND_TEST
7 
8 #include "include/filter_interpreter.h"
9 #include "include/finger_metrics.h"
10 #include "include/gestures.h"
11 #include "include/prop_registry.h"
12 #include "include/tracer.h"
13 
14 #ifndef GESTURES_SPLIT_CORRECTING_FILTER_INTERPRETER_H_
15 #define GESTURES_SPLIT_CORRECTING_FILTER_INTERPRETER_H_
16 
17 namespace gestures {
18 
19 // This interepreter corrects problems that can occur with some touchpads.
20 // Currently, it corrects for the case where a large finger can erroneously
21 // "split" into two contacts. It works around this by looking for a contact
22 // to seemingly split into two, and fakes that the split didn't occur.
23 
24 // This struct tracks an unmerged contact. By default the output and input
25 // IDs will be the same value, however after merge cycles, that may no longer
26 // be the case.
27 struct UnmergedContact {
UnmergedContactUnmergedContact28   UnmergedContact() : input_id(-1) {}
ValidUnmergedContact29   bool Valid() const { return input_id != -1; }
InvalidateUnmergedContact30   void Invalidate() { input_id = -1; }
31   short input_id;
32   short output_id;
33   float position_x;
34   float position_y;
35 };
36 
37 // Tracks two input contacts that are being combined into one output contact
38 // because we believe they are actually two parts of the same real contact.
39 struct MergedContact {
MergedContactMergedContact40   MergedContact() : output_id(-1) {}
ValidMergedContact41   bool Valid() const { return output_id != -1; }
InvalidateMergedContact42   void Invalidate() { output_id = -1; }
43   FingerState input_fingers[2];  // initial state
44   short output_id;
45 };
46 
47 class SplitCorrectingFilterInterpreter : public FilterInterpreter {
48   FRIEND_TEST(SplitCorrectingFilterInterpreterTest, DistFromPointToLineTest);
49  public:
50   // Takes ownership of |next|:
51   SplitCorrectingFilterInterpreter(PropRegistry* prop_reg, Interpreter* next,
52                                    Tracer* tracer);
~SplitCorrectingFilterInterpreter()53   virtual ~SplitCorrectingFilterInterpreter() {}
54 
Enable()55   void Enable() { enabled_.val_ = 1; }
56 
57  protected:
58   virtual void SyncInterpretImpl(HardwareState& hwstate, stime_t* timeout);
59 
60  private:
61   void RemoveMissingUnmergedContacts(const HardwareState& hwstate);
62   void MergeFingers(const HardwareState& hwstate);
63   void UnmergeFingers(const HardwareState& hwstate);
64   void UpdateUnmergedLocations(const HardwareState& hwstate);
65 
66   // Given a line that goes through (x0, y0) and (x1, y1), and a separate
67   // point, compute the square of the smallest distance from the point to the
68   // line.
69   static float DistSqFromPointToLine(float line_x_0, float line_y_0,
70                                      float line_x_1, float line_y_1,
71                                      float point_x, float point_y);
72 
73   // Based on merged_ and unmeged_, updates the current hwstate.
74   void UpdateHwState(HardwareState& hwstate) const;
75   // Tests to see if new_contact, when paired w/ existing_contact
76   // are a good match for the unmerged contact, merge_recipient.
77   // new_contact is the current state of the finger in merge_recipient.
78   // Returns < 0 if this is not a good match, or an error value if it's good.
79   // The smaller the error, the better.
80   float AreMergePair(const FingerState& existing_contact,
81                      const FingerState& new_contact,
82                      const UnmergedContact& merge_recipient) const;
83 
84   void AppendMergedContact(const FingerState& input_a,
85                            const FingerState& input_b,
86                            short output_id);
87   void AppendUnmergedContact(const FingerState& fs, short output_id);
88 
89   const UnmergedContact* FindUnmerged(short input_id) const;
90   const MergedContact* FindMerged(short input_id) const;
91 
92   static void JoinFingerState(FingerState* in_out,
93                               const FingerState& newfinger);
94   static void RemoveFingerStateFromHardwareState(HardwareState& hs,
95                                                  FingerState* fs);
96 
97   // Sets last_tracking_ids_ to the ids in the passed hwstate.
98   void SetLastTrackingIds(const HardwareState& hwstate);
99 
100   // Dumps internal state and hwstate.
101   void Dump(const HardwareState& hwstate) const;
102 
103   std::set<short> last_tracking_ids_;
104   UnmergedContact unmerged_[kMaxFingers];
105   MergedContact merged_[kMaxFingers / 2 + 1];
106 
107   // We only enable on non-T5R2 pads
108   BoolProperty enabled_;
109 
110   // Contacts must be separated by less than this amount to be considered for
111   // merging.
112   DoubleProperty merge_max_separation_;
113   // The most [mm] that a finger in a merged contact can move before we break
114   // out and unmerge.
115   DoubleProperty merge_max_movement_;
116   // When merging, we expect that the two fingers that appear are on either
117   // side of the old merged contact from last frame, and that the angle from
118   // the old merged contact, to the new finger with the same id, to the new
119   // finger with a new ID has a max angle. This angle then computes the max
120   // ratio of: (distance from new ID point to line defined by old and new
121   // contacts that have the same ID) / (length from new ID point to old ID point
122   // in newer frame).
123   DoubleProperty merge_max_ratio_;
124 };
125 
126 }  // namespace gestures
127 
128 #endif  // GESTURES_SPLIT_CORRECTING_FILTER_INTERPRETER_H_
129