Skip to content

Commit

Permalink
feat: ✨ Add names to button listeners
Browse files Browse the repository at this point in the history
  • Loading branch information
ion098 committed Jul 5, 2024
1 parent 1832d76 commit fb93b84
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 76 deletions.
17 changes: 9 additions & 8 deletions include/gamepad/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <cstdint>
#include <functional>
#include <string>
#ifndef PROS_USE_SIMPLE_NAMES
#define PROS_USE_SIMPLE_NAMES
#endif
Expand Down Expand Up @@ -30,21 +31,21 @@ class Button {
uint32_t time_released = 0;
uint32_t long_press_threshold = 500;

uint32_t onPress(std::function<void(void)> func) const;
uint32_t onLongPress(std::function<void(void)> func) const;
uint32_t onRelease(std::function<void(void)> func) const;
uint32_t addListener(EventType event, std::function<void(void)> func) const;
bool removeListener(uint32_t id) const;
bool onPress(std::string listenerName, std::function<void(void)> func) const;
bool onLongPress(std::string listenerName, std::function<void(void)> func) const;
bool onRelease(std::string listenerName, std::function<void(void)> func) const;
bool addListener(EventType event, std::string listenerName, std::function<void(void)> func) const;
bool removeListener(std::string listenerName) const;

explicit operator bool() const { return is_pressed; }
private:
void update(bool is_held);

uint32_t last_update_time = pros::millis();
mutable EventHandler<> onPressEvent {};
mutable EventHandler<std::string> onPressEvent {};
uint32_t last_long_press_time = 0;
mutable EventHandler<> onLongPressEvent {};
mutable EventHandler<> onReleaseEvent {};
mutable EventHandler<std::string> onLongPressEvent {};
mutable EventHandler<std::string> onReleaseEvent {};
};

class Controller {
Expand Down
44 changes: 19 additions & 25 deletions include/gamepad/event_handler.hpp
Original file line number Diff line number Diff line change
@@ -1,42 +1,35 @@
#pragma once

#include <mutex>
#include <utility>
#include <functional>
#include <map>
#include <atomic>
#include <vector>
#include <algorithm>

#include "gamepad/recursive_mutex.hpp"

namespace Gamepad {

class MonotonicCounter {
template <typename... Args> friend class EventHandler;

static uint32_t next_value() {
static std::atomic<uint32_t> counter = 0;
return ++counter;
}
};

template <typename... Args> class EventHandler {
template <typename Key, typename... Args> class EventHandler {
public:
using Listener = std::function<void(Args...)>;

uint32_t add_listener(Listener func) {
bool add_listener(Key key, Listener func) {
std::lock_guard lock(mutex);
uint32_t id = MonotonicCounter::next_value();
listeners.emplace(id, std::move(func));
return id;
if (std::find(keys.begin(), keys.end(), key) == keys.end()) return false;
keys.push_back(key);
listeners.push_back(func);
return true;
}

bool remove_listener(uint32_t id) {
bool remove_listener(Key key) {
std::lock_guard lock(mutex);
if (listeners.find(id) == listeners.end()) {
return false;
auto i = std::find(keys.begin(), keys.end(), key);
if (i != keys.end()) {
keys.erase(i);
listeners.erase(listeners.begin() + (i - keys.begin()));
return true;
}
listeners.erase(id);
return true;
return false;
}

bool is_empty() {
Expand All @@ -46,10 +39,11 @@ template <typename... Args> class EventHandler {

void fire(Args... args) {
std::lock_guard lock(mutex);
for (auto listener : listeners) { listener.second(args...); }
for (auto listener : listeners) { listener(args...); }
}
private:
std::map<uint32_t, Listener> listeners;
Gamepad::RecursiveMutex mutex;
std::vector<Key> keys {};
std::vector<Listener> listeners {};
Gamepad::RecursiveMutex mutex {};
};
} // namespace Gamepad
28 changes: 14 additions & 14 deletions src/gamepad/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,33 @@

namespace Gamepad {

uint32_t Button::onPress(std::function<void(void)> func) const {
return this->onPressEvent.add_listener(std::move(func));
bool Button::onPress(std::string listenerName, std::function<void(void)> func) const {
return this->onPressEvent.add_listener(std::move(listenerName), std::move(func));
}

uint32_t Button::onLongPress(std::function<void(void)> func) const {
return this->onLongPressEvent.add_listener(std::move(func));
bool Button::onLongPress(std::string listenerName, std::function<void(void)> func) const {
return this->onLongPressEvent.add_listener(std::move(listenerName), std::move(func));
}

uint32_t Button::onRelease(std::function<void(void)> func) const {
return this->onReleaseEvent.add_listener(std::move(func));
bool Button::onRelease(std::string listenerName, std::function<void(void)> func) const {
return this->onReleaseEvent.add_listener(std::move(listenerName), std::move(func));
}

uint32_t Button::addListener(EventType event, std::function<void(void)> func) const {
bool Button::addListener(EventType event, std::string listenerName, std::function<void(void)> func) const {
switch (event) {
case Gamepad::EventType::ON_PRESS: return this->onPress(std::move(func));
case Gamepad::EventType::ON_LONG_PRESS: return this->onLongPress(std::move(func));
case Gamepad::EventType::ON_RELEASE: return this->onRelease(std::move(func));
case Gamepad::EventType::ON_PRESS: return this->onPress(std::move(listenerName), std::move(func));
case Gamepad::EventType::ON_LONG_PRESS: return this->onLongPress(std::move(listenerName), std::move(func));
case Gamepad::EventType::ON_RELEASE: return this->onRelease(std::move(listenerName), std::move(func));
default:
TODO("add error logging")
errno = EINVAL;
return 0;
return false;
}
}

bool Button::removeListener(uint32_t id) const {
return this->onPressEvent.remove_listener(id) || this->onLongPressEvent.remove_listener(id) ||
this->onReleaseEvent.remove_listener(id);
bool Button::removeListener(std::string listenerName) const {
return this->onPressEvent.remove_listener(listenerName) || this->onLongPressEvent.remove_listener(listenerName) ||
this->onReleaseEvent.remove_listener(listenerName);
}

void Button::update(const bool is_held) {
Expand Down
45 changes: 16 additions & 29 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ Gamepad::Controller master(CONTROLLER_MASTER);
* All other competition modes are blocked by initialize; it is recommended
* to keep execution time for this mode under a few seconds.
*/
void initialize() {
}
void initialize() {}

/**
* Runs while the robot is in the disabled state of Field Management System or
Expand Down Expand Up @@ -58,31 +57,19 @@ void autonomous() {}
* task, not resume it from where it left off.
*/
void opcontrol() {
master.Down.onPress([](){
printf("Down Press!\n");
});
master.Down.onLongPress([](){
printf("Down longPress!\n");
});
master.Down.onRelease([](){
printf("Down Release!\n");
});
master.Up.onPress([](){
printf("Up Press!\n");
});
master.Up.onLongPress([](){
printf("Up longPress!\n");
});
auto i = master.Up.onRelease([](){
printf("Up Release!\n");
});
master.Up.onRelease([=](){
master.Up.removeListener(i);
printf("Up Release 2!\n");
});
while (true) {
master.update();
pros::screen::print(TEXT_MEDIUM, 3, "%f %f %f %f", master.LeftX, master.LeftY, master.RightX, master.RightY);
pros::delay(20);
}
master.Down.onPress("downPress1", []() { printf("Down Press!\n"); });
master.Down.onLongPress("downLongPress1", []() { printf("Down longPress!\n"); });
master.Down.onRelease("downRelease1", []() { printf("Down Release!\n"); });
master.Up.onPress("uppress1", []() { printf("Up Press!\n"); });
master.Up.onLongPress("upLongPress1", []() { printf("Up longPress!\n"); });
master.Up.onRelease("upRelease1", []() { printf("Up Release!\n"); });
master.Up.onRelease("upRelease2", [=]() {
master.Up.removeListener("upRelease1");
printf("Up Release 2!\n");
});
while (true) {
master.update();
pros::screen::print(TEXT_MEDIUM, 3, "%f %f %f %f", master.LeftX, master.LeftY, master.RightX, master.RightY);
pros::delay(20);
}
}

0 comments on commit fb93b84

Please sign in to comment.