Skip to content

Releases: LennartHennigs/Button2

v2.7.0

Choose a tag to compare

@LennartHennigs LennartHennigs released this 06 Jun 17:11
  • 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

Choose a tag to compare

@LennartHennigs LennartHennigs released this 06 Jun 11:04
  • 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

Choose a tag to compare

@LennartHennigs LennartHennigs released this 09 May 17:00

What's Changed

  • Fixed (CRITICAL): Type mismatch in internal timing methods — _handlePress(), _handleRelease(), _pressedNow(), _releasedNow(), and _checkForLongClick() now accept unsigned long instead of long, matching the return type of millis(). The previous long parameter caused incorrect timing arithmetic after ~24.8 days of uptime on AVR and ESP platforms
  • Fixed: waitForClick(), waitForDouble(), waitForTriple(), and waitForLong() were silently ignoring their keepState parameter — it is now correctly forwarded to read()
  • Fixed: _pressedState and longclick_retriggerable member variables had no default initializers; they are now initialized to LOW and false respectively, preventing undefined behavior if query methods are called before begin()
  • Fixed: Wrong initialization order in test_configuration.cpp where begin() was called before setButtonStateFunction(), causing the initial state to be read via digitalRead() instead of the injected state function
  • Changed: getLongClickCount() return type changed from uint8_t to uint16_t to match the uint16_t longclick_counter storage — with a 200ms retriggerable interval the previous uint8_t wrapped after ~51 seconds
  • Changed: _nextID static counter type changed from int to uint8_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

Choose a tag to compare

@LennartHennigs LennartHennigs released this 25 Oct 20:14

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 empty enum value when compiling with libraries that use using namespace std;. The library now uses qualified references (clickType::empty) internally to avoid conflicts with std::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 uses const Button2& parameter and const method qualifier [Button2.h:177, Button2.cpp:98]
  • Fixed test initialization order bug where setButtonStateFunction() was called after begin(), 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 when begin() 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.ino example 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.md and test/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 return const char* instead of String to 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 from String to const char* - most code will work unchanged, but assignments to String variables 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:
    • Virtual buttons and custom state handlers section
    • Efficient pattern for multiple I2C buttons with caching example
    • Updated std::function platform support documentation [Issue #58]
    • Added scoped enum usage recommendation for clickType::empty [Issue #82]
  • 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::empty scoped syntax to avoid naming conflicts [Issue #82]

2.4.1

Choose a tag to compare

@LennartHennigs LennartHennigs released this 19 Jul 06:41
  • 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

Choose a tag to compare

@LennartHennigs LennartHennigs released this 19 Jul 05:11

What's Changed

New Contributors

Full Changelog: 2.3.5...2.4.0

2.3.5

Choose a tag to compare

@LennartHennigs LennartHennigs released this 01 May 12:13
  • fixed contant name in example M5StackCore2CustomHandler.ino
  • replaced boolean with bool as requested in #81
  • replaced byte with uint_8 as requested in #79

2.3.4

Choose a tag to compare

@LennartHennigs LennartHennigs released this 26 Jan 20:33
  • added dummy file main.cpp to be able to compile lib in VSCode/PIO

2.3.3

Choose a tag to compare

@LennartHennigs LennartHennigs released this 30 May 12:37
  • 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

Choose a tag to compare

@LennartHennigs LennartHennigs released this 19 Feb 07:45
  • expanded conditions to check for API version 2.0 (for UNO R4, RP2040, ...) in Hardware.h