daily pastebin goal
62%
SHARE
TWEET

platform_conio.h

mvaganov Jan 1st, 2015 (edited) 356 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #pragma once
  2. #ifndef __PLATFORM_CONIO_H
  3. #define __PLATFORM_CONIO_H
  4. /*
  5. utility functions for the command-line console, usable in both Windows and Linux/Unix v20150415 http://pastebin.com/c0DQsNLQ
  6. author: mvaganov@hotmail.com
  7. license: MIT (http://opensource.org/licenses/MIT). TL;DR - this is free software, I won't fix it for you!
  8. */
  9.  
  10. /** move the cursor to the given location in the console */
  11. void platform_move(long row, long col);
  12. /** true (non-zero) if a key is pressed */
  13. long platform_kbhit();
  14. /** return what key is currently pressed as a character, or -1 if not pressed. PLATFORM_KEY_XXX special keys are different on windows/linux */
  15. long platform_getchar();
  16. /** set the color of the command line cursor. linux gets more colors than windows. ignore negative values (use current color) */
  17. void platform_setColor(long foreground, long background);
  18. /** converts the given 0-255 RGB value to an approximate in the command-line console */
  19. int platform_getApproxColor(unsigned char r, unsigned char g, unsigned char b);
  20. /** pause the thread for the given number of milliseconds */
  21. void platform_sleep(long ms);
  22. /** how many milliseconds since first use of this API */
  23. long long platform_upTimeMS();
  24. /** set the memory at the given rows/columns variable to the size (in rows and columns) of the console */
  25. void platform_consoleSize(long & out_rows, long & out_columns);
  26. /** wait for any key to be pressed (thread blocking call) */
  27. inline void platform_waitForAnyKey() { while (!platform_kbhit()) { platform_sleep(1); } }
  28. /** a blocking version of platform_getchar(), usable as replacement for _getch() in conio.h */
  29. inline long platform_getch() { platform_waitForAnyKey(); return platform_getchar(); }
  30.  
  31. /*
  32. // example console application using this library:
  33. #include "platform_conio.h"
  34. #include <string.h>         // for strlen
  35.  
  36. /// fills a rectangle in the console with the given character
  37. void fillRect(int row, int col, int width, int height, char character)
  38. {
  39.   for(int y = row; y < row+height; y++) {
  40.     platform_move(y, col);
  41.     for(int x = col; x < col+width; x++) {
  42.       putchar(character);
  43.     }
  44.   }
  45. }
  46.  
  47. int main(int argc, char * argv[])
  48. {
  49.   int userInput;
  50.   const int frameDelay = 100; // how many milliseconds for each frame of animation
  51.   long long now, whenToStopWaiting; // timing variables
  52.  
  53.   // character animation \ - / | \ - / | \ - / | \ - / |
  54.   const char * animation = "\\-/|";
  55.   int numframes = strlen(animation);
  56.   int frameIndex = 0;
  57.  
  58.   // color shifting for blinking messate
  59.   int colors[] = { 8, 7, 15, 7 };
  60.   int numColors = sizeof(colors) / sizeof(colors[0]);
  61.   int colorIndex = 0;
  62.   do {
  63.     // animation
  64.     platform_setColor(7, 0);
  65.     platform_move(3, 10);
  66.     putchar(animation[frameIndex++]);
  67.     frameIndex %= numframes;
  68.  
  69.     // blinking message
  70.     platform_move(3, 12);
  71.     platform_setColor(colors[colorIndex++], 0);
  72.     printf("Press \'a\' to continue ");
  73.     colorIndex %= numColors;
  74.  
  75.     // wait the specified time, or until there is a keyboard hit (interruptable throttle code)
  76.     now = platform_upTimeMS();
  77.     whenToStopWaiting = now + frameDelay;
  78.     while (platform_upTimeMS() < whenToStopWaiting && !platform_kbhit()) { platform_sleep(1); }
  79.  
  80.     userInput = platform_getchar(); // platform_getchar() returns -1 if no key is pressed
  81.   } while (userInput != 'a');
  82.   // prep to make the console look more usable after the program is done
  83.   platform_setColor(-1, -1);    // reset colors to original
  84.   fillRect(0, 0, 80, 10, ' ');  // clear the top 10 lines (80 columns per line)
  85.   platform_move(0,0);           // move the cursor back to back to the start
  86.   return 0;
  87. }
  88. */
  89.  
  90. #include <stdio.h>      // printf and putchar
  91.  
  92. #ifdef _WIN32
  93. // how to do console utility stuff for Windows
  94.  
  95. // escape sequence for arrow keys
  96. #define PLATFORM_KEY_UP 18656 //'H\340'
  97. #define PLATFORM_KEY_LEFT 19424 //'K\340'
  98. #define PLATFORM_KEY_RIGHT 19936 //'M\340'
  99. #define PLATFORM_KEY_DOWN 20704 //'P\340'
  100. // used for the first 16 colors of platform_setColor
  101. #define PLATFORM_COLOR_INTENSITY (1 << 3)
  102. #define PLATFORM_COLOR_RED (1 << 2)
  103. #define PLATFORM_COLOR_GREEN (1 << 1)
  104. #define PLATFORM_COLOR_BLUE (1 << 0)
  105.  
  106. #define NOMINMAX // keeps Windows from defining "min" and "max"
  107. #include <windows.h>    // move cursor, change color, sleep
  108. #include <conio.h>      // non-blocking input
  109. #include <time.h>       // clock()
  110.  
  111. inline HANDLE * __stdOutputHandle() {
  112.     static HANDLE g_h = 0;
  113.     return &g_h;
  114. }
  115.  
  116. /** keep track of the old terminal settings */
  117. inline WORD * __oldAttributes() {
  118.     static WORD oldAttributes;
  119.     return &oldAttributes;
  120. }
  121.  
  122. inline void __platform_release() {
  123.     if (*__stdOutputHandle() != 0) {
  124.         platform_setColor(*__oldAttributes() & 0xf, *__oldAttributes() & 0xf0);
  125.         *__stdOutputHandle() = 0;
  126.     }
  127. }
  128.  
  129. inline void __platform_init() {
  130.     if (*__stdOutputHandle() == 0) {
  131.         *__stdOutputHandle() = GetStdHandle(STD_OUTPUT_HANDLE);
  132.         CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo;
  133.         GetConsoleScreenBufferInfo(*__stdOutputHandle(), &lpConsoleScreenBufferInfo);
  134.         *__oldAttributes() = lpConsoleScreenBufferInfo.wAttributes;
  135.         atexit(__platform_release);
  136.     }
  137. }
  138.  
  139. inline void platform_move(long row, long col) {
  140.     if (col < 0) col = 0;
  141.     if (row < 0) row = 0;
  142.     COORD p = { (short)col, (short)row };
  143.     __platform_init();
  144.     SetConsoleCursorPosition(*__stdOutputHandle(), p);
  145. }
  146.  
  147. inline long platform_kbhit() {
  148.     __platform_init();
  149.     return _kbhit() != 0;
  150. }
  151.  
  152. inline long platform_getchar() {
  153.     long input;
  154.     if (!platform_kbhit()) return -1;
  155.     input = _getch();
  156.     switch ((char)input){
  157.     case '\0': case '\340':
  158.         if (_kbhit()) {
  159.             long nextByte = _getch();
  160.             input |= (nextByte & 0xff) << 8;
  161.         }
  162.     }
  163.     return input;
  164. }
  165.  
  166. inline void platform_setColor(long foreground, long background) {
  167.     __platform_init();
  168.     if (foreground < 0){ foreground = (*__oldAttributes()) & 0xf; }
  169.     if (background < 0){ background = (*__oldAttributes() & 0xf0) >> 4; }
  170.     SetConsoleTextAttribute(*__stdOutputHandle(), (foreground & 0xf) | ((background & 0xf) << 4));
  171. }
  172.  
  173. // TODO better algorithm needed here.
  174. inline int platform_getApproxColor(unsigned char r, unsigned char g, unsigned char b) {
  175.     int finalColor = 0;
  176.     for (int threshhold = 160; threshhold > 32; threshhold -= 32) {
  177.         if (finalColor == 0) {
  178.             if (r >= threshhold) finalColor |= FOREGROUND_RED;
  179.             if (g >= threshhold) finalColor |= FOREGROUND_GREEN;
  180.             if (b >= threshhold) finalColor |= FOREGROUND_BLUE;
  181.             if (finalColor != 0 && threshhold > 128) finalColor |= FOREGROUND_INTENSITY;
  182.         }
  183.         if (finalColor != 0) break;
  184.     }
  185.     return finalColor;
  186. }
  187.  
  188. inline void platform_sleep(long ms) {
  189.     Sleep(ms);
  190. }
  191.  
  192. inline long long platform_upTimeMS() {
  193.     return clock();
  194. }
  195.  
  196. inline void platform_consoleSize(long & out_rows, long & out_columns) {
  197.     CONSOLE_SCREEN_BUFFER_INFO csbi;
  198.     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
  199.     out_columns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
  200.     out_rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
  201. }
  202.  
  203. #else // #ifdef _WIN32
  204. // how to do console utility stuff for *NIX
  205.  
  206. // escape sequence for arrow keys
  207. #define PLATFORM_KEY_UP 4283163 //'A[\033'
  208. #define PLATFORM_KEY_DOWN 4348699 //'B[\033'
  209. #define PLATFORM_KEY_RIGHT 4414235 //'C[\033'
  210. #define PLATFORM_KEY_LEFT 4479771 //'D[\033'
  211. // used for the first 16 colors of platform_setColor
  212. #define PLATFORM_COLOR_RED (1 << 0)
  213. #define PLATFORM_COLOR_GREEN (1 << 1)
  214. #define PLATFORM_COLOR_BLUE (1 << 2)
  215. #define PLATFORM_COLOR_INTENSITY (1 << 3)
  216.  
  217. #include <unistd.h>     // sleep
  218. #include <sys/select.h> // select, fd_set (for raw, low-level access to input)
  219. #include <sys/time.h>   // for wall-clock timer (as opposed to clock cycle timer)
  220. #include <sys/ioctl.h>  // for ioctl, which can get the console size
  221. #include <termios.h>    // standard terminal i/o stuff
  222. #include <stdlib.h>     // atexit (calls code to clean up when the program exits)
  223.  
  224. // using ANSI TTY console features to control color and cursor position by default.
  225. // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
  226.  
  227. /** keep track of the old terminal settings */
  228. inline termios * __oldTerminalIOSettings() {
  229.     static termios oldTerminalIOSettings;
  230.     return &oldTerminalIOSettings;
  231. }
  232.  
  233. inline long * __initialized() {
  234.     static long initted = 0;
  235.     return &initted;
  236. }
  237.  
  238. /** Linux keeps track of time this way. clock() returns CPU cycles, not time. */
  239. inline timeval * __g_startTime() {
  240.     static timeval g_startTime = { 0, 0 };
  241.     return &g_startTime;
  242. }
  243.  
  244. /** input check during kbhit */
  245. inline fd_set * __g_fds() {
  246.     static fd_set g_fds;
  247.     return &g_fds;
  248. }
  249.  
  250. inline void __platform_release() {
  251.     if (*__initialized() != 0) {
  252.         platform_setColor(-1, -1); // set to not-intense-white
  253.         *__initialized() = 0;
  254.     }
  255. }
  256.  
  257. inline void __platform__init() {
  258.     if (*__initialized() == 0) {
  259.         *__initialized() = 1;
  260.         FD_ZERO(__g_fds()); // initialize the struct that checks for input
  261.         gettimeofday(__g_startTime(), NULL);    // start the timer
  262.         atexit(__platform_release);
  263.     }
  264. }
  265.  
  266. inline void __platform_doConsoleInputMode() {
  267.     __platform__init();
  268.     // make getch read right at the key press, without echoing
  269.     tcgetattr(STDIN_FILENO, __oldTerminalIOSettings());
  270.     termios currentTerminalIOSettings = *__oldTerminalIOSettings();
  271.     currentTerminalIOSettings.c_lflag &= ~(ICANON | ECHO);  // don't wait for enter, don't print
  272.     tcsetattr(STDIN_FILENO, TCSANOW, &currentTerminalIOSettings);
  273. }
  274.  
  275. inline void __platform_undoConsoleInputMode() {
  276.     tcsetattr(STDIN_FILENO, TCSANOW, __oldTerminalIOSettings());
  277. }
  278.  
  279. /** checks if there is input in the keyboard buffer --requires __platform_doConsoleInputMode() */
  280. inline long __platform_kbhitCheck() {
  281.     static timeval g_tv_zero = { 0, 0 };
  282.     long result;
  283.     // check the hardware input stream if there is data waiting
  284.     FD_SET(STDIN_FILENO, __g_fds());
  285.     result = select(STDIN_FILENO + 1, __g_fds(), NULL, NULL, &g_tv_zero);
  286.     // specifically, check for data to be read
  287.     return result && (FD_ISSET(0, __g_fds()));
  288. }
  289.  
  290. inline long platform_kbhit() {
  291.     long result;
  292.     __platform_doConsoleInputMode();
  293.     result = __platform_kbhitCheck();
  294.     __platform_undoConsoleInputMode();
  295.     return result;
  296. }
  297.  
  298. inline long platform_getchar() {
  299.     long buffer = -1;
  300.     __platform_doConsoleInputMode(); // go into single-character-not-printed mode
  301.     if (__platform_kbhitCheck()) {
  302.         buffer = 0;
  303.         read(STDIN_FILENO, (char *)&buffer, 1); // read only one byte
  304.         switch (buffer) {
  305.         case '\033': // if it is an escape sequence, read some more...
  306.             read(STDIN_FILENO, ((char *)&buffer) + 1, 1);
  307.             switch (((char *)&buffer)[1]) {
  308.             case '[': // possibly arrow keys
  309.                 read(STDIN_FILENO, ((char *)&buffer) + 2, 1);
  310.                 break;
  311.             }
  312.             break;
  313.         }
  314.     }
  315.     __platform_undoConsoleInputMode(); // revert to regular input mode, so scanf/std::cin will work
  316.     return buffer;
  317. }
  318.  
  319. inline void platform_move(long row, long col) {
  320.     if (col < 0) col = 0;
  321.     if (row < 0) row = 0;
  322.     __platform__init();
  323.     fflush(stdout);
  324.     printf("\033[%d;%df", (int)row + 1, (int)col + 1);  // move cursor, using TTY codes (without ncurses)
  325.     fflush(stdout);
  326. }
  327.  
  328. inline void platform_setColor(long foreground, long background) {
  329.     static int cached_bg = -1, cached_fg = -1;
  330.     __platform__init();
  331.     // don't bother running the TTY commands if no actual change needs to happen.
  332.     if(foreground == cached_fg && background == cached_bg) { return; } cached_fg = foreground; cached_bg = background;
  333.     fflush(stdout);
  334.     // colorRGB and colorGRAY usable for TTY (unix/linux) expanded console color
  335.     if (foreground >= 0)
  336.         printf("\033[38;5;%dm", (int)foreground);
  337.     else
  338.         printf("\033[39m");// default foreground color
  339.     if (background >= 0)
  340.         printf("\033[48;5;%dm", (int)background);
  341.     else
  342.         printf("\033[49m");// default background color
  343.     fflush(stdout);
  344. }
  345.  
  346. inline void platform_sleep(long a_ms) {
  347.     //  long seconds = a_ms / 1000;
  348.     __platform__init();
  349.     //  a_ms -= seconds * 1000;
  350.     //  timespec time = { seconds, a_ms * 1000000 }; // 1 millisecond = 1,000,000 Nanoseconds
  351.     //  nanosleep(&time, NULL);
  352.     usleep((useconds_t)(a_ms * 1000));
  353. }
  354.  
  355. inline long long platform_upTimeMS() {
  356.     static timeval now;
  357.     static time_t seconds, useconds, ms;
  358.     __platform__init();
  359.     gettimeofday(&now, NULL);
  360.     seconds = now.tv_sec - __g_startTime()->tv_sec;
  361.     useconds = now.tv_usec - __g_startTime()->tv_usec;
  362.     ms = seconds * 1000 + useconds / 1000;
  363.     return ms;
  364. }
  365.  
  366. inline void platform_consoleSize(long & out_rows, long & out_columns) {
  367.     struct winsize w;
  368.     ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
  369.     out_columns = w.ws_col;
  370.     out_rows = w.ws_row;
  371. }
  372.  
  373. /**
  374. * pass to setColor function. Only works in linux/unix TTY
  375. * @param R, G, B values must be between 0 and 5 (inclusive)
  376. */
  377. inline int PLATFORM_COLOR_RGB8bit(int R, int G, int B){ return (16 + (B + (G * 6) + (R * 36))); }
  378.  
  379. inline int platform_getApproxColor(unsigned char r, unsigned char g, unsigned char b) {
  380.     int finalColor = 0;
  381.     if(r == g && g == b) {
  382.         int gray = (r/255.0)*23;
  383.         finalColor = (232+gray);
  384.     } else {
  385.         int R = (int)((r/255.0)*5);
  386.         int G = (int)((g/255.0)*5);
  387.         int B = (int)((b/255.0)*5);
  388.         finalColor = (16+(B+(G*6)+(R*36)));
  389.     }
  390.     return finalColor;
  391. }
  392.  
  393. /**
  394. * pass to setColor function. Only works in linux/unix
  395. * @param gray must be between 0 and 23 (inclusive)
  396. */
  397. inline int PLATFORM_COLOR_GRAYSCALE24(int gray){ return (232 + gray); }
  398. #endif // #ifdef _WIN32 #else
  399.  
  400. #endif // __PLATFORM_CONIO_H
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top