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 >