1 #ifndef WIN32
2 
3 #include <fcntl.h>
4 #include <signal.h>
5 #include <ctype.h>
6 #include <sys/ioctl.h>
7 #include <unistd.h>
8 #include <sys/types.h>
9 #include <sys/time.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include "config.h"
15 
16 #ifdef HAVE_SYS_SELECT_H
17 #include <sys/select.h>
18 #endif
19 
20 #ifdef HAVE_LINUX_KD_H
21 	#define HAVE_RAW_KEYBOARD
22 	#include <linux/kd.h>
23 #endif
24 
25 #ifdef HAVE_LINUX_VT_H
26 	#define HAVE_VT_SWITCH
27 	#include <linux/vt.h>
28 #endif
29 
30 #ifdef __EMX__
31 	#define INCL_DOS
32 	#define INCL_DOSERRORS
33 	#define INCL_DOSMONITORS
34 	#define INCL_KBD
35 	#include <os2.h>
36 	#define HAVE_OS2_KEYBOARD
37 #endif
38 
39 #include "kbd.h"
40 #include "console.h"
41 
42 #define KBD_RAW 0
43 #define KBD_STD 1
44 
45 #define KBD_BUFFER_SIZE 256  /* size of buffer for incoming keys */
46 
47 #ifdef HAVE_RAW_KEYBOARD
48 	static int oldkbmode;   /* original keyboard mode */
49 #endif
50 int keyboard_type;
51 
52 /* RAW-MODE KEYBOARD */
53 /* keyboard bitmaps: current and previous */
54 static unsigned char keyboard[128]; /* 0=not pressed, !0=pressed */
55 static unsigned char old_keyboard[128]; /* 0=not pressed, !0=pressed */
56 
57 /* NON-RAW KEYBOARD: */
58 int current_key;
59 int shift_pressed;
60 
61 #ifdef HAVE_OS2_KEYBOARD
62 
63 #define OS2_ALIGN(var) (_THUNK_PTR_STRUCT_OK(&var##1) ? &var##1 : &var##2)
64 
65 HMONITOR os2_hmon;
66 
67 struct os2_key_packet {
68 	USHORT mon_flag;
69 	UCHAR chr;
70 	UCHAR scan;
71 	UCHAR dbcs;
72 	UCHAR dbcs_shift;
73 	USHORT shift_state;
74 	ULONG ms;
75 	USHORT dd_flag;
76 };
77 
78 struct os2_buffer {
79 	USHORT cb;
80 	struct os2_key_packet packet;
81 	char pad[20];
82 };
83 
84 struct os2_key_packet *os2_key;
85 struct os2_buffer *os2_in;
86 struct os2_buffer *os2_out;
87 
os2_read_mon(unsigned char * data,int len)88 int os2_read_mon(unsigned char *data, int len)
89 {
90 	static int prefix = 0;
91 	int bytes_read = 0;
92 	int r;
93 	USHORT count = sizeof(struct os2_key_packet);
94 	while (bytes_read < len) {
95 		int scan;
96 		r = DosMonRead((void *)os2_in, IO_NOWAIT, (void *)os2_key, &count);
97 		if (r == ERROR_MON_BUFFER_EMPTY) break;
98 		if (r) {
99 			fprintf(stderr, "DosMonRead: %d\n", r);
100 			sleep(1);
101 			break;
102 		}
103 		/*fprintf(stderr, "monflag: %04x, scan %02x, shift %04x\n", os2_key->mon_flag, os2_key->scan, os2_key->shift_state);*/
104 		scan = os2_key->mon_flag >> 8;
105 		/*fprintf(stderr, "scan: %02x\n", scan); fflush(stderr);*/
106 		if (scan == 0xE0) {
107 			prefix = 1;
108 			c:continue;
109 		}
110 		if (prefix) {
111 			prefix = 0;
112 			switch (scan & 0x7f) {
113 			case 29:	scan = scan & 0x80 | 97; break;
114 			case 71:	scan = scan & 0x80 | 102; break;
115 			case 72:	scan = scan & 0x80 | 103; break;
116 			case 73:	scan = scan & 0x80 | 104; break;
117 			case 75:	scan = scan & 0x80 | 105; break;
118 			case 77:	scan = scan & 0x80 | 106; break;
119 			case 79:	scan = scan & 0x80 | 107; break;
120 			case 80:	scan = scan & 0x80 | 108; break;
121 			case 81:	scan = scan & 0x80 | 109; break;
122 			case 82:	scan = scan & 0x80 | 110; break;
123 			case 83:	scan = scan & 0x80 | 111; break;
124 			default:
125 		/*fprintf(stderr, "scan: %02x\n", scan); fflush(stderr);*/
126 					goto c;
127 			}
128 		}
129 		data[bytes_read++] = scan;
130 	}
131 	return bytes_read;
132 }
133 
134 #endif
135 
136 /* reads byte from input */
my_getchar(void)137 int my_getchar(void)
138 {
139 	unsigned char a;
140 	read(0,&a,1);
141 	return a;
142 }
143 
144 
145 /* test if there's something on input */
kbhit(void)146 int kbhit(void)
147 {
148 	fd_set fds;
149 	struct timeval tv;
150 
151 	FD_ZERO(&fds);
152 	FD_SET(0,&fds);
153 	tv.tv_sec=0;
154 	tv.tv_usec=0;
155 
156 	return !!(select(1,&fds,NULL,NULL,&tv));
157 }
158 
159 
test_shift(int k)160 void test_shift(int k)
161 {
162 	switch(k)
163 	{
164 		case '~':
165 		case '!':
166 		case '@':
167 		case '#':
168 		case '$':
169 		case '%':
170 		case '^':
171 		case '&':
172 		case '*':
173 		case '(':
174 		case ')':
175 		case '_':
176 		case '+':
177 		case '|':
178 		case 'Q':
179 		case 'W':
180 		case 'E':
181 		case 'R':
182 		case 'T':
183 		case 'Y':
184 		case 'U':
185 		case 'I':
186 		case 'O':
187 		case 'P':
188 		case '{':
189 		case '}':
190 		case 'A':
191 		case 'S':
192 		case 'D':
193 		case 'F':
194 		case 'G':
195 		case 'H':
196 		case 'J':
197 		case 'K':
198 		case 'L':
199 		case ':':
200 		case '"':
201 		case 'Z':
202 		case 'X':
203 		case 'C':
204 		case 'V':
205 		case 'B':
206 		case 'N':
207 		case 'M':
208 		case '<':
209 		case '>':
210 		case '?':
211 		shift_pressed=1;
212 	}
213 }
214 
215 
216 /* non-raw keyboard */
getkey(void)217 int getkey(void)
218 {
219 	int k;
220 	k=my_getchar();
221 	shift_pressed=0;
222 	switch(k)
223 	{
224 		case 0:
225 		switch(my_getchar())
226 		{
227 			case 72:
228 			return K_UP;
229 
230 			case 75:
231 			return K_LEFT;
232 
233 			case 77:
234 			return K_RIGHT;
235 
236 			case 80:
237 			return K_DOWN;
238 
239 			default:
240 			return 0;
241 		}
242 
243 		case 8:
244 		return K_BACKSPACE;
245 
246 		case 9:
247 		return K_TAB;
248 
249 		case 13:
250 		return K_ENTER;
251 
252 		case 27:
253 		if (kbhit())
254 			switch(my_getchar())
255 			{
256 				case 91:
257 				switch(my_getchar())
258 				{
259 					case 65:
260 					return K_UP;
261 
262 					case 66:
263 					return K_DOWN;
264 
265 					case 67:
266 					return K_RIGHT;
267 
268 					case 68:
269 					return K_LEFT;
270 				}
271 			}
272 		return K_ESCAPE;
273 
274 		case 127:
275 		return K_BACKSPACE;
276 
277 		default:
278 		test_shift(k);
279 		return tolower(k);
280 	}
281 }
282 
283 
284 /* on error returns 1 */
kbd_init(void)285 void kbd_init(void)
286 {
287 #ifdef HAVE_RAW_KEYBOARD
288 
289 	keyboard_type=KBD_RAW;
290 
291 	/* raw keyboard */
292 	if (ioctl(0,KDGKBMODE,&oldkbmode))goto std;
293 	if (ioctl(0,KDSKBMODE,K_MEDIUMRAW))goto std;
294 
295 	/* GREAT EXPLANATION TO A SMALL FCNTL: */
296 	/* ----------------------------------- */
297 
298 	/* this fcntl is a great cheat */
299 	/* it switches STDOUT!!!!! to noblocking mode */
300 	/* as i know 0 is STDIN so why it changes STDOUT settings?????? */
301 	/* (does anyone know why???? (if you know send me a mail - you win million:-) (stupid joke...))) */
302 	/* it causes scrambled picture on xterm and telnet */
303 	/* because terminal doesn't manage and loses characters */
304 	/* fortunatelly this fcntl is necessary only with raw keyboard */
305 	/* and to switch keyboard to raw mode you must physically sit on the machine */
306 	/* and when you sit on the machine, terminal is fast enough to manage ;-) */
307 	fcntl(0,F_SETFL,fcntl(0,F_GETFL)|O_NONBLOCK);
308 
309 	memset(keyboard,0,128);
310 	memset(old_keyboard,0,128);
311 	return;
312 std:
313 #endif
314 
315 #ifdef HAVE_OS2_KEYBOARD
316 	keyboard_type=KBD_RAW;
317 	{
318 		static struct os2_key_packet os2_key1, os2_key2;
319 		static struct os2_buffer os2_in1, os2_in2, os2_out1, os2_out2;
320 		int r;
321 		if ((r = DosMonOpen("KBD$", &os2_hmon))) {
322 			fprintf(stderr, "DosMonOpen: %d\n", r);
323 			sleep(1);
324 			goto std;
325 		}
326 		os2_key = OS2_ALIGN(os2_key);
327 		os2_in = OS2_ALIGN(os2_in);
328 		os2_out = OS2_ALIGN(os2_out);
329 		os2_in->cb = sizeof(struct os2_buffer) - sizeof(USHORT);
330 		os2_out->cb = sizeof(struct os2_buffer) - sizeof(USHORT);
331 		if ((r = DosMonReg(os2_hmon, (void *)os2_in, (void *)os2_out, MONITOR_END, -1))) {
332 			if (r = ERROR_MONITORS_NOT_SUPPORTED) {
333 				fprintf(stderr, "RAW keyboard is disabled. Please run 0verkill in full-screen session.%c%c%c", (char)7, (char)7, (char)7);
334 				sleep(5);
335 			} else {
336 				fprintf(stderr, "DosMonReg: %d\n", r);
337 				sleep(1);
338 			}
339 			goto std1;
340 		}
341 	}
342 	memset(keyboard,0,128);
343 	memset(old_keyboard,0,128);
344 	return;
345 std1:	DosMonClose(os2_hmon);
346 std:
347 #endif
348 
349 	/* standard keyboard */
350 	keyboard_type=KBD_STD;
351 	/* nothing to initialize */
352 	current_key=0;
353 	return;
354 }
355 
356 
kbd_close(void)357 void kbd_close(void)
358 {
359 	switch(keyboard_type)
360 	{
361 #ifdef HAVE_RAW_KEYBOARD
362 		case KBD_RAW:
363 		ioctl(0,KDSKBMODE,oldkbmode);
364 		return;
365 #endif
366 
367 #ifdef HAVE_OS2_KEYBOARD
368 		case KBD_RAW:
369 		DosMonClose(os2_hmon);
370 		return;
371 #endif
372 
373 		case KBD_STD:
374 		/* nothing to close */
375 		return;
376 	}
377 }
378 
379 
380 /* convert key from scancode to key constant */
remap_out(int k)381 int remap_out(int k)
382 {
383 	int remap_table[128]={
384 	0,K_ESCAPE,'1','2','3','4','5','6','7','8','9','0','-','=',K_BACKSPACE,K_TAB,
385 	'q','w','e','r','t','y','u','i','o','p','[',']',K_ENTER,K_LEFT_CTRL,'a','s',
386 	'd','f','g','h','j','k','l',';','\'','`',K_LEFT_SHIFT,'\\','z','x','c','v',
387 	'b','n','m',',','.','/',K_RIGHT_SHIFT,K_NUM_ASTERISK,K_LEFT_ALT,' ',K_CAPS_LOCK,K_F1,K_F2,K_F3,K_F4,K_F5,
388 	K_F6,K_F7,K_F8,K_F9,K_F10,K_NUM_LOCK,K_SCROLL_LOCK,K_NUM7,K_NUM8,K_NUM9,K_NUM_MINUS,K_NUM4,K_NUM5,K_NUM6,K_NUM_PLUS,K_NUM1,
389 	K_NUM2,K_NUM3,K_NUM0,K_NUM_DOT,0,0,0,K_F11,K_F12,0,0,0,0,0,0,0,
390 	K_NUM_ENTER,K_RIGHT_CTRL,K_NUM_SLASH,K_SYSRQ,K_RIGHT_ALT,0,K_HOME,K_UP,K_PGUP,K_LEFT,K_RIGHT,K_END,K_DOWN,K_PGDOWN,K_INSERT,K_DELETE,
391 	0,0,0,0,0,0,0,K_PAUSE,0,0,0,0,0,0,0,0
392 	};
393 
394 	return remap_table[k];
395 }
396 
397 
398 /* convert key constant to scancode */
remap_in(int k)399 int remap_in(int k)
400 {
401 	switch (k)
402 	{
403 		case K_ESCAPE: return 1;
404 		case '1': return 2;
405 		case '2': return 3;
406 		case '3': return 4;
407 		case '4': return 5;
408 		case '5': return 6;
409 		case '6': return 7;
410 		case '7': return 8;
411 		case '8': return 9;
412 		case '9': return 10;
413 		case '0': return 11;
414 		case '-': return 12;
415 		case '=': return 13;
416 		case K_BACKSPACE: return 14;
417 		case K_TAB: return 15;
418 		case 'q': return 16;
419 		case 'w': return 17;
420 		case 'e': return 18;
421 		case 'r': return 19;
422 		case 't': return 20;
423 		case 'y': return 21;
424 		case 'u': return 22;
425 		case 'i': return 23;
426 		case 'o': return 24;
427 		case 'p': return 25;
428 		case '[': return 26;
429 		case ']': return 27;
430 		case K_ENTER: return 28;
431 		case K_LEFT_CTRL: return 29;
432 		case 'a': return 30;
433 		case 's': return 31;
434 		case 'd': return 32;
435 		case 'f': return 33;
436 		case 'g': return 34;
437 		case 'h': return 35;
438 		case 'j': return 36;
439 		case 'k': return 37;
440 		case 'l': return 38;
441 		case ';': return 39;
442 		case '\'': return 40;
443 		case '`': return 41;
444 		case K_LEFT_SHIFT: return 42;
445 		case '\\': return 43;
446 		case 'z': return 44;
447 		case 'x': return 45;
448 		case 'c': return 46;
449 		case 'v': return 47;
450 		case 'b': return 48;
451 		case 'n': return 49;
452 		case 'm': return 50;
453 		case ',': return 51;
454 		case '.': return 52;
455 		case '/': return 53;
456 		case K_RIGHT_SHIFT: return 54;
457 		case K_NUM_ASTERISK: return 55;
458 		case K_LEFT_ALT: return 56;
459 		case ' ': return 57;
460 		case K_CAPS_LOCK: return 58;
461 		case K_F1: return 59;
462 		case K_F2: return 60;
463 		case K_F3: return 61;
464 		case K_F4: return 62;
465 		case K_F5: return 63;
466 		case K_F6: return 64;
467 		case K_F7: return 65;
468 		case K_F8: return 66;
469 		case K_F9: return 67;
470 		case K_F10: return 68;
471 		case K_NUM_LOCK: return 69;
472 		case K_SCROLL_LOCK: return 70;
473 		case K_NUM7: return 71;
474 		case K_NUM8: return 72;
475 		case K_NUM9: return 73;
476 		case K_NUM_MINUS: return 74;
477 		case K_NUM4: return 75;
478 		case K_NUM5: return 76;
479 		case K_NUM6: return 77;
480 		case K_NUM_PLUS: return 78;
481 		case K_NUM1: return 79;
482 		case K_NUM2: return 80;
483 		case K_NUM3: return 81;
484 		case K_NUM0: return 82;
485 		case K_NUM_DOT: return 83;
486 		case K_F11: return 87;
487 		case K_F12: return 88;
488 		case K_NUM_ENTER: return 96;
489 		case K_RIGHT_CTRL: return 97;
490 		case K_NUM_SLASH: return 98;
491 		case K_SYSRQ: return 99;
492 		case K_RIGHT_ALT: return 100;
493 		case K_HOME: return 102;
494 		case K_UP: return 103;
495 		case K_PGUP: return 104;
496 		case K_LEFT: return 105;
497 		case K_RIGHT: return 106;
498 		case K_END: return 107;
499 		case K_DOWN: return 108;
500 		case K_PGDOWN: return 109;
501 		case K_INSERT: return 110;
502 		case K_DELETE: return 111;
503 		case K_PAUSE: return 119;
504 		default: return 0;
505 	}
506 
507 }
508 
509 
510 /* returns zero if nothing was read, non-zero otherwise */
kbd_update(void)511 int kbd_update(void)
512 {
513 	unsigned char buffer[KBD_BUFFER_SIZE];
514 	int bytesread,a;
515 
516 	switch(keyboard_type)
517 	{
518 		case KBD_RAW:
519 		memcpy(old_keyboard,keyboard,128);
520 #ifndef HAVE_OS2_KEYBOARD
521 		bytesread=read(0,buffer,KBD_BUFFER_SIZE);
522 #else
523 		bytesread=os2_read_mon(buffer, KBD_BUFFER_SIZE);
524 #endif
525 		if (bytesread<=0)return 0;
526 read_again:
527 		for (a=0;a<bytesread;a++)
528 			keyboard[(buffer[a])&127]=!((buffer[a])&128);
529 		if (bytesread==KBD_BUFFER_SIZE)
530 		{
531 #ifndef HAVE_OS2_KEYBOARD
532 			bytesread=read(0,buffer,KBD_BUFFER_SIZE);
533 #else
534 			bytesread=os2_read_mon(buffer, KBD_BUFFER_SIZE);
535 #endif
536 			if (bytesread<=0)return 1;
537 			goto read_again;
538 		}
539 
540 		/* CTRL-C */
541 		if ((keyboard[29]||keyboard[97])&&keyboard[46])
542 			raise(SIGINT);
543 
544 #ifdef HAVE_VT_SWITCH
545 		/* console switching */
546 		if (keyboard[56]||keyboard[100])  /* alt */
547 		{
548 			for(a=59;a<=68;a++)  /* function keys */
549 				if (keyboard[a])
550 				{
551 					memset(keyboard,0,128); /* terminal is inactive=>keys can't be pressed */
552 					memset(old_keyboard,0,128); /* terminal is inactive=>keys can't be pressed */
553 					ioctl(0,VT_ACTIVATE,a-58);  /* VT switch */
554 					break;
555 				}
556 			if (keyboard[87])
557 			{
558 				memset(keyboard,0,128); /* terminal is inactive=>keys can't be pressed */
559 				memset(old_keyboard,0,128); /* terminal is inactive=>keys can't be pressed */
560 				ioctl(0,VT_ACTIVATE,11);  /* VT switch */
561 			}
562 			else if (keyboard[88])
563 			{
564 				memset(keyboard,0,128); /* terminal is inactive=>keys can't be pressed */
565 				memset(old_keyboard,0,128); /* terminal is inactive=>keys can't be pressed */
566 				ioctl(0,VT_ACTIVATE,12);  /* VT switch */
567 			}
568 		}
569 #endif
570 		return 1;
571 
572 		case KBD_STD:
573 		current_key=0;
574 		if (!kbhit())return 0;
575 		current_key=getkey();
576 		return 1;
577 	}
578 	return 0;
579 }
580 
581 
582 /* returns 1 if given key is pressed, 0 otherwise */
kbd_is_pressed(int key)583 int kbd_is_pressed(int key)
584 {
585 	switch(keyboard_type)
586 	{
587 		case KBD_RAW:
588 		return keyboard[remap_in(key)];
589 
590 		case KBD_STD:
591 		if (key==K_LEFT_SHIFT||key==K_RIGHT_SHIFT)return shift_pressed;
592 		return (current_key==key);
593 	}
594 	return 0;
595 }
596 
597 
598 /* same as kbd_is_pressed but tests rising edge of the key */
kbd_was_pressed(int key)599 int kbd_was_pressed(int key)
600 {
601 	switch(keyboard_type)
602 	{
603 		case KBD_RAW:
604 		return !old_keyboard[remap_in(key)]&&keyboard[remap_in(key)];
605 
606 		case KBD_STD:
607 		return kbd_is_pressed(key);
608 	}
609 	return 0;
610 }
611 
612 
kbd_wait_for_key(void)613 void kbd_wait_for_key(void)
614 {
615 	fd_set fds;
616 
617 #ifdef __EMX__
618 	if (keyboard_type == KBD_RAW) return;
619 #endif
620 	FD_ZERO(&fds);
621 	FD_SET(0,&fds);
622 	select(1,&fds,NULL,NULL,0);
623 }
624 
625 #else
626 	#include "winkbd.c"
627 #endif
628