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 "include/stuck_button_inhibitor_filter_interpreter.h"
6
7 #include "include/logging.h"
8 #include "include/tracer.h"
9
10 namespace gestures {
11
StuckButtonInhibitorFilterInterpreter(Interpreter * next,Tracer * tracer)12 StuckButtonInhibitorFilterInterpreter::StuckButtonInhibitorFilterInterpreter(
13 Interpreter* next, Tracer* tracer)
14 : FilterInterpreter(nullptr, next, tracer, false),
15 incoming_button_must_be_up_(true),
16 sent_buttons_down_(0),
17 next_expects_timer_(false) {
18 InitName();
19 }
20
SyncInterpretImpl(HardwareState & hwstate,stime_t * timeout)21 void StuckButtonInhibitorFilterInterpreter::SyncInterpretImpl(
22 HardwareState& hwstate, stime_t* timeout) {
23 const char name[] =
24 "StuckButtonInhibitorFilterInterpreter::SyncInterpretImpl";
25 LogHardwareStatePre(name, hwstate);
26
27 HandleHardwareState(hwstate);
28
29 stime_t next_timeout = NO_DEADLINE;
30 LogHardwareStatePost(name, hwstate);
31 next_->SyncInterpret(hwstate, &next_timeout);
32 HandleTimeouts(next_timeout, timeout);
33 }
34
HandleTimerImpl(stime_t now,stime_t * timeout)35 void StuckButtonInhibitorFilterInterpreter::HandleTimerImpl(
36 stime_t now, stime_t* timeout) {
37 const char name[] = "StuckButtonInhibitorFilterInterpreter::HandleTimerImpl";
38 LogHandleTimerPre(name, now, timeout);
39
40 stime_t next_timeout = NO_DEADLINE;
41 if (next_expects_timer_) {
42 next_->HandleTimer(now, &next_timeout);
43 } else {
44 if (!sent_buttons_down_) {
45 Err("Bug: got callback, but no gesture to send.");
46 return;
47 } else {
48 Err("Mouse button seems stuck down. Sending button-up.");
49 auto button_change = Gesture(kGestureButtonsChange,
50 now, now, 0, sent_buttons_down_,
51 false); // is_tap
52 LogGestureProduce(name, button_change);
53 ProduceGesture(button_change);
54 sent_buttons_down_ = 0;
55 }
56 }
57 HandleTimeouts(next_timeout, timeout);
58 LogHandleTimerPost(name, now, timeout);
59 }
60
HandleHardwareState(const HardwareState & hwstate)61 void StuckButtonInhibitorFilterInterpreter::HandleHardwareState(
62 const HardwareState& hwstate) {
63 incoming_button_must_be_up_ =
64 hwstate.touch_cnt == 0 && hwstate.buttons_down == 0;
65 }
66
ConsumeGesture(const Gesture & gesture)67 void StuckButtonInhibitorFilterInterpreter::ConsumeGesture(
68 const Gesture& gesture) {
69 const char name[] = "StuckButtonInhibitorFilterInterpreter::ConsumeGesture";
70 LogGestureConsume(name, gesture);
71
72 if (gesture.type == kGestureTypeButtonsChange) {
73 Gesture result = gesture;
74 // process buttons going down
75 if (sent_buttons_down_ & result.details.buttons.down) {
76 Err("Odd. result is sending buttons down that are already down: "
77 "Existing down: %d. New down: %d. fixing.",
78 sent_buttons_down_, result.details.buttons.down);
79 result.details.buttons.down &= ~sent_buttons_down_;
80 }
81 sent_buttons_down_ |= result.details.buttons.down;
82 if ((~sent_buttons_down_) & result.details.buttons.up) {
83 Err("Odd. result is sending buttons up for buttons we didn't send down: "
84 "Existing down: %d. New up: %d.",
85 sent_buttons_down_, result.details.buttons.up);
86 result.details.buttons.up &= sent_buttons_down_;
87 }
88 sent_buttons_down_ &= ~result.details.buttons.up;
89 if (!result.details.buttons.up && !result.details.buttons.down)
90 return; // skip gesture
91 LogGestureProduce(name, result);
92 ProduceGesture(result);
93 } else {
94 LogGestureProduce(name, gesture);
95 ProduceGesture(gesture);
96 }
97 }
98
HandleTimeouts(stime_t next_timeout,stime_t * timeout)99 void StuckButtonInhibitorFilterInterpreter::HandleTimeouts(
100 stime_t next_timeout, stime_t* timeout) {
101 if (next_timeout >= 0.0) {
102 // next_ is doing stuff, so don't interfere
103 *timeout = next_timeout;
104 next_expects_timer_ = true;
105 } else {
106 next_expects_timer_ = false;
107 if (incoming_button_must_be_up_ && sent_buttons_down_) {
108 // We should lift the buttons before too long.
109 const stime_t kTimeoutLength = 1.0;
110 *timeout = kTimeoutLength;
111 }
112 }
113 }
114
115 } // namespace gestures
116