diff --git a/Button.cpp b/Button.cpp index 746ce21..c364fbd 100644 --- a/Button.cpp +++ b/Button.cpp @@ -1,6 +1,6 @@ /* Button - a small library for Arduino to handle button debouncing - + MIT licensed. */ @@ -13,6 +13,9 @@ Button::Button(uint8_t pin, uint16_t debounce_ms) , _state(HIGH) , _ignore_until(0) , _has_changed(false) +, _reported_repeats(0) +, _repeat_delay_ms(-1) +, _repeat_ms(-1) { } @@ -21,9 +24,9 @@ void Button::begin() pinMode(_pin, INPUT_PULLUP); } -// +// // public methods -// +// bool Button::read() { @@ -32,15 +35,26 @@ bool Button::read() { // ignore any changes during this period } - - // pin has changed + + // pin has changed else if (digitalRead(_pin) != _state) { - _ignore_until = millis() + _delay; _state = !_state; + + if (_state == RELEASED) + { + _reported_repeats = repeats_since_press(); + } + + else + { + _reported_repeats = 0; + } + + _ignore_until = millis() + _delay; _has_changed = true; } - + return _state; } @@ -62,10 +76,25 @@ bool Button::has_changed() return false; } -// has the button gone from off -> on +// how many repeated press events occured since the button was pressed +uint16_t Button::repeat_count() +{ + return _state == PRESSED ? repeats_since_press() : _reported_repeats; +} + +// has the button gone from off -> on or pressed repeatedly bool Button::pressed() { - return (read() == PRESSED && has_changed()); + if (read() == PRESSED) + { + uint16_t old_repeats = _reported_repeats; + _reported_repeats = repeats_since_press(); + return (has_changed() || old_repeats != _reported_repeats); + } + else + { + return false; + } } // has the button gone from on -> off @@ -73,3 +102,25 @@ bool Button::released() { return (read() == RELEASED && has_changed()); } + +void Button::set_repeat(int16_t delay_ms, int16_t repeat_ms) +{ + _repeat_delay_ms = delay_ms > _delay ? delay_ms - _delay : 0; + _repeat_ms = repeat_ms; +} + +uint16_t Button::repeats_since_press() +{ + if (_repeat_delay_ms == -1 || millis() < _ignore_until + _repeat_delay_ms) + { + return 0; + } + + if (_repeat_ms <= 0) + { + return 1; + } + + uint32_t press_time = millis() - _ignore_until; + return 1 + (press_time - _repeat_delay_ms) / _repeat_ms; +} diff --git a/Button.h b/Button.h index 6a23b29..631d6e7 100644 --- a/Button.h +++ b/Button.h @@ -1,6 +1,6 @@ /* Button - a small library for Arduino to handle button debouncing - + MIT licensed. */ @@ -18,16 +18,23 @@ class Button bool pressed(); bool released(); bool has_changed(); - + uint16_t repeat_count(); + void set_repeat(int16_t delay_ms, int16_t repeat_ms); + const static bool PRESSED = LOW; const static bool RELEASED = HIGH; - + private: + uint16_t repeats_since_press(); + uint8_t _pin; uint16_t _delay; bool _state; uint32_t _ignore_until; bool _has_changed; + uint16_t _reported_repeats; + int16_t _repeat_delay_ms; + int16_t _repeat_ms; }; #endif diff --git a/README.md b/README.md index fcdfb6d..16a7b0c 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,8 @@ Features ** when a button is pressed ** when a button is released ** or when a button changes (i.e. pressing or releasing) +** repeated press (i.e. when the button is kept pressed for a long time, like on a computer keyboard) +** long press Requirements ------------ @@ -93,6 +95,16 @@ Returns true whenever the button is pressed or released, i.e., its position is t **bool read()** Returns the current debounced state of the button, i.e. Button::PRESSED or Button::RELEASED. +**void set_repeat(int16_t delay_ms, int16_t repeat_ms)** +Set the repeated press timer: `delay_ms` specifies the time in milliseconds after before the first repeated press event, and `repeat_ms` specifies the time in milliseconds between subsequent events. You can set `delay_ms` to -1 to disable repeated press event (that's also the default), and similarly, set `repeat_ms` +to -1 to disable subsequent press event. This way you can detect a long press, but not repeated press events. + +**uint16_t repeat_count()** +Returns the number of repeated press event since the button was last `pressed()`. When the button is first pressed, this method will return 0, and then the +number will increment by 1 for any repeated press event. You can also read the `repeat_count()` value after the button is `released()`, and then react +differently in case of a short press vs a long press. Note that you need to call `set_repeat()` first, otherwise repeated pressed will not be detected and +`repeat_count()` will always return `0`. + **bool has_changed()** Returns whether the position/state of the button has changed after calling the previous read() function. Unlikely to be used except by Super Gurus. diff --git a/keywords.txt b/keywords.txt index 1372b4a..6d37b03 100644 --- a/keywords.txt +++ b/keywords.txt @@ -17,6 +17,8 @@ toggled KEYWORD2 pressed KEYWORD2 released KEYWORD2 has_changed KEYWORD2 +repeat_count KEYWORD2 +set_repeat KEYWORD2 ####################################### # Constants (LITERAL1)