1
+ #pragma once
2
+
3
+ #include < cstdint>
4
+ #include < functional>
5
+ #include < string>
6
+
7
+ #include " event_handler.hpp"
8
+
9
+ namespace gamepad {
10
+ enum EventType {
11
+ ON_PRESS,
12
+ ON_LONG_PRESS,
13
+ ON_RELEASE,
14
+ ON_SHORT_RELEASE,
15
+ ON_LONG_RELEASE,
16
+ ON_REPEAT_PRESS,
17
+ };
18
+
19
+ class Button {
20
+ friend class Gamepad ;
21
+ public:
22
+ // / Whether the button has just been pressed
23
+ bool rising_edge = false ;
24
+ // / Whether the button has just been released
25
+ bool falling_edge = false ;
26
+ // / Whether the button is currently held down
27
+ bool is_pressed = false ;
28
+ // / How long the button has been held down
29
+ uint32_t time_held = 0 ;
30
+ // / How long the button has been released
31
+ uint32_t time_released = 0 ;
32
+ // / How many times the button has been repeat-pressed
33
+ uint32_t repeat_iterations = 0 ;
34
+ /* *
35
+ * @brief Set the time for a press to be considered a long press for the button
36
+ *
37
+ * @note this is likely to be used with the onLongPress(), onShortRelease(), onLongRelease(), or onRepeatPress()
38
+ * events
39
+ *
40
+ * @param threshold the time in ms that would be considered a long press
41
+ *
42
+ * @b Example:
43
+ * @code {.cpp}
44
+ * // change the threshold
45
+ * gamepad::master.Left.set_long_press_threshold(5000);
46
+ * // then call the function
47
+ * gamepad::master.Left.onLongPress("longPress1", []() {
48
+ * std::cout << "I was held for 5000ms instead of the 500ms default!" << std::endl;
49
+ * });
50
+ * @endcode
51
+ */
52
+ void set_long_press_threshold (uint32_t threshold) const ;
53
+ /* *
54
+ * @brief Set the interval for the repeatPress event to repeat
55
+ *
56
+ * @note this is likely to be used with the onRepeatPress() event
57
+ *
58
+ * @param cooldown the interval in ms
59
+ *
60
+ * @b Example:
61
+ * @code {.cpp}
62
+ * // change the threshold
63
+ * gamepad::master.Up.set_repeat_cooldown(100);
64
+ * // then call the function
65
+ * gamepad::master.Up.onRepeatPress("repeatPress1", []() {
66
+ * std::cout << "I'm being repeated every 100ms instead of the 50ms default!" << std::endl;
67
+ * });
68
+ * @endcode
69
+ */
70
+ void set_repeat_cooldown (uint32_t cooldown) const ;
71
+ /* *
72
+ * @brief Register a function to run when the button is pressed.
73
+ *
74
+ * @param listenerName The name of the listener, this must be a unique name
75
+ * @param func The function to run when the button is pressed, the function MUST NOT block
76
+ * @return true The listener was successfully registered
77
+ * @return false The listener was not successfully registered (there is already a listener with this name)
78
+ *
79
+ * @b Example:
80
+ * @code {.cpp}
81
+ * // Use a function...
82
+ * gamepad::master.Down.onPress("downPress1", downPress1);
83
+ * // ...or a lambda
84
+ * gamepad::master.Up.onPress("upPress1", []() { std::cout << "I was pressed!" << std::endl; });
85
+ * @endcode
86
+ */
87
+ bool onPress (std::string listenerName, std::function<void (void )> func) const ;
88
+ /* *
89
+ * @brief Register a function to run when the button is long pressed.
90
+ *
91
+ * By default, onLongPress will fire when the button has been held down for
92
+ * 500ms or more, this threshold can be adjusted via the set_long_press_threshold() method.
93
+ *
94
+ * @warning When using this event along with onPress, both the onPress
95
+ * and onlongPress listeners may fire together.
96
+ *
97
+ * @param listenerName The name of the listener, this must be a unique name
98
+ * @param func The function to run when the button is long pressed, the function MUST NOT block
99
+ * @return true The listener was successfully registered
100
+ * @return false The listener was not successfully registered (there is already a listener with this name)
101
+ *
102
+ * @b Example:
103
+ * @code {.cpp}
104
+ * // Use a function...
105
+ * gamepad::master.Left.onLongPress("fireCatapult", fireCatapult);
106
+ * // ...or a lambda
107
+ * gamepad::master.Right.onLongPress("print_right", []() { std::cout << "Right button was long pressed!" <<
108
+ * std::endl; });
109
+ * @endcode
110
+ */
111
+ bool onLongPress (std::string listenerName, std::function<void (void )> func) const ;
112
+ /* *
113
+ * @brief Register a function to run when the button is released.
114
+ *
115
+ * @param listenerName The name of the listener, this must be a unique name
116
+ * @param func The function to run when the button is released, the function MUST NOT block
117
+ * @return true The listener was successfully registered
118
+ * @return false The listener was not successfully registered (there is already a listener with this name)
119
+ *
120
+ * @b Example:
121
+ * @code {.cpp}
122
+ * // Use a function...
123
+ * gamepad::master.X.onRelease("stopFlywheel", stopFlywheel);
124
+ * // ...or a lambda
125
+ * gamepad::master.Y.onRelease("stopIntake", []() { intake.move(0); });
126
+ * @endcode
127
+ */
128
+ bool onRelease (std::string listenerName, std::function<void (void )> func) const ;
129
+ /* *
130
+ * @brief Register a function to run when the button is short released.
131
+ *
132
+ * By default, shortRelease will fire when the button has been released before 500ms, this threshold can be
133
+ * adjusted via the set_long_press_threshold() method.
134
+ *
135
+ * @note This event will most likely be used along with the longPress event.
136
+ *
137
+ * @param listenerName The name of the listener, this must be a unique name
138
+ * @param func The function to run when the button is short released, the function MUST NOT block
139
+ * @return true The listener was successfully registered
140
+ * @return false The listener was not successfully registered (there is already a listener with this name)
141
+ *
142
+ * @b Example:
143
+ * @code {.cpp}
144
+ * // Use a function...
145
+ * gamepad::master.A.onShortRelease("raiseLiftOneLevel", raiseLiftOneLevel);
146
+ * // ...or a lambda
147
+ * gamepad::master.B.onShortRelease("intakeOnePiece", []() { intake.move_relative(600, 100); });
148
+ * @endcode
149
+ */
150
+ bool onShortRelease (std::string listenerName, std::function<void (void )> func) const ;
151
+ /* *
152
+ * @brief Register a function to run when the button is long released.
153
+ *
154
+ * By default, longRelease will fire when the button has been released after 500ms, this threshold can be
155
+ * adjusted via the set_long_press_threshold() method.
156
+ *
157
+ * @param listenerName The name of the listener, this must be a unique name
158
+ * @param func The function to run when the button is long released, the function MUST NOT block
159
+ * @return true The listener was successfully registered
160
+ * @return false The listener was not successfully registered (there is already a listener with this name)
161
+ *
162
+ * @b Example:
163
+ * @code {.cpp}
164
+ * // Use a function...
165
+ * gamepad::master.Up.onLongRelease("moveLiftToGround", moveLiftToGround);
166
+ * // ...or a lambda
167
+ * gamepad::master.Left.onLongRelease("spinIntake", []() { intake.move(127); });
168
+ * @endcode
169
+ *
170
+ */
171
+ bool onLongRelease (std::string listenerName, std::function<void (void )> func) const ;
172
+ /* *
173
+ * @brief Register a function to run periodically after its been held
174
+ *
175
+ * By default repeatPress will start repeating after 500ms and repeat every 50ms, this can be adjusted via the
176
+ * set_long_press_threshold() and set_repeat_cooldown() methods respectively
177
+ *
178
+ * @param listenerName The name of the listener, this must be a unique name
179
+ * @param func the function to run periodically when the button is held, the function MUST NOT block
180
+ * @return true The listener was successfully registered
181
+ * @return false The listener was not successfully registered (there is already a listener with this name)
182
+ *
183
+ * @b Example:
184
+ * @code {.cpp}
185
+ * // Use a function...
186
+ * gamepad::master.X.onRepeatPress("shootDisk", shootOneDisk);
187
+ * // ...or a lambda
188
+ * gamepad::master.A.onRepeatPress("scoreOneRing", []() { intake.move_relative(200, 100); });
189
+ * @endcode
190
+ *
191
+ */
192
+ bool onRepeatPress (std::string listenerName, std::function<void (void )> func) const ;
193
+ /* *
194
+ * @brief Register a function to run for a given event.
195
+ *
196
+ * @param event Which event to register the listener on.
197
+ * @param listenerName The name of the listener, this must be a unique name
198
+ * @param func The function to run for the given event, the function MUST NOT block
199
+ * @return true The listener was successfully registered
200
+ * @return false The listener was not successfully registered (there is already a listener with this name)
201
+ *
202
+ * @b Example:
203
+ * @code {.cpp}
204
+ * // Use a function...
205
+ * gamepad::master.L1.addListener(gamepad::ON_PRESS, "start_spin", startSpin);
206
+ * // ...or a lambda
207
+ * gamepad::master.L1.addListener(gamepad::ON_RELEASE, "stop_spin", []() { motor1.brake(); });
208
+ * @endcode
209
+ */
210
+ bool addListener (EventType event, std::string listenerName, std::function<void (void )> func) const ;
211
+ /* *
212
+ * @brief Removes a listener from the button
213
+ * @warning Usage of this function is discouraged.
214
+ *
215
+ * @param listenerName The name of the listener to remove
216
+ * @return true The specified listener was successfully removed
217
+ * @return false The specified listener could not be removed
218
+ *
219
+ * @b Example:
220
+ * @code {.cpp}
221
+ * // Add an event listener...
222
+ * gamepad::master.L1.addListener(gamepad::ON_PRESS, "do_something", doSomething);
223
+ * // ...and now get rid of it
224
+ * gamepad::master.L1.removeListener("do_something");
225
+ * @endcode
226
+ */
227
+ bool removeListener (std::string listenerName) const ;
228
+
229
+ /* *
230
+ * @brief Returns a value indicating whether the button is currently being held.
231
+ *
232
+ * @return true The button is currently pressed
233
+ * @return false The button is not currently pressed
234
+ */
235
+ explicit operator bool () const { return is_pressed; }
236
+ private:
237
+ /* *
238
+ * @brief Updates the button and runs any event handlers, if necessary
239
+ *
240
+ * @param is_held Whether or not the button is currently held down
241
+ */
242
+ void update (bool is_held);
243
+ // / How long the threshold should be for the longPress and shortRelease events
244
+ mutable uint32_t long_press_threshold = 500 ;
245
+ // / How often repeatPress is called
246
+ mutable uint32_t repeat_cooldown = 50 ;
247
+ // / The last time the update function was called
248
+ uint32_t last_update_time = pros::millis();
249
+ // / The last time the long press event was fired
250
+ uint32_t last_long_press_time = 0 ;
251
+ // / The last time the repeat event was called
252
+ uint32_t last_repeat_time = 0 ;
253
+ mutable _impl::EventHandler<std::string> onPressEvent {};
254
+ mutable _impl::EventHandler<std::string> onLongPressEvent {};
255
+ mutable _impl::EventHandler<std::string> onReleaseEvent {};
256
+ mutable _impl::EventHandler<std::string> onShortReleaseEvent {};
257
+ mutable _impl::EventHandler<std::string> onLongReleaseEvent {};
258
+ mutable _impl::EventHandler<std::string> onRepeatPressEvent {};
259
+ };
260
+ } // namespace gamepad
0 commit comments