# HG changeset patch # User John Tsiombikas # Date 1379900083 -10800 # Node ID 03a0b307706a5b4f47027759d1d35fa30691e704 # Parent 7c8402e27b7c227676010a284c05e00833ffb376 added proper keyboard handling diff -r 7c8402e27b7c -r 03a0b307706a .hgignore --- a/.hgignore Sun Sep 22 18:37:46 2013 +0300 +++ b/.hgignore Mon Sep 23 04:34:43 2013 +0300 @@ -3,7 +3,7 @@ \.OBJ$ \.d$ \.swp$ -^test$ +^deepstone$ \.exe$ \.EXE$ ^OBJECTS.LNK$ diff -r 7c8402e27b7c -r 03a0b307706a Makefile --- a/Makefile Sun Sep 22 18:37:46 2013 +0300 +++ b/Makefile Mon Sep 23 04:34:43 2013 +0300 @@ -1,12 +1,12 @@ obj = main.obj & - wvga.obj dpmi.obj timer.obj mouse.obj & + wvga.obj dpmi.obj timer.obj mouse.obj keyb.obj & mingl.obj mglrast.obj mglclip.obj mglgen.obj & texture.obj palman.obj scene.obj cvec.obj & fixedp.obj bin = deepston.exe CC = wcc386 -CFLAGS = -5 -fp5 -otexan -zq -bt=dos -dRAST_FLOAT -dDBG_USE_FLOAT +CFLAGS = -5 -fp5 -otexan -zq -bt=dos -DRAST_FLOAT -DDBG_USE_FLOAT LD = wlink $(bin): $(obj) diff -r 7c8402e27b7c -r 03a0b307706a RUN --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RUN Mon Sep 23 04:34:43 2013 +0300 @@ -0,0 +1,3 @@ +#!/bin/sh + +DOSEMU_SCALE=3 ./deepstone $* diff -r 7c8402e27b7c -r 03a0b307706a src/fixcase --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/fixcase Mon Sep 23 04:34:43 2013 +0300 @@ -0,0 +1,10 @@ +#!/bin/sh + +# when I ftp files over from the dos machine, everything becomes uppercase... +# just run this in the source dir to fix them all + +for i in *.C *.H; do + fixedname="`echo $i | tr '[:upper:]' '[:lower:]'`" + echo "$i -> $fixedname" + mv "$i" "$fixedname" +done diff -r 7c8402e27b7c -r 03a0b307706a src/keyb.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/keyb.c Mon Sep 23 04:34:43 2013 +0300 @@ -0,0 +1,194 @@ +/* +DOS interrupt-based keyboard driver. +Copyright (C) 2013 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the program. If not, see +*/ +#define KEYB_C_ + +#include +#include +#include +#include +#include +#include +#include "keyb.h" +#include "scancode.h" + +#define KB_INTR 0x9 +#define KB_PORT 0x60 + +#define PIC1_CMD_PORT 0x20 +#define OCW2_EOI (1 << 5) + +#define DONE_INIT (prev_handler) + +static void __interrupt __far kbintr(); + +static void (__interrupt __far *prev_handler)(); + +static int *buffer; +static int buffer_size, buf_ridx, buf_widx; +static int last_key; + +static unsigned int num_pressed; +static unsigned char keystate[256]; + +#define ADVANCE(x) ((x) = ((x) + 1) % buffer_size) + +int kb_init(int bufsz) +{ + if(DONE_INIT) { + fprintf(stderr, "keyboard driver already initialized!\n"); + return 0; + } + + buffer_size = bufsz; + if(buffer_size && !(buffer = malloc(buffer_size * sizeof *buffer))) { + fprintf(stderr, "failed to allocate input buffer, continuing without\n"); + buffer_size = 0; + } + buf_ridx = buf_widx = 0; + last_key = -1; + + memset(keystate, 0, sizeof keystate); + num_pressed = 0; + + /* set our interrupt handler */ + _disable(); + prev_handler = _dos_getvect(KB_INTR); + _dos_setvect(KB_INTR, kbintr); + _enable(); + + return 0; +} + +void kb_shutdown(void) +{ + if(!DONE_INIT) { + return; + } + + /* restore the original interrupt handler */ + _disable(); + _dos_setvect(KB_INTR, prev_handler); + _enable(); + + free(buffer); +} + +int kb_isdown(int key) +{ + if(key == KB_ANY) { + return num_pressed; + } + return (int)keystate[key]; +} + +void kb_wait(void) +{ + int key; + while((key = kb_getkey()) == -1) { + /* put the processor to sleep while waiting for keypresses, but first + * make sure interrupts are enabled, or we'll sleep forever + */ + __asm { + sti + hlt + } + } + kb_putback(key); +} + +int kb_getkey(void) +{ + int res; + + if(buffer) { + if(buf_ridx == buf_widx) { + return -1; + } + res = buffer[buf_ridx]; + ADVANCE(buf_ridx); + } else { + res = last_key; + last_key = -1; + } + return res; +} + +void kb_putback(int key) +{ + if(buffer) { + /* go back a place */ + if(--buf_ridx < 0) { + buf_ridx += buffer_size; + } + + /* if the write end hasn't caught up with us, go back one place + * and put it there, otherwise just overwrite the oldest key which + * is right where we were. + */ + if(buf_ridx == buf_widx) { + ADVANCE(buf_ridx); + } + + buffer[buf_ridx] = key; + } else { + last_key = key; + } +} + +static void __interrupt __far kbintr() +{ + unsigned char code; + int key, press; + + code = inp(KB_PORT); + + if(code >= 128) { + press = 0; + code -= 128; + + if(num_pressed > 0) { + num_pressed--; + } + } else { + press = 1; + + num_pressed++; + } + + key = scantbl[code]; + + if(press) { + /* append to buffer */ + last_key = key; + if(buffer_size > 0) { + buffer[buf_widx] = key; + ADVANCE(buf_widx); + /* if the write end overtook the read end, advance the read end + * too, to discard the oldest keypress from the buffer + */ + if(buf_widx == buf_ridx) { + ADVANCE(buf_ridx); + } + } + } + + /* and update keystate table */ + keystate[key] = press; + + outp(PIC1_CMD_PORT, OCW2_EOI); /* send end-of-interrupt */ +} diff -r 7c8402e27b7c -r 03a0b307706a src/keyb.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/keyb.h Mon Sep 23 04:34:43 2013 +0300 @@ -0,0 +1,40 @@ +/* +DOS interrupt-based keyboard driver. +Copyright (C) 2013 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the program. If not, see +*/ +#ifndef KEYB_H_ +#define KEYB_H_ + +#define KB_ANY (-1) + +int kb_init(int bufsz); /* bufsz can be 0 for no buffered keys */ +void kb_shutdown(void); /* don't forget to call this at the end! */ + +/* Boolean predicate for testing the current state of a particular key. + * You may also pass KB_ANY to test if any key is held down. + */ +int kb_isdown(int key); + +/* waits for any keypress */ +void kb_wait(void); + +/* removes and returns a signle key from the input buffer. + * If buffering is disabled (initialized with kb_init(0)), then it always + * returns the last key pressed. + */ +int kb_getkey(void); + +#endif /* KEYB_H_ */ diff -r 7c8402e27b7c -r 03a0b307706a src/main.c --- a/src/main.c Sun Sep 22 18:37:46 2013 +0300 +++ b/src/main.c Mon Sep 23 04:34:43 2013 +0300 @@ -6,6 +6,7 @@ #include "wvga.h" #include "mingl.h" #include "timer.h" +#include "keyb.h" #include "mouse.h" #include "texture.h" #include "palman.h" @@ -17,7 +18,7 @@ static void shutdown(void); static void redraw(void); static int proc_events(void); -static int keyb(int key); +static int proc_keyb_input(void); static void mouse_button(int bn, int x, int y); static void mouse_motion(int x, int y); static void sighandler(int s); @@ -28,7 +29,12 @@ static float walk_speed = 0.5; static float look_speed = 1.0; + +#ifdef __DOS__ +static int mouse_look = 1; +#else static int mouse_look = 0; +#endif static void *fbuf; static struct scene scn; @@ -58,6 +64,7 @@ hfov = vfov * aspect; init_timer(100); + kb_init(16); /* 16 characters input buffer */ set_video_mode(0x13); @@ -119,6 +126,7 @@ { mgl_free(); set_video_mode(3); + kb_shutdown(); } static void redraw(void) @@ -153,12 +161,10 @@ static int proc_events(void) { static int prev_mx, prev_my, prev_bnmask; - int mx, my, bnmask; + int mx, my, bnmask, key; - if(kbhit()) { - if(keyb(getch()) == 0) { - return 0; - } + if(!proc_keyb_input()) { + return 0; } bnmask = read_mouse(&mx, &my); @@ -174,35 +180,37 @@ return 1; } -static int keyb(int key) +static int proc_keyb_input(void) { - switch(key) { - case 27: - return 0; + /* first examine all keypresses and handle non-movement keys */ + int key; + while((key = kb_getkey()) != -1) { + switch(key) { + case 27: + return 0; - case 'w': + case '`': + mouse_look = !mouse_look; + break; + + default: + break; + } + } + + /* for the movement keys we just care if they are pressed at the moment */ + if(kb_isdown('w') || kb_isdown('W')) cam_move(0, walk_speed); - break; - case 's': + if(kb_isdown('s') || kb_isdown('S')) cam_move(0, -walk_speed); - break; - case 'a': + if(kb_isdown('a') || kb_isdown('A')) cam_move(-walk_speed, 0); - break; - case 'd': + if(kb_isdown('d') || kb_isdown('D')) cam_move(walk_speed, 0); - break; - case '`': - mouse_look = !mouse_look; - break; - - default: - break; - } return 1; } @@ -214,11 +222,22 @@ static void mouse_motion(int x, int y) { - static int prev_x, prev_y; + static int prev_x = -1, prev_y; int dx = x - prev_x; int dy = y - prev_y; - prev_x = x; - prev_y = y; + + if(mouse_look) { + if(prev_x == -1) { + dx = dy = 0; + } + + set_mouse(160, 100); + prev_x = 160; + prev_y = 100; + } else { + prev_x = x; + prev_y = y; + } if(mouse_look || bnstate) { cam_theta += dx * look_speed; diff -r 7c8402e27b7c -r 03a0b307706a src/scancode.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/scancode.h Mon Sep 23 04:34:43 2013 +0300 @@ -0,0 +1,31 @@ +#ifndef KEYB_C_ +#error "do not include scancode.h anywhere..." +#endif + +/* special keys */ +enum { + LALT, RALT, + LCTRL, RCTRL, + LSHIFT, RSHIFT, + F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, + CAPSLK, NUMLK, SCRLK, SYSRQ, + ESC = 27, + INSERT, DEL, HOME, END, PGUP, PGDN, LEFT, RIGHT, UP, DOWN, + NUM_DOT, NUM_ENTER, NUM_PLUS, NUM_MINUS, NUM_MUL, NUM_DIV, + NUM_0, NUM_1, NUM_2, NUM_3, NUM_4, NUM_5, NUM_6, NUM_7, NUM_8, NUM_9, + BACKSP = 127 +}; + +/* table with rough translations from set 1 scancodes to ASCII-ish */ +static int scantbl[] = { + 0, ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', /* 0 - e */ + '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* f - 1c */ + LCTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', /* 1d - 29 */ + LSHIFT, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', RSHIFT, /* 2a - 36 */ + NUM_MUL, LALT, ' ', CAPSLK, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, /* 37 - 44 */ + NUMLK, SCRLK, NUM_7, NUM_8, NUM_9, NUM_MINUS, NUM_4, NUM_5, NUM_6, NUM_PLUS, /* 45 - 4e */ + NUM_1, NUM_2, NUM_3, NUM_0, NUM_DOT, SYSRQ, 0, 0, F11, F12, /* 4d - 58 */ + 0, 0, 0, 0, 0, 0, 0, /* 59 - 5f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 70 - 7f */ +};