// terminalhelp from mini-rv32ima. #ifndef _TERMINALHELP_H #define _TERMINALHELP_H #include // Provides the following: static void CaptureKeyboardInput() __attribute__((used)); static void ResetKeyboardInput() __attribute__((used)); static uint64_t GetTimeMicroseconds() __attribute__((used)); static int ReadKBByte() __attribute__((used)); static int IsKBHit() __attribute__((used)); #if defined(WINDOWS) || defined(WIN32) || defined(_WIN32) #include #include #define strtoll _strtoi64 static void CaptureKeyboardInput() { system(""); // Poorly documented tick: Enable VT100 Windows mode. } static void ResetKeyboardInput() { } static uint64_t GetTimeMicroseconds() { static LARGE_INTEGER lpf; LARGE_INTEGER li; if( !lpf.QuadPart ) QueryPerformanceFrequency( &lpf ); QueryPerformanceCounter( &li ); return ((uint64_t)li.QuadPart * 1000000LL) / (uint64_t)lpf.QuadPart; } static int IsKBHit() { return _kbhit(); } static int ReadKBByte() { // This code is kind of tricky, but used to convert windows arrow keys // to VT100 arrow keys. static int is_escape_sequence = 0; int r; if( is_escape_sequence == 1 ) { is_escape_sequence++; return '['; } r = _getch(); if( is_escape_sequence ) { is_escape_sequence = 0; switch( r ) { case 'H': return 'A'; // Up case 'P': return 'B'; // Down case 'K': return 'D'; // Left case 'M': return 'C'; // Right case 'G': return 'H'; // Home case 'O': return 'F'; // End default: return r; // Unknown code. } } else { switch( r ) { case 13: return 10; //cr->lf case 224: is_escape_sequence = 1; return 27; // Escape arrow keys default: return r; } } } #else #include #include #undef BS0 #undef BS1 #include #include #include static void CtrlC() { fprintf( stderr, "Minichlink Closing\n" ); ResetKeyboardInput(); exit( 0 ); } // Override keyboard, so we can capture all keyboard input for the VM. static void CaptureKeyboardInput() { // Hook exit, because we want to re-enable keyboard. atexit(ResetKeyboardInput); signal(SIGINT, CtrlC); signal(SIGPIPE, CtrlC); struct termios term; tcgetattr(0, &term); term.c_lflag &= ~(ICANON | ECHO); // Disable echo as well tcsetattr(0, TCSANOW, &term); } static void ResetKeyboardInput() { // Re-enable echo, etc. on keyboard. struct termios term; tcgetattr(0, &term); term.c_lflag |= ICANON | ECHO; tcsetattr(0, TCSANOW, &term); } static uint64_t GetTimeMicroseconds() { struct timeval tv; gettimeofday( &tv, 0 ); return tv.tv_usec + ((uint64_t)(tv.tv_sec)) * 1000000LL; } static int is_eofd; static int ReadKBByte() { if( is_eofd ) return 0xffffffff; char rxchar = 0; int rread = read(fileno(stdin), (char*)&rxchar, 1); if( rread > 0 ) // Tricky: getchar can't be used with arrow keys. return rxchar; else return -1; } static int IsKBHit() { if( is_eofd ) return -1; int byteswaiting; ioctl(0, FIONREAD, &byteswaiting); if( !byteswaiting && write( fileno(stdin), 0, 0 ) != 0 ) { is_eofd = 1; return -1; } // Is end-of-file for return !!byteswaiting; } #endif #endif