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