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

Reply via email to