Sign in to follow this  
Eric Poitras

Arrow Keys and getch

Recommended Posts

Eric Poitras    122
Hey, I'm writing a win32 console app with VC++ Express Edition and I'm trying to get the arrow keys to work with getch but it's not working, I can get any other key to respond but not the arrow keys. Any Ideas?

Share this post


Link to post
Share on other sites
Aardvajk    13207
I don't think int86() will work with 32-bit applications any more.

I once put the following together that sort of simulates the codes the getch() used to return for the arrow keys. getch() used to return first a zero, then on the second call one of 72, 80, 75 or 77 for the arrow keys. The following creates a structure with x and y members that represent the two calls. A normal key will have its ASCII code in x. If x is zero, y will contain the old code for the arrow key. The struct also has boolean members that represent the state of the shift and control keys:

keys.h

#ifndef keys_H
#define keys_H

namespace keys
{

class code
{
public:
code(int a=0,int b=0,bool s=false,bool c=false)
: x(a),y(b),shift(s),ctrl(c) { }

int x,y; bool shift,ctrl;
};

void acquire();
code get();

}

#endif




keys.cpp

#include "keys.h"

#include <windows.h>

namespace
{

HANDLE hIn;
INPUT_RECORD InRec;
DWORD NumRead;

}

void keys::acquire()
{
hIn=GetStdHandle(STD_INPUT_HANDLE);
SetConsoleMode(hIn,0);
}

keys::code keys::get()
{
code c;
while(true)
{
ReadConsoleInput(hIn,&InRec,1,&NumRead);

if(InRec.EventType==KEY_EVENT)
{
if(InRec.Event.KeyEvent.bKeyDown==0) continue;

if(InRec.Event.KeyEvent.wVirtualKeyCode==16) continue;
if(InRec.Event.KeyEvent.wVirtualKeyCode==17) continue;
if(InRec.Event.KeyEvent.wVirtualKeyCode==18) continue;

c.x=InRec.Event.KeyEvent.uChar.AsciiChar;
c.y=0;
c.shift=bool(InRec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED);
c.ctrl=bool(InRec.Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED);

if(InRec.Event.KeyEvent.wVirtualKeyCode==38)
{
c.x=0; c.y=72;
}

if(InRec.Event.KeyEvent.wVirtualKeyCode==40)
{
c.x=0; c.y=80;
}

if(InRec.Event.KeyEvent.wVirtualKeyCode==37)
{
c.x=0; c.y=75;
}

if(InRec.Event.KeyEvent.wVirtualKeyCode==39)
{
c.x=0; c.y=77;
}

return c;
}
}
}




You need to call keys::acquire() at the start of the program. You can then call get() like:


void f()
{
keys::code c=keys::get();

switch(c.x)
{
case 0:
switch(c.y)
{
case 72: /* up */ break;
case 80: /* down */ break;
case 75: /* left */ break;
case 77: /* right */ break;
}
break;

case 'a': break;
case 'z': break;
}
}


Obviously you can extend the get() function to convert other scan codes into the old getch() double codes for the other extended keys if you need to.

Equally of course you could (unlike me) move out of the 1980s and actually just respond to the scan codes directly instead.

HTH

Share this post


Link to post
Share on other sites
Eric Poitras    122
Is there an easier way to get all keyboard input to work in a console app without all that extra code, I don't care if i'm not using getch.

Also I'm having this link error now and I don't know why, any ideas?

pdcurses.lib(initscr.obj) : error LNK2019: unresolved external symbol __iob referenced in function _Xinitscr
1>pdcurses.lib(pdcscrn.obj) : error LNK2001: unresolved external symbol __iob
1>pdcurses.lib(terminfo.obj) : error LNK2001: unresolved external symbol __iob
1>C:\Documents and Settings\Eric\My Documents\Visual Studio 2005\Projects\SoA\Debug\SoA.exe : fatal error LNK1120: 1 unresolved externals

Share this post


Link to post
Share on other sites
Eric Poitras    122
ok I fixed the linking errors. all I need know is to get the arrow keys to work. I'm just writing a rogue-like game with pdcurses btw and I can't seem to ge the arrow keys to work to get my character to move... I tried with wasd and that works but i really want to use the arrow keys instead.

Share this post


Link to post
Share on other sites
Aardvajk    13207
The way I've described above is the only way I could ever find to respond to all the keyboard keys.

Borland's compiler has a getch() that works under 32-bit and will respond to the arrow keys as well, but it may be that it just sits on top of code like the above.

Share this post


Link to post
Share on other sites
KulSeran    3267
you know, with slight modification, that code still works with getch()....
You dont need all that console setup and console specific reads.

Atleast on my machine i never had any problems.(VS2005ee)

void f()
{ char c=getch();

switch(c)
{
case 0:
char y = getch()

switch(y)
{
case 72: /* up */ break;
case 80: /* down */ break;
case 75: /* left */ break;
case 77: /* right */ break;
}
break;
}
}

Share this post


Link to post
Share on other sites
Aardvajk    13207
Having just tested this, KulSeran is quite correct. _getch() under VS2005 Express does in fact respond to the keypresses. According to my test, it is returning 224 first, then 72, 80, 75 or 77 as above.

The code I posted above was from when I was using Digital Mars compiler to write a text editor. The DM getch() would not respond to arrow keys (or any extended keys) at all, so I'd just assumed that VS was the same based on the OP's post. Sorry about that.

To the OP, what exactly is the problem you are having with using _getch() (or getch()) to respond to the arrow keys? Seems to work fine for me:


#include <conio.h>
#include <iostream>

int main()
{
int x=_getch();

while(x!=27)
{
std::cout << x << std::endl;
x=_getch();
}

return 0;
}



Pressing the UP arrow key in the above program prints:

224
72

Same with Insert, Delete and so on - first you get 224, then a subsequent press gives a code that identifies the key. I wonder why I'm getting 224 instead of 0 though?

Share this post


Link to post
Share on other sites
Eric Poitras    122
arg... that's not working, I used that code and you have to press the keys like 4 times before anything happens... here's my code:

void CheckForInput( void )
{
c = getch(); // Get Input
/* Act depending on the last key received. */

switch (c)
{
case 'd': //Right arrow key
g_cPlayer.x++;
break;

case 'a': //Left arrow key
g_cPlayer.x--;
break;

case 72: //Up arrow key
g_cPlayer.y--;
break;

case 's': //Down arrow key
g_cPlayer.y++;
break;

default:
break;
}
}

Share this post


Link to post
Share on other sites
Aardvajk    13207
Well since I'm getting a 224 as the first code where KulSeran was getting a 0, and you are getting different results from both of us, I can only assume that the results of _getch() are different with different hardware or something.

Unless anyone can explain these different results better, I can only suggest that you use the Win32 API key event code I posted first. That should work the same on any windows machine.

All very strange though.

Share this post


Link to post
Share on other sites
BigFreak    184
Quote:
Original post by EasilyConfused
Well since I'm getting a 224 as the first code where KulSeran was getting a 0.

Had a wee look around cos this interested me. Have a butcher's 'ere.
Quote:
the first return value will be either 0xE0 or 0x00, depending on which extended key is pressed.

So that'd be that then :o

Share this post


Link to post
Share on other sites
Aardvajk    13207
Quote:
Original post by BigFreak
Quote:
Original post by EasilyConfused
Well since I'm getting a 224 as the first code where KulSeran was getting a 0.

Had a wee look around cos this interested me. Have a butcher's 'ere.
Quote:
the first return value will be either 0xE0 or 0x00, depending on which extended key is pressed.

So that'd be that then :o


Well, that does explain the 224, but how come KulSeran was getting a zero as the first code for the arrow keys and I was getting the 224? Borland's compiler returns 0 as the first code for the arrow keys.

It's also still a mystery why the OP reports having to press keys four times to get my code snippet above to respond.

Thanks for the link though, BTW.

Share this post


Link to post
Share on other sites
BigFreak    184
Yeah, really no idea. But wouldn't it be fair to just cover all your bases with the old if (char == 0 || char == 244) and then call getch() again? No idea why there'd be a discrepency within the same compiler though. 'sodd.

Share this post


Link to post
Share on other sites
KulSeran    3267
Sorry, i was typing faster than i was thinking.
I get (byte)-32 as the first code for the arrow keys/pgup pgdown
and (byte)0 as the first code for function keys

Eric, the problem with your code is that you aren't checking for 2 key presses.

void CheckForInput( void )
{
c = getch(); // Get Input
/* Act depending on the last key received. */
switch ( c )
{
case -32: // <------------------------------------------------
c = getch()

switch (c)
{
case 'M': //Right arrow key
g_cPlayer.x++;
break;

case 'K': //Left arrow key
g_cPlayer.x--;
break;

case 'H': //Up arrow key
g_cPlayer.y--;
break;

case 'P': //Down arrow key
g_cPlayer.y++;
break;

default:
break;
}
}




Share this post


Link to post
Share on other sites
Eric Poitras    122
yeah I tried with 2 key presses but it still won't work, Here's what I changed:

void CheckForInput( void )
{
c = getch(); // Get 1st Scan
/* Act depending on the last key received. */

if (c == 0x00 || c == 0XE0) // <-----------------
{
y = getch(); // get 2nd scan
switch (y)
{
case 77: //Right arrow key
g_cPlayer.x++;
break;

case 75: //Left arrow key
g_cPlayer.x--;
break;

case 72: //Up arrow key
g_cPlayer.y--;
break;

case 80: //Down arrow key
g_cPlayer.y++;
break;

default:
break;
}
}

}
};

Share this post


Link to post
Share on other sites
Eric Poitras    122
hey I just tried to see what value c = getch() was returning when I hit the arrow keys and nothing gets returned! I tried all the other keys and they return a number but when I press the arrow keys nothing happens... odd.

EDIT: ok I just tried it with _getch() instead and it works somewhat but now it seems to wait for a key press. Also I have to press twice for it to get the right key press. If I press left it won't show up but once I press something else it'll print out the value of left. I don't even know what the difference is between getch and _getch.

Anyway that's where I'm at.

[Edited by - Eric Poitras on November 27, 2006 4:14:09 PM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this