2

I need a way to use kbhit and getch functionality in a portable way. I'm currently developing a simple ascii game and I need to detect if a key is pressed. If it is I need to read it and if it isn't I need to continue without waiting for input. I would prefer not to echo it, but I won't be to picky about that. I think kbhit and getch would be great for this, BUT I'm only allowed to use fully portable code(well at least code for linux, mac and PC, not a lot of other OSes come to mind though). As I understand it the termios, curses, and conio libraries aren't fully implemented on all three OSes I need. I'm at a loss. Every solution I have found uses non-portable code. Is there someway I'm able to write portable functions for this myself? I'm currently including stdio.h, stdlib.h, and time.h. I also need a portable way to clear the screen as I'm currently using system("cls") and system("clear") which must also be changed every time I change the OS, or is the a way I could do an if-else and detect the OS the code is running on to switch between these two statements. Here is a segment of code that has these functions:

    char key = ' ';
    while(1)
    {
        system("cls");
        if (_kbhit())
        {
            key =_getch();
            printf("output: %c", key);
        }    
        else
            printf("output:");
    }

This is essentially what functionality I need in my code, but I can't figure out a portable way to do it, and my teacher requires the code to work on Linux, mac, and pc using standard c and standard libraries. Please help! And no c++ please, we are using c.

EDIT: I don't think ncurses wasn't quite what I was looking for. Someone recommended I use #ifdef to implement these at compile time. I like this solution, but I need some help understanding how to do this on linux and mac as I can only test on windows with my current setup. hopefully I will soon have linux running on my other machine for testing, but OSX has a big price tag with it, so I would appreciate the help. Here's the current code:

 //libraries
#include <stdio.h>      //used for i/o
#include <stdlib.h>     //used for clearing the screen
#include <time.h>       //used to get time for random number generator

//check OS and include necessary libraries
#ifdef _WIN32
    //code for Windows (32-bit and 64-bit, this part is common)
    #include <conio.h>
    #define CLEARSCREEN system("cls")
    #define CHECKKEY _kbhit()
    #define NBGETCHAR getch()

#elif __APPLE__
    //code for mac
    #define CLEARSCREEN system("clear")
    #define CHECKKEY 
    #define NBGETCHAR 

#elif __linux__
    //code for linux
    #define CLEARSCREEN system("clear")
    #define CHECKKEY 
    #define NBGETCHAR 

#else
#   error "Unknown compiler"
#endif

int main()
{
    char key = ' ';
    while(1)
    {
        CLEARSCREEN;
        if (CHECKKEY)
        {
            key=NBGETCHAR;
            printf("output: %c", key);
        }    
        else
            printf("output:");
    }
}
  • 2
    One solution is to use `#ifdef` to select (at compile time) the correct code for the OS. Portable code doesn't mean "compile once, run everywhere". It means compile on each OS, with only as many OS dependencies as necessary. – user3386109 Dec 10 '15 at 01:53
  • 2
    There's no portable way to do this. The closest you can come is some sort of third party library that handles the portability issues for you. Curses probably comes the closest to doing that. Otherwise you have to write your own clear(), kbhit(), and getch() functions, with separate versions of each for each operating system. – Ross Ridge Dec 10 '15 at 02:02
  • 1
    WHY is there no portable way to do this? – Dmytro Apr 12 '16 at 19:03
  • 1
    Because unix-like operating systems (Mac OS X, GNU/Linux etc) and Microsoft Windows NT are completely different. In Windows there are **APIs** to do funny stuff with the console window, while in the unixes one uses curses to read and write **magical byte sequences** that were introduced by physical terminals such as VT100 and are still used by the terminal emulators. / History is why there is no portable way to do that. – Oskar Skog Oct 15 '16 at 13:12

1 Answers1

4

You should look into the portable ncurses library. In addition to many other tools for drawing in the terminal, it provides a keyboard interface which includes a getch() function.

Jon Purdy
  • 53,300
  • 8
  • 96
  • 166
  • 2
    This is not the solution. ncurses takes over your screen and is not compatible with existing console programs. Once you go curses you have to convert your whole program to curses to be consistent. ncurses also clears your screen, which usually scares a user used to just running programs that only scroll. – Dmytro Apr 12 '16 at 19:02