Arrow Keys and getch

Started by
15 comments, last by Eric Poitras 17 years, 4 months ago
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?
All that is necessary for the triumph of evil is that good men do nothing. -Edmund Burke
Advertisement
Maybe this will help.

Dave
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_Hnamespace 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
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
All that is necessary for the triumph of evil is that good men do nothing. -Edmund Burke
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.
All that is necessary for the triumph of evil is that good men do nothing. -Edmund Burke
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.
Look up GetKeyState and GetAsyncKeyState - they may work in your situation.
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;
}
}
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?
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;
}
}
All that is necessary for the triumph of evil is that good men do nothing. -Edmund Burke

This topic is closed to new replies.

Advertisement