/** * Author......: Jens Steube * License.....: MIT */ #include "common.h" #include "terminal.h" #if defined (__linux__) static struct termios savemodes; static int havemodes = 0; int tty_break() { struct termios modmodes; if (tcgetattr (fileno (stdin), &savemodes) < 0) return -1; havemodes = 1; modmodes = savemodes; modmodes.c_lflag &= ~ICANON; modmodes.c_cc[VMIN] = 1; modmodes.c_cc[VTIME] = 0; return tcsetattr (fileno (stdin), TCSANOW, &modmodes); } int tty_getchar() { fd_set rfds; FD_ZERO (&rfds); FD_SET (fileno (stdin), &rfds); struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; int retval = select (1, &rfds, NULL, NULL, &tv); if (retval == 0) return 0; if (retval == -1) return -1; return getchar(); } int tty_fix() { if (!havemodes) return 0; return tcsetattr (fileno (stdin), TCSADRAIN, &savemodes); } #endif #if defined(__APPLE__) || defined(__FreeBSD__) static struct termios savemodes; static int havemodes = 0; int tty_break() { struct termios modmodes; if (ioctl (fileno (stdin), TIOCGETA, &savemodes) < 0) return -1; havemodes = 1; modmodes = savemodes; modmodes.c_lflag &= ~ICANON; modmodes.c_cc[VMIN] = 1; modmodes.c_cc[VTIME] = 0; return ioctl (fileno (stdin), TIOCSETAW, &modmodes); } int tty_getchar() { fd_set rfds; FD_ZERO (&rfds); FD_SET (fileno (stdin), &rfds); struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; int retval = select (1, &rfds, NULL, NULL, &tv); if (retval == 0) return 0; if (retval == -1) return -1; return getchar(); } int tty_fix() { if (!havemodes) return 0; return ioctl (fileno (stdin), TIOCSETAW, &savemodes); } #endif #if defined (_WIN) static DWORD saveMode = 0; int tty_break() { HANDLE stdinHandle = GetStdHandle (STD_INPUT_HANDLE); GetConsoleMode (stdinHandle, &saveMode); SetConsoleMode (stdinHandle, ENABLE_PROCESSED_INPUT); return 0; } int tty_getchar() { HANDLE stdinHandle = GetStdHandle (STD_INPUT_HANDLE); DWORD rc = WaitForSingleObject (stdinHandle, 1000); if (rc == WAIT_TIMEOUT) return 0; if (rc == WAIT_ABANDONED) return -1; if (rc == WAIT_FAILED) return -1; // The whole ReadConsoleInput () part is a workaround. // For some unknown reason, maybe a mingw bug, a random signal // is sent to stdin which unblocks WaitForSingleObject () and sets rc 0. // Then it wants to read with getche () a keyboard input // which has never been made. INPUT_RECORD buf[100]; DWORD num = 0; memset (buf, 0, sizeof (buf)); ReadConsoleInput (stdinHandle, buf, 100, &num); FlushConsoleInputBuffer (stdinHandle); for (DWORD i = 0; i < num; i++) { if (buf[i].EventType != KEY_EVENT) continue; KEY_EVENT_RECORD KeyEvent = buf[i].Event.KeyEvent; if (KeyEvent.bKeyDown != TRUE) continue; return KeyEvent.uChar.AsciiChar; } return 0; } int tty_fix() { HANDLE stdinHandle = GetStdHandle (STD_INPUT_HANDLE); SetConsoleMode (stdinHandle, saveMode); return 0; } #endif