#ifndef BUTTON_h #define BUTTON_h class Button { private: int _pin; int _id; bool _state; volatile bool _inputFlag = false; bool _changeFlag = false; bool _pressedFlag = false; bool _holdFlag = false; unsigned long _previousTimer; int _clickInterval = 1000; int _holdInterval = 1000; int _repeatInterval = 1000; void (*_cb)(Button*, uint8_t, bool); // Callback function bool _read() { return digitalRead(_pin); } void _setClickInterval(int x) { _clickInterval = x; } void _setHoldInterval(int x) { _holdInterval = x; } void _setRepeatInterval(int x) { _repeatInterval = x; } public: // Public members: static const uint8_t kEventPressed = 0; // Button was pressed static const uint8_t kEventReleased = 1; // Button was released static const uint8_t kEventClicked = 2; // Button was clicked (pressed and released within _clickInterval) static const uint8_t kEventHeld = 3; // Button was held down for longer than _holdInterval static const uint8_t kEventTick = 4; // Event released every _repeatInterval when button held // Public functions: Button(int pin, int id = 99) : _pin(pin), _id(id) { pinMode(_pin, INPUT_PULLUP); _state = _read(); _previousTimer = millis(); } void initInterrupts(void(*function)()) { attachInterrupt(_pin, function, CHANGE); } void setEventHandler(void(*function)(Button*, uint8_t, bool)) { _cb = function; } bool getState() { return _state; } int getId() { return _id; } int getClickInterval() { return _clickInterval; } int getHoldInterval() { return _holdInterval; } int getRepeatInterval() { return _repeatInterval; } void check() { unsigned long timer = millis(); unsigned long deltaTime = timer - _previousTimer; _state = _read(); if (_inputFlag == true) { _inputFlag = false; // Button pressed if (_state == LOW && _pressedFlag == false) { _pressedFlag = true; _previousTimer = timer; _cb(this, kEventPressed, _state); return; // Button clicked } else if (_state == HIGH && deltaTime < _clickInterval && _holdFlag == false) { _pressedFlag = false; _previousTimer = timer; _cb(this, kEventClicked, _state); return; // Button released } else if (_state == HIGH) { _pressedFlag = false; _holdFlag = false; _previousTimer = timer; _cb(this, kEventReleased, _state); return; } } // Button held if (_state == LOW && deltaTime > _holdInterval && _holdFlag == false) { _holdFlag = true; _previousTimer = timer; _cb(this, kEventHeld, _state); return; // Button tick } else if (_state == LOW && deltaTime > _repeatInterval && _holdFlag == true) { _previousTimer = timer; _cb(this, kEventTick, _state); return; } } void ICACHE_RAM_ATTR tick() { _inputFlag = true; } }; #endif