Hi Tomek, I agree with you, but in this first "incarnation" it will support only two actions, but people are invited to improve it later.
Notice that I used INPUT_SBUTTON, so the "Dual Action" is just a Kconfig message, easy to change. :-) Now my idea is just to add the improvements that Michał Łyszczek added in the review and add a debouncing, because after more tests I discovered that sometimes it was returning invalid key press. The driver itself is very simple, less than 300 LoC, so I hope everybody can understand how it works. BR, Alan On Fri, Jul 11, 2025 at 7:39 PM Tomek CEDRO <to...@cedro.info> wrote: > Very cool thanks Alan! :-) > > I think there may be more actions with one button: > 1. single click. > 2. double click. > 3. triple click. > 4. short press. > 5. long press. > etc > > So it is not only dual action button, there may be more actions :-) > > It would be great if the driver could return event code or have return > codes configurable (build time?) on selected actions. That would make > things really versatile :-) > > Thanks :-) > Tomek > > > On Fri, Jul 11, 2025 at 11:26 PM Alan C. Assis <acas...@gmail.com> wrote: > > > > Hi Everyone, > > > > The driver is done: https://github.com/apache/nuttx/pull/16714 > > > > I started using drivers/input/spq10kbd.c as reference, but then I > realized > > that there was already a keyboard_upper.c that I could use to send key > > events/strokes. > > > > After that the driver was easier to implement than I thought initially. > > > > BR, > > > > Alan > > > > On Wed, Jul 9, 2025 at 10:16 AM Alan C. Assis <acas...@gmail.com> wrote: > > > > > Hi Everyone, > > > > > > Some years ago a customer asked me to develop a project with NuttX for > > > this board that used a small OLED display and a single button. > > > That button should be used to navigate in the menu, as a side note: > > > initially he suggested: quick press and release will work as a ENTER > and > > > long press will work as TAB (move to other option), > > > but while testing the application I released the was faster if quick > press > > > work as TAB and long press as enter. > > > > > > This video implements the same idea on a ESP32-Devkit board that also > has > > > only a single button: https://www.youtube.com/shorts/vfQLW-a2JhA > > > > > > The daemon that detect the button and define the type of input is > > > something like this: > > > > > > /* Define the notifications events */ > > > > > > btnevents.bn_press = supported; > > > btnevents.bn_release = supported; > > > > > > btnevents.bn_event.sigev_notify = SIGEV_SIGNAL; > > > btnevents.bn_event.sigev_signo = CONFIG_INPUT_BUTTONS_SIGNO; > > > > > > /* Register to receive a signal when buttons are pressed/released */ > > > > > > ret = ioctl(fd, BTNIOC_REGISTER, > > > (unsigned long)((uintptr_t)&btnevents)); > > > if (ret < 0) > > > { > > > int errcode = errno; > > > printf("button_daemon: ERROR: ioctl(BTNIOC_SUPPORTED) failed: > %d\n", > > > errcode); > > > goto errout_with_fd; > > > } > > > > > > /* Ignore the default signal action */ > > > > > > signal(CONFIG_INPUT_BUTTONS_SIGNO, SIG_IGN); > > > > > > /* Now loop forever, waiting BUTTONs events */ > > > > > > for (; ; ) > > > { > > > struct siginfo value; > > > sigset_t set; > > > > > > bool timeout; > > > int nbytes; > > > > > > /* Wait for a signal */ > > > > > > sigemptyset(&set); > > > sigaddset(&set, CONFIG_INPUT_BUTTONS_SIGNO); > > > ret = sigwaitinfo(&set, &value); > > > if (ret < 0) > > > { > > > int errcode = errno; > > > printf("ERROR: sigwaitinfo() failed: %d\n", errcode); > > > goto errout_with_fd; > > > } > > > > > > sample = (btn_buttonset_t)value.si_value.sival_int; > > > > > > if (sample & 0x01) > > > { > > > /* Button pressed, start measuring time */ > > > > > > clock_gettime(CLOCK_REALTIME, &start); > > > } > > > else > > > { > > > /* Button released, calculate the elapsed time */ > > > > > > clock_gettime(CLOCK_REALTIME, &curr); > > > > > > elapsed.tv_sec = curr.tv_sec - start.tv_sec; > > > if (curr.tv_nsec >= start.tv_nsec) > > > { > > > elapsed.tv_nsec = curr.tv_nsec - start.tv_nsec; > > > } > > > else > > > { > > > unsigned long borrow = 1000000000 - start.tv_nsec; > > > elapsed.tv_sec--; > > > elapsed.tv_nsec = curr.tv_nsec + borrow; > > > } > > > > > > unsigned long ftime = (elapsed.tv_sec * 1000000000) + elapsed.tv_nsec; > > > > > > /*printf("Elapsed miliseconds = %d\n", ftime / 1000000);*/ > > > if (ftime < 500000000) > > > { > > > input_event(INPUT_TAB); > > > } > > > else > > > { > > > input_event(INPUT_ENTER); > > > } > > > } > > > > > > /* Make sure that everything is displayed */ > > > > > > fflush(stdout); > > > > > > usleep(1000); > > > } > > > > > > But today while taking a shower and thinking about other subjects that > > > fact came to mind and I asked myself: how to develop that thing in a > more > > > standard way to avoid the "kludge" above? (in fact it is not kludge, > but we > > > can improve, right?) > > > > > > So, I realized it would be nice to have a kind of "action button" > driver > > > that generates this kind of event (detecting long press and short > press) > > > automatically returning INPUT_ENTER or INPUT_TAB. > > > > > > In fact the driver will be more similar to djoystick.c than the > ordinary > > > buttons driver itself (for simplicity). > > > > > > Please let me know if someone already implemented something similar or > > > other suggestions before I implement it. > > > > > > BR, > > > > > > Alan > > > > > > > -- > CeDeROM, SQ7MHZ, http://www.tomek.cedro.info >