Calling select() to check whether input from the terminal is available fails for all but the first byte in the cygwin console if multiple bytes are entered at once, like function or cursor keys or non-ASCII UTF-8 characters. Actually, the issue is volatile, sometimes it works for characters and most function keys. The problem most likely arises with the escape sequences mouse scroll and window focus out/in (both enabled by the test program). I tried to use read() with timeout instead, trying various combinations of tcsetattr setting VMIN/VTIME, fcntl setting O_NONBLOCK, using read() with buffer length 0, trying to interrupt read() with a timer signal, or even a combination of setitimer() and siglongjmp(). None of this works.
Thanks to the cygwin time machine, I could track back this bug to have appeared in 1.7.10 (around the time I had reported another select() issue: https://sourceware.org/ml/cygwin/2011-05/msg00418.html which I hope doesn’t interfere, nor the later issue https://sourceware.org/ml/cygwin/2013-01/msg00139.html). ------ Thomas --- Diese E-Mail wurde von Avast Antivirus-Software auf Viren geprüft. http://www.avast.com
#include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <termios.h> #include <stdio.h> #include <sys/select.h> #include <time.h> #include <signal.h> struct termios saved_tattr; void restore_tattr (void) { if (isatty (STDIN_FILENO)) tcsetattr (STDIN_FILENO, TCSANOW, &saved_tattr); } int ready_select () { struct timeval timeoutstru; fd_set readfds; int nfds; static int rv = 0; timeoutstru.tv_sec = 0; timeoutstru.tv_usec = 800000; FD_ZERO (& readfds); FD_SET (STDIN_FILENO, & readfds); nfds = select (STDIN_FILENO + 1, & readfds, 0, 0, & timeoutstru); printf ("(%d)", nfds); return nfds; } int main (void) { if (isatty (STDIN_FILENO)) { struct termios tattr; tcgetattr (STDIN_FILENO, &saved_tattr); tattr = saved_tattr; /* tattr.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); tattr.c_oflag &= ~OPOST; tattr.c_cflag &= ~(CSIZE|PARENB); tattr.c_cflag |= CS8; tattr.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); */ /* use miminal change for test case: */ tattr.c_lflag &= ~(ICANON); tcsetattr (STDIN_FILENO, TCSAFLUSH, &tattr); atexit (restore_tattr); } setbuf (stdout, 0); printf ("\033[?1000h\033[?1006h\033[?1004h"); while (1) { unsigned char c; int res; while (! ready_select ()) { } res = read (STDIN_FILENO, & c, 1); switch (c & 0xFF) { case 0x00 ... 0x1f: putchar ('^'); putchar (c + 0x40); if (c == '\r') printf ("\r\n"); break; case 0x7f: putchar ('^'); putchar ('?'); break; case 0x80 ... 0xFF: printf ("\\x%2X", c); break; default: putchar (c); } fflush (stdout); } printf ("\033[?1000l\033[?1004l\r\nbye\r\n"); return 0; }
-- Problem reports: http://cygwin.com/problems.html FAQ: http://cygwin.com/faq/ Documentation: http://cygwin.com/docs.html Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple