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 +};