portable alternative to kbhit() and getch() and system("cls") - c

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:");
}
}

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.

Related

C - Portable code on Windows and Unix

I'm creating a program and I want it to run on Windows and UNIX. However I've used many functions that are either Windows or Unix specific. For example functions located in #include<unistd.h> and #include <sys/utsname.h> for UNIX and #include <winsock2.h>and #include <windows.h>for Windows. I've got them working independently but I want to merge them together.
Here is an example:
struct timespec start, end; // UNIX code
LARGE_INTEGER clockFrequency; // Windows code
QueryPerformanceFrequency(&clockFrequency);
LARGE_INTEGER startTime;
LARGE_INTEGER endTime;
LARGE_INTEGER elapsedTime;
//...
QueryPerformanceCounter(&startTime); // Windows code
clock_gettime(CLOCK_REALTIME, &start); // UNIX code
CalculateVectorInputs();
QueryPerformanceCounter(&endTime); // Windows code
clock_gettime(CLOCK_REALTIME, &end); // UNIX code
I'm well aware of ifdef:
#ifdef _WIN32
// Windows code
#else
#ifdef __unix__
// UNIX code
#endif
#endif
but this seems very messy to add all throughout my code, seeing as my program is around 500 lines long. Is there an elegant way to approach this?
A fairly common approach is to write your main application in standard C wherever possible and put all platform specific code in a custom module.
For example, your main application could do
#include "foo_timer.h"
...
foo_timer_t start, end;
foo_get_time(&start);
calculate_stuff();
foo_get_time(&end);
foo_time_delta(start, end, &elapsed);
with no #ifdefs at all.
foo_timer.h might make use of #ifdef to select platform specific typedefs and declarations, but the main implementation will be in separate files:
foo_timer_unix.c contains unix-specific code that implements the foo_timer.h interface.
foo_timer_windows.c contains windows-specific code that implements the foo_timer.h interface.
When your application is compiled, only one of foo_timer_unix.c and foo_timer_windows.c is compiled and linked into the application. The details of this step depend on your build system.

checking whether library exist via preprocessor

There are two libraries zconf.h and unistd.h which are used to at least to get pid of the process. I generally test my code on Mac OSX and Ubuntu 18.04 in which they use zconf.h preferably(compiler offers zconf.h in lieu of unistd.h) if I forget to add, then if the code works, it's ok. However, in some prior day I needed to test the code in another machine AFAIR it has Ubuntu 10 or 12. Its compiler complained that there is no zconf.h. I wonder whether there is a way to check a machine has zconf.h, if not, use unistd.h. Can it be done using preprocessors like,
#ifdef ITS_IF_CONDITION
#include <zconf.h>
#else
#include <unistd.h>
Newer versions of GCC, clang and MSVC compilers implement the __has_include feature. Although it's a C++ 17 feature, I believe all three support it in plain C too.
But the traditional (and probably more portable) way is to check the existence of include files in a config script before the build process. Both autoconf and cmake have ways to achieve this.
#ifdef __has_include
#if __has_include(<zconf.h>)
#include <zconf.h>
#else
#include <unistd.h>
#endif
#else
#include <unistd.h>
#endif

Can't get different compilers to use specific header files?

I'm writing a C project for college, and I want to use the Sleep() function in my header file. The people marking it could be using Linux and I'm developing in VS2013 for Windows. I found out that Sleep() exists in two different header files depending on whether the compiler uses Windows or Linux, I've looked over the web and found suggestions to use "#ifdef" in the preprocessor. However I'm new to preprocessor work so I'm not sure what to use when there's many different suggestions out there, I'm particularly unsure as to whether these suggestions are for the same purpose as mine, so apologies if this is a common question. I've tried the following:
#ifdef _WIN32 || _WIN64
#include<windows.h>
#elif __linux
#include<unistd.h>
#else
#include<unistd.h>
#endif
This compiles fine in VS2013 but I get errors on a linux machine for Sleep() so the code I'm using doesn't seem to work outside of VS2013. Could someone explain what needs to be specified in order to get Windows and Linux to use their respective headers?
The Linux function is named sleep(), in lowercase, but the Windows one is Sleep(), with an uppercase S. And C is case-sensitive. Moreover, the Windows Sleep() takes the argument as milliseconds while the Linux alternative uses seconds.
So something like this is required:
#ifdef _WIN32 || _WIN64
#include<windows.h>
#define sleep(x) Sleep((x) * 1000)
#elif __linux
#include<unistd.h>
#else
#include<unistd.h>
#endif
Or if you prefer, you can do the other way around, but you'll have precision issues. (Consider using nanosleep() if that's an issue).

putwchar / getwchar encoding?

I'm writing code which runs on both Windows and Linux. The application works with unicode strings, and I'm looking to output them to the console using common code.
Will putwchar and getwchar do the trick? For example, can I provide unicode character values to these functions, and they will both display the same character on Linux and Windows?
You are about to enter a world of pain. Invariably *nix consoles prefer you to send them UTF-8 encoded char* data.
Windows on the other hand uses UTF-16 for its Unicode APIs and for console APIs I believe it is limited to UCS2.
You need probably need to find some library code that abstracts away the differences for you. I don't have a good recommendation for you but I am sure that putwchar and getwchar are not the solution.
One of the many ways to reconcile them is to use explicit conversion modes in Windows:
#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#endif
#include <wchar.h>
#include <stdio.h>
#include <locale.h>
int main()
{
#ifdef _WIN32
_setmode(_fileno(stdout), _O_WTEXT);
#else
setlocale(LC_ALL, "en_US.UTF-8");
#endif
fputws(L"Кошка\n", stdout);
}
tested with gcc 4.6.1 on Linux and Visual Studio 2010 on windows
There's also a _O_U8TEXT and _O_U16TEXT in Windows. Your mileage may vary.
See the putwchar man page on Linux. It says that the behavior depends on LC_CTYPE and says "It is reasonable to expect that putwchar() will actually write the multibyte sequence corresponding to the wide character wc." Similarly, getwchar() should read a multibyte sequence from standard input, and return it as a wide character.
Don't assume that they will read/write a constant number of bytes like they would in UCS2.
All that said, character-by-character I/O isn't usually the fastest solution, and when you start optimizing, do keep in mind that on Linux and Unix you'll be working in UTF-8.

Equivalent to Windows getch() for Mac/Linux crashes

I am using getch() and my app crashes instantly. Including when doing:
int main()
{
getch();
}
I can't find the link but supposedly the problem is that it needs to turn off buffering or something strange along those lines, and I still want cout to work along with cross platform code.
I was told to use std::cin.get(), but I'd like the app to quit when a key is pressed, not when the user typed in a letter or number then press enter to quit.
Is there any function for this? The code must work under Mac (my os) and Windows.
Linking/compiling is not an issue; I include <curses.h> and link with -lcurses in XCode, while Windows uses <conio.h>.
Have you looked in <curses.h> to see what the getch() function does?
Hint: OSX and Linux are not the same as Windows.
Specifically, as a macro in <curses.h>, we find:
#define getch() wgetch(stdscr)
Now, there appears, on your system, to be an actual function getch() in the curses library, but it expects stdscr to be set up, and that is done by the curses initialization functions (initscr() and relatives), and that is signally not done by your code. So, your code is invoking undefined behaviour by calling curses routines before the correct initialization is done, leading to the crash.
(Good hint from dmckee - it helped get the link line out of acidzombie24, which was important.)
To get to a point where a single key-stroke can be read and the program terminated cleanly, you have to do a good deal of work on Unix (OSX, Linux). You would have to trap the initial state of the terminal, arrange for an atexit() function - or some similar mechanism - to restore the state of the terminal, change the terminal from cooked mode into raw mode, then invoke a function to read a character (possibly just read(0, &c, 1)), and do your exit. There might be other ways to do it - but it certainly will involve some setup and teardown operations.
One book that might help is Advanced Unix Programming, 2nd Edn by Mark Rochkind; it covers terminal handling at the level needed. Alternatively, you can use <curses.h> properly - that will be simpler than a roll-your-own solution, and probably more reliable.
You have not exhibited a
#include <stdio.h>
or
#include <curses.h>
or similar line. Are you sure that you are linking against a library that includes getch()?
Use the cin.get() function for example:
#include <iostream>
using namespace std;
int main()
{
char input = cin.get();
cout << "You Pressed: " << input;
}
The program would then wait for you to press a key.
Once you have, the key you pressed would be printed to the screen.
The getch function is not available on Unix-like systems, but you can replace it with console commands through your compiler with the system function.
Usage:
In Windows you can use system("pause");
In Unix-like systems (such as OSX) you can use system("read -n1 -p ' ' key");
Note: system is declared in <stdlib.h>.

Resources