Skip to content

Commit 970fed3

Browse files
authored
Merge pull request #15 from LemLib/main
🔖 v0.1.0 Release!
2 parents 30e329f + 99897dc commit 970fed3

File tree

12 files changed

+609
-41
lines changed

12 files changed

+609
-41
lines changed

.devcontainer/devcontainer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"postCreateCommand": "chmod 777 .devcontainer/postCreateCommand.bash && .devcontainer/postCreateCommand.bash"
3-
}
2+
"postCreateCommand": "chmod 777 .devcontainer/postCreateCommand.bash && .devcontainer/postCreateCommand.bash && source ~/.bashrc"
3+
}

.devcontainer/postCreateCommand.bash

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,3 @@ curl https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-rm/10.3
66
tar -xjvf gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2
77
echo "PATH=$PATH:/home/codespace/gcc-arm-none-eabi-10.3-2021.10/bin" >> ~/.bashrc
88
popd
9-
source ~/.bashrc

.github/workflows/clang-format.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: test-clang-format
2+
3+
on:
4+
push:
5+
branches:
6+
- '*'
7+
pull_request:
8+
workflow_dispatch:
9+
10+
11+
jobs:
12+
build:
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- uses: actions/checkout@v2
17+
- uses: DoozyX/[email protected]
18+
with:
19+
source: './src/gamepad ./include/gamepad'
20+
extensions: 'hpp,cpp'
21+
clangFormatVersion: 18

.github/workflows/pr-comment.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
2727
const old_marker = new RegExp(marker.replace("\r\n", "\r?\n")).exec(old_body)?.[0] ?? marker;
2828
29-
body = old_body.split(old_marker)[0] + marker + body;
29+
body = (old_body ?? "").split(old_marker)[0] + marker + body;
3030
await github.request('PATCH /repos/{owner}/{repo}/pulls/{pull_number}', {
3131
owner: owner,
3232
repo: repo,

.github/workflows/pros-build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ jobs:
1313

1414
steps:
1515
- uses: actions/checkout@v4
16-
- uses: LemLib/pros-build@v1.0.0
16+
- uses: LemLib/pros-build@v2.0.2
1717
with:
1818
library-path: gamepad

include/gamepad/api.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#pragma once
2+
3+
#include "gamepad/event_handler.hpp" // IWYU pragma: export
4+
#include "gamepad/controller.hpp" // IWYU pragma: export

include/gamepad/controller.hpp

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
#pragma once
2+
3+
#include "pros/misc.h"
4+
#include <cstdint>
5+
#include <functional>
6+
#include <string>
7+
#ifndef PROS_USE_SIMPLE_NAMES
8+
#define PROS_USE_SIMPLE_NAMES
9+
#endif
10+
11+
#include "event_handler.hpp"
12+
#include "pros/misc.hpp"
13+
#include "pros/rtos.hpp"
14+
15+
namespace Gamepad {
16+
17+
enum EventType {
18+
ON_PRESS,
19+
ON_LONG_PRESS,
20+
ON_RELEASE,
21+
ON_SHORT_RELEASE,
22+
};
23+
24+
class Button {
25+
friend class Controller;
26+
public:
27+
/// Whether the button has just been pressed
28+
bool rising_edge = false;
29+
/// Whether the button has just been released
30+
bool falling_edge = false;
31+
/// Whether the button is currently held down
32+
bool is_pressed = false;
33+
/// How long the button has been held down
34+
uint32_t time_held = 0;
35+
/// How long the button has been released
36+
uint32_t time_released = 0;
37+
/// How long the threshold should be for the longPress and shortRelease events
38+
uint32_t long_press_threshold = 500;
39+
/**
40+
* @brief Register a function to run when the button is pressed.
41+
*
42+
* @param listenerName The name of the listener, this must be a unique name
43+
* @param func The function to run when the button is pressed, the function MUST NOT block
44+
* @return true The listener was successfully registered
45+
* @return false The listener was not successfully registered (there is already a listener with this name)
46+
*
47+
* @b Example:
48+
* @code {.cpp}
49+
* // Use a function...
50+
* Gamepad::master.Down.onPress("downPress1", downPress1);
51+
* // ...or a lambda
52+
* Gamepad::master.Up.onPress("upPress1", []() { std::cout << "I was pressed!" << std::endl; });
53+
* @endcode
54+
*/
55+
bool onPress(std::string listenerName, std::function<void(void)> func) const;
56+
/**
57+
* @brief Register a function to run when the button is long pressed.
58+
*
59+
* By default, onLongPress will fire when the button has been held down for
60+
* 500ms or more, this threshold can be adjusted by changing long_press_threshold.
61+
*
62+
* @warning When using this event along with onPress, both the onPress
63+
* and onlongPress listeners may fire together.
64+
*
65+
* @param listenerName The name of the listener, this must be a unique name
66+
* @param func The function to run when the button is long pressed, the function MUST NOT block
67+
* @return true The listener was successfully registered
68+
* @return false The listener was not successfully registered (there is already a listener with this name)
69+
*
70+
* @b Example:
71+
* @code {.cpp}
72+
* // Use a function...
73+
* Gamepad::master.Left.onLongPress("fireCatapult", fireCatapult);
74+
* // ...or a lambda
75+
* Gamepad::master.Right.onLongPress("print_right", []() { std::cout << "Right button was long pressed!" <<
76+
* std::endl; });
77+
* @endcode
78+
*/
79+
bool onLongPress(std::string listenerName, std::function<void(void)> func) const;
80+
/**
81+
* @brief Register a function to run when the button is released.
82+
*
83+
* @param listenerName The name of the listener, this must be a unique name
84+
* @param func The function to run when the button is released, the function MUST NOT block
85+
* @return true The listener was successfully registered
86+
* @return false The listener was not successfully registered (there is already a listener with this name)
87+
*
88+
* @b Example:
89+
* @code {.cpp}
90+
* // Use a function...
91+
* Gamepad::master.X.onRelease("stopFlywheel", stopFlywheel);
92+
* // ...or a lambda
93+
* Gamepad::master.Y.onRelease("stopIntake", []() { intake.move(0); });
94+
* @endcode
95+
*/
96+
bool onRelease(std::string listenerName, std::function<void(void)> func) const;
97+
/**
98+
* @brief Register a function to run when the button is short released.
99+
*
100+
* By default, shortRelease will fire when the button has been released before 500ms, this threshold can be
101+
* adjusted by changing long_press_threshold.
102+
*
103+
* @note This event will most likely be used along with the longPress event.
104+
*
105+
* @param listenerName The name of the listener, this must be a unique name
106+
* @param func The function to run when the button is short released, the function MUST NOT block
107+
* @return true The listener was successfully registered
108+
* @return false The listener was not successfully registered (there is already a listener with this name)
109+
*
110+
* @b Example:
111+
* @code {.cpp}
112+
* // Use a function...
113+
* Gamepad::master.A.onShortRelease("raiseLiftOneLevel", raiseLiftOneLevel);
114+
* // ...or a lambda
115+
* Gamepad::master.B.onShortRelease("intakeOnePicce", []() { intake.move_relative(600, 100); });
116+
* @endcode
117+
*/
118+
bool onShortRelease(std::string listenerName, std::function<void(void)> func) const;
119+
/**
120+
* @brief Register a function to run for a given event.
121+
*
122+
* @param event Which event to register the listener on.
123+
* @param listenerName The name of the listener, this must be a unique name
124+
* @param func The function to run for the given event, the function MUST NOT block
125+
* @return true The listener was successfully registered
126+
* @return false The listener was not successfully registered (there is already a listener with this name)
127+
*
128+
* @b Example:
129+
* @code {.cpp}
130+
* // Use a function...
131+
* Gamepad::master.L1.addListener(Gamepad::ON_PRESS, "start_spin", startSpin);
132+
* // ...or a lambda
133+
* Gamepad::master.L1.addListener(Gamepad::ON_RELEASE, "stop_spin", []() { motor1.brake(); });
134+
* @endcode
135+
*/
136+
bool addListener(EventType event, std::string listenerName, std::function<void(void)> func) const;
137+
/**
138+
* @brief Removes a listener from the button
139+
* @warning Usage of this function is discouraged.
140+
*
141+
* @param listenerName The name of the listener to remove
142+
* @return true The specified listener was successfully removed
143+
* @return false The specified listener could not be removed
144+
*
145+
* @b Example:
146+
* @code {.cpp}
147+
* // Add an event listener...
148+
* Gamepad::master.L1.addListener(Gamepad::ON_PRESS, "do_something", doSomething);
149+
* // ...and now get rid of it
150+
* Gamepad::master.L1.removeListener("do_something");
151+
* @endcode
152+
*/
153+
bool removeListener(std::string listenerName) const;
154+
155+
/**
156+
* @brief Returns a value indicating whether the button is currently being held.
157+
*
158+
* @return true The button is currently pressed
159+
* @return false The button is not currently pressed
160+
*/
161+
explicit operator bool() const { return is_pressed; }
162+
private:
163+
/**
164+
* @brief Updates the button and runs any event handlers, if necessary
165+
*
166+
* @param is_held Whether or not the button is currently held down
167+
*/
168+
void update(bool is_held);
169+
/// he last time the update function was called
170+
uint32_t last_update_time = pros::millis();
171+
/// The last time the long press event was fired
172+
uint32_t last_long_press_time = 0;
173+
mutable _impl::EventHandler<std::string> onPressEvent {};
174+
mutable _impl::EventHandler<std::string> onLongPressEvent {};
175+
mutable _impl::EventHandler<std::string> onReleaseEvent {};
176+
mutable _impl::EventHandler<std::string> onShortReleaseEvent {};
177+
};
178+
179+
class Controller {
180+
public:
181+
/**
182+
* @brief Updates the state of the gamepad (all joysticks and buttons), and also runs
183+
* any registered listeners.
184+
*
185+
* @note This function should be called at the beginning of every loop iteration.
186+
*
187+
* @b Example:
188+
* @code {.cpp}
189+
* while (true) {
190+
* Gamepad::master.update();
191+
* // do robot control stuff here...
192+
* pros::delay(25);
193+
* }
194+
* @endcode
195+
*
196+
*/
197+
void update();
198+
/**
199+
* @brief Get the state of a button on the controller.
200+
*
201+
* @param button Which button to return
202+
*
203+
* @b Example:
204+
* @code {.cpp}
205+
* if(Gamepad::master[DIGITAL_L1]) {
206+
* // do something here...
207+
* }
208+
* @endcode
209+
*
210+
*/
211+
const Button& operator[](pros::controller_digital_e_t button);
212+
/**
213+
* @brief Get the value of a joystick axis on the controller.
214+
*
215+
* @param joystick Which joystick axis to return
216+
*
217+
* @b Example:
218+
* @code {.cpp}
219+
* // control a motor with a joystick
220+
* intake.move(Gamepad::master[ANALOG_RIGHT_Y]);
221+
* @endcode
222+
*
223+
*/
224+
float operator[](pros::controller_analog_e_t joystick);
225+
const Button& L1 {m_L1};
226+
const Button& L2 {m_L2};
227+
const Button& R1 {m_R1};
228+
const Button& R2 {m_R2};
229+
const Button& Up {m_Up};
230+
const Button& Down {m_Down};
231+
const Button& Left {m_Left};
232+
const Button& Right {m_Right};
233+
const Button& X {m_X};
234+
const Button& B {m_B};
235+
const Button& Y {m_Y};
236+
const Button& A {m_A};
237+
const float& LeftX = m_LeftX;
238+
const float& LeftY = m_LeftY;
239+
const float& RightX = m_RightX;
240+
const float& RightY = m_RightY;
241+
/// The master controller, same as @ref Gamepad::master
242+
static Controller master;
243+
/// The partner controller, same as @ref Gamepad::partner
244+
static Controller partner;
245+
private:
246+
Controller(pros::controller_id_e_t id)
247+
: controller(id) {}
248+
249+
Button m_L1 {}, m_L2 {}, m_R1 {}, m_R2 {}, m_Up {}, m_Down {}, m_Left {}, m_Right {}, m_X {}, m_B {}, m_Y {},
250+
m_A {};
251+
float m_LeftX = 0, m_LeftY = 0, m_RightX = 0, m_RightY = 0;
252+
Button Fake {};
253+
/**
254+
* @brief Gets a unique name for a listener that will not conflict with user listener names.
255+
*
256+
* @important: when using the function, you must register the listener by
257+
* directly calling add_listener on the EventHandler, do NOT use onPress/addListener,etc.
258+
*
259+
* @return std::string A unique listener name
260+
*/
261+
static std::string unique_name();
262+
static Button Controller::*button_to_ptr(pros::controller_digital_e_t button);
263+
void updateButton(pros::controller_digital_e_t button_id);
264+
pros::Controller controller;
265+
};
266+
267+
inline Controller Controller::master {pros::E_CONTROLLER_MASTER};
268+
inline Controller Controller::partner {pros::E_CONTROLLER_PARTNER};
269+
/// The master controller
270+
inline Controller& master = Controller::master;
271+
/// The partner controller
272+
inline Controller& partner = Controller::partner;
273+
274+
} // namespace Gamepad

0 commit comments

Comments
 (0)