Releases: LennartHennigs/Button2
Releases · LennartHennigs/Button2
Release list
v2.7.0
- Added: `setContext(void*)` / `getContext()` — attach arbitrary caller data to a button instance and retrieve it inside any callback handler, without globals. Useful on AVR (no lambda captures) and for the explicit context pattern on any platform. Context is not cleared by `reset()` or `resetPressedState()`
- Added: `CallbackContext` example — two buttons sharing the same handler functions, each with a different `ButtonCtx` struct attached via `setContext()`
- Added: `setButtonStateFunction(StateCallbackFunctionBtn f)` overload — state callback now optionally receives a `const Button2&` reference, enabling multiple virtual buttons to share one state function and differentiate by ID or config. Useful for capacitive touch arrays (e.g. ESP32 `touchRead`) and I2C expanders
- Added: `ESP32MultiCapTouch` example demonstrating two capacitive touch buttons sharing a single state handler via `btn.getID()`
- Tests: Added consecutive double-click and bounce-injection investigation tests; `injectBounce()` helper in `test_helpers.h`
- Internal: Standardised `TestRunner::setTimeout(90)` across all six test suites to prevent sporadic timeouts on `epoxy-nano`
v2.6.1
- Fixed (Issue #88): Compilation error on Arduino Pico (RP2040) — `INPUT_PULLUP`, `OUTPUT`, and `INPUT` are defined as a `PinMode` enum on Pico, not as macros. Wrapped the fallback defines in `#ifndef ARDUINO` so they only apply in non-Arduino environments (e.g. native test builds)
- Updated: Decoupled long-click retrigger interval from initial threshold
- Fixed (Issue #96): `wasPressedFor()` always returned 0 when called after `read()`. `down_time_ms` is a completed measurement and must not be reset by `resetPressedState()`; removed the erroneous zero from that function
- Tests: Added `read()` contract tests — verifying return value, state reset on `read()`, and state preservation on `read(true)`
v2.6.0
What's Changed
- Fixed (CRITICAL): Type mismatch in internal timing methods —
_handlePress(),_handleRelease(),_pressedNow(),_releasedNow(), and_checkForLongClick()now acceptunsigned longinstead oflong, matching the return type ofmillis(). The previouslongparameter caused incorrect timing arithmetic after ~24.8 days of uptime on AVR and ESP platforms - Fixed:
waitForClick(),waitForDouble(),waitForTriple(), andwaitForLong()were silently ignoring theirkeepStateparameter — it is now correctly forwarded toread() - Fixed:
_pressedStateandlongclick_retriggerablemember variables had no default initializers; they are now initialized toLOWandfalserespectively, preventing undefined behavior if query methods are called beforebegin() - Fixed: Wrong initialization order in
test_configuration.cppwherebegin()was called beforesetButtonStateFunction(), causing the initial state to be read viadigitalRead()instead of the injected state function - Changed:
getLongClickCount()return type changed fromuint8_ttouint16_tto match theuint16_t longclick_counterstorage — with a 200ms retriggerable interval the previousuint8_twrapped after ~51 seconds - Changed:
_nextIDstatic counter type changed frominttouint8_t, saving 1 byte of static RAM on AVR - Added:
setLongClickDetectedRetriggerable(bool retriggerable, unsigned int interval_ms)overload — allows setting the retrigger interval in a single call - Internal: Extracted shared test infrastructure into
test/shared/test_helpers.h, removing ~80 lines of duplicated boilerplate from each of the 6 test suites
2.5.0
Fixed
- CRITICAL: Fixed integer overflow in long click counter calculation on AVR platforms (Arduino Nano/Uno). The multiplication
longclick_time_ms * (longclick_counter + 1)now uses proper casting to prevent 16-bit overflow that could cause incorrect long click timing [Button2.cpp:415] - Issue #82: Fixed ambiguous reference to
emptyenum value when compiling with libraries that useusing namespace std;. The library now uses qualified references (clickType::empty) internally to avoid conflicts withstd::empty()from C++17 standard library. This fix maintains 100% backward compatibility - user code does not need to change [Button2.h:117, Button2.cpp:225] - Fixed uninitialized member variables (
click_ms,down_ms,state,prev_state) in constructor that could cause phantom button presses and incorrect click detection on startup [Button2.h:69-76] - Fixed
resetPressedState()to properly reset all timing variables (click_ms,down_ms,last_click_count) for complete state reset [Button2.cpp:223-235] - Fixed
operator==const correctness - now properly usesconst Button2¶meter andconstmethod qualifier [Button2.h:177, Button2.cpp:98] - Fixed test initialization order bug where
setButtonStateFunction()was called afterbegin(), causing phantom press/release transitions - Fixed compile_examples.sh: Removed unnecessary AUnit dependency from example compilation
- Fixed compile_examples.sh: Corrected M5StackCore2CustomHandler exclusion logic - now properly runs on M5Stack platform
- Fixed compile_examples.sh: Improved platformio.ini generation for M5Stack dependencies
Added
- Issue #69: Added optional initialization callback parameter to
begin()method for virtual buttons. This allows hardware initialization (I2C/SPI expanders, touch sensors, etc.) to be encapsulated within the button setup. The callback is invoked immediately whenbegin()is called, ensuring hardware is ready before button polling starts. Example:button.begin(BTN_VIRTUAL_PIN, INPUT, true, initCallback);[Button2.h:141, Button2.cpp:34-43] - Issue #70: Added
I2CPortExpanderButtons.inoexample demonstrating the efficient caching pattern for multiple buttons on I2C port expanders (PCF8574, MCP23017). The example shows how to read the entire port once per loop cycle and use bit masking in state handlers, reducing I2C bus traffic from N transactions to just 1 per cycle. This pattern scales efficiently to 8+ buttons while minimizing I2C overhead - Comprehensive Test Suite: Added 70 tests across 6 test suites using AUnit framework:
- test_basics (10 tests): Initialization, configuration, default values, init callback
- test_clicks (11 tests): Click detection - single, double, triple, long
- test_callbacks (12 tests): All event handler callbacks
- test_states (19 tests): State management, queries, timing edge cases
- test_configuration (7 tests): Runtime settings and configuration
- test_multiple (11 tests): Multiple button interactions
- Added EpoxyDuino-based native testing (no hardware required) - tests run on host machine emulating ESP8266/ESP32
- Added automated compilation testing script (
test/compile_examples.sh) that tests all examples across multiple platforms (ESP8266, ESP32, AVR) - Added comprehensive test documentation in
test/README.mdandtest/CLAUDE.md - Added extensive inline code documentation explaining:
- Asymmetric debouncing strategy (press vs release edge handling)
- Long click detection design (only on first click to avoid multi-click ambiguity)
- Critical importance of calling
loop()regularly (recommended 1-10ms frequency) - Virtual button usage and I2C port expander patterns
- Added documentation for
wasPressedFor()behavior in multi-click scenarios (returns duration of most recent click only) [Issue #35]
Changed
- OPTIMIZATION: Reordered struct members for better memory packing, reducing padding overhead on 32-bit platforms (ESP32/ESP8266) [Button2.h:66-122]
- PERFORMANCE: Changed
clickToString()to returnconst char*instead ofStringto avoid heap allocation and memory fragmentation on low-memory devices (AVR) [Button2.h:172, Button2.cpp:206] - CODE QUALITY: Replaced NULL with BUTTON2_NULL macro (nullptr on C++11+, NULL on AVR) for consistent modern C++ practices while maintaining Arduino compatibility
- Breaking Change (Minor): Return type of
clickToString()changed fromStringtoconst char*- most code will work unchanged, but assignments toStringvariables may need explicit casting - Improved test reliability through proper initialization order and state management
- TEST PERFORMANCE: Reduced setup delays in all test suites from 1000ms to 100ms, improving native test execution time by ~5 seconds and reducing intermittent timeouts
- Enhanced README.md with:
- Updated CustomButtonStateHandler.ino example to demonstrate initialization callback usage
- Updated documentation (CLAUDE.md) to reflect current testing approach using
setButtonStateFunction()
Removed
- Removed Hardware.h abstraction layer (replaced with simpler
setButtonStateFunction()approach) - Removed unused Button2TestHelper utility class
Documentation
- Documented current behavior of
wasPressedFor()for multi-click scenarios [Issue #35] - Documented std::function support now works on all C++11+ platforms except AVR [Issue #58]
- Added comprehensive virtual button documentation with I2C port expander examples
- Added notes about
clickType::emptyscoped syntax to avoid naming conflicts [Issue #82]
2.4.1
- Improved detection and enabling of std::function support for callback handlers. Now uses C++11 check and excludes AVR platforms, providing broader compatibility for modern boards (ESP32, ESP8266, ARM, RP2040, etc.).
2.4.0
2.3.5
2.3.4
- added dummy file
main.cppto be able to compile lib in VSCode/PIO
2.3.3
- fixed bug that first long press was not properly detected; see issue #72
- added
byte resetClickCount()function - click count is no longer resetted in
resetPressedState() - updated examples
2.3.2
- expanded conditions to check for API version 2.0 (for UNO R4, RP2040, ...) in
Hardware.h