Non-blocking stdin read on win32

Started by
4 comments, last by Telastyn 19 years, 4 months ago
I am currently in the process of porting the server side of my current project over to win32 from unix-world. Part of the app allows for someone at the console to enter in simple commands via keyboard. On the unix side, this was fairly simple. I added 0 to the read fdset, and then read(0,buf,bufsize) when select said there was stuff to read. Being on a line buffered terminal made this even nicer. Windows though kind of complicates matters. select() doesn't seem to like trying to select over non-socket file descriptors, which wouldn't really suprise me. The fix I tried was setting select() to non-blocking, and placing the console read in the main while(1) loop. read() [or _read on win32] blocks though, so I went looking into the STL; which I'm admittedly not very familiar with. cin.readsome() appears to do what I'd like, which is read what data is available, and return ASAP. It doesn't though. Type-echo doesn't even seem to work, and the keystrokes sent to the app are instead sent to the CLI after the app closes. So what gives? Am I just ignorant of a little STL trick, or am I barking up the wrong tree? What's the proper way on win32 to read keystrokes from the console without blocking the rest of the app?
Advertisement

Interesting problem :)

I scratched my head on this for quite a bit myself.

but I managed to get a solution (well, I think it is)

from what I can tell, you want a way to tell if someone has typed something into the console, but that doesn't block..
I'm not a *nix person, so I would have never thought of using sockets??!

well... anyway this is the test code

...#include <conio.h>int main(int argc, char* argv[]){	while (true)	{		int i=_kbhit();		while (i--)		{			char msg[256];			cin.getline(msg,256);			printf("****\n");			printf(msg);			printf("\n****\n");		}		Sleep(1000);		printf("beep\n");	}}



seems to work. Yay for msdn.
If all you need is byte input (i.e. char) from the keyboard, you can use _kbhit() to decide when to call _getch() or similar functions. Alternatively - and preferably - you can use ReadConsole() which is a Win32 API call. You can determine the console handle attached to stdin with GetStdHandle().

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

ReadFile.

Windows doesn't support the UNIX notion that "everything is a file," nor does it have the strong C underpinnings of UNIX, so it introduces its own APIs for accomplishing a lot of tasks that are doable in plain ol' C in UNIX.
Keep in mind that getch, kbhit and the rest of <conio.h> is non-standard, meaning the compiler vendor is not guaranteed to supply them. Everything in <windows.h>, OTOH, is guaranteed to be available for Win32 platforms.

And, yeah, I think ReadConsole is a better option than ReadFile.
Hrm, unfortunately ReadConsole blocks until there's at least 1 char to read. A combination of the two [as well as fiddling with the console settings] seems to do the trick though.

Code, for anyone curious.

// Server Setup Procedures Above#ifdef  _WIN32        // set to line buffered mode.        SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT);#endifwhile (1){        /* the main gameserver loop.           All connection handling, message passing and gameplay calculations will occur from here.        */        selected=fds;        #ifdef  _WIN32                if (_kbhit()){                        bzero(buf,cmdlen);                        ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE),buf,cmdlen-2,(unsigned long *)&rtn,0);                        if (debug && rtn){ printf ("%i:%i=%s",testfd,rtn,buf); }                        // damned windows.                        //  message() expects newline delimited.                        //  and the line buffered mode doesn't echo newlines...                        strcat(buf,"\n");                        printf("\n");                        if (rtn && strstr(buf,"\n")){                                message(testfd,buf,rtn);                        }else{                                if (debug){printf ("No newline, chucking.\n");}                        }                }        #endif                // Proceed with select() and client message handling here.                }


And my appologies if anything is ugly or newb-tacular, this is my first experience with trying to make code which compiles nicely on multiple platforms, and I've never had any even semi-serious code reviewed/critiqued by others.

Now that this is complete, hopefully I can now package everything up and get something akin to a tech demo out for people to critique.

Many thanks.

This topic is closed to new replies.

Advertisement