lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


It was thus said that the Great John Hind once stated:
> > On Fri, 29 Nov 2013, Jose Torre-Bueno wrote:
> > Is there a way from inside Lua to check whether any key has been
> > pressed?  io.read() will get a line from the console but if there
> > is no input it pends waiting for input.  I would like to be able
> > to write a test that gets input if any is ready but would continue
> > if there is none.  It is not obvious to me if this can be done at
> > all.
> 
> Not a solution, but some background. Here is a a Lua C function to do it
> extracted from one of my libraries, complete with comment:
> 
> /* R1: Boolean, true if there is outstanding data in the keyboard buffer.
> ** This is a helper to allow a demonstration terminal program implemented on the command line.
> ** Need a solution for Linux, although _kbhit is POSIX there seem to be theological reasons for not
> ** having it in Linux and it is not in baseline C.
> */
> static int luakbhit(lua_State* L) {
> #if defined(LUA_WIN)
> 	lua_pushboolean(L, _kbhit());
> #else
> 	lua_pushboolean(L, FALSE);
> #endif
> 	return 1;
> }
> 
> Search online for "_kbhit" for more background on the theology!

  If you *really* want to do this for Unix, the code is quite involved.  You
first need to get the "keyboard" [1] into raw mode:

#include <errno.h>
#include <termios.h>
#include <unistd.h>

struct termios init_term;
struct termios curr_term;

int set_raw(void)
{
  if (!isatty(STDIN_FILENO))
    return ENOTTY;
  if (tcgetattr(STDIN_FILENO,&init_term) < 0)
    return errno;
  curr_term = init_term;
#if HAVE_CFMAKERAW
  cfmakeraw(&curr_term);    
#else
  curr_term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
  curr_term.c_oflag &= ~OPOST;
  curr_term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
  curr_term.c_cflag &= ~(CSIZE|PARENB);
  curr_term.c_cflag |= CS8;
#endif
  if (tcsetattr(STDIN_FILENO,TCSANOW,&curr_term) < 0)
    return errno;
  return 0;
}

And now that you have the "keyboard" [1] in raw mode, you can now write
_kbhit() [2]

#include <sys/poll.h>
#include <unistd.h>

int _kbhit(void)
{
  struct poll fds;

  fds.fd     = STDIN_FILENO;
  fds.events = POLLIN;
  if (poll(&fds,1,0) == 0)
    return 1;
  else
    return 0;
}

  Now, just make sure to call tcsetattr(STDIN_FILENO,TCSANOW,&init_term)
before the program ends, to restore the "keyboard" mode.

  -spc (If your Unix system doesn't have poll(), you can use select(), but
	that's an exercise for the reader ... )

[1]	It's really the input stream.

[2]	Technically, this violates the C standard for naming---any
	identifier starting with a single _ is reserved for the C
	implementation and *NOT* user code.  You have been warned.