Non-blocking stdin read on win32
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?
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().
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.
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.
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.
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.
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
Popular Topics
Advertisement