deepstone

changeset 33:03a0b307706a

added proper keyboard handling
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 23 Sep 2013 04:34:43 +0300
parents 7c8402e27b7c
children c6406e4aa0fb
files .hgignore Makefile RUN src/fixcase src/keyb.c src/keyb.h src/main.c src/scancode.h
diffstat 8 files changed, 328 insertions(+), 31 deletions(-) [+]
line diff
     1.1 --- a/.hgignore	Sun Sep 22 18:37:46 2013 +0300
     1.2 +++ b/.hgignore	Mon Sep 23 04:34:43 2013 +0300
     1.3 @@ -3,7 +3,7 @@
     1.4  \.OBJ$
     1.5  \.d$
     1.6  \.swp$
     1.7 -^test$
     1.8 +^deepstone$
     1.9  \.exe$
    1.10  \.EXE$
    1.11  ^OBJECTS.LNK$
     2.1 --- a/Makefile	Sun Sep 22 18:37:46 2013 +0300
     2.2 +++ b/Makefile	Mon Sep 23 04:34:43 2013 +0300
     2.3 @@ -1,12 +1,12 @@
     2.4  obj = main.obj &
     2.5 -	  wvga.obj dpmi.obj timer.obj mouse.obj &
     2.6 +	  wvga.obj dpmi.obj timer.obj mouse.obj keyb.obj &
     2.7  	  mingl.obj mglrast.obj mglclip.obj mglgen.obj &
     2.8  	  texture.obj palman.obj scene.obj cvec.obj &
     2.9  	  fixedp.obj
    2.10  bin = deepston.exe
    2.11  
    2.12  CC = wcc386
    2.13 -CFLAGS = -5 -fp5 -otexan -zq -bt=dos -dRAST_FLOAT -dDBG_USE_FLOAT
    2.14 +CFLAGS = -5 -fp5 -otexan -zq -bt=dos -DRAST_FLOAT -DDBG_USE_FLOAT
    2.15  LD = wlink
    2.16  
    2.17  $(bin): $(obj)
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/RUN	Mon Sep 23 04:34:43 2013 +0300
     3.3 @@ -0,0 +1,3 @@
     3.4 +#!/bin/sh
     3.5 +
     3.6 +DOSEMU_SCALE=3 ./deepstone $*
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/fixcase	Mon Sep 23 04:34:43 2013 +0300
     4.3 @@ -0,0 +1,10 @@
     4.4 +#!/bin/sh
     4.5 +
     4.6 +# when I ftp files over from the dos machine, everything becomes uppercase...
     4.7 +# just run this in the source dir to fix them all
     4.8 +
     4.9 +for i in *.C *.H; do
    4.10 +	fixedname="`echo $i | tr '[:upper:]' '[:lower:]'`"
    4.11 +	echo "$i -> $fixedname" 
    4.12 +	mv "$i" "$fixedname"
    4.13 +done
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/keyb.c	Mon Sep 23 04:34:43 2013 +0300
     5.3 @@ -0,0 +1,194 @@
     5.4 +/*
     5.5 +DOS interrupt-based keyboard driver.
     5.6 +Copyright (C) 2013  John Tsiombikas <nuclear@member.fsf.org>
     5.7 +
     5.8 +This program is free software: you can redistribute it and/or modify
     5.9 +it under the terms of the GNU General Public License as published by
    5.10 +the Free Software Foundation, either version 3 of the License, or
    5.11 +(at your option) any later version.
    5.12 +
    5.13 +This program is distributed in the hope that it will be useful,
    5.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    5.16 +GNU General Public License  for more details.
    5.17 +
    5.18 +You should have received a copy of the GNU General Public License
    5.19 +along with the program. If not, see <http://www.gnu.org/licenses/>
    5.20 +*/
    5.21 +#define KEYB_C_
    5.22 +
    5.23 +#include <stdio.h>
    5.24 +#include <stdlib.h>
    5.25 +#include <string.h>
    5.26 +#include <conio.h>
    5.27 +#include <dos.h>
    5.28 +#include <i86.h>
    5.29 +#include "keyb.h"
    5.30 +#include "scancode.h"
    5.31 +
    5.32 +#define KB_INTR		0x9
    5.33 +#define KB_PORT		0x60
    5.34 +
    5.35 +#define PIC1_CMD_PORT	0x20
    5.36 +#define OCW2_EOI		(1 << 5)
    5.37 +
    5.38 +#define DONE_INIT	(prev_handler)
    5.39 +
    5.40 +static void __interrupt __far kbintr();
    5.41 +
    5.42 +static void (__interrupt __far *prev_handler)();
    5.43 +
    5.44 +static int *buffer;
    5.45 +static int buffer_size, buf_ridx, buf_widx;
    5.46 +static int last_key;
    5.47 +
    5.48 +static unsigned int num_pressed;
    5.49 +static unsigned char keystate[256];
    5.50 +
    5.51 +#define ADVANCE(x)	((x) = ((x) + 1) % buffer_size)
    5.52 +
    5.53 +int kb_init(int bufsz)
    5.54 +{
    5.55 +	if(DONE_INIT) {
    5.56 +		fprintf(stderr, "keyboard driver already initialized!\n");
    5.57 +		return 0;
    5.58 +	}
    5.59 +
    5.60 +	buffer_size = bufsz;
    5.61 +	if(buffer_size && !(buffer = malloc(buffer_size * sizeof *buffer))) {
    5.62 +		fprintf(stderr, "failed to allocate input buffer, continuing without\n");
    5.63 +		buffer_size = 0;
    5.64 +	}
    5.65 +	buf_ridx = buf_widx = 0;
    5.66 +	last_key = -1;
    5.67 +
    5.68 +	memset(keystate, 0, sizeof keystate);
    5.69 +	num_pressed = 0;
    5.70 +
    5.71 +	/* set our interrupt handler */
    5.72 +	_disable();
    5.73 +	prev_handler = _dos_getvect(KB_INTR);
    5.74 +	_dos_setvect(KB_INTR, kbintr);
    5.75 +	_enable();
    5.76 +
    5.77 +	return 0;
    5.78 +}
    5.79 +
    5.80 +void kb_shutdown(void)
    5.81 +{
    5.82 +	if(!DONE_INIT) {
    5.83 +		return;
    5.84 +	}
    5.85 +
    5.86 +	/* restore the original interrupt handler */
    5.87 +	_disable();
    5.88 +	_dos_setvect(KB_INTR, prev_handler);
    5.89 +	_enable();
    5.90 +
    5.91 +	free(buffer);
    5.92 +}
    5.93 +
    5.94 +int kb_isdown(int key)
    5.95 +{
    5.96 +	if(key == KB_ANY) {
    5.97 +		return num_pressed;
    5.98 +	}
    5.99 +	return (int)keystate[key];
   5.100 +}
   5.101 +
   5.102 +void kb_wait(void)
   5.103 +{
   5.104 +	int key;
   5.105 +	while((key = kb_getkey()) == -1) {
   5.106 +		/* put the processor to sleep while waiting for keypresses, but first
   5.107 +		 * make sure interrupts are enabled, or we'll sleep forever
   5.108 +		 */
   5.109 +		__asm {
   5.110 +			sti
   5.111 +			hlt
   5.112 +		}
   5.113 +	}
   5.114 +	kb_putback(key);
   5.115 +}
   5.116 +
   5.117 +int kb_getkey(void)
   5.118 +{
   5.119 +	int res;
   5.120 +
   5.121 +	if(buffer) {
   5.122 +		if(buf_ridx == buf_widx) {
   5.123 +			return -1;
   5.124 +		}
   5.125 +		res = buffer[buf_ridx];
   5.126 +		ADVANCE(buf_ridx);
   5.127 +	} else {
   5.128 +		res = last_key;
   5.129 +		last_key = -1;
   5.130 +	}
   5.131 +	return res;
   5.132 +}
   5.133 +
   5.134 +void kb_putback(int key)
   5.135 +{
   5.136 +	if(buffer) {
   5.137 +		/* go back a place */
   5.138 +		if(--buf_ridx < 0) {
   5.139 +			buf_ridx += buffer_size;
   5.140 +		}
   5.141 +
   5.142 +		/* if the write end hasn't caught up with us, go back one place
   5.143 +		 * and put it there, otherwise just overwrite the oldest key which
   5.144 +		 * is right where we were.
   5.145 +		 */
   5.146 +		if(buf_ridx == buf_widx) {
   5.147 +			ADVANCE(buf_ridx);
   5.148 +		}
   5.149 +
   5.150 +		buffer[buf_ridx] = key;
   5.151 +	} else {
   5.152 +		last_key = key;
   5.153 +	}
   5.154 +}
   5.155 +
   5.156 +static void __interrupt __far kbintr()
   5.157 +{
   5.158 +	unsigned char code;
   5.159 +	int key, press;
   5.160 +
   5.161 +	code = inp(KB_PORT);
   5.162 +
   5.163 +	if(code >= 128) {
   5.164 +		press = 0;
   5.165 +		code -= 128;
   5.166 +
   5.167 +		if(num_pressed > 0) {
   5.168 +			num_pressed--;
   5.169 +		}
   5.170 +	} else {
   5.171 +		press = 1;
   5.172 +
   5.173 +		num_pressed++;
   5.174 +	}
   5.175 +
   5.176 +	key = scantbl[code];
   5.177 +
   5.178 +	if(press) {
   5.179 +		/* append to buffer */
   5.180 +		last_key = key;
   5.181 +		if(buffer_size > 0) {
   5.182 +			buffer[buf_widx] = key;
   5.183 +			ADVANCE(buf_widx);
   5.184 +			/* if the write end overtook the read end, advance the read end
   5.185 +			 * too, to discard the oldest keypress from the buffer
   5.186 +			 */
   5.187 +			if(buf_widx == buf_ridx) {
   5.188 +				ADVANCE(buf_ridx);
   5.189 +			}
   5.190 +		}
   5.191 +	}
   5.192 +
   5.193 +	/* and update keystate table */
   5.194 +	keystate[key] = press;
   5.195 +
   5.196 +	outp(PIC1_CMD_PORT, OCW2_EOI);	/* send end-of-interrupt */
   5.197 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/keyb.h	Mon Sep 23 04:34:43 2013 +0300
     6.3 @@ -0,0 +1,40 @@
     6.4 +/*
     6.5 +DOS interrupt-based keyboard driver.
     6.6 +Copyright (C) 2013  John Tsiombikas <nuclear@member.fsf.org>
     6.7 +
     6.8 +This program is free software: you can redistribute it and/or modify
     6.9 +it under the terms of the GNU General Public License as published by
    6.10 +the Free Software Foundation, either version 3 of the License, or
    6.11 +(at your option) any later version.
    6.12 +
    6.13 +This program is distributed in the hope that it will be useful,
    6.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
    6.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    6.16 +GNU General Public License  for more details.
    6.17 +
    6.18 +You should have received a copy of the GNU General Public License
    6.19 +along with the program. If not, see <http://www.gnu.org/licenses/>
    6.20 +*/
    6.21 +#ifndef KEYB_H_
    6.22 +#define KEYB_H_
    6.23 +
    6.24 +#define KB_ANY	(-1)
    6.25 +
    6.26 +int kb_init(int bufsz);	/* bufsz can be 0 for no buffered keys */
    6.27 +void kb_shutdown(void); /* don't forget to call this at the end! */
    6.28 +
    6.29 +/* Boolean predicate for testing the current state of a particular key.
    6.30 + * You may also pass KB_ANY to test if any key is held down.
    6.31 + */
    6.32 +int kb_isdown(int key);
    6.33 +
    6.34 +/* waits for any keypress */
    6.35 +void kb_wait(void);
    6.36 +
    6.37 +/* removes and returns a signle key from the input buffer.
    6.38 + * If buffering is disabled (initialized with kb_init(0)), then it always
    6.39 + * returns the last key pressed.
    6.40 + */
    6.41 +int kb_getkey(void);
    6.42 +
    6.43 +#endif	/* KEYB_H_ */
     7.1 --- a/src/main.c	Sun Sep 22 18:37:46 2013 +0300
     7.2 +++ b/src/main.c	Mon Sep 23 04:34:43 2013 +0300
     7.3 @@ -6,6 +6,7 @@
     7.4  #include "wvga.h"
     7.5  #include "mingl.h"
     7.6  #include "timer.h"
     7.7 +#include "keyb.h"
     7.8  #include "mouse.h"
     7.9  #include "texture.h"
    7.10  #include "palman.h"
    7.11 @@ -17,7 +18,7 @@
    7.12  static void shutdown(void);
    7.13  static void redraw(void);
    7.14  static int proc_events(void);
    7.15 -static int keyb(int key);
    7.16 +static int proc_keyb_input(void);
    7.17  static void mouse_button(int bn, int x, int y);
    7.18  static void mouse_motion(int x, int y);
    7.19  static void sighandler(int s);
    7.20 @@ -28,7 +29,12 @@
    7.21  
    7.22  static float walk_speed = 0.5;
    7.23  static float look_speed = 1.0;
    7.24 +
    7.25 +#ifdef __DOS__
    7.26 +static int mouse_look = 1;
    7.27 +#else
    7.28  static int mouse_look = 0;
    7.29 +#endif
    7.30  
    7.31  static void *fbuf;
    7.32  static struct scene scn;
    7.33 @@ -58,6 +64,7 @@
    7.34  	hfov = vfov * aspect;
    7.35  
    7.36  	init_timer(100);
    7.37 +	kb_init(16); /* 16 characters input buffer */
    7.38  
    7.39  	set_video_mode(0x13);
    7.40  
    7.41 @@ -119,6 +126,7 @@
    7.42  {
    7.43  	mgl_free();
    7.44  	set_video_mode(3);
    7.45 +	kb_shutdown();
    7.46  }
    7.47  
    7.48  static void redraw(void)
    7.49 @@ -153,12 +161,10 @@
    7.50  static int proc_events(void)
    7.51  {
    7.52  	static int prev_mx, prev_my, prev_bnmask;
    7.53 -	int mx, my, bnmask;
    7.54 +	int mx, my, bnmask, key;
    7.55  
    7.56 -	if(kbhit()) {
    7.57 -		if(keyb(getch()) == 0) {
    7.58 -			return 0;
    7.59 -		}
    7.60 +	if(!proc_keyb_input()) {
    7.61 +		return 0;
    7.62  	}
    7.63  
    7.64  	bnmask = read_mouse(&mx, &my);
    7.65 @@ -174,35 +180,37 @@
    7.66  	return 1;
    7.67  }
    7.68  
    7.69 -static int keyb(int key)
    7.70 +static int proc_keyb_input(void)
    7.71  {
    7.72 -	switch(key) {
    7.73 -	case 27:
    7.74 -		return 0;
    7.75 +	/* first examine all keypresses and handle non-movement keys */
    7.76 +	int key;
    7.77 +	while((key = kb_getkey()) != -1) {
    7.78 +		switch(key) {
    7.79 +		case 27:
    7.80 +			return 0;
    7.81  
    7.82 -	case 'w':
    7.83 +		case '`':
    7.84 +			mouse_look = !mouse_look;
    7.85 +			break;
    7.86 +
    7.87 +		default:
    7.88 +			break;
    7.89 +		}
    7.90 +	}
    7.91 +
    7.92 +	/* for the movement keys we just care if they are pressed at the moment */
    7.93 +	if(kb_isdown('w') || kb_isdown('W'))
    7.94  		cam_move(0, walk_speed);
    7.95 -		break;
    7.96  
    7.97 -	case 's':
    7.98 +	if(kb_isdown('s') || kb_isdown('S'))
    7.99  		cam_move(0, -walk_speed);
   7.100 -		break;
   7.101  
   7.102 -	case 'a':
   7.103 +	if(kb_isdown('a') || kb_isdown('A'))
   7.104  		cam_move(-walk_speed, 0);
   7.105 -		break;
   7.106  
   7.107 -	case 'd':
   7.108 +	if(kb_isdown('d') || kb_isdown('D'))
   7.109  		cam_move(walk_speed, 0);
   7.110 -		break;
   7.111  
   7.112 -	case '`':
   7.113 -		mouse_look = !mouse_look;
   7.114 -		break;
   7.115 -
   7.116 -	default:
   7.117 -		break;
   7.118 -	}
   7.119  	return 1;
   7.120  }
   7.121  
   7.122 @@ -214,11 +222,22 @@
   7.123  
   7.124  static void mouse_motion(int x, int y)
   7.125  {
   7.126 -	static int prev_x, prev_y;
   7.127 +	static int prev_x = -1, prev_y;
   7.128  	int dx = x - prev_x;
   7.129  	int dy = y - prev_y;
   7.130 -	prev_x = x;
   7.131 -	prev_y = y;
   7.132 +
   7.133 +	if(mouse_look) {
   7.134 +		if(prev_x == -1) {
   7.135 +			dx = dy = 0;
   7.136 +		}
   7.137 +
   7.138 +		set_mouse(160, 100);
   7.139 +		prev_x = 160;
   7.140 +		prev_y = 100;
   7.141 +	} else {
   7.142 +		prev_x = x;
   7.143 +		prev_y = y;
   7.144 +	}
   7.145  
   7.146  	if(mouse_look || bnstate) {
   7.147  		cam_theta += dx * look_speed;
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/scancode.h	Mon Sep 23 04:34:43 2013 +0300
     8.3 @@ -0,0 +1,31 @@
     8.4 +#ifndef KEYB_C_
     8.5 +#error "do not include scancode.h anywhere..."
     8.6 +#endif
     8.7 +
     8.8 +/* special keys */
     8.9 +enum {
    8.10 +	LALT, RALT,
    8.11 +	LCTRL, RCTRL,
    8.12 +	LSHIFT, RSHIFT,
    8.13 +	F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
    8.14 +	CAPSLK, NUMLK, SCRLK, SYSRQ,
    8.15 +	ESC		= 27,
    8.16 +	INSERT, DEL, HOME, END, PGUP, PGDN, LEFT, RIGHT, UP, DOWN,
    8.17 +	NUM_DOT, NUM_ENTER, NUM_PLUS, NUM_MINUS, NUM_MUL, NUM_DIV,
    8.18 +	NUM_0, NUM_1, NUM_2, NUM_3, NUM_4, NUM_5, NUM_6, NUM_7, NUM_8, NUM_9,
    8.19 +	BACKSP	= 127
    8.20 +};
    8.21 +
    8.22 +/* table with rough translations from set 1 scancodes to ASCII-ish */
    8.23 +static int scantbl[] = {
    8.24 +	0, ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',		/* 0 - e */
    8.25 +	'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',			/* f - 1c */
    8.26 +	LCTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',				/* 1d - 29 */
    8.27 +	LSHIFT, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', RSHIFT,			/* 2a - 36 */
    8.28 +	NUM_MUL, LALT, ' ', CAPSLK, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10,			/* 37 - 44 */
    8.29 +	NUMLK, SCRLK, NUM_7, NUM_8, NUM_9, NUM_MINUS, NUM_4, NUM_5, NUM_6, NUM_PLUS,	/* 45 - 4e */
    8.30 +	NUM_1, NUM_2, NUM_3, NUM_0, NUM_DOT, SYSRQ, 0, 0, F11, F12,						/* 4d - 58 */
    8.31 +	0, 0, 0, 0, 0, 0, 0,															/* 59 - 5f */
    8.32 +	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,									/* 60 - 6f */
    8.33 +	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0									/* 70 - 7f */
    8.34 +};