Link to home
Start Free TrialLog in
Avatar of beyonddeath
beyonddeath

asked on

Getting non line buffered keyboard data in vc++ 6

In Visual C++ 6 i need to be able to get user input on the keyboard without enter keypress, i have getch, getche but they are returning crazy values ... paticularily 77 224 and 72 which is all ive been able to receive so far,  none of which mach to the key i press.

If anyone has a way i can do this it is for my multiplayer pong game im makin so its a fairly important peice hehe

THANKS
(nietod remember me ;)
Avatar of jkr
jkr
Flag of Germany image

I have no idea what a 'multilayer pong game' is, but you might want to use 'GetKeyState()' to check whether a key is pressed (Quote from the docs):

"GetKeyState
The GetKeyState function retrieves the status of the specified virtual key. The status specifies whether the key is up, down, or toggled (on, off — alternating each time the key is pressed).

SHORT GetKeyState(
  int nVirtKey   // virtual-key code
);
 
Parameters
nVirtKey
Specifies a virtual key. If the desired virtual key is a letter or digit (A through Z, a through z, or 0 through 9), nVirtKey must be set to the ASCII value of that character. For other keys, it must be a virtual-key code.
If a non-English keyboard layout is used, virtual keys with values in the range ASCII A through Z and 0 through 9 are used to specify most of the character keys. For example, for the German keyboard layout, the virtual key of value ASCII O (0x4F) refers to the "o" key, whereas VK_OEM_1 refers to the "o with umlaut" key.

Return Values
The return value specifies the status of the given virtual key, as follows:

If the high-order bit is 1, the key is down; otherwise, it is up.
If the low-order bit is 1, the key is toggled. A key, such as the caps lock key, is toggled if it is turned on. The key is off and untoggled if the low-order bit is 0. A toggle key's indicator light (if any) on the keyboard will be on when the key is toggled, and off when the key is untoggled.
Remarks
The key status returned from this function changes as a given thread reads key messages from its message queue. The status does not reflect the interrupt-level state associated with the hardware. Use the GetAsyncKeyState function to retrieve that information.

An application calls GetKeyState in response to a keyboard-input message. This function retrieves the state of the key when the input message was generated.

To retrieve state information for all the virtual keys, use the GetKeyboardState function. "

ASKER CERTIFIED SOLUTION
Avatar of nietod
nietod

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of beyonddeath
beyonddeath

ASKER

Nietod firstly sorry i cant spell ur name right ;)

now it may be it got garbled through the system but i get errors in all of your code, if there is an easier way im looking for access to really only up and down and just whether or not they are pushed or not.  

As for jkr Ive got the function but what exactly is a "virtual-key code".
and how exactly should i call this function to receive the value all i manage to get is 0.

Thanks allot sorry for long delay for response school bitez
Edited text of question.
"virtual-key code" is the scan code for each key on the keyboard - they're listed in 'winuser.h'. The ASCII codes for the alphanumeric keys directly correspond to them:

/* VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */
/* VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */

and there are lots more:

/*
 * Virtual Keys, Standard Set
 */
#define VK_LBUTTON        0x01
#define VK_RBUTTON        0x02
#define VK_CANCEL         0x03
#define VK_MBUTTON        0x04    /* NOT contiguous with L & RBUTTON */

#define VK_BACK           0x08
#define VK_TAB            0x09

#define VK_CLEAR          0x0C
#define VK_RETURN         0x0D

#define VK_SHIFT          0x10
#define VK_CONTROL        0x11
#define VK_MENU           0x12
#define VK_PAUSE          0x13
#define VK_CAPITAL        0x14
oic THANKS jkr that should work i will try it now and give u the points if it works ;)
In the last question you said you were working in DOS.  Now you said VC 6 which is only for windows.  Have things changed?  The OS will make a big difference!   The solutions posted here will work only in windows.

I'm not sure how well jkr's solution will work by itself.  The problem is that it tells you the current state of the keys.  but it does not read the key information posted to your program's input buffer.  If that information is not read by some other mechanism this may be a problem.  (I'm not sure of that, JKR might know more about it.)  That is why I suggested you use the windows API console input functions.  That is what they are there for.

The functions I posted will work fine.  but you may need to make sure your program includes the needed files, like window.h and that it links to the necessary libraries.
well it doesnt error but it doesnt work either ;( im calling it like this
int retval;
retval = GetKeyState(VK_UP);
printf("%d",retval);
in this it always will return 1 if it is pressed or if it isnt
Are you using this from a console program?  I'm not sure how well GetKeyState() is going to work from a console program, since it is message based and the OS is handling the console's messages.  I'm not sure it is a problem, but it might be.   It is possible that GetAsyncKeyState() will work better, but I still think it is a step in the wrong direction.  Windows has provided functions for doing this sort of thing from consoles, like ReadConsoleInput().   it will probably take a little programming to make it usable from your program, but it will probably yield the best results.
>>I'm not sure it is a problem, but it
>>might be

It is - it won't work from a console program, as it relies on the fact that the calling thread has a message queue...
Adjusted points from 100 to 117
yes its console unfourtunatly i dont know mfc..... yet ;p

thanks for all the help also is there any commands in vc 6 to move the cursor to a xy cord and start typing (also color?!?) THANKS
hmmm also how do i change the console title ;) if its possible
Code for moving the cursor, outputting text at the cursor, outputing colored text and more.

enum Color
{
   Red,
   Green,
   Blue,
   Yellow,
   Purple,
   Cyan,  
   White,
   Black
};

void GotoXY(int X,int Y)
{
      HANDLE StdOut = GetStdHandle(STD_OUTPUT_HANDLE);
      COORD Coord = {X,Y};
      SetConsoleCursorPosition(StdOut,Coord);
}
void OutputStr(const char *S)
{
      HANDLE StdOut = GetStdHandle(STD_OUTPUT_HANDLE);
      int StrLen = strlen(S);
      DWORD LenWrt;
      WriteConsole(StdOut,S,StrLen,&LenWrt,NULL);
}
void OutputStr(int X,int Y,const char *S)
{
      GotoXY(X,Y);
      OutputStr(S);
}

void ClearScreen()
{
   HANDLE StdOut = GetStdHandle(STD_OUTPUT_HANDLE);
   CONSOLE_SCREEN_BUFFER_INFO BufInf;
   COORD Origin = {0,0};
   DWORD LenWrt;

   GetConsoleScreenBufferInfo(StdOut,&BufInf); // Get screen rows and columns.
 
   int ChrCnt = BufInf.dwSize.X * BufInf.dwSize.Y; // Number of chars on screen.
   
   FillConsoleOutputAttribute(StdOut,0,ChrCnt,Origin,&LenWrt);
   FillConsoleOutputCharacter(StdOut,' ',ChrCnt,Origin,&LenWrt);
}
void SetColor(Color TxtCol,Color BckCol)
{
   HANDLE StdOut = GetStdHandle(STD_OUTPUT_HANDLE);
   WORD   Col    = 0;

   switch (TxtCol)
   {
   case Red:    Col |= FOREGROUND_RED;   break;
   case Green:  Col |= FOREGROUND_GREEN; break;
   case Blue:   Col |= FOREGROUND_BLUE;  break;
   case Yellow: Col |= FOREGROUND_RED | FOREGROUND_GREEN;   break;
   case Purple: Col |= FOREGROUND_RED | FOREGROUND_BLUE;    break;
   case Cyan:   Col |= FOREGROUND_GREEN | FOREGROUND_BLUE;  break;
   case White:  Col |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
   }
   switch (BckCol)
   {
   case Red:    Col |= BACKGROUND_RED;   break;
   case Green:  Col |= BACKGROUND_GREEN; break;
   case Blue:   Col |= BACKGROUND_BLUE;  break;
   case Yellow: Col |= BACKGROUND_RED | BACKGROUND_GREEN;   break;
   case Purple: Col |= BACKGROUND_RED | BACKGROUND_BLUE;    break;
   case Cyan:   Col |= BACKGROUND_GREEN | BACKGROUND_BLUE;  break;
   case White:  Col |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
   }
   SetConsoleTextAttribute(StdOut,Col);
}
You can use SetConsoleTitle() to set the title.
thanks allot nietod thats great ;) now to watch it compile ... i hope :)  so is there a way for me to get the keyboard info...

They should really have a good function for getting keyboard input in the ansii c++ specs eheh

THANKS allot
hey it works GREAT THANKS sooooo much eheh now i can use my program start functions that display my name ;)
about ur color code for LIGHTRED etc do i just change:
 case Red:    Col |= FOREGROUND_RED;   break;
to
 case Red:    Col |= FOREGROUND_LIGHTRED;   break;
Thanks allot sorry for off topic crap
actually nietod in your code after fixing a 3 typos(i presume they are typos u copied from one to the next) in the first of you functions (iskeywaiting) the error returned is:
G:\winsocktest\win.cpp(311) : error C2664: 'WaitForSingleObject' : cannot convert parameter 2 from 'void *' to 'unsigned long'
        This conversion requires a reinterpret_cast, a C-style cast or function-style cast


hope that will help i dont understand why that should make that error... then again i dont really under stand this paticular function ;)
seemed to have fixed it by changing the call to:
WaitForSingleObject(0, StdInHnd)
to
WaitForSingleObject(StdInHnd, 0)
is this ok or will it pose a threat hehe
my bad that crashes ;)

anything else i can try is there somthing i can use in bios.h the last time i asked u said somthing about it...
yes, the parameters are reversed

Where does it crash?

Hmmm, that is not the exact code I use in my program, I don't use a static handle like that.  Check that the handle you are using is not NULL.
hmmmmm ok so how exactly should i do that i dont have any idea what a HANDLE is...
yes if i put it the way you originally had it, it says cannot convert void * to bool a c type blah so its got a prob somewhere but i dont know enough c++ to fix this one...
No oe except the windows programmers really knows.  But if the handle is NULL, it is invalid.  If it is not NULL, it is valid.  Its possible that it is being set to NULL because the static handle is being initialized before the console stuff is initialized.  If that is the case, just make the variable non-static.

>> if i put it the way you originally had it,
That was reversed.  The way you changed it was correct.
now u tell me lol ok i will do that but im off to school i will change it when i get back THANKS allot
I said that before.

"yes, the parameters are reversed "

perhaps that wasn't clear enough as to "when" they were reversed,  i.e. origianlly or after you reversed them.
Adjusted points from 117 to 122
ok... so even if they are why does it crash the program...or better yet how do i fix it.. ...


also is there a delay or wait function in vc++ i should know about heehe damn program goes through to fast for comfort.

Thanks for all the help
oh and how do i find if that handle is void or not?
check the handle in the debugger.  it will be 0 if it is NULL.

You can use sleep() to hold up a program's execution.  (for temporary purposes, i.e. when debugging.)
ok thnx i take it sleep take a variable but i can find out if that handle is void for you know ;)
Are you running under the debugger?  You should just be able to look at the handle variable in the variables window.
ummmm HANDLE is defined as a void * is that a good thing?????
sleep is an undeclared identifier or somthing like that .... owell i dont need it that bad ;)
The issue isn't what the handle is defined to be, the issue is what value it has in that procedure.  Is it being set to a non-zero value or a zero value?

Sleep() is part of the windows API.  It is defined in <windows.h>.  It is available on all windows computers.   You can find it documented in the VC help, like all the other functiosn I've mentioned.  
o i see  ok i will print the value in that after it is run... if it will run that is
yes that worked all too well ;)
crashes the program ;( i hate keyboards lol
its non zero aka value 8 ;)

this is before it calls the return value crap though if that changes anything it didnt crash though it might be clashing with winsock is that possible
its very capable of returning TRUE all the time ;) then crashing in the ConGetChr function...

am i out of luck ;(
Try

bool IsKeyPressed()
{
   static HANDLE StdInHnd = GetStdHandle(STD_INPUT_HANDLE);

   bool retval WaitForSingleObject(StdInHnd,0) == WAIT_OBJECT_0;

   return retval;
}

see if it is crashing before, in, or after the WaitForSingleobject() call.
that function i found doesnt actually crash it its the chr ConGetChr that crashes because IsKeyPressed is ALWAYS returning 1 or true ;(
How do i go about adding LIGHTBLUE or LIGHTRED etc to your color code you gave me above? if its possible?
Adjusted points from 122 to 127
Adjusted points from 127 to 132
ne1 able to help???

is anyone alive???
I've been very busy.

I think I know what the problem is.  it is detecting mouse input and always returning true.  I can show you how to fix it.  But I don't have time now.  If you don't hear from me in 12 hours.  post to this questiona gain to remind me.
ok thanks.... but why would it detect mouse movement if im not movind the mouse im using my other computer to connect winsock to it so it will run your function...

THANKS

its not a problem if u are busy just wondering where every one went ;)
what you need to do is to set the console mode so that mouse input and "window input"  (consoel window moving and sizing info) is not "read" from the console handle.   All this information will still be processed correctly, but won't be made available to you, which is fine because you probably don't want it.   The following code sets the console to not report this information and flushes the input buffer so any information already there is cleared out.  Just do this at start-up and you should be fine.

  HANDLE InpHnd = GetStdHandle(STD_INPUT_HANDLE);
  DWORD Mod;

  GetConsoleMode(InpHnd,&Mod);
  Mod &= ~ENABLE_WINDOW_INPUT;
  Mod &= ~ENABLE_MOUSE_INPUT;
  SetConsoleMode(InpHnd,Mod);
  FlushConsoleInputBuffer(InpHnd);

>> why would it detect mouse movement if
>> im not movind the mouse
I don't know, it may be that it reports an initial mouse position to you or an intial windows position.  It it might report the mouse position at regular time intervals.  I've never tried reading the mouse or window information from standard iinput to know much about it.  But turning it off definitely cures the problem.

As to the colors, you coudl add "bright" colors to the color enum, like "brightred", "brightblue" etc  and then add those entries to the color switch statements.  When a color is bright you need to specify FORGROUND_INTENSITRY or BACKGROUND_INTENSITY  i.e. llike

 case BrightRed:    Col |= FOREGROUND_RED | FORGROUND_INTENSITY;   break;
unfourtunate as it may be it still picks up movement if its at the top of main() but if it is in the IsKeyWaiting() function it returns 0 all the time even if i do press a button...

This is a pain in the ass i say just rip the mouse cable out of the computer and work from their ;)
actually even if i dont move the mouse its still returning 1... well.... if it cant be done... thats life
Adjusted points from 132 to 137
Is it possible that because in the program you have to type after i call your code that it is returning 1? if so, is there a way to only return whats happening at any given time and not saving it all up

THANKS
I assure you it can be done.  I do it.  The code works for me.
ive got it working now ;) thanks but, is there a way to get it not to get the next key from the buffer or for it to clear the buffer and still read if a key is there, because it seems if i push a button (space for example) it returns 1 no matter how many times i call the function not if its pushed at the time of calling the function

i tryied using the code to flush the buffer but it also erased all incoming keys and returned 0 no matter what...

im going to try and call fflush(stdin) and see if that will work


THANKS
It should return trie when a key is pressed, but when the key is then read it should return false until another key is read.
is that so... ok i will try and see if it crashes or not
it freezes the console when i do a ConGetChr call after a true return
anything i can do?
What do you mean by that?   I don't seem to have any problem.
ok when i get a true return from IsKeyWaiting then it calls ConGetChr and freezes the console (stops it from continuing) and i have to ctrl-c out of the program. and ConGetChr never finishes
What do you mean by "true return" ?
Where in ConGetChr() is it stopped?
when your IsKeyWaiting function returns true my if statment will run ConGetChr i will look and find out where it freezes now
ReadConsole(StdInpHnd,&Chr,1,&ChrRed,NULL);
is where it freezes ;(
hope that will help
hmmm it just started working how odd musta been my fault incredible
only thing is if i push more than one button it saves them all up and iskeywaiting returns 1 until they all get read is that fixable?
correction it works if a key is pressed but if no key is pressed it still returns 1 and then goes and calls ConGetChr which fails because there is no key to be read...
also its fairly random ive actually found ;p arrow keys freezes ConGetChr which is not good,and it doesnt save it into buffer when iskeywaiting is called it is when it is pressed which is good and bad because if i push up down left right in rapid succsession it saves those all until i call ConGetChr on them which freezes, also i have to call it 4 times to get onto new things even though i didnt call IsKeyWaiting.

Sorry for all this crap ive been posting hope you can help ;(
im reposting this under the same or similar name so you remember nietod ;)
>>  it saves them all up and iskeywaiting returns 1
>> until they all get read is that fixable?
No.  The function isn't really telling you if a key is currently down, it is telling you if a key is waiting to be read from the console's input buffer.  that is, it tells you if ConGetChr() has information that it can return.

>> if no key is pressed it still returns 1
It should be working.

>> arrow keys freezes ConGetChr which is not good
again, this should not be happening

I am getting very close to a deadline (tomorrow) and then I leave for a week. I don't think I can provide you with much help until I get back.  (certainly no help once I leave.)

Did you set the console mode corectly at the start of the program?  Did it stay "set".  i.e. if you obtain the console mode later, is it okay?
should be, its not urgent ive got to do some work (theres a new concept) so i can wait until you get back

sort of annoying but surly not urgent ;)

Thanks for all the help ill look into the console mode more deeply (this will take time i dont have now to make sure its there throughout the program) anyway if i call the Flush Console Buffer right before the IsKeyWaiting and i run the program it returns 0 after a slight pause even if i hold down the key and my comp starts beeping.  

I cant have delay in my code (tried) cause it screwes up some nonblocking sockets so its got to be quick!

Thanks for all the help

Its only a week right no biggy work on my q3a mod til u get back ;)
Adjusted points from 137 to 222
Adjusted points from 222 to 237
as far as i can tell the console mode is still the same throughout the program, i was just trying with getch() and i can retrieve the value of the up and down of the arrow keys, but when i call it the key needs to be comming up or it does nothing, this is what i want but i cant have it saying that a was pressed then when the key is off then it says the arrow was pressed... Thanks for the help can that be fixed and is _getch() the same thing?
i will have to live with the H K P and D that it returns on the second call that way it keeps things simple enough.  I will give you the points because of all the code youve givin me.

THANKS again nietod!
Thanks for all these code snippets ;)

ill work my program around the flaw in getch() but it is still doable!