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(NULL, 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 HandleHardwareState(*hwstate);
24 stime_t next_timeout = NO_DEADLINE;
25 next_->SyncInterpret(hwstate, &next_timeout);
26 HandleTimeouts(next_timeout, timeout);
27 }
28
HandleTimerImpl(stime_t now,stime_t * timeout)29 void StuckButtonInhibitorFilterInterpreter::HandleTimerImpl(
30 stime_t now, stime_t* timeout) {
31 if (!next_expects_timer_) {
32 if (!sent_buttons_down_) {
33 Err("Bug: got callback, but no gesture to send.");
34 return;
35 } else {
36 Err("Mouse button seems stuck down. Sending button-up.");
37 ProduceGesture(Gesture(kGestureButtonsChange,
38 now, now, 0, sent_buttons_down_,
39 false)); // is_tap
40 sent_buttons_down_ = 0;
41 }
42 }
43 stime_t next_timeout = NO_DEADLINE;
44 next_->HandleTimer(now, &next_timeout);
45 HandleTimeouts(next_timeout, timeout);
46 }
47
HandleHardwareState(const HardwareState & hwstate)48 void StuckButtonInhibitorFilterInterpreter::HandleHardwareState(
49 const HardwareState& hwstate) {
50 incoming_button_must_be_up_ =
51 hwstate.touch_cnt == 0 && hwstate.buttons_down == 0;
52 }
53
ConsumeGesture(const Gesture & gesture)54 void StuckButtonInhibitorFilterInterpreter::ConsumeGesture(
55 const Gesture& gesture) {
56 if (gesture.type == kGestureTypeButtonsChange) {
57 Gesture result = gesture;
58 // process buttons going down
59 if (sent_buttons_down_ & result.details.buttons.down) {
60 Err("Odd. result is sending buttons down that are already down: "
61 "Existing down: %d. New down: %d. fixing.",
62 sent_buttons_down_, result.details.buttons.down);
63 result.details.buttons.down &= ~sent_buttons_down_;
64 }
65 sent_buttons_down_ |= result.details.buttons.down;
66 if ((~sent_buttons_down_) & result.details.buttons.up) {
67 Err("Odd. result is sending buttons up for buttons we didn't send down: "
68 "Existing down: %d. New up: %d.",
69 sent_buttons_down_, result.details.buttons.up);
70 result.details.buttons.up &= sent_buttons_down_;
71 }
72 sent_buttons_down_ &= ~result.details.buttons.up;
73 if (!result.details.buttons.up && !result.details.buttons.down)
74 return; // skip gesture
75 ProduceGesture(result);
76 } else {
77 ProduceGesture(gesture);
78 }
79 }
80
HandleTimeouts(stime_t next_timeout,stime_t * timeout)81 void StuckButtonInhibitorFilterInterpreter::HandleTimeouts(
82 stime_t next_timeout, stime_t* timeout) {
83 if (next_timeout >= 0.0) {
84 // next_ is doing stuff, so don't interfere
85 *timeout = next_timeout;
86 next_expects_timer_ = true;
87 } else {
88 next_expects_timer_ = false;
89 if (incoming_button_must_be_up_ && sent_buttons_down_) {
90 // We should lift the buttons before too long.
91 const stime_t kTimeoutLength = 1.0;
92 *timeout = kTimeoutLength;
93 }
94 }
95 }
96
97 } // namespace gestures
98