Sign in to follow this  
obi-wan shinobi

Reading a single character from the keyboard

Recommended Posts

How can I make a function/method to read a character from the keyboard and return that character? I've been using conio.h and getch() in c++, but I have no idea how to do this in other languages (and peeking inside conio.h didn't get me much). What I'm looking for is a way to return a character at the console in a single press without having to press enter, such as with Console::Read(). I know how to do this with a Windows Form/Java Frame, but I want to focus on the console. Is there a general theory behind this that will work in most languages, or is it language-specific?

Share this post


Link to post
Share on other sites
dave    2187
Each language that is designed to receieve input from std::in will have it's own implementation for getting it. conion.h is an old style C header and therefore looking in it wouldn't help you learn anything that isn't to do with C.

ace

Share this post


Link to post
Share on other sites
Oberon_Command    6086
I know this isn't in C++ (it's in 16-bit x86 ASM), but still:



; first we call the interrupt to get the key
; when the interrupt is called, the ASCII code of the key pressed will be in AL
mov ah, 00 ; set function to 00h (read key)
int 16h ; call the keyboard interrupt


; now, we can optionally print out the key that was pressed
; if you don't want to do this, just omit this part
mov dl, al ; tell DOS which character to output
mov ah, 02h ; tell DOS to output a character
int 21h ; call the interrupt


Just a look at how things might go a bit lower-level. Of course, it won't work like that for Windows, but that's how it might have worked in the Old Days.

Share this post


Link to post
Share on other sites
pulpfist    528
I have some simple examples of how to write your own keyboard ISR.
It is written for games, so it will basically just track every key press at all times, without any delay.
Since this is 'very old-style', and I'm not sure this is what you want, I wont
post it unless you realy want it.

If you are writing games in 16 bit dos environment this might just be what you want

Maybe this is better http://benryves.com/tutorials/?t=winconsole&c=all

Share this post


Link to post
Share on other sites
Oberon_Command: Is it possible to use code like that you provided along with some inline assembly to get similar results in a higher-level language?

pulpfist: Go ahead and post it. I'll know if it helps once I see it.

Share this post


Link to post
Share on other sites
pulpfist    528
Ok I got most of this stuff from an old book by Andre LaMothe

keydef.h

#ifndef __KEYDEF_H__
#define __KEYDEF_H__

#define MAKE_ESC 1
#define MAKE_1 2
#define MAKE_2 3
#define MAKE_3 4
#define MAKE_4 5
#define MAKE_5 6
#define MAKE_6 7
#define MAKE_7 8
#define MAKE_8 9
#define MAKE_9 10
#define MAKE_0 11
#define MAKE_MINUS 12
#define MAKE_EQUALS 13
#define MAKE_BKSP 14
#define MAKE_TAB 15
#define MAKE_Q 16
#define MAKE_W 17
#define MAKE_E 18
#define MAKE_R 19
#define MAKE_T 20
#define MAKE_Y 21
#define MAKE_U 22
#define MAKE_I 23
#define MAKE_O 24
#define MAKE_P 25
#define MAKE_LFT_BRACKET 26
#define MAKE_RGT_BRACKET 27
#define MAKE_ENTER 28
#define MAKE_CNTRL 29
#define MAKE_A 30
#define MAKE_S 31
#define MAKE_D 32
#define MAKE_F 33
#define MAKE_G 34
#define MAKE_H 35
#define MAKE_J 36
#define MAKE_K 37
#define MAKE_L 38
#define MAKE_SEMI 39
#define MAKE_APOS 40
#define MAKE_TILDE 41
#define MAKE_SHIFTL 42
#define MAKE_BACK_SLASH 43
#define MAKE_Z 44
#define MAKE_X 45
#define MAKE_C 46
#define MAKE_V 47
#define MAKE_B 48
#define MAKE_N 49
#define MAKE_M 50
#define MAKE_COMMA 51
#define MAKE_PERIOD 52
#define MAKE_FOWARD_SLASH 53
#define MAKE_SHIFTR 54
#define MAKE_PRT_SCRN 55
#define MAKE_ALT 56
#define MAKE_SPACE 57
#define MAKE_CAPS_LOCK 58
#define MAKE_F1 59
#define MAKE_F2 60
#define MAKE_F3 61
#define MAKE_F4 62
#define MAKE_F5 63
#define MAKE_F6 64
#define MAKE_F7 65
#define MAKE_F8 66
#define MAKE_F9 67
#define MAKE_F10 68
#define MAKE_NUM_LOCK 69
#define MAKE_SCROLL_LOCK 70
#define MAKE_HOME 71
#define MAKE_UP 72
#define MAKE_PGUP 73
#define MAKE_NUM_MINUS 74
#define MAKE_LT 75
#define MAKE_CENTER 76
#define MAKE_RT 77
#define MAKE_NUM_PLUS 78
#define MAKE_END 79
#define MAKE_DN 80
#define MAKE_PGDWN 81
#define MAKE_INS 82
#define MAKE_DEL 83

#define BREAK_ESC 129
#define BREAK_1 130
#define BREAK_2 131
#define BREAK_3 132
#define BREAK_4 133
#define BREAK_5 134
#define BREAK_6 135
#define BREAK_7 136
#define BREAK_8 137
#define BREAK_9 138
#define BREAK_0 139
#define BREAK_MINUS 140
#define BREAK_EQUALS 141
#define BREAK_BKSP 142
#define BREAK_TAB 143
#define BREAK_Q 144
#define BREAK_W 145
#define BREAK_E 146
#define BREAK_R 147
#define BREAK_T 148
#define BREAK_Y 149
#define BREAK_U 150
#define BREAK_I 151
#define BREAK_O 152
#define BREAK_P 153
#define BREAK_LFT_BRACKET 154
#define BREAK_RGT_BRACKET 155
#define BREAK_ENTER 156
#define BREAK_CNTRL 157
#define BREAK_A 158
#define BREAK_S 159
#define BREAK_D 160
#define BREAK_F 161
#define BREAK_G 162
#define BREAK_H 163
#define BREAK_J 164
#define BREAK_K 165
#define BREAK_L 166
#define BREAK_SEMI 167
#define BREAK_APOS 168
#define BREAK_TILDE 169
#define BREAK_SHIFTL 170
#define BREAK_BACK_SLASH 171
#define BREAK_Z 172
#define BREAK_X 173
#define BREAK_C 174
#define BREAK_V 175
#define BREAK_B 176
#define BREAK_N 177
#define BREAK_M 178
#define BREAK_COMMA 179
#define BREAK_PERIOD 180
#define BREAK_FOWARD_SLASH 181
#define BREAK_SHIFTR 182
#define BREAK_PRT_SCRN 183
#define BREAK_ALT 184
#define BREAK_SPACE 185
#define BREAK_CAPS_LOCK 186
#define BREAK_F1 187
#define BREAK_F2 188
#define BREAK_F3 189
#define BREAK_F4 190
#define BREAK_F5 191
#define BREAK_F6 192
#define BREAK_F7 193
#define BREAK_F8 194
#define BREAK_F9 195
#define BREAK_F10 196
#define BREAK_NUM_LOCK 197
#define BREAK_SCROLL_LOCK 198
#define BREAK_HOME 199
#define BREAK_UP 200
#define BREAK_PGUP 201
#define BREAK_NUM_MINUS 202
#define BREAK_LT 203
#define BREAK_CENTER 204
#define BREAK_RT 205
#define BREAK_NUM_PLUS 206
#define BREAK_END 207
#define BREAK_DN 208
#define BREAK_PGDWN 209
#define BREAK_INS 210
#define BREAK_DEL 211

#endif




keyboard.h

#ifndef __KEYBOARD_H__
#define __KEYBOARD_H__

#define KEYBOARD_INTERRUPT 0x09
#define PIC_PORT 0x20

#define KEY_BUFFER 0x60
#define KEY_CONTROL 0x61

#define KEY_UP 0x00
#define KEY_DOWN 0x01

#include "keydef.h"

class Keyboard
{
private:

static int keyboard_state[128];
static int nkeys_active;

#ifdef __cplusplus
#define __CPPARGS ...
#else
#define __CPPARGS
#endif
static void interrupt keyboard_driver(__CPPARGS);

public:

static void init();
static void exit();

static bool key_up(unsigned int make_code) { return keyboard_state[make_code] == KEY_UP; }
static bool key_down(unsigned int make_code) { return keyboard_state[make_code] == KEY_DOWN; }
static int keys_active() { return nkeys_active; }
};
#endif




keyboard.cpp

//==================================
#include "keyboard.h"
#include <dos.h>

int Keyboard::keyboard_state[128];
int Keyboard::nkeys_active = 0;

void interrupt (*old_keyboard_isr)(__CPPARGS);

//==================================
void Keyboard::init()
{
int index;
for(index=0; index<128; index++)
keyboard_state[index] = KEY_UP;

old_keyboard_isr = _dos_getvect(KEYBOARD_INTERRUPT);
_dos_setvect(KEYBOARD_INTERRUPT, keyboard_driver);
}
//==================================
void Keyboard::exit()
{
_dos_setvect(KEYBOARD_INTERRUPT, old_keyboard_isr);
}
//==================================
void interrupt Keyboard::keyboard_driver(__CPPARGS)
{
int raw_scan_code = 0;

_asm {
sti
in al, KEY_BUFFER
xor ah, ah
mov raw_scan_code, ax
in al, KEY_CONTROL
or al, 82h
out KEY_CONTROL, al
and al, 7fh
out KEY_CONTROL, al
mov al, 20h
out PIC_PORT, al
}

if(raw_scan_code < 128) {
if(keyboard_state[raw_scan_code] == KEY_UP) {
nkeys_active++;
keyboard_state[raw_scan_code] = KEY_DOWN;
}
}
else {
if(keyboard_state[raw_scan_code - 128] == KEY_DOWN) {
nkeys_active--;
keyboard_state[raw_scan_code - 128] = KEY_UP;
}
}
}
//==================================




main.cpp

//================================
//#include <math.h>
#include "timer.h"
#include "keyboard.h"
#include "video.h"
#include "bitmaps.h"
//================================
int smiley_x = 156, smiley_y = 96;

int process_keys(const Keyboard &kb);
int render_buffer(VGA &v);
//================================
int main(int argc, char **argv)
{
Keyboard keyboard;
VGA vga;
Timer timer;

keyboard.init();
vga.init(0x0013, 320, 200);
timer.set_hz(Timer::hz60);
timer.start();

do {
render_buffer(vga);
vga.flip();
timer.wait(1);
timer.start();
} while(!process_keys(keyboard));

timer.set_hz(Timer::hz18);
vga.exit();
keyboard.exit();

return 0;
}
//================================
int process_keys(const Keyboard &kb)
{
// process keys
if(kb.keys_active())
{
if(kb.key_down(MAKE_ESC))
return 1;

if(kb.key_down(MAKE_W)) {
smiley_y--;
if(smiley_y < 0)
smiley_y = 0;
}

if(kb.key_down(MAKE_S)) {
smiley_y++;
if(smiley_y > 200 - 8)
smiley_y = 200 - 8;
}

if(kb.key_down(MAKE_A)) {
smiley_x--;
if(smiley_x < 0)
smiley_x = 0;
}

if(kb.key_down(MAKE_D)) {
smiley_x++;
if(smiley_x > 320 - 8)
smiley_x = 320 - 8;
}
}

return 0;
}
//================================
int render_buffer(VGA &v)
{
v.clear();

v.blit(smiley_x, smiley_y, bmp_smiley, 8, 8);

return 0;
}
//================================




Its pretty much the hardest possible way to read one single character on a 16 bit platform hehe
For a win32 project you can check out the GetAsyncKeyState function instead ^^

Share this post


Link to post
Share on other sites
Undeadlnsanity    233
Why not use an API such as Win32 and simply do:
#include <windows.h>

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE :
DestroyWindow(hwnd);
break;

case WM_DESTROY :
PostQuitMessage(0);

case WM_KEYDOWN :
if (wParam == 'T')
MessageBox(hwnd, "T Pressed", "T", MB_OK);
else if (wParam == VK_ESCAPE)
SendMessage(hwnd, WM_CLOSE, 0, 0);
break;

case WM_KEYUP :
if (wParam == 'R')
MessageBox(hwnd, "R Pressed", "R", MB_OK);
break;
}

return DefWindowProc(hwnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd)
{
LPCTSTR className = "ClassName";
WNDCLASSEX wc;

wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = className;
wc.hIconSm = LoadIcon(NULL, IDI_WINLOGO);

if (!RegisterClassEx(&wc))
{
MessageBox(NULL, "Error registering class",
"Error", MB_OK | MB_ICONERROR);
return 1;
}

HWND hwnd = CreateWindowEx(
0,
className,
"07 - Keyboard Input",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
300, 300,
NULL,
NULL,
hInstance,
NULL
);

if (!hwnd)
{
MessageBox(NULL, "Error creating window",
"Error", MB_OK | MB_ICONERROR);
return 1;
}

ShowWindow(hwnd, nShowCmd);

MSG msg;

while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

return (int)msg.wParam;
}



??

Share this post


Link to post
Share on other sites
Undead Insanity: I could try using Win32 (or .net), but the method you suggested looks as if it were only usable when creating a window. As my original post says, I'm looking for a way to do this at the console output level, in a manner that can be mimicked in several languages. For example, a console-run program that would have a prompt like "Quit: y/n" and would stop the instant 'y' is pressed, continue if 'n' is pressed, and ask again otherwise.

pulpfist: Thanks for the code. Unfortunately, it looks like the same problem I mention above. I'm not necessarily looking for code that will suit a game or anything with its own window, but something at the console-prompt level that can be used (or made) as easily as printf().

Share this post


Link to post
Share on other sites
Oberon_Command    6086
Quote:
Original post by obi-wan shinobi
Oberon_Command: Is it possible to use code like that you provided along with some inline assembly to get similar results in a higher-level language?


It is possible, but AFAIK it won't work in 32-bit mode (AKA protected mode), so it will only work properly when you're using 16-bit code.

And yes, definitely check out the iostream library if you haven't already.

Share this post


Link to post
Share on other sites
Mastaba    761
Well, in Windows, even a console has a windows handle; you just don't normally need it. Which is also the case with this problem, you don't need it. Simply use GetKeyState if you want to see if a particular key is down, or use GetKeyboardState to get the state of all the keys. Or if you just want to read buffered keyboard input, use ReadConsoleInput. And if you just simply don't want to use Win32, you could try using the get member function of the cin standard input stream.


[Edited by - Mastaba on November 27, 2005 12:27:21 AM]

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