Handling Button Press, Longpress, and Double-Tap with the Zephyr Input Subsystem

Originally published at: Handling Button Press, Longpress, and Double-Tap with the Zephyr Input Subsystem - The Golioth Developer Blog

Embedded engineers know the joys and pains with button inputs: debouncing them, triggering actions, and more advanced input patterns like long holding the button down or quickly clicking more than once. If your project is based on Zephyr, you should take a look at the input subsystem to see if it can do some of the hard work for you. Today we’ll look at using input events to handle button presses, double-taps, and longpresses. Input Events in Zephyr The input event system has been around for the last few version of Zephyr, but starting with the next release it will be the default system for the samples/basic/button application, replacing the more esoteric system of setting up callbacks. For me this is a welcome change as it makes a lot more sense: #include <zephyr/input/input.h> static void button_input_cb(struct input_event *evt, void *user_data) { if (evt->sync == 0) { return; } printk(“Button %d %s at %” PRIu32 “\n”, evt->code, evt->value ? “pressed” : “released”, k_cycle_get_32()); } INPUT_CALLBACK_DEFINE(NULL, button_input_cb, NULL); The code above is all that it takes to register a callback that runs on every input event. The event includes a key code (evt->code) to test which keypress triggered the callback. The evt->value will be 1 for “pressed” and 0 for “released”. In your devicetree, ensure that each button has a input code associated with it: #include <zephyr/dt-bindings/input/input-event-codes.h> / { buttons { compatible = “gpio-keys”; button0: button_0 { gpios = <&gpio0 11 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = “Push button switch 0”; zephyr,code = <INPUT_KEY_0>; }; }; }; This is already a fantastic shortcut for controlling your application based on button presses, but there are two additional bindings that you may find useful: input-longpress…