@@ -33,6 +33,7 @@ class HardwareButtons(Singleton):
33
33
KEY2_PIN = 12
34
34
KEY3_PIN = 8
35
35
36
+
36
37
@classmethod
37
38
def get_instance (cls ):
38
39
# This is the only way to access the one and only instance
@@ -53,8 +54,6 @@ def get_instance(cls):
53
54
cls ._instance .GPIO = GPIO
54
55
cls ._instance .override_ind = False
55
56
56
- cls ._instance .add_events ([HardwareButtonsConstants .KEY_UP , HardwareButtonsConstants .KEY_DOWN , HardwareButtonsConstants .KEY_PRESS , HardwareButtonsConstants .KEY_LEFT , HardwareButtonsConstants .KEY_RIGHT , HardwareButtonsConstants .KEY1 , HardwareButtonsConstants .KEY2 , HardwareButtonsConstants .KEY3 ])
57
-
58
57
# Track state over time so we can apply input delays/ignores as needed
59
58
cls ._instance .cur_input = None # Track which direction or button was last pressed
60
59
cls ._instance .cur_input_started = None # Track when that input began
@@ -65,25 +64,30 @@ def get_instance(cls):
65
64
return cls ._instance
66
65
67
66
68
-
69
67
@classmethod
70
68
def get_instance_no_hardware (cls ):
71
69
# This is the only way to access the one and only instance
72
70
if cls ._instance is None :
73
71
cls ._instance = cls .__new__ (cls )
74
72
75
73
74
+ def wait_for (self , keys = []) -> int :
75
+ """
76
+ Block execution until one of the target keys is pressed.
76
77
77
- def wait_for (self , keys = [], check_release = True , release_keys = []) -> int :
78
+ Optionally override the wait by calling `trigger_override()`.
79
+ """
78
80
# TODO: Refactor to keep control in the Controller and not here
79
81
from seedsigner .controller import Controller
80
82
controller = Controller .get_instance ()
81
-
82
- if not release_keys :
83
- release_keys = keys
84
83
self .override_ind = False
85
84
86
85
while True :
86
+ if self .override_ind :
87
+ # Break out of the wait_for without waiting for user input
88
+ self .override_ind = False
89
+ return HardwareButtonsConstants .OVERRIDE
90
+
87
91
cur_time = int (time .time () * 1000 )
88
92
if cur_time - self .last_input_time > controller .screensaver_activation_ms and not controller .is_screensaver_running :
89
93
# Start the screensaver. Will block execution until input detected.
@@ -99,48 +103,42 @@ def wait_for(self, keys=[], check_release=True, release_keys=[]) -> int:
99
103
# Resume from a fresh loop
100
104
continue
101
105
106
+ # Check each candidate key to see if it was pressed
102
107
for key in keys :
103
- if not check_release or ((check_release and key in release_keys and HardwareButtonsConstants .release_lock ) or check_release and key not in release_keys ):
104
- # when check release is False or the release lock is released (True)
105
- if self .GPIO .input (key ) == GPIO .LOW or self .override_ind :
106
- HardwareButtonsConstants .release_lock = False
107
- if self .override_ind :
108
- self .override_ind = False
109
- return HardwareButtonsConstants .OVERRIDE
110
-
111
- if self .cur_input != key :
112
- self .cur_input = key
113
- self .cur_input_started = int (time .time () * 1000 ) # in milliseconds
114
- self .last_input_time = self .cur_input_started
108
+ if self .GPIO .input (key ) == GPIO .LOW :
109
+ if self .cur_input != key :
110
+ self .cur_input = key
111
+ self .cur_input_started = int (time .time () * 1000 ) # in milliseconds
112
+ self .last_input_time = self .cur_input_started
113
+ return key
114
+
115
+ else :
116
+ # Still pressing the same input
117
+ if cur_time - self .last_input_time > self .next_repeat_threshold :
118
+ # Too much time has elapsed to consider this the same
119
+ # continuous input. Treat as a new separate press.
120
+ self .cur_input_started = cur_time
121
+ self .last_input_time = cur_time
122
+ return key
123
+
124
+ elif cur_time - self .cur_input_started > self .first_repeat_threshold :
125
+ # We're good to relay this immediately as continuous
126
+ # input.
127
+ self .last_input_time = cur_time
115
128
return key
116
129
117
130
else :
118
- # Still pressing the same input
119
- if cur_time - self .last_input_time > self .next_repeat_threshold :
120
- # Too much time has elapsed to consider this the same
121
- # continuous input. Treat as a new separate press.
122
- self .cur_input_started = cur_time
123
- self .last_input_time = cur_time
124
- return key
125
-
126
- elif cur_time - self .cur_input_started > self .first_repeat_threshold :
127
- # We're good to relay this immediately as continuous
128
- # input.
129
- self .last_input_time = cur_time
130
- return key
131
-
132
- else :
133
- # We're not yet at the first repeat threshold; triggering
134
- # a key now would be too soon and yields a bad user
135
- # experience when only a single click was intended but
136
- # a second input is processed because of race condition
137
- # against human response time to release the button.
138
- # So there has to be a delay before we allow the first
139
- # continuous repeat to register. So we'll ignore this
140
- # round's input and **won't update any of our
141
- # timekeeping vars**. But once we cross the threshold,
142
- # we let the repeats fly.
143
- pass
131
+ # We're not yet at the first repeat threshold; triggering
132
+ # a key now would be too soon and yields a bad user
133
+ # experience when only a single click was intended but
134
+ # a second input is processed because of race condition
135
+ # against human response time to release the button.
136
+ # So there has to be a delay before we allow the first
137
+ # continuous repeat to register. So we'll ignore this
138
+ # round's input and **won't update any of our
139
+ # timekeeping vars**. But once we cross the threshold,
140
+ # we let the repeats fly.
141
+ pass
144
142
145
143
time .sleep (0.01 ) # wait 10 ms to give CPU chance to do other things
146
144
@@ -149,29 +147,13 @@ def update_last_input_time(self):
149
147
self .last_input_time = int (time .time () * 1000 )
150
148
151
149
152
- def add_events (self , keys = []):
153
- for key in keys :
154
- GPIO .add_event_detect (key , self .GPIO .RISING , callback = HardwareButtons .rising_callback )
155
-
150
+ def trigger_override (self ) -> bool :
151
+ """ Set the override flag to break out of the current `wait_for` loop """
152
+ self .override_ind = True
156
153
157
- def rising_callback (channel ):
158
- HardwareButtonsConstants .release_lock = True
159
-
160
-
161
- def trigger_override (self , force_release = False ) -> bool :
162
- if force_release :
163
- HardwareButtonsConstants .release_lock = True
164
-
165
- if not self .override_ind :
166
- self .override_ind = True
167
- return True
168
- return False
169
-
170
- def force_release (self ) -> bool :
171
- HardwareButtonsConstants .release_lock = True
172
- return True
173
154
174
155
def check_for_low (self , key : int = None , keys : List [int ] = None ) -> bool :
156
+ """ Returns True if one of the target keys/key is pressed """
175
157
if key :
176
158
keys = [key ]
177
159
for key in keys :
@@ -181,15 +163,16 @@ def check_for_low(self, key: int = None, keys: List[int] = None) -> bool:
181
163
else :
182
164
return False
183
165
166
+
184
167
def has_any_input (self ) -> bool :
168
+ """ Returns True if any of the keys are pressed """
185
169
for key in HardwareButtonsConstants .ALL_KEYS :
186
170
if self .GPIO .input (key ) == GPIO .LOW :
187
171
return True
188
172
return False
189
173
174
+
190
175
# class used as short hand for static button/channel lookup values
191
- # TODO: Implement `release_lock` functionality as a global somewhere. Mixes up design
192
- # patterns to have a static constants class plus a settable global value.
193
176
class HardwareButtonsConstants :
194
177
if GPIO .RPI_INFO ['P1_REVISION' ] == 3 : #This indicates that we have revision 3 GPIO
195
178
KEY_UP = 31
@@ -227,5 +210,3 @@ class HardwareButtonsConstants:
227
210
228
211
KEYS__LEFT_RIGHT_UP_DOWN = [KEY_LEFT , KEY_RIGHT , KEY_UP , KEY_DOWN ]
229
212
KEYS__ANYCLICK = [KEY_PRESS , KEY1 , KEY2 , KEY3 ]
230
-
231
- release_lock = True # released when True, locked when False
0 commit comments