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