OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
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 "ui/events/ozone/evdev/touch_noise/single_position_touch_noise_filter.h
" | |
6 | |
7 #include "base/logging.h" | |
8 #include "base/strings/stringprintf.h" | |
9 | |
10 namespace ui { | |
11 | |
12 namespace { | |
13 | |
14 // Max squared distance between fingers for the fingers to be considered in the | |
15 // same position. | |
16 const int kSamePositionMaxDistance2 = 2 * 2; | |
17 | |
18 // Max squared movement of a finger before it's no longer considered noise. | |
19 const int kNoiseMaxMovement2 = 2 * 2; | |
20 | |
21 // Min duration in milliseconds after which touches in the same position are | |
22 // considered noise. | |
23 const int kMinDurationMs = 2000; | |
24 | |
25 // Max duration in milliseconds to check for common positions with previous | |
26 // touches. | |
27 const int kMaxDurationMs = 4000; | |
28 | |
29 // Returns the squared distance between (|x1|, |y1|) and (|x2|, |y2|) | |
30 int Distance2(int x1, int y1, int x2, int y2) { | |
31 int offset_x = x2 - x1; | |
32 int offset_y = y2 - y1; | |
33 return offset_x * offset_x + offset_y * offset_y; | |
34 } | |
35 | |
36 } // namespace | |
37 | |
38 SinglePositionTouchNoiseFilter::SinglePositionTouchNoiseFilter() | |
39 : tracked_touches_start_(0), tracked_touches_end_(0) { | |
40 for (size_t i = 0; i < kNumTouchEvdevSlots; ++i) | |
41 tracked_slots_[i] = kNumTrackedTouches; | |
42 } | |
43 | |
44 void SinglePositionTouchNoiseFilter::Filter( | |
45 const std::vector<InProgressTouchEvdev>& touches, | |
46 base::TimeDelta time, | |
47 std::bitset<kNumTouchEvdevSlots>* slots_with_noise) { | |
48 // Forget old touches which will no longer be considered for overlap. | |
49 base::TimeDelta touch_cutoff = | |
50 time - base::TimeDelta::FromMilliseconds(kMaxDurationMs); | |
51 for (size_t i = tracked_touches_start_; i != tracked_touches_end_; | |
52 i = (i + 1) % kNumTrackedTouches) { | |
53 if (!tracked_touches_[i].valid) | |
54 continue; | |
55 if (tracked_touches_[i].end < touch_cutoff) | |
56 StopTrackingTouch(i); | |
57 } | |
58 | |
59 for (const InProgressTouchEvdev& touch : touches) { | |
60 size_t slot = touch.slot; | |
61 | |
62 bool arrived = touch.touching && !touch.was_touching; | |
63 bool departed = !touch.touching && touch.was_touching; | |
64 if (departed) | |
65 tracked_slots_[slot] = kNumTrackedTouches; | |
66 if (!touch.touching) | |
67 continue; | |
68 | |
69 // Track all new touches until they move too far. | |
70 if (arrived) | |
71 TrackTouch(touch, time); | |
72 | |
73 size_t t_ind = tracked_slots_[slot]; | |
74 if (t_ind != kNumTrackedTouches) { | |
75 tracked_touches_[t_ind].end = time; | |
76 // Stop tracking if touch moves more than sqrt(kNoiseMaxMovement2). | |
77 if (Distance2(touch.x, touch.y, tracked_touches_[t_ind].x, | |
78 tracked_touches_[t_ind].y) > kNoiseMaxMovement2) { | |
79 StopTrackingTouch(t_ind); | |
80 } else { | |
81 // Determine duration over which touches have been occuring in this | |
82 // position. | |
83 base::TimeDelta max_duration; | |
84 for (size_t i = tracked_touches_start_; i != tracked_touches_end_; | |
85 i = (i + 1) % kNumTrackedTouches) { | |
86 TrackedTouch* tracked_touch = &tracked_touches_[i]; | |
87 if (!tracked_touch->valid) | |
88 continue; | |
89 if (Distance2(touch.x, touch.y, tracked_touch->x, tracked_touch->y) <= | |
90 kSamePositionMaxDistance2) { | |
91 base::TimeDelta duration = time - tracked_touch->begin; | |
92 if (duration > max_duration) | |
93 max_duration = duration; | |
94 } | |
95 } | |
96 | |
97 if (max_duration.InMilliseconds() > kMinDurationMs) { | |
98 VLOG(2) << base::StringPrintf( | |
99 "Cancel tracking id %d, in position occurring for %ldms", | |
100 touch.tracking_id, max_duration.InMilliseconds()); | |
101 slots_with_noise->set(slot); | |
102 } | |
103 } | |
104 } | |
105 } | |
106 } | |
107 | |
108 void SinglePositionTouchNoiseFilter::StopTrackingTouch(size_t index) { | |
109 size_t slot = tracked_touches_[index].slot; | |
110 if (tracked_slots_[slot] == index) | |
111 tracked_slots_[slot] = kNumTrackedTouches; | |
112 tracked_touches_[index].valid = false; | |
113 | |
114 // If first touch is canceled, remove all dead touches. | |
115 if (index == tracked_touches_start_) { | |
116 while (!tracked_touches_[tracked_touches_start_].valid && | |
117 tracked_touches_start_ != tracked_touches_end_) { | |
118 tracked_touches_start_ = | |
119 (tracked_touches_start_ + 1) % kNumTrackedTouches; | |
120 } | |
121 } | |
122 } | |
123 | |
124 void SinglePositionTouchNoiseFilter::TrackTouch( | |
125 const InProgressTouchEvdev& touch, | |
126 base::TimeDelta time) { | |
127 size_t index = (tracked_touches_end_ + 1) % kNumTrackedTouches; | |
128 // If we would reach the start touch index, we cannot track any more touches. | |
129 if (index == tracked_touches_start_) | |
130 return; | |
131 | |
132 tracked_touches_end_ = index; | |
133 tracked_touches_[index].valid = true; | |
134 tracked_touches_[index].slot = touch.slot; | |
135 tracked_touches_[index].x = touch.x; | |
136 tracked_touches_[index].y = touch.y; | |
137 tracked_touches_[index].begin = time; | |
138 tracked_touches_[index].end = time; | |
139 tracked_slots_[touch.slot] = index; | |
140 } | |
141 | |
142 SinglePositionTouchNoiseFilter::SinglePositionTouchNoiseFilter::TrackedTouch:: | |
143 TrackedTouch() | |
144 : valid(false), slot(0), x(0), y(0) { | |
145 } | |
146 | |
147 SinglePositionTouchNoiseFilter::SinglePositionTouchNoiseFilter::TrackedTouch:: | |
148 ~TrackedTouch() { | |
149 } | |
150 | |
151 } // namespace ui | |
OLD | NEW |