SDL-1.2.14
[sdl_omap.git] / src / video / ps2gs / SDL_gsevents.c
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2009 Sam Lantinga
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Lesser General Public License for more details.
14
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19     Sam Lantinga
20     slouken@libsdl.org
21 */
22 #include "SDL_config.h"
23
24 /* Handle the event stream, converting console events into SDL events */
25
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <sys/ioctl.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <limits.h>
33
34 /* For parsing /proc */
35 #include <dirent.h>
36 #include <ctype.h>
37
38 #include <linux/vt.h>
39 #include <linux/kd.h>
40 #include <linux/keyboard.h>
41
42 #include "SDL_mutex.h"
43 #include "../SDL_sysvideo.h"
44 #include "../../events/SDL_sysevents.h"
45 #include "../../events/SDL_events_c.h"
46 #include "SDL_gsvideo.h"
47 #include "SDL_gsevents_c.h"
48 #include "SDL_gskeys.h"
49
50 #ifndef GPM_NODE_FIFO
51 #define GPM_NODE_FIFO   "/dev/gpmdata"
52 #endif
53
54 /* The translation tables from a console scancode to a SDL keysym */
55 #define NUM_VGAKEYMAPS  (1<<KG_CAPSSHIFT)
56 static Uint16 vga_keymap[NUM_VGAKEYMAPS][NR_KEYS];
57 static SDLKey keymap[128];
58 static Uint16 keymap_temp[128]; /* only used at startup */
59 static SDL_keysym *TranslateKey(int scancode, SDL_keysym *keysym);
60
61 /* Ugh, we have to duplicate the kernel's keysym mapping code...
62    Oh, it's not so bad. :-)
63
64    FIXME: Add keyboard LED handling code
65  */
66 static void GS_vgainitkeymaps(int fd)
67 {
68         struct kbentry entry;
69         int map, i;
70
71         /* Don't do anything if we are passed a closed keyboard */
72         if ( fd < 0 ) {
73                 return;
74         }
75
76         /* Load all the keysym mappings */
77         for ( map=0; map<NUM_VGAKEYMAPS; ++map ) {
78                 SDL_memset(vga_keymap[map], 0, NR_KEYS*sizeof(Uint16));
79                 for ( i=0; i<NR_KEYS; ++i ) {
80                         entry.kb_table = map;
81                         entry.kb_index = i;
82                         if ( ioctl(fd, KDGKBENT, &entry) == 0 ) {
83                                 /* fill keytemp. This replaces SDL_fbkeys.h */
84                                 if ( (map == 0) && (i<128) ) {
85                                         keymap_temp[i] = entry.kb_value;
86                                 }
87                                 /* The "Enter" key is a special case */
88                                 if ( entry.kb_value == K_ENTER ) {
89                                         entry.kb_value = K(KT_ASCII,13);
90                                 }
91                                 /* Handle numpad specially as well */
92                                 if ( KTYP(entry.kb_value) == KT_PAD ) {
93                                         switch ( entry.kb_value ) {
94                                         case K_P0:
95                                         case K_P1:
96                                         case K_P2:
97                                         case K_P3:
98                                         case K_P4:
99                                         case K_P5:
100                                         case K_P6:
101                                         case K_P7:
102                                         case K_P8:
103                                         case K_P9:
104                                                 vga_keymap[map][i]=entry.kb_value;
105                                                 vga_keymap[map][i]+= '0';
106                                                 break;
107                                                                                 case K_PPLUS:
108                                                 vga_keymap[map][i]=K(KT_ASCII,'+');
109                                                 break;
110                                                                                 case K_PMINUS:
111                                                 vga_keymap[map][i]=K(KT_ASCII,'-');
112                                                 break;
113                                                                                 case K_PSTAR:
114                                                 vga_keymap[map][i]=K(KT_ASCII,'*');
115                                                 break;
116                                                                                 case K_PSLASH:
117                                                 vga_keymap[map][i]=K(KT_ASCII,'/');
118                                                 break;
119                                                                                 case K_PENTER:
120                                                 vga_keymap[map][i]=K(KT_ASCII,'\r');
121                                                 break;
122                                                                                 case K_PCOMMA:
123                                                 vga_keymap[map][i]=K(KT_ASCII,',');
124                                                 break;
125                                                                                 case K_PDOT:
126                                                 vga_keymap[map][i]=K(KT_ASCII,'.');
127                                                 break;
128                                         default:
129                                                 break;
130                                         }
131                                 }
132                                 /* Do the normal key translation */
133                                 if ( (KTYP(entry.kb_value) == KT_LATIN) ||
134                                          (KTYP(entry.kb_value) == KT_ASCII) ||
135                                          (KTYP(entry.kb_value) == KT_LETTER) ) {
136                                         vga_keymap[map][i] = entry.kb_value;
137                                 }
138                         }
139                 }
140         }
141 }
142
143 int GS_InGraphicsMode(_THIS)
144 {
145         return((keyboard_fd >= 0) && (saved_kbd_mode >= 0));
146 }
147
148 int GS_EnterGraphicsMode(_THIS)
149 {
150         struct termios keyboard_termios;
151
152         /* Set medium-raw keyboard mode */
153         if ( (keyboard_fd >= 0) && !GS_InGraphicsMode(this) ) {
154
155                 /* Switch to the correct virtual terminal */
156                 if ( current_vt > 0 ) {
157                         struct vt_stat vtstate;
158
159                         if ( ioctl(keyboard_fd, VT_GETSTATE, &vtstate) == 0 ) {
160                                 saved_vt = vtstate.v_active;
161                         }
162                         if ( ioctl(keyboard_fd, VT_ACTIVATE, current_vt) == 0 ) {
163                                 ioctl(keyboard_fd, VT_WAITACTIVE, current_vt);
164                         }
165                 }
166
167                 /* Set the terminal input mode */
168                 if ( tcgetattr(keyboard_fd, &saved_kbd_termios) < 0 ) {
169                         SDL_SetError("Unable to get terminal attributes");
170                         if ( keyboard_fd > 0 ) {
171                                 close(keyboard_fd);
172                         }
173                         keyboard_fd = -1;
174                         return(-1);
175                 }
176                 if ( ioctl(keyboard_fd, KDGKBMODE, &saved_kbd_mode) < 0 ) {
177                         SDL_SetError("Unable to get current keyboard mode");
178                         if ( keyboard_fd > 0 ) {
179                                 close(keyboard_fd);
180                         }
181                         keyboard_fd = -1;
182                         return(-1);
183                 }
184                 keyboard_termios = saved_kbd_termios;
185                 keyboard_termios.c_lflag &= ~(ICANON | ECHO | ISIG);
186                 keyboard_termios.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON);
187                 keyboard_termios.c_cc[VMIN] = 0;
188                 keyboard_termios.c_cc[VTIME] = 0;
189                 if (tcsetattr(keyboard_fd, TCSAFLUSH, &keyboard_termios) < 0) {
190                         GS_CloseKeyboard(this);
191                         SDL_SetError("Unable to set terminal attributes");
192                         return(-1);
193                 }
194                 /* This will fail if we aren't root or this isn't our tty */
195                 if ( ioctl(keyboard_fd, KDSKBMODE, K_MEDIUMRAW) < 0 ) {
196                         GS_CloseKeyboard(this);
197                         SDL_SetError("Unable to set keyboard in raw mode");
198                         return(-1);
199                 }
200                 if ( ioctl(keyboard_fd, KDSETMODE, KD_GRAPHICS) < 0 ) {
201                         GS_CloseKeyboard(this);
202                         SDL_SetError("Unable to set keyboard in graphics mode");
203                         return(-1);
204                 }
205         }
206         return(keyboard_fd);
207 }
208
209 void GS_LeaveGraphicsMode(_THIS)
210 {
211         if ( GS_InGraphicsMode(this) ) {
212                 ioctl(keyboard_fd, KDSETMODE, KD_TEXT);
213                 ioctl(keyboard_fd, KDSKBMODE, saved_kbd_mode);
214                 tcsetattr(keyboard_fd, TCSAFLUSH, &saved_kbd_termios);
215                 saved_kbd_mode = -1;
216
217                 /* Head back over to the original virtual terminal */
218                 if ( saved_vt > 0 ) {
219                         ioctl(keyboard_fd, VT_ACTIVATE, saved_vt);
220                 }
221         }
222 }
223
224 void GS_CloseKeyboard(_THIS)
225 {
226         if ( keyboard_fd >= 0 ) {
227                 GS_LeaveGraphicsMode(this);
228                 if ( keyboard_fd > 0 ) {
229                         close(keyboard_fd);
230                 }
231         }
232         keyboard_fd = -1;
233 }
234
235 int GS_OpenKeyboard(_THIS)
236 {
237         /* Open only if not already opened */
238         if ( keyboard_fd < 0 ) {
239                 char *tty0[] = { "/dev/tty0", "/dev/vc/0", NULL };
240                 char *vcs[] = { "/dev/vc/%d", "/dev/tty%d", NULL };
241                 int i, tty0_fd;
242
243                 /* Try to query for a free virtual terminal */
244                 tty0_fd = -1;
245                 for ( i=0; tty0[i] && (tty0_fd < 0); ++i ) {
246                         tty0_fd = open(tty0[i], O_WRONLY, 0);
247                 }
248                 if ( tty0_fd < 0 ) {
249                         tty0_fd = dup(0); /* Maybe stdin is a VT? */
250                 }
251                 ioctl(tty0_fd, VT_OPENQRY, &current_vt);
252                 close(tty0_fd);
253                 if ( (geteuid() == 0) && (current_vt > 0) ) {
254                         for ( i=0; vcs[i] && (keyboard_fd < 0); ++i ) {
255                                 char vtpath[12];
256
257                                 SDL_snprintf(vtpath, SDL_arraysize(vtpath), vcs[i], current_vt);
258                                 keyboard_fd = open(vtpath, O_RDWR, 0);
259 #ifdef DEBUG_KEYBOARD
260                                 fprintf(stderr, "vtpath = %s, fd = %d\n",
261                                         vtpath, keyboard_fd);
262 #endif /* DEBUG_KEYBOARD */
263
264                                 /* This needs to be our controlling tty
265                                    so that the kernel ioctl() calls work
266                                 */
267                                 if ( keyboard_fd >= 0 ) {
268                                         tty0_fd = open("/dev/tty", O_RDWR, 0);
269                                         if ( tty0_fd >= 0 ) {
270                                                 ioctl(tty0_fd, TIOCNOTTY, 0);
271                                                 close(tty0_fd);
272                                         }
273                                 }
274                         }
275                 }
276                 if ( keyboard_fd < 0 ) {
277                         /* Last resort, maybe our tty is a usable VT */
278                         current_vt = 0;
279                         keyboard_fd = open("/dev/tty", O_RDWR);
280                 }
281 #ifdef DEBUG_KEYBOARD
282                 fprintf(stderr, "Current VT: %d\n", current_vt);
283 #endif
284                 saved_kbd_mode = -1;
285
286                 /* Make sure that our input is a console terminal */
287                 { int dummy;
288                   if ( ioctl(keyboard_fd, KDGKBMODE, &dummy) < 0 ) {
289                         close(keyboard_fd);
290                         keyboard_fd = -1;
291                         SDL_SetError("Unable to open a console terminal");
292                   }
293                 }
294
295                 /* Set up keymap */
296                 GS_vgainitkeymaps(keyboard_fd);
297         }
298         return(keyboard_fd);
299 }
300
301 static enum {
302         MOUSE_NONE = -1,
303         MOUSE_GPM,      /* Note: GPM uses the MSC protocol */
304         MOUSE_PS2,
305         MOUSE_IMPS2,
306         MOUSE_MS,
307         MOUSE_BM,
308         NUM_MOUSE_DRVS
309 } mouse_drv = MOUSE_NONE;
310
311 void GS_CloseMouse(_THIS)
312 {
313         if ( mouse_fd > 0 ) {
314                 close(mouse_fd);
315         }
316         mouse_fd = -1;
317 }
318
319 /* Returns processes listed in /proc with the desired name */
320 static int find_pid(DIR *proc, const char *wanted_name)
321 {
322         struct dirent *entry;
323         int pid;
324
325         /* First scan proc for the gpm process */
326         pid = 0;
327         while ( (pid == 0) && ((entry=readdir(proc)) != NULL) ) {
328                 if ( isdigit(entry->d_name[0]) ) {
329                         FILE *status;
330                         char path[PATH_MAX];
331                         char name[PATH_MAX];
332
333                         SDL_snprintf(path, SDL_arraysize(path), "/proc/%s/status", entry->d_name);
334                         status=fopen(path, "r");
335                         if ( status ) {
336                                 name[0] = '\0';
337                                 fscanf(status, "Name: %s", name);
338                                 if ( SDL_strcmp(name, wanted_name) == 0 ) {
339                                         pid = atoi(entry->d_name);
340                                 }
341                                 fclose(status);
342                         }
343                 }
344         }
345         return pid;
346 }
347
348 /* Returns true if /dev/gpmdata is being written to by gpm */
349 static int gpm_available(void)
350 {
351         int available;
352         DIR *proc;
353         int pid;
354         int cmdline, len, arglen;
355         char path[PATH_MAX];
356         char args[PATH_MAX], *arg;
357
358         /* Don't bother looking if the fifo isn't there */
359         if ( access(GPM_NODE_FIFO, F_OK) < 0 ) {
360                 return(0);
361         }
362
363         available = 0;
364         proc = opendir("/proc");
365         if ( proc ) {
366                 while ( (pid=find_pid(proc, "gpm")) > 0 ) {
367                         SDL_snprintf(path, SDL_arraysize(path), "/proc/%d/cmdline", pid);
368                         cmdline = open(path, O_RDONLY, 0);
369                         if ( cmdline >= 0 ) {
370                                 len = read(cmdline, args, sizeof(args));
371                                 arg = args;
372                                 while ( len > 0 ) {
373                                         if ( SDL_strcmp(arg, "-R") == 0 ) {
374                                                 available = 1;
375                                         }
376                                         arglen = SDL_strlen(arg)+1;
377                                         len -= arglen;
378                                         arg += arglen;
379                                 }
380                                 close(cmdline);
381                         }
382                 }
383                 closedir(proc);
384         }
385         return available;
386 }
387
388
389 /* rcg06112001 Set up IMPS/2 mode, if possible. This gives
390  *  us access to the mousewheel, etc. Returns zero if
391  *  writes to device failed, but you still need to query the
392  *  device to see which mode it's actually in.
393  */
394 static int set_imps2_mode(int fd)
395 {
396         /* If you wanted to control the mouse mode (and we do :)  ) ...
397                 Set IMPS/2 protocol:
398                         {0xf3,200,0xf3,100,0xf3,80}
399                 Reset mouse device:
400                         {0xFF}
401         */
402         Uint8 set_imps2[] = {0xf3, 200, 0xf3, 100, 0xf3, 80};
403         Uint8 reset = 0xff;
404         fd_set fdset;
405         struct timeval tv;
406         int retval = 0;
407
408         if ( write(fd, &set_imps2, sizeof(set_imps2)) == sizeof(set_imps2) ) {
409                 if (write(fd, &reset, sizeof (reset)) == sizeof (reset) ) {
410                         retval = 1;
411                 }
412         }
413
414         /* Get rid of any chatter from the above */
415         FD_ZERO(&fdset);
416         FD_SET(fd, &fdset);
417         tv.tv_sec = 0;
418         tv.tv_usec = 0;
419         while ( select(fd+1, &fdset, 0, 0, &tv) > 0 ) {
420                 char temp[32];
421                 read(fd, temp, sizeof(temp));
422         }
423
424         return retval;
425 }
426
427
428 /* Returns true if the mouse uses the IMPS/2 protocol */
429 static int detect_imps2(int fd)
430 {
431         int imps2;
432
433         imps2 = 0;
434
435         if ( SDL_getenv("SDL_MOUSEDEV_IMPS2") ) {
436                 imps2 = 1;
437         }
438         if ( ! imps2 ) {
439                 Uint8 query_ps2 = 0xF2;
440                 fd_set fdset;
441                 struct timeval tv;
442
443                 /* Get rid of any mouse motion noise */
444                 FD_ZERO(&fdset);
445                 FD_SET(fd, &fdset);
446                 tv.tv_sec = 0;
447                 tv.tv_usec = 0;
448                 while ( select(fd+1, &fdset, 0, 0, &tv) > 0 ) {
449                         char temp[32];
450                         read(fd, temp, sizeof(temp));
451                 }
452
453                 /* Query for the type of mouse protocol */
454                 if ( write(fd, &query_ps2, sizeof (query_ps2)) == sizeof (query_ps2)) {
455                         Uint8 ch = 0;
456
457                         /* Get the mouse protocol response */
458                         do {
459                                 FD_ZERO(&fdset);
460                                 FD_SET(fd, &fdset);
461                                 tv.tv_sec = 1;
462                                 tv.tv_usec = 0;
463                                 if ( select(fd+1, &fdset, 0, 0, &tv) < 1 ) {
464                                         break;
465                                 }
466                         } while ( (read(fd, &ch, sizeof (ch)) == sizeof (ch)) &&
467                                   ((ch == 0xFA) || (ch == 0xAA)) );
468
469                         /* Experimental values (Logitech wheelmouse) */
470 #ifdef DEBUG_MOUSE
471 fprintf(stderr, "Last mouse mode: 0x%x\n", ch);
472 #endif
473                         if ( ch == 3 ) {
474                                 imps2 = 1;
475                         }
476                 }
477         }
478         return imps2;
479 }
480
481 int GS_OpenMouse(_THIS)
482 {
483         int i;
484         const char *mousedev;
485         const char *mousedrv;
486
487         mousedrv = SDL_getenv("SDL_MOUSEDRV");
488         mousedev = SDL_getenv("SDL_MOUSEDEV");
489         mouse_fd = -1;
490
491         /* STD MICE */
492
493         if ( mousedev == NULL ) {
494                 /* FIXME someday... allow multiple mice in this driver */
495                 char *ps2mice[] = {
496                     "/dev/input/mice", "/dev/usbmouse", "/dev/psaux", NULL
497                 };
498                 /* First try to use GPM in repeater mode */
499                 if ( mouse_fd < 0 ) {
500                         if ( gpm_available() ) {
501                                 mouse_fd = open(GPM_NODE_FIFO, O_RDONLY, 0);
502                                 if ( mouse_fd >= 0 ) {
503 #ifdef DEBUG_MOUSE
504 fprintf(stderr, "Using GPM mouse\n");
505 #endif
506                                         mouse_drv = MOUSE_GPM;
507                                 }
508                         }
509                 }
510                 /* Now try to use a modern PS/2 mouse */
511                 for ( i=0; (mouse_fd < 0) && ps2mice[i]; ++i ) {
512                         mouse_fd = open(ps2mice[i], O_RDWR, 0);
513                         if (mouse_fd < 0) {
514                                 mouse_fd = open(ps2mice[i], O_RDONLY, 0);
515                         }
516                         if (mouse_fd >= 0) {
517                                 /* rcg06112001 Attempt to set IMPS/2 mode */
518                                 if ( i == 0 ) {
519                                         set_imps2_mode(mouse_fd);
520                                 }
521                                 if (detect_imps2(mouse_fd)) {
522 #ifdef DEBUG_MOUSE
523 fprintf(stderr, "Using IMPS2 mouse\n");
524 #endif
525                                         mouse_drv = MOUSE_IMPS2;
526                                 } else {
527                                         mouse_drv = MOUSE_PS2;
528 #ifdef DEBUG_MOUSE
529 fprintf(stderr, "Using PS2 mouse\n");
530 #endif
531                                 }
532                         }
533                 }
534                 /* Next try to use a PPC ADB port mouse */
535                 if ( mouse_fd < 0 ) {
536                         mouse_fd = open("/dev/adbmouse", O_RDONLY, 0);
537                         if ( mouse_fd >= 0 ) {
538 #ifdef DEBUG_MOUSE
539 fprintf(stderr, "Using ADB mouse\n");
540 #endif
541                                 mouse_drv = MOUSE_BM;
542                         }
543                 }
544         }
545         /* Default to a serial Microsoft mouse */
546         if ( mouse_fd < 0 ) {
547                 if ( mousedev == NULL ) {
548                         mousedev = "/dev/mouse";
549                 }
550                 mouse_fd = open(mousedev, O_RDONLY, 0);
551                 if ( mouse_fd >= 0 ) {
552                         struct termios mouse_termios;
553
554                         /* Set the sampling speed to 1200 baud */
555                         tcgetattr(mouse_fd, &mouse_termios);
556                         mouse_termios.c_iflag = IGNBRK | IGNPAR;
557                         mouse_termios.c_oflag = 0;
558                         mouse_termios.c_lflag = 0;
559                         mouse_termios.c_line = 0;
560                         mouse_termios.c_cc[VTIME] = 0;
561                         mouse_termios.c_cc[VMIN] = 1;
562                         mouse_termios.c_cflag = CREAD | CLOCAL | HUPCL;
563                         mouse_termios.c_cflag |= CS8;
564                         mouse_termios.c_cflag |= B1200;
565                         tcsetattr(mouse_fd, TCSAFLUSH, &mouse_termios);
566 #ifdef DEBUG_MOUSE
567 fprintf(stderr, "Using Microsoft mouse on %s\n", mousedev);
568 #endif
569                         mouse_drv = MOUSE_MS;
570                 }
571         }
572         if ( mouse_fd < 0 ) {
573                 mouse_drv = MOUSE_NONE;
574         }
575         return(mouse_fd);
576 }
577
578 static int posted = 0;
579
580 void GS_vgamousecallback(int button, int dx, int dy)
581 {
582         int button_1, button_3;
583         int button_state;
584         int state_changed;
585         int i;
586         Uint8 state;
587
588         if ( dx || dy ) {
589                 posted += SDL_PrivateMouseMotion(0, 1, dx, dy);
590         }
591
592         /* Swap button 1 and 3 */
593         button_1 = (button & 0x04) >> 2;
594         button_3 = (button & 0x01) << 2;
595         button &= ~0x05;
596         button |= (button_1|button_3);
597
598         /* See what changed */
599         button_state = SDL_GetMouseState(NULL, NULL);
600         state_changed = button_state ^ button;
601         for ( i=0; i<8; ++i ) {
602                 if ( state_changed & (1<<i) ) {
603                         if ( button & (1<<i) ) {
604                                 state = SDL_PRESSED;
605                         } else {
606                                 state = SDL_RELEASED;
607                         }
608                         posted += SDL_PrivateMouseButton(state, i+1, 0, 0);
609                 }
610         }
611 }
612
613 /* For now, use GPM, PS/2, and MS protocols
614    Driver adapted from the SVGAlib mouse driver code (taken from gpm, etc.)
615  */
616 static void handle_mouse(_THIS)
617 {
618         static int start = 0;
619         static unsigned char mousebuf[BUFSIZ];
620         int i, nread;
621         int button = 0;
622         int dx = 0, dy = 0;
623         int packetsize = 0;
624
625         /* Figure out the mouse packet size */
626         switch (mouse_drv) {
627                 case MOUSE_NONE:
628                         /* Ack! */
629                         read(mouse_fd, mousebuf, BUFSIZ);
630                         return;
631                 case MOUSE_GPM:
632                         packetsize = 5;
633                         break;
634                 case MOUSE_IMPS2:
635                         packetsize = 4;
636                         break;
637                 case MOUSE_PS2:
638                 case MOUSE_MS:
639                 case MOUSE_BM:
640                         packetsize = 3;
641                         break;
642                 case NUM_MOUSE_DRVS:
643                         /* Uh oh.. */
644                         packetsize = 0;
645                         break;
646         }
647
648         /* Read as many packets as possible */
649         nread = read(mouse_fd, &mousebuf[start], BUFSIZ-start);
650         if ( nread < 0 ) {
651                 return;
652         }
653         nread += start;
654 #ifdef DEBUG_MOUSE
655         fprintf(stderr, "Read %d bytes from mouse, start = %d\n", nread, start);
656 #endif
657         for ( i=0; i<(nread-(packetsize-1)); i += packetsize ) {
658                 switch (mouse_drv) {
659                         case MOUSE_NONE:
660                                 break;
661                         case MOUSE_GPM:
662                                 /* GPM protocol has 0x80 in high byte */
663                                 if ( (mousebuf[i] & 0xF8) != 0x80 ) {
664                                         /* Go to next byte */
665                                         i -= (packetsize-1);
666                                         continue;
667                                 }
668                                 /* Get current mouse state */
669                                 button = (~mousebuf[i]) & 0x07;
670                                 dx =   (signed char)(mousebuf[i+1]) +
671                                        (signed char)(mousebuf[i+3]);
672                                 dy = -((signed char)(mousebuf[i+2]) +
673                                        (signed char)(mousebuf[i+4]));
674                                 break;
675                         case MOUSE_PS2:
676                                 /* PS/2 protocol has nothing in high byte */
677                                 if ( (mousebuf[i] & 0xC0) != 0 ) {
678                                         /* Go to next byte */
679                                         i -= (packetsize-1);
680                                         continue;
681                                 }
682                                 /* Get current mouse state */
683                                 button = (mousebuf[i] & 0x04) >> 1 | /*Middle*/
684                                          (mousebuf[i] & 0x02) >> 1 | /*Right*/
685                                          (mousebuf[i] & 0x01) << 2;  /*Left*/
686                                 dx = (mousebuf[i] & 0x10) ?
687                                       mousebuf[i+1] - 256 : mousebuf[i+1];
688                                 dy = (mousebuf[i] & 0x20) ?
689                                       -(mousebuf[i+2] - 256) : -mousebuf[i+2];
690                                 break;
691                         case MOUSE_IMPS2:
692                                 /* Get current mouse state */
693                                 button = (mousebuf[i] & 0x04) >> 1 | /*Middle*/
694                                          (mousebuf[i] & 0x02) >> 1 | /*Right*/
695                                          (mousebuf[i] & 0x01) << 2 | /*Left*/
696                                          (mousebuf[i] & 0x40) >> 3 | /* 4 */
697                                          (mousebuf[i] & 0x80) >> 3;  /* 5 */
698                                 dx = (mousebuf[i] & 0x10) ?
699                                       mousebuf[i+1] - 256 : mousebuf[i+1];
700                                 dy = (mousebuf[i] & 0x20) ?
701                                       -(mousebuf[i+2] - 256) : -mousebuf[i+2];
702                                 switch (mousebuf[i+3]&0x0F) {
703                                     case 0x0E: /* DX = +1 */
704                                     case 0x02: /* DX = -1 */
705                                         break;
706                                     case 0x0F: /* DY = +1 (map button 4) */
707                                        FB_vgamousecallback(button | (1<<3),
708                                                            1, 0, 0);
709                                         break;
710                                     case 0x01: /* DY = -1 (map button 5) */
711                                        FB_vgamousecallback(button | (1<<4),
712                                                            1, 0, 0);
713                                         break;
714                                 }
715                                 break;
716                         case MOUSE_MS:
717                                 /* Microsoft protocol has 0x40 in high byte */
718                                 if ( (mousebuf[i] & 0x40) != 0x40 ) {
719                                         /* Go to next byte */
720                                         i -= (packetsize-1);
721                                         continue;
722                                 }
723                                 /* Get current mouse state */
724                                 button = ((mousebuf[i] & 0x20) >> 3) |
725                                          ((mousebuf[i] & 0x10) >> 4);
726                                 dx = (signed char)(((mousebuf[i] & 0x03) << 6) |
727                                                    (mousebuf[i + 1] & 0x3F));
728                                 dy = (signed char)(((mousebuf[i] & 0x0C) << 4) |
729                                                     (mousebuf[i + 2] & 0x3F));
730                                 break;
731                         case MOUSE_BM:
732                                 /* BusMouse protocol has 0xF8 in high byte */
733                                 if ( (mousebuf[i] & 0xF8) != 0x80 ) {
734                                         /* Go to next byte */
735                                         i -= (packetsize-1);
736                                         continue;
737                                 }
738                                 /* Get current mouse state */
739                                 button = (~mousebuf[i]) & 0x07;
740                                 dx =  (signed char)mousebuf[i+1];
741                                 dy = -(signed char)mousebuf[i+2];
742                                 break;
743                         case NUM_MOUSE_DRVS:
744                                 /* Uh oh.. */
745                                 dx = 0;
746                                 dy = 0;
747                                 break;
748                 }
749                 GS_vgamousecallback(button, dx, dy);
750         }
751         if ( i < nread ) {
752                 SDL_memcpy(mousebuf, &mousebuf[i], (nread-i));
753                 start = (nread-i);
754         } else {
755                 start = 0;
756         }
757         return;
758 }
759
760 static void handle_keyboard(_THIS)
761 {
762         unsigned char keybuf[BUFSIZ];
763         int i, nread;
764         int pressed;
765         int scancode;
766         SDL_keysym keysym;
767
768         nread = read(keyboard_fd, keybuf, BUFSIZ);
769         for ( i=0; i<nread; ++i ) {
770                 scancode = keybuf[i] & 0x7F;
771                 if ( keybuf[i] & 0x80 ) {
772                         pressed = SDL_RELEASED;
773                 } else {
774                         pressed = SDL_PRESSED;
775                 }
776                 TranslateKey(scancode, &keysym);
777                 posted += SDL_PrivateKeyboard(pressed, &keysym);
778         }
779 }
780
781 void GS_PumpEvents(_THIS)
782 {
783         fd_set fdset;
784         int max_fd;
785         static struct timeval zero;
786
787         do {
788                 posted = 0;
789
790                 FD_ZERO(&fdset);
791                 max_fd = 0;
792                 if ( keyboard_fd >= 0 ) {
793                         FD_SET(keyboard_fd, &fdset);
794                         if ( max_fd < keyboard_fd ) {
795                                 max_fd = keyboard_fd;
796                         }
797                 }
798                 if ( mouse_fd >= 0 ) {
799                         FD_SET(mouse_fd, &fdset);
800                         if ( max_fd < mouse_fd ) {
801                                 max_fd = mouse_fd;
802                         }
803                 }
804                 if ( select(max_fd+1, &fdset, NULL, NULL, &zero) > 0 ) {
805                         if ( keyboard_fd >= 0 ) {
806                                 if ( FD_ISSET(keyboard_fd, &fdset) ) {
807                                         handle_keyboard(this);
808                                 }
809                         }
810                         if ( mouse_fd >= 0 ) {
811                                 if ( FD_ISSET(mouse_fd, &fdset) ) {
812                                         handle_mouse(this);
813                                 }
814                         }
815                 }
816         } while ( posted );
817 }
818
819 void GS_InitOSKeymap(_THIS)
820 {
821         int i;
822
823         /* Initialize the Linux key translation table */
824
825         /* First get the ascii keys and others not well handled */
826         for (i=0; i<SDL_arraysize(keymap); ++i) {
827           switch(i) {
828           /* These aren't handled by the x86 kernel keymapping (?) */
829           case SCANCODE_PRINTSCREEN:
830             keymap[i] = SDLK_PRINT;
831             break;
832           case SCANCODE_BREAK:
833             keymap[i] = SDLK_BREAK;
834             break;
835           case SCANCODE_BREAK_ALTERNATIVE:
836             keymap[i] = SDLK_PAUSE;
837             break;
838           case SCANCODE_LEFTSHIFT:
839             keymap[i] = SDLK_LSHIFT;
840             break;
841           case SCANCODE_RIGHTSHIFT:
842             keymap[i] = SDLK_RSHIFT;
843             break;
844           case SCANCODE_LEFTCONTROL:
845             keymap[i] = SDLK_LCTRL;
846             break;
847           case SCANCODE_RIGHTCONTROL:
848             keymap[i] = SDLK_RCTRL;
849             break;
850           case SCANCODE_RIGHTWIN:
851             keymap[i] = SDLK_RSUPER;
852             break;
853           case SCANCODE_LEFTWIN:
854             keymap[i] = SDLK_LSUPER;
855             break;
856           case 127:
857             keymap[i] = SDLK_MENU;
858             break;
859           /* this should take care of all standard ascii keys */
860           default:
861             keymap[i] = KVAL(vga_keymap[0][i]);
862             break;
863           }
864         }
865         for (i=0; i<SDL_arraysize(keymap); ++i) {
866           switch(keymap_temp[i]) {
867             case K_F1:  keymap[i] = SDLK_F1;  break;
868             case K_F2:  keymap[i] = SDLK_F2;  break;
869             case K_F3:  keymap[i] = SDLK_F3;  break;
870             case K_F4:  keymap[i] = SDLK_F4;  break;
871             case K_F5:  keymap[i] = SDLK_F5;  break;
872             case K_F6:  keymap[i] = SDLK_F6;  break;
873             case K_F7:  keymap[i] = SDLK_F7;  break;
874             case K_F8:  keymap[i] = SDLK_F8;  break;
875             case K_F9:  keymap[i] = SDLK_F9;  break;
876             case K_F10: keymap[i] = SDLK_F10; break;
877             case K_F11: keymap[i] = SDLK_F11; break;
878             case K_F12: keymap[i] = SDLK_F12; break;
879
880             case K_DOWN:  keymap[i] = SDLK_DOWN;  break;
881             case K_LEFT:  keymap[i] = SDLK_LEFT;  break;
882             case K_RIGHT: keymap[i] = SDLK_RIGHT; break;
883             case K_UP:    keymap[i] = SDLK_UP;    break;
884
885             case K_P0:     keymap[i] = SDLK_KP0; break;
886             case K_P1:     keymap[i] = SDLK_KP1; break;
887             case K_P2:     keymap[i] = SDLK_KP2; break;
888             case K_P3:     keymap[i] = SDLK_KP3; break;
889             case K_P4:     keymap[i] = SDLK_KP4; break;
890             case K_P5:     keymap[i] = SDLK_KP5; break;
891             case K_P6:     keymap[i] = SDLK_KP6; break;
892             case K_P7:     keymap[i] = SDLK_KP7; break;
893             case K_P8:     keymap[i] = SDLK_KP8; break;
894             case K_P9:     keymap[i] = SDLK_KP9; break;
895             case K_PPLUS:  keymap[i] = SDLK_KP_PLUS; break;
896             case K_PMINUS: keymap[i] = SDLK_KP_MINUS; break;
897             case K_PSTAR:  keymap[i] = SDLK_KP_MULTIPLY; break;
898             case K_PSLASH: keymap[i] = SDLK_KP_DIVIDE; break;
899             case K_PENTER: keymap[i] = SDLK_KP_ENTER; break;
900             case K_PDOT:   keymap[i] = SDLK_KP_PERIOD; break;
901
902             case K_SHIFT:  if ( keymap[i] != SDLK_RSHIFT )
903                              keymap[i] = SDLK_LSHIFT;
904                            break;
905             case K_SHIFTL: keymap[i] = SDLK_LSHIFT; break;
906             case K_SHIFTR: keymap[i] = SDLK_RSHIFT; break;
907             case K_CTRL:  if ( keymap[i] != SDLK_RCTRL )
908                              keymap[i] = SDLK_LCTRL;
909                            break;
910             case K_CTRLL:  keymap[i] = SDLK_LCTRL;  break;
911             case K_CTRLR:  keymap[i] = SDLK_RCTRL;  break;
912             case K_ALT:    keymap[i] = SDLK_LALT;   break;
913             case K_ALTGR:  keymap[i] = SDLK_RALT;   break;
914
915             case K_INSERT: keymap[i] = SDLK_INSERT;   break;
916             case K_REMOVE: keymap[i] = SDLK_DELETE;   break;
917             case K_PGUP:   keymap[i] = SDLK_PAGEUP;   break;
918             case K_PGDN:   keymap[i] = SDLK_PAGEDOWN; break;
919             case K_FIND:   keymap[i] = SDLK_HOME;     break;
920             case K_SELECT: keymap[i] = SDLK_END;      break;
921
922             case K_NUM:  keymap[i] = SDLK_NUMLOCK;   break;
923             case K_CAPS: keymap[i] = SDLK_CAPSLOCK;  break;
924
925             case K_F13:   keymap[i] = SDLK_PRINT;     break;
926             case K_HOLD:  keymap[i] = SDLK_SCROLLOCK; break;
927             case K_PAUSE: keymap[i] = SDLK_PAUSE;     break;
928
929             case 127: keymap[i] = SDLK_BACKSPACE; break;
930              
931             default: break;
932           }
933         }
934 }
935
936 static SDL_keysym *TranslateKey(int scancode, SDL_keysym *keysym)
937 {
938         /* Set the keysym information */
939         keysym->scancode = scancode;
940         keysym->sym = keymap[scancode];
941         keysym->mod = KMOD_NONE;
942
943         /* If UNICODE is on, get the UNICODE value for the key */
944         keysym->unicode = 0;
945         if ( SDL_TranslateUNICODE ) {
946                 int map;
947                 SDLMod modstate;
948
949                 modstate = SDL_GetModState();
950                 map = 0;
951                 if ( modstate & KMOD_SHIFT ) {
952                         map |= (1<<KG_SHIFT);
953                 }
954                 if ( modstate & KMOD_CTRL ) {
955                         map |= (1<<KG_CTRL);
956                 }
957                 if ( modstate & KMOD_ALT ) {
958                         map |= (1<<KG_ALT);
959                 }
960                 if ( modstate & KMOD_MODE ) {
961                         map |= (1<<KG_ALTGR);
962                 }
963                 if ( KTYP(vga_keymap[map][scancode]) == KT_LETTER ) {
964                         if ( modstate & KMOD_CAPS ) {
965                                 map ^= (1<<KG_SHIFT);
966                         }
967                 }
968                 if ( KTYP(vga_keymap[map][scancode]) == KT_PAD ) {
969                         if ( modstate & KMOD_NUM ) {
970                                 keysym->unicode=KVAL(vga_keymap[map][scancode]);
971                         }
972                 } else {
973                         keysym->unicode = KVAL(vga_keymap[map][scancode]);
974                 }
975         }
976         return(keysym);
977 }