src/video/fbcon/SDL_fbevents.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 29 May 2006 04:04:35 +0000
branchSDL-1.3
changeset 1668 4da1ee79c9af
parent 1662 782fd950bd46
permissions -rw-r--r--
more tweaking indent options
     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 <stdio.h>
    27 #include <sys/types.h>
    28 #include <sys/time.h>
    29 #include <sys/ioctl.h>
    30 #include <unistd.h>
    31 #include <fcntl.h>
    32 #include <errno.h>
    33 #include <limits.h>
    34 
    35 /* For parsing /proc */
    36 #include <dirent.h>
    37 #include <ctype.h>
    38 
    39 #include <linux/vt.h>
    40 #include <linux/kd.h>
    41 #include <linux/keyboard.h>
    42 
    43 #include "SDL_timer.h"
    44 #include "SDL_mutex.h"
    45 #include "../SDL_sysvideo.h"
    46 #include "../../events/SDL_sysevents.h"
    47 #include "../../events/SDL_events_c.h"
    48 #include "SDL_fbvideo.h"
    49 #include "SDL_fbevents_c.h"
    50 #include "SDL_fbkeys.h"
    51 
    52 #include "SDL_fbelo.h"
    53 
    54 #ifndef GPM_NODE_FIFO
    55 #define GPM_NODE_FIFO	"/dev/gpmdata"
    56 #endif
    57 
    58 /*#define DEBUG_KEYBOARD*/
    59 /*#define DEBUG_MOUSE*/
    60 
    61 /* The translation tables from a console scancode to a SDL keysym */
    62 #define NUM_VGAKEYMAPS	(1<<KG_CAPSSHIFT)
    63 static Uint16 vga_keymap[NUM_VGAKEYMAPS][NR_KEYS];
    64 static SDLKey keymap[128];
    65 static Uint16 keymap_temp[128]; /* only used at startup */
    66 static SDL_keysym *TranslateKey(int scancode, SDL_keysym * keysym);
    67 
    68 /* Ugh, we have to duplicate the kernel's keysym mapping code...
    69    Oh, it's not so bad. :-)
    70 
    71    FIXME: Add keyboard LED handling code
    72  */
    73 static void
    74 FB_vgainitkeymaps(int fd)
    75 {
    76     struct kbentry entry;
    77     int map, i;
    78 
    79     /* Don't do anything if we are passed a closed keyboard */
    80     if (fd < 0) {
    81         return;
    82     }
    83 
    84     /* Load all the keysym mappings */
    85     for (map = 0; map < NUM_VGAKEYMAPS; ++map) {
    86         SDL_memset(vga_keymap[map], 0, NR_KEYS * sizeof(Uint16));
    87         for (i = 0; i < NR_KEYS; ++i) {
    88             entry.kb_table = map;
    89             entry.kb_index = i;
    90             if (ioctl(fd, KDGKBENT, &entry) == 0) {
    91                 /* fill keytemp. This replaces SDL_fbkeys.h */
    92                 if ((map == 0) && (i < 128)) {
    93                     keymap_temp[i] = entry.kb_value;
    94                 }
    95                 /* The "Enter" key is a special case */
    96                 if (entry.kb_value == K_ENTER) {
    97                     entry.kb_value = K(KT_ASCII, 13);
    98                 }
    99                 /* Handle numpad specially as well */
   100                 if (KTYP(entry.kb_value) == KT_PAD) {
   101                     switch (entry.kb_value) {
   102                     case K_P0:
   103                     case K_P1:
   104                     case K_P2:
   105                     case K_P3:
   106                     case K_P4:
   107                     case K_P5:
   108                     case K_P6:
   109                     case K_P7:
   110                     case K_P8:
   111                     case K_P9:
   112                         vga_keymap[map][i] = entry.kb_value;
   113                         vga_keymap[map][i] += '0';
   114                         break;
   115                     case K_PPLUS:
   116                         vga_keymap[map][i] = K(KT_ASCII, '+');
   117                         break;
   118                     case K_PMINUS:
   119                         vga_keymap[map][i] = K(KT_ASCII, '-');
   120                         break;
   121                     case K_PSTAR:
   122                         vga_keymap[map][i] = K(KT_ASCII, '*');
   123                         break;
   124                     case K_PSLASH:
   125                         vga_keymap[map][i] = K(KT_ASCII, '/');
   126                         break;
   127                     case K_PENTER:
   128                         vga_keymap[map][i] = K(KT_ASCII, '\r');
   129                         break;
   130                     case K_PCOMMA:
   131                         vga_keymap[map][i] = K(KT_ASCII, ',');
   132                         break;
   133                     case K_PDOT:
   134                         vga_keymap[map][i] = K(KT_ASCII, '.');
   135                         break;
   136                     default:
   137                         break;
   138                     }
   139                 }
   140                 /* Do the normal key translation */
   141                 if ((KTYP(entry.kb_value) == KT_LATIN) ||
   142                     (KTYP(entry.kb_value) == KT_ASCII) ||
   143                     (KTYP(entry.kb_value) == KT_LETTER)) {
   144                     vga_keymap[map][i] = entry.kb_value;
   145                 }
   146             }
   147         }
   148     }
   149 }
   150 
   151 int
   152 FB_InGraphicsMode(_THIS)
   153 {
   154     return ((keyboard_fd >= 0) && (saved_kbd_mode >= 0));
   155 }
   156 
   157 int
   158 FB_EnterGraphicsMode(_THIS)
   159 {
   160     struct termios keyboard_termios;
   161 
   162     /* Set medium-raw keyboard mode */
   163     if ((keyboard_fd >= 0) && !FB_InGraphicsMode(this)) {
   164 
   165         /* Switch to the correct virtual terminal */
   166         if (current_vt > 0) {
   167             struct vt_stat vtstate;
   168 
   169             if (ioctl(keyboard_fd, VT_GETSTATE, &vtstate) == 0) {
   170                 saved_vt = vtstate.v_active;
   171             }
   172             if (ioctl(keyboard_fd, VT_ACTIVATE, current_vt) == 0) {
   173                 ioctl(keyboard_fd, VT_WAITACTIVE, current_vt);
   174             }
   175         }
   176 
   177         /* Set the terminal input mode */
   178         if (tcgetattr(keyboard_fd, &saved_kbd_termios) < 0) {
   179             SDL_SetError("Unable to get terminal attributes");
   180             if (keyboard_fd > 0) {
   181                 close(keyboard_fd);
   182             }
   183             keyboard_fd = -1;
   184             return (-1);
   185         }
   186         if (ioctl(keyboard_fd, KDGKBMODE, &saved_kbd_mode) < 0) {
   187             SDL_SetError("Unable to get current keyboard mode");
   188             if (keyboard_fd > 0) {
   189                 close(keyboard_fd);
   190             }
   191             keyboard_fd = -1;
   192             return (-1);
   193         }
   194         keyboard_termios = saved_kbd_termios;
   195         keyboard_termios.c_lflag &= ~(ICANON | ECHO | ISIG);
   196         keyboard_termios.c_iflag &=
   197             ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON);
   198         keyboard_termios.c_cc[VMIN] = 0;
   199         keyboard_termios.c_cc[VTIME] = 0;
   200         if (tcsetattr(keyboard_fd, TCSAFLUSH, &keyboard_termios) < 0) {
   201             FB_CloseKeyboard(this);
   202             SDL_SetError("Unable to set terminal attributes");
   203             return (-1);
   204         }
   205         /* This will fail if we aren't root or this isn't our tty */
   206         if (ioctl(keyboard_fd, KDSKBMODE, K_MEDIUMRAW) < 0) {
   207             FB_CloseKeyboard(this);
   208             SDL_SetError("Unable to set keyboard in raw mode");
   209             return (-1);
   210         }
   211         if (ioctl(keyboard_fd, KDSETMODE, KD_GRAPHICS) < 0) {
   212             FB_CloseKeyboard(this);
   213             SDL_SetError("Unable to set keyboard in graphics mode");
   214             return (-1);
   215         }
   216         /* Prevent switching the virtual terminal */
   217         ioctl(keyboard_fd, VT_LOCKSWITCH, 1);
   218     }
   219     return (keyboard_fd);
   220 }
   221 
   222 void
   223 FB_LeaveGraphicsMode(_THIS)
   224 {
   225     if (FB_InGraphicsMode(this)) {
   226         ioctl(keyboard_fd, KDSETMODE, KD_TEXT);
   227         ioctl(keyboard_fd, KDSKBMODE, saved_kbd_mode);
   228         tcsetattr(keyboard_fd, TCSAFLUSH, &saved_kbd_termios);
   229         saved_kbd_mode = -1;
   230 
   231         /* Head back over to the original virtual terminal */
   232         ioctl(keyboard_fd, VT_UNLOCKSWITCH, 1);
   233         if (saved_vt > 0) {
   234             ioctl(keyboard_fd, VT_ACTIVATE, saved_vt);
   235         }
   236     }
   237 }
   238 
   239 void
   240 FB_CloseKeyboard(_THIS)
   241 {
   242     if (keyboard_fd >= 0) {
   243         FB_LeaveGraphicsMode(this);
   244         if (keyboard_fd > 0) {
   245             close(keyboard_fd);
   246         }
   247     }
   248     keyboard_fd = -1;
   249 }
   250 
   251 int
   252 FB_OpenKeyboard(_THIS)
   253 {
   254     /* Open only if not already opened */
   255     if (keyboard_fd < 0) {
   256         static const char *const tty0[] = { "/dev/tty0", "/dev/vc/0", NULL };
   257         static const char *const vcs[] = { "/dev/vc/%d", "/dev/tty%d", NULL };
   258         int i, tty0_fd;
   259 
   260         /* Try to query for a free virtual terminal */
   261         tty0_fd = -1;
   262         for (i = 0; tty0[i] && (tty0_fd < 0); ++i) {
   263             tty0_fd = open(tty0[i], O_WRONLY, 0);
   264         }
   265         if (tty0_fd < 0) {
   266             tty0_fd = dup(0);   /* Maybe stdin is a VT? */
   267         }
   268         ioctl(tty0_fd, VT_OPENQRY, &current_vt);
   269         close(tty0_fd);
   270         if ((geteuid() == 0) && (current_vt > 0)) {
   271             for (i = 0; vcs[i] && (keyboard_fd < 0); ++i) {
   272                 char vtpath[12];
   273 
   274                 SDL_snprintf(vtpath, SDL_arraysize(vtpath), vcs[i],
   275                              current_vt);
   276                 keyboard_fd = open(vtpath, O_RDWR, 0);
   277 #ifdef DEBUG_KEYBOARD
   278                 fprintf(stderr, "vtpath = %s, fd = %d\n",
   279                         vtpath, keyboard_fd);
   280 #endif /* DEBUG_KEYBOARD */
   281 
   282                 /* This needs to be our controlling tty
   283                    so that the kernel ioctl() calls work
   284                  */
   285                 if (keyboard_fd >= 0) {
   286                     tty0_fd = open("/dev/tty", O_RDWR, 0);
   287                     if (tty0_fd >= 0) {
   288                         ioctl(tty0_fd, TIOCNOTTY, 0);
   289                         close(tty0_fd);
   290                     }
   291                 }
   292             }
   293         }
   294         if (keyboard_fd < 0) {
   295             /* Last resort, maybe our tty is a usable VT */
   296             struct vt_stat vtstate;
   297 
   298             keyboard_fd = open("/dev/tty", O_RDWR);
   299 
   300             if (ioctl(keyboard_fd, VT_GETSTATE, &vtstate) == 0) {
   301                 current_vt = vtstate.v_active;
   302             } else {
   303                 current_vt = 0;
   304             }
   305         }
   306 #ifdef DEBUG_KEYBOARD
   307         fprintf(stderr, "Current VT: %d\n", current_vt);
   308 #endif
   309         saved_kbd_mode = -1;
   310 
   311         /* Make sure that our input is a console terminal */
   312         {
   313             int dummy;
   314             if (ioctl(keyboard_fd, KDGKBMODE, &dummy) < 0) {
   315                 close(keyboard_fd);
   316                 keyboard_fd = -1;
   317                 SDL_SetError("Unable to open a console terminal");
   318             }
   319         }
   320 
   321         /* Set up keymap */
   322         FB_vgainitkeymaps(keyboard_fd);
   323     }
   324     return (keyboard_fd);
   325 }
   326 
   327 static enum
   328 {
   329     MOUSE_NONE = -1,
   330     MOUSE_MSC,                  /* Note: GPM uses the MSC protocol */
   331     MOUSE_PS2,
   332     MOUSE_IMPS2,
   333     MOUSE_MS,
   334     MOUSE_BM,
   335     MOUSE_ELO,
   336     MOUSE_TSLIB,
   337     NUM_MOUSE_DRVS
   338 } mouse_drv = MOUSE_NONE;
   339 
   340 void
   341 FB_CloseMouse(_THIS)
   342 {
   343 #if SDL_INPUT_TSLIB
   344     if (ts_dev != NULL) {
   345         ts_close(ts_dev);
   346         ts_dev = NULL;
   347         mouse_fd = -1;
   348     }
   349 #endif /* SDL_INPUT_TSLIB */
   350     if (mouse_fd > 0) {
   351         close(mouse_fd);
   352     }
   353     mouse_fd = -1;
   354 }
   355 
   356 /* Returns processes listed in /proc with the desired name */
   357 static int
   358 find_pid(DIR * proc, const char *wanted_name)
   359 {
   360     struct dirent *entry;
   361     int pid;
   362 
   363     /* First scan proc for the gpm process */
   364     pid = 0;
   365     while ((pid == 0) && ((entry = readdir(proc)) != NULL)) {
   366         if (isdigit(entry->d_name[0])) {
   367             FILE *status;
   368             char path[PATH_MAX];
   369             char name[PATH_MAX];
   370 
   371             SDL_snprintf(path, SDL_arraysize(path), "/proc/%s/status",
   372                          entry->d_name);
   373             status = fopen(path, "r");
   374             if (status) {
   375                 name[0] = '\0';
   376                 fscanf(status, "Name: %s", name);
   377                 if (SDL_strcmp(name, wanted_name) == 0) {
   378                     pid = SDL_atoi(entry->d_name);
   379                 }
   380                 fclose(status);
   381             }
   382         }
   383     }
   384     return pid;
   385 }
   386 
   387 /* Returns true if /dev/gpmdata is being written to by gpm */
   388 static int
   389 gpm_available(char *proto, size_t protolen)
   390 {
   391     int available;
   392     DIR *proc;
   393     int pid;
   394     int cmdline, len, arglen;
   395     char path[PATH_MAX];
   396     char args[PATH_MAX], *arg;
   397 
   398     /* Don't bother looking if the fifo isn't there */
   399 #ifdef DEBUG_MOUSE
   400     fprintf(stderr, "testing gpm\n");
   401 #endif
   402     if (access(GPM_NODE_FIFO, F_OK) < 0) {
   403         return (0);
   404     }
   405 
   406     available = 0;
   407     proc = opendir("/proc");
   408     if (proc) {
   409         char raw_proto[10] = { '\0' };
   410         char repeat_proto[10] = { '\0' };
   411         while (!available && (pid = find_pid(proc, "gpm")) > 0) {
   412             SDL_snprintf(path, SDL_arraysize(path), "/proc/%d/cmdline", pid);
   413             cmdline = open(path, O_RDONLY, 0);
   414             if (cmdline >= 0) {
   415                 len = read(cmdline, args, sizeof(args));
   416                 arg = args;
   417                 while (len > 0) {
   418                     arglen = SDL_strlen(arg) + 1;
   419 #ifdef DEBUG_MOUSE
   420                     fprintf(stderr, "gpm arg %s len %d\n", arg, arglen);
   421 #endif
   422                     if (SDL_strcmp(arg, "-t") == 0) {
   423                         /* protocol string, keep it for later */
   424                         char *t, *s;
   425                         t = arg + arglen;
   426                         s = SDL_strchr(t, ' ');
   427                         if (s)
   428                             *s = 0;
   429                         SDL_strlcpy(raw_proto, t, SDL_arraysize(raw_proto));
   430                         if (s)
   431                             *s = ' ';
   432                     }
   433                     if (SDL_strncmp(arg, "-R", 2) == 0) {
   434                         char *t, *s;
   435                         available = 1;
   436                         t = arg + 2;
   437                         s = SDL_strchr(t, ' ');
   438                         if (s)
   439                             *s = 0;
   440                         SDL_strlcpy(repeat_proto, t,
   441                                     SDL_arraysize(repeat_proto));
   442                         if (s)
   443                             *s = ' ';
   444                     }
   445                     len -= arglen;
   446                     arg += arglen;
   447                 }
   448                 close(cmdline);
   449             }
   450         }
   451         closedir(proc);
   452 
   453         if (available) {
   454             if (SDL_strcmp(repeat_proto, "raw") == 0) {
   455                 SDL_strlcpy(proto, raw_proto, protolen);
   456             } else if (*repeat_proto) {
   457                 SDL_strlcpy(proto, repeat_proto, protolen);
   458             } else {
   459                 SDL_strlcpy(proto, "msc", protolen);
   460             }
   461         }
   462     }
   463     return available;
   464 }
   465 
   466 
   467 /* rcg06112001 Set up IMPS/2 mode, if possible. This gives
   468  *  us access to the mousewheel, etc. Returns zero if
   469  *  writes to device failed, but you still need to query the
   470  *  device to see which mode it's actually in.
   471  */
   472 static int
   473 set_imps2_mode(int fd)
   474 {
   475     /* If you wanted to control the mouse mode (and we do :)  ) ...
   476        Set IMPS/2 protocol:
   477        {0xf3,200,0xf3,100,0xf3,80}
   478        Reset mouse device:
   479        {0xFF}
   480      */
   481     Uint8 set_imps2[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
   482     /*Uint8 reset = 0xff; */
   483     fd_set fdset;
   484     struct timeval tv;
   485     int retval = 0;
   486 
   487     if (write(fd, &set_imps2, sizeof(set_imps2)) == sizeof(set_imps2)) {
   488         /* Don't reset it, that'll clear IMPS/2 mode on some mice
   489            if (write(fd, &reset, sizeof (reset)) == sizeof (reset) ) {
   490            retval = 1;
   491            }
   492          */
   493     }
   494 
   495     /* Get rid of any chatter from the above */
   496     FD_ZERO(&fdset);
   497     FD_SET(fd, &fdset);
   498     tv.tv_sec = 0;
   499     tv.tv_usec = 0;
   500     while (select(fd + 1, &fdset, 0, 0, &tv) > 0) {
   501         char temp[32];
   502         read(fd, temp, sizeof(temp));
   503     }
   504 
   505     return retval;
   506 }
   507 
   508 
   509 /* Returns true if the mouse uses the IMPS/2 protocol */
   510 static int
   511 detect_imps2(int fd)
   512 {
   513     int imps2;
   514 
   515     imps2 = 0;
   516 
   517     if (SDL_getenv("SDL_MOUSEDEV_IMPS2")) {
   518         imps2 = 1;
   519     }
   520     if (!imps2) {
   521         Uint8 query_ps2 = 0xF2;
   522         fd_set fdset;
   523         struct timeval tv;
   524 
   525         /* Get rid of any mouse motion noise */
   526         FD_ZERO(&fdset);
   527         FD_SET(fd, &fdset);
   528         tv.tv_sec = 0;
   529         tv.tv_usec = 0;
   530         while (select(fd + 1, &fdset, 0, 0, &tv) > 0) {
   531             char temp[32];
   532             read(fd, temp, sizeof(temp));
   533         }
   534 
   535         /* Query for the type of mouse protocol */
   536         if (write(fd, &query_ps2, sizeof(query_ps2)) == sizeof(query_ps2)) {
   537             Uint8 ch = 0;
   538 
   539             /* Get the mouse protocol response */
   540             do {
   541                 FD_ZERO(&fdset);
   542                 FD_SET(fd, &fdset);
   543                 tv.tv_sec = 1;
   544                 tv.tv_usec = 0;
   545                 if (select(fd + 1, &fdset, 0, 0, &tv) < 1) {
   546                     break;
   547                 }
   548             }
   549             while ((read(fd, &ch, sizeof(ch)) == sizeof(ch)) &&
   550                    ((ch == 0xFA) || (ch == 0xAA)));
   551 
   552             /* Experimental values (Logitech wheelmouse) */
   553 #ifdef DEBUG_MOUSE
   554             fprintf(stderr, "Last mouse mode: 0x%x\n", ch);
   555 #endif
   556             if ((ch == 3) || (ch == 4)) {
   557                 imps2 = 1;
   558             }
   559         }
   560     }
   561     return imps2;
   562 }
   563 
   564 int
   565 FB_OpenMouse(_THIS)
   566 {
   567     int i;
   568     const char *mousedev;
   569     const char *mousedrv;
   570 
   571     mousedrv = SDL_getenv("SDL_MOUSEDRV");
   572     mousedev = SDL_getenv("SDL_MOUSEDEV");
   573     mouse_fd = -1;
   574 
   575 #if SDL_INPUT_TSLIB
   576     if (mousedrv && (SDL_strcmp(mousedrv, "TSLIB") == 0)) {
   577         if (mousedev == NULL)
   578             mousedev = SDL_getenv("TSLIB_TSDEVICE");
   579         if (mousedev != NULL) {
   580             ts_dev = ts_open(mousedev, 1);
   581             if ((ts_dev != NULL) && (ts_config(ts_dev) >= 0)) {
   582 #ifdef DEBUG_MOUSE
   583                 fprintf(stderr, "Using tslib touchscreen\n");
   584 #endif
   585                 mouse_drv = MOUSE_TSLIB;
   586                 mouse_fd = ts_fd(ts_dev);
   587                 return mouse_fd;
   588             }
   589         }
   590         mouse_drv = MOUSE_NONE;
   591         return mouse_fd;
   592     }
   593 #endif /* SDL_INPUT_TSLIB */
   594 
   595     /* ELO TOUCHSCREEN SUPPORT */
   596 
   597     if (mousedrv && (SDL_strcmp(mousedrv, "ELO") == 0)) {
   598         mouse_fd = open(mousedev, O_RDWR);
   599         if (mouse_fd >= 0) {
   600             if (eloInitController(mouse_fd)) {
   601 #ifdef DEBUG_MOUSE
   602                 fprintf(stderr, "Using ELO touchscreen\n");
   603 #endif
   604                 mouse_drv = MOUSE_ELO;
   605             }
   606 
   607         } else if (mouse_fd < 0) {
   608             mouse_drv = MOUSE_NONE;
   609         }
   610 
   611         return (mouse_fd);
   612     }
   613 
   614     /* STD MICE */
   615 
   616     if (mousedev == NULL) {
   617         /* FIXME someday... allow multiple mice in this driver */
   618         static const char *ps2mice[] = {
   619             "/dev/input/mice", "/dev/usbmouse", "/dev/psaux", NULL
   620         };
   621         /* First try to use GPM in repeater mode */
   622         if (mouse_fd < 0) {
   623             char proto[10];
   624             if (gpm_available(proto, SDL_arraysize(proto))) {
   625                 mouse_fd = open(GPM_NODE_FIFO, O_RDONLY, 0);
   626                 if (mouse_fd >= 0) {
   627                     if (SDL_strcmp(proto, "msc") == 0) {
   628                         mouse_drv = MOUSE_MSC;
   629                     } else if (SDL_strcmp(proto, "ps2") == 0) {
   630                         mouse_drv = MOUSE_PS2;
   631                     } else if (SDL_strcmp(proto, "imps2") == 0) {
   632                         mouse_drv = MOUSE_IMPS2;
   633                     } else if (SDL_strcmp(proto, "ms") == 0 ||
   634                                SDL_strcmp(proto, "bare") == 0) {
   635                         mouse_drv = MOUSE_MS;
   636                     } else if (SDL_strcmp(proto, "bm") == 0) {
   637                         mouse_drv = MOUSE_BM;
   638                     } else {
   639                         /* Unknown protocol... */
   640 #ifdef DEBUG_MOUSE
   641                         fprintf(stderr,
   642                                 "GPM mouse using unknown protocol = %s\n",
   643                                 proto);
   644 #endif
   645                         close(mouse_fd);
   646                         mouse_fd = -1;
   647                     }
   648                 }
   649 #ifdef DEBUG_MOUSE
   650                 if (mouse_fd >= 0) {
   651                     fprintf(stderr,
   652                             "Using GPM mouse, protocol = %s\n", proto);
   653                 }
   654 #endif /* DEBUG_MOUSE */
   655             }
   656         }
   657         /* Now try to use a modern PS/2 mouse */
   658         for (i = 0; (mouse_fd < 0) && ps2mice[i]; ++i) {
   659             mouse_fd = open(ps2mice[i], O_RDWR, 0);
   660             if (mouse_fd < 0) {
   661                 mouse_fd = open(ps2mice[i], O_RDONLY, 0);
   662             }
   663             if (mouse_fd >= 0) {
   664                 /* rcg06112001 Attempt to set IMPS/2 mode */
   665                 set_imps2_mode(mouse_fd);
   666                 if (detect_imps2(mouse_fd)) {
   667 #ifdef DEBUG_MOUSE
   668                     fprintf(stderr, "Using IMPS2 mouse\n");
   669 #endif
   670                     mouse_drv = MOUSE_IMPS2;
   671                 } else {
   672 #ifdef DEBUG_MOUSE
   673                     fprintf(stderr, "Using PS2 mouse\n");
   674 #endif
   675                     mouse_drv = MOUSE_PS2;
   676                 }
   677             }
   678         }
   679         /* Next try to use a PPC ADB port mouse */
   680         if (mouse_fd < 0) {
   681             mouse_fd = open("/dev/adbmouse", O_RDONLY, 0);
   682             if (mouse_fd >= 0) {
   683 #ifdef DEBUG_MOUSE
   684                 fprintf(stderr, "Using ADB mouse\n");
   685 #endif
   686                 mouse_drv = MOUSE_BM;
   687             }
   688         }
   689     }
   690     /* Default to a serial Microsoft mouse */
   691     if (mouse_fd < 0) {
   692         if (mousedev == NULL) {
   693             mousedev = "/dev/mouse";
   694         }
   695         mouse_fd = open(mousedev, O_RDONLY, 0);
   696         if (mouse_fd >= 0) {
   697             struct termios mouse_termios;
   698 
   699             /* Set the sampling speed to 1200 baud */
   700             tcgetattr(mouse_fd, &mouse_termios);
   701             mouse_termios.c_iflag = IGNBRK | IGNPAR;
   702             mouse_termios.c_oflag = 0;
   703             mouse_termios.c_lflag = 0;
   704             mouse_termios.c_line = 0;
   705             mouse_termios.c_cc[VTIME] = 0;
   706             mouse_termios.c_cc[VMIN] = 1;
   707             mouse_termios.c_cflag = CREAD | CLOCAL | HUPCL;
   708             mouse_termios.c_cflag |= CS8;
   709             mouse_termios.c_cflag |= B1200;
   710             tcsetattr(mouse_fd, TCSAFLUSH, &mouse_termios);
   711             if (mousedrv && (SDL_strcmp(mousedrv, "PS2") == 0)) {
   712 #ifdef DEBUG_MOUSE
   713                 fprintf(stderr,
   714                         "Using (user specified) PS2 mouse on %s\n", mousedev);
   715 #endif
   716                 mouse_drv = MOUSE_PS2;
   717             } else {
   718 #ifdef DEBUG_MOUSE
   719                 fprintf(stderr, "Using (default) MS mouse on %s\n", mousedev);
   720 #endif
   721                 mouse_drv = MOUSE_MS;
   722             }
   723         }
   724     }
   725     if (mouse_fd < 0) {
   726         mouse_drv = MOUSE_NONE;
   727     }
   728     return (mouse_fd);
   729 }
   730 
   731 static int posted = 0;
   732 
   733 void
   734 FB_vgamousecallback(int button, int relative, int dx, int dy)
   735 {
   736     int button_1, button_3;
   737     int button_state;
   738     int state_changed;
   739     int i;
   740     Uint8 state;
   741 
   742     if (dx || dy) {
   743         posted += SDL_PrivateMouseMotion(0, relative, dx, dy);
   744     }
   745 
   746     /* Swap button 1 and 3 */
   747     button_1 = (button & 0x04) >> 2;
   748     button_3 = (button & 0x01) << 2;
   749     button &= ~0x05;
   750     button |= (button_1 | button_3);
   751 
   752     /* See what changed */
   753     button_state = SDL_GetMouseState(NULL, NULL);
   754     state_changed = button_state ^ button;
   755     for (i = 0; i < 8; ++i) {
   756         if (state_changed & (1 << i)) {
   757             if (button & (1 << i)) {
   758                 state = SDL_PRESSED;
   759             } else {
   760                 state = SDL_RELEASED;
   761             }
   762             posted += SDL_PrivateMouseButton(state, i + 1, 0, 0);
   763         }
   764     }
   765 }
   766 
   767 /* Handle input from tslib */
   768 #if SDL_INPUT_TSLIB
   769 static void
   770 handle_tslib(_THIS)
   771 {
   772     struct ts_sample sample;
   773     int button;
   774 
   775     while (ts_read(ts_dev, &sample, 1) > 0) {
   776         button = (sample.pressure > 0) ? 1 : 0;
   777         button <<= 2;           /* must report it as button 3 */
   778         FB_vgamousecallback(button, 0, sample.x, sample.y);
   779     }
   780     return;
   781 }
   782 #endif /* SDL_INPUT_TSLIB */
   783 
   784 /* For now, use MSC, PS/2, and MS protocols
   785    Driver adapted from the SVGAlib mouse driver code (taken from gpm, etc.)
   786  */
   787 static void
   788 handle_mouse(_THIS)
   789 {
   790     static int start = 0;
   791     static unsigned char mousebuf[BUFSIZ];
   792     static int relative = 1;
   793 
   794     int i, nread;
   795     int button = 0;
   796     int dx = 0, dy = 0;
   797     int packetsize = 0;
   798     int realx, realy;
   799 
   800     /* Figure out the mouse packet size */
   801     switch (mouse_drv) {
   802     case MOUSE_NONE:
   803         /* Ack! */
   804         read(mouse_fd, mousebuf, BUFSIZ);
   805         return;
   806     case MOUSE_MSC:
   807         packetsize = 5;
   808         break;
   809     case MOUSE_IMPS2:
   810         packetsize = 4;
   811         break;
   812     case MOUSE_PS2:
   813     case MOUSE_MS:
   814     case MOUSE_BM:
   815         packetsize = 3;
   816         break;
   817     case MOUSE_ELO:
   818         /* try to read the next packet */
   819         if (eloReadPosition
   820             (this, mouse_fd, &dx, &dy, &button, &realx, &realy)) {
   821             button = (button & 0x01) << 2;
   822             FB_vgamousecallback(button, 0, dx, dy);
   823         }
   824         return;                 /* nothing left to do */
   825     case MOUSE_TSLIB:
   826 #if SDL_INPUT_TSLIB
   827         handle_tslib(this);
   828 #endif
   829         return;                 /* nothing left to do */
   830     default:
   831         /* Uh oh.. */
   832         packetsize = 0;
   833         break;
   834     }
   835 
   836     /* Special handling for the quite sensitive ELO controller */
   837     if (mouse_drv == MOUSE_ELO) {
   838 
   839     }
   840 
   841     /* Read as many packets as possible */
   842     nread = read(mouse_fd, &mousebuf[start], BUFSIZ - start);
   843     if (nread < 0) {
   844         return;
   845     }
   846     nread += start;
   847 #ifdef DEBUG_MOUSE
   848     fprintf(stderr, "Read %d bytes from mouse, start = %d\n", nread, start);
   849 #endif
   850     for (i = 0; i < (nread - (packetsize - 1)); i += packetsize) {
   851         switch (mouse_drv) {
   852         case MOUSE_NONE:
   853             break;
   854         case MOUSE_MSC:
   855             /* MSC protocol has 0x80 in high byte */
   856             if ((mousebuf[i] & 0xF8) != 0x80) {
   857                 /* Go to next byte */
   858                 i -= (packetsize - 1);
   859                 continue;
   860             }
   861             /* Get current mouse state */
   862             button = (~mousebuf[i]) & 0x07;
   863             dx = (signed char) (mousebuf[i + 1]) +
   864                 (signed char) (mousebuf[i + 3]);
   865             dy = -((signed char) (mousebuf[i + 2]) +
   866                    (signed char) (mousebuf[i + 4]));
   867             break;
   868         case MOUSE_PS2:
   869             /* PS/2 protocol has nothing in high byte */
   870             if ((mousebuf[i] & 0xC0) != 0) {
   871                 /* Go to next byte */
   872                 i -= (packetsize - 1);
   873                 continue;
   874             }
   875             /* Get current mouse state */
   876             button = (mousebuf[i] & 0x04) >> 1 |        /*Middle */
   877                 (mousebuf[i] & 0x02) >> 1 |     /*Right */
   878                 (mousebuf[i] & 0x01) << 2;      /*Left */
   879             dx = (mousebuf[i] & 0x10) ?
   880                 mousebuf[i + 1] - 256 : mousebuf[i + 1];
   881             dy = (mousebuf[i] & 0x20) ?
   882                 -(mousebuf[i + 2] - 256) : -mousebuf[i + 2];
   883             break;
   884         case MOUSE_IMPS2:
   885             /* Get current mouse state */
   886             button = (mousebuf[i] & 0x04) >> 1 |        /*Middle */
   887                 (mousebuf[i] & 0x02) >> 1 |     /*Right */
   888                 (mousebuf[i] & 0x01) << 2 |     /*Left */
   889                 (mousebuf[i] & 0x40) >> 3 |     /* 4 */
   890                 (mousebuf[i] & 0x80) >> 3;      /* 5 */
   891             dx = (mousebuf[i] & 0x10) ?
   892                 mousebuf[i + 1] - 256 : mousebuf[i + 1];
   893             dy = (mousebuf[i] & 0x20) ?
   894                 -(mousebuf[i + 2] - 256) : -mousebuf[i + 2];
   895             switch (mousebuf[i + 3] & 0x0F) {
   896             case 0x0E:         /* DX = +1 */
   897             case 0x02:         /* DX = -1 */
   898                 break;
   899             case 0x0F:         /* DY = +1 (map button 4) */
   900                 FB_vgamousecallback(button | (1 << 3), 1, 0, 0);
   901                 break;
   902             case 0x01:         /* DY = -1 (map button 5) */
   903                 FB_vgamousecallback(button | (1 << 4), 1, 0, 0);
   904                 break;
   905             }
   906             break;
   907         case MOUSE_MS:
   908             /* Microsoft protocol has 0x40 in high byte */
   909             if ((mousebuf[i] & 0x40) != 0x40) {
   910                 /* Go to next byte */
   911                 i -= (packetsize - 1);
   912                 continue;
   913             }
   914             /* Get current mouse state */
   915             button = ((mousebuf[i] & 0x20) >> 3) |
   916                 ((mousebuf[i] & 0x10) >> 4);
   917             dx = (signed char) (((mousebuf[i] & 0x03) << 6) |
   918                                 (mousebuf[i + 1] & 0x3F));
   919             dy = (signed char) (((mousebuf[i] & 0x0C) << 4) |
   920                                 (mousebuf[i + 2] & 0x3F));
   921             break;
   922         case MOUSE_BM:
   923             /* BusMouse protocol has 0xF8 in high byte */
   924             if ((mousebuf[i] & 0xF8) != 0x80) {
   925                 /* Go to next byte */
   926                 i -= (packetsize - 1);
   927                 continue;
   928             }
   929             /* Get current mouse state */
   930             button = (~mousebuf[i]) & 0x07;
   931             dx = (signed char) mousebuf[i + 1];
   932             dy = -(signed char) mousebuf[i + 2];
   933             break;
   934         default:
   935             /* Uh oh.. */
   936             dx = 0;
   937             dy = 0;
   938             break;
   939         }
   940         FB_vgamousecallback(button, relative, dx, dy);
   941     }
   942     if (i < nread) {
   943         SDL_memcpy(mousebuf, &mousebuf[i], (nread - i));
   944         start = (nread - i);
   945     } else {
   946         start = 0;
   947     }
   948     return;
   949 }
   950 
   951 /* Handle switching to another VC, returns when our VC is back */
   952 static void
   953 switch_vt_prep(_THIS)
   954 {
   955     SDL_Surface *screen = SDL_VideoSurface;
   956 
   957     SDL_PrivateAppActive(0,
   958                          (SDL_APPACTIVE | SDL_APPINPUTFOCUS |
   959                           SDL_APPMOUSEFOCUS));
   960 
   961     /* Save the contents of the screen, and go to text mode */
   962     wait_idle(this);
   963     screen_arealen = ((screen->h + (2 * this->offset_y)) * screen->pitch);
   964     screen_contents = (Uint8 *) SDL_malloc(screen_arealen);
   965     if (screen_contents) {
   966         SDL_memcpy(screen_contents, screen->pixels, screen_arealen);
   967     }
   968     FB_SavePaletteTo(this, 256, screen_palette);
   969     ioctl(console_fd, FBIOGET_VSCREENINFO, &screen_vinfo);
   970     ioctl(keyboard_fd, KDSETMODE, KD_TEXT);
   971     ioctl(keyboard_fd, VT_UNLOCKSWITCH, 1);
   972 }
   973 static void
   974 switch_vt_done(_THIS)
   975 {
   976     SDL_Surface *screen = SDL_VideoSurface;
   977 
   978     /* Restore graphics mode and the contents of the screen */
   979     ioctl(keyboard_fd, VT_LOCKSWITCH, 1);
   980     ioctl(keyboard_fd, KDSETMODE, KD_GRAPHICS);
   981     ioctl(console_fd, FBIOPUT_VSCREENINFO, &screen_vinfo);
   982     FB_RestorePaletteFrom(this, 256, screen_palette);
   983     if (screen_contents) {
   984         SDL_memcpy(screen->pixels, screen_contents, screen_arealen);
   985         SDL_free(screen_contents);
   986         screen_contents = NULL;
   987     }
   988 
   989     /* Get updates to the shadow surface while switched away */
   990     if (SDL_ShadowSurface) {
   991         SDL_UpdateRect(SDL_ShadowSurface, 0, 0, 0, 0);
   992     }
   993 
   994     SDL_PrivateAppActive(1,
   995                          (SDL_APPACTIVE | SDL_APPINPUTFOCUS |
   996                           SDL_APPMOUSEFOCUS));
   997 }
   998 static void
   999 switch_vt(_THIS, unsigned short which)
  1000 {
  1001     struct vt_stat vtstate;
  1002 
  1003     /* Figure out whether or not we're switching to a new console */
  1004     if ((ioctl(keyboard_fd, VT_GETSTATE, &vtstate) < 0) ||
  1005         (which == vtstate.v_active)) {
  1006         return;
  1007     }
  1008 
  1009     /* New console, switch to it */
  1010     SDL_mutexP(hw_lock);
  1011     switch_vt_prep(this);
  1012     if (ioctl(keyboard_fd, VT_ACTIVATE, which) == 0) {
  1013         ioctl(keyboard_fd, VT_WAITACTIVE, which);
  1014         switched_away = 1;
  1015     } else {
  1016         switch_vt_done(this);
  1017     }
  1018     SDL_mutexV(hw_lock);
  1019 }
  1020 
  1021 static void
  1022 handle_keyboard(_THIS)
  1023 {
  1024     unsigned char keybuf[BUFSIZ];
  1025     int i, nread;
  1026     int pressed;
  1027     int scancode;
  1028     SDL_keysym keysym;
  1029 
  1030     nread = read(keyboard_fd, keybuf, BUFSIZ);
  1031     for (i = 0; i < nread; ++i) {
  1032         scancode = keybuf[i] & 0x7F;
  1033         if (keybuf[i] & 0x80) {
  1034             pressed = SDL_RELEASED;
  1035         } else {
  1036             pressed = SDL_PRESSED;
  1037         }
  1038         TranslateKey(scancode, &keysym);
  1039         /* Handle Ctrl-Alt-FN for vt switch */
  1040         switch (keysym.sym) {
  1041         case SDLK_F1:
  1042         case SDLK_F2:
  1043         case SDLK_F3:
  1044         case SDLK_F4:
  1045         case SDLK_F5:
  1046         case SDLK_F6:
  1047         case SDLK_F7:
  1048         case SDLK_F8:
  1049         case SDLK_F9:
  1050         case SDLK_F10:
  1051         case SDLK_F11:
  1052         case SDLK_F12:
  1053             if ((SDL_GetModState() & KMOD_CTRL) &&
  1054                 (SDL_GetModState() & KMOD_ALT)) {
  1055                 if (pressed) {
  1056                     switch_vt(this, (keysym.sym - SDLK_F1) + 1);
  1057                 }
  1058                 break;
  1059             }
  1060             /* Fall through to normal processing */
  1061         default:
  1062             posted += SDL_PrivateKeyboard(pressed, &keysym);
  1063             break;
  1064         }
  1065     }
  1066 }
  1067 
  1068 void
  1069 FB_PumpEvents(_THIS)
  1070 {
  1071     fd_set fdset;
  1072     int max_fd;
  1073     static struct timeval zero;
  1074 
  1075     do {
  1076         if (switched_away) {
  1077             struct vt_stat vtstate;
  1078 
  1079             SDL_mutexP(hw_lock);
  1080             if ((ioctl(keyboard_fd, VT_GETSTATE, &vtstate) == 0) &&
  1081                 vtstate.v_active == current_vt) {
  1082                 switched_away = 0;
  1083                 switch_vt_done(this);
  1084             }
  1085             SDL_mutexV(hw_lock);
  1086         }
  1087 
  1088         posted = 0;
  1089 
  1090         FD_ZERO(&fdset);
  1091         max_fd = 0;
  1092         if (keyboard_fd >= 0) {
  1093             FD_SET(keyboard_fd, &fdset);
  1094             if (max_fd < keyboard_fd) {
  1095                 max_fd = keyboard_fd;
  1096             }
  1097         }
  1098         if (mouse_fd >= 0) {
  1099             FD_SET(mouse_fd, &fdset);
  1100             if (max_fd < mouse_fd) {
  1101                 max_fd = mouse_fd;
  1102             }
  1103         }
  1104         if (select(max_fd + 1, &fdset, NULL, NULL, &zero) > 0) {
  1105             if (keyboard_fd >= 0) {
  1106                 if (FD_ISSET(keyboard_fd, &fdset)) {
  1107                     handle_keyboard(this);
  1108                 }
  1109             }
  1110             if (mouse_fd >= 0) {
  1111                 if (FD_ISSET(mouse_fd, &fdset)) {
  1112                     handle_mouse(this);
  1113                 }
  1114             }
  1115         }
  1116     }
  1117     while (posted);
  1118 }
  1119 
  1120 void
  1121 FB_InitOSKeymap(_THIS)
  1122 {
  1123     int i;
  1124 
  1125     /* Initialize the Linux key translation table */
  1126 
  1127     /* First get the ascii keys and others not well handled */
  1128     for (i = 0; i < SDL_arraysize(keymap); ++i) {
  1129         switch (i) {
  1130             /* These aren't handled by the x86 kernel keymapping (?) */
  1131         case SCANCODE_PRINTSCREEN:
  1132             keymap[i] = SDLK_PRINT;
  1133             break;
  1134         case SCANCODE_BREAK:
  1135             keymap[i] = SDLK_BREAK;
  1136             break;
  1137         case SCANCODE_BREAK_ALTERNATIVE:
  1138             keymap[i] = SDLK_PAUSE;
  1139             break;
  1140         case SCANCODE_LEFTSHIFT:
  1141             keymap[i] = SDLK_LSHIFT;
  1142             break;
  1143         case SCANCODE_RIGHTSHIFT:
  1144             keymap[i] = SDLK_RSHIFT;
  1145             break;
  1146         case SCANCODE_LEFTCONTROL:
  1147             keymap[i] = SDLK_LCTRL;
  1148             break;
  1149         case SCANCODE_RIGHTCONTROL:
  1150             keymap[i] = SDLK_RCTRL;
  1151             break;
  1152         case SCANCODE_RIGHTWIN:
  1153             keymap[i] = SDLK_RSUPER;
  1154             break;
  1155         case SCANCODE_LEFTWIN:
  1156             keymap[i] = SDLK_LSUPER;
  1157             break;
  1158         case SCANCODE_LEFTALT:
  1159             keymap[i] = SDLK_LALT;
  1160             break;
  1161         case SCANCODE_RIGHTALT:
  1162             keymap[i] = SDLK_RALT;
  1163             break;
  1164         case 127:
  1165             keymap[i] = SDLK_MENU;
  1166             break;
  1167             /* this should take care of all standard ascii keys */
  1168         default:
  1169             keymap[i] = KVAL(vga_keymap[0][i]);
  1170             break;
  1171         }
  1172     }
  1173     for (i = 0; i < SDL_arraysize(keymap); ++i) {
  1174         switch (keymap_temp[i]) {
  1175         case K_F1:
  1176             keymap[i] = SDLK_F1;
  1177             break;
  1178         case K_F2:
  1179             keymap[i] = SDLK_F2;
  1180             break;
  1181         case K_F3:
  1182             keymap[i] = SDLK_F3;
  1183             break;
  1184         case K_F4:
  1185             keymap[i] = SDLK_F4;
  1186             break;
  1187         case K_F5:
  1188             keymap[i] = SDLK_F5;
  1189             break;
  1190         case K_F6:
  1191             keymap[i] = SDLK_F6;
  1192             break;
  1193         case K_F7:
  1194             keymap[i] = SDLK_F7;
  1195             break;
  1196         case K_F8:
  1197             keymap[i] = SDLK_F8;
  1198             break;
  1199         case K_F9:
  1200             keymap[i] = SDLK_F9;
  1201             break;
  1202         case K_F10:
  1203             keymap[i] = SDLK_F10;
  1204             break;
  1205         case K_F11:
  1206             keymap[i] = SDLK_F11;
  1207             break;
  1208         case K_F12:
  1209             keymap[i] = SDLK_F12;
  1210             break;
  1211 
  1212         case K_DOWN:
  1213             keymap[i] = SDLK_DOWN;
  1214             break;
  1215         case K_LEFT:
  1216             keymap[i] = SDLK_LEFT;
  1217             break;
  1218         case K_RIGHT:
  1219             keymap[i] = SDLK_RIGHT;
  1220             break;
  1221         case K_UP:
  1222             keymap[i] = SDLK_UP;
  1223             break;
  1224 
  1225         case K_P0:
  1226             keymap[i] = SDLK_KP0;
  1227             break;
  1228         case K_P1:
  1229             keymap[i] = SDLK_KP1;
  1230             break;
  1231         case K_P2:
  1232             keymap[i] = SDLK_KP2;
  1233             break;
  1234         case K_P3:
  1235             keymap[i] = SDLK_KP3;
  1236             break;
  1237         case K_P4:
  1238             keymap[i] = SDLK_KP4;
  1239             break;
  1240         case K_P5:
  1241             keymap[i] = SDLK_KP5;
  1242             break;
  1243         case K_P6:
  1244             keymap[i] = SDLK_KP6;
  1245             break;
  1246         case K_P7:
  1247             keymap[i] = SDLK_KP7;
  1248             break;
  1249         case K_P8:
  1250             keymap[i] = SDLK_KP8;
  1251             break;
  1252         case K_P9:
  1253             keymap[i] = SDLK_KP9;
  1254             break;
  1255         case K_PPLUS:
  1256             keymap[i] = SDLK_KP_PLUS;
  1257             break;
  1258         case K_PMINUS:
  1259             keymap[i] = SDLK_KP_MINUS;
  1260             break;
  1261         case K_PSTAR:
  1262             keymap[i] = SDLK_KP_MULTIPLY;
  1263             break;
  1264         case K_PSLASH:
  1265             keymap[i] = SDLK_KP_DIVIDE;
  1266             break;
  1267         case K_PENTER:
  1268             keymap[i] = SDLK_KP_ENTER;
  1269             break;
  1270         case K_PDOT:
  1271             keymap[i] = SDLK_KP_PERIOD;
  1272             break;
  1273 
  1274         case K_SHIFT:
  1275             if (keymap[i] != SDLK_RSHIFT)
  1276                 keymap[i] = SDLK_LSHIFT;
  1277             break;
  1278         case K_SHIFTL:
  1279             keymap[i] = SDLK_LSHIFT;
  1280             break;
  1281         case K_SHIFTR:
  1282             keymap[i] = SDLK_RSHIFT;
  1283             break;
  1284         case K_CTRL:
  1285             if (keymap[i] != SDLK_RCTRL)
  1286                 keymap[i] = SDLK_LCTRL;
  1287             break;
  1288         case K_CTRLL:
  1289             keymap[i] = SDLK_LCTRL;
  1290             break;
  1291         case K_CTRLR:
  1292             keymap[i] = SDLK_RCTRL;
  1293             break;
  1294         case K_ALT:
  1295             keymap[i] = SDLK_LALT;
  1296             break;
  1297         case K_ALTGR:
  1298             keymap[i] = SDLK_RALT;
  1299             break;
  1300 
  1301         case K_INSERT:
  1302             keymap[i] = SDLK_INSERT;
  1303             break;
  1304         case K_REMOVE:
  1305             keymap[i] = SDLK_DELETE;
  1306             break;
  1307         case K_PGUP:
  1308             keymap[i] = SDLK_PAGEUP;
  1309             break;
  1310         case K_PGDN:
  1311             keymap[i] = SDLK_PAGEDOWN;
  1312             break;
  1313         case K_FIND:
  1314             keymap[i] = SDLK_HOME;
  1315             break;
  1316         case K_SELECT:
  1317             keymap[i] = SDLK_END;
  1318             break;
  1319 
  1320         case K_NUM:
  1321             keymap[i] = SDLK_NUMLOCK;
  1322             break;
  1323         case K_CAPS:
  1324             keymap[i] = SDLK_CAPSLOCK;
  1325             break;
  1326 
  1327         case K_F13:
  1328             keymap[i] = SDLK_PRINT;
  1329             break;
  1330         case K_HOLD:
  1331             keymap[i] = SDLK_SCROLLOCK;
  1332             break;
  1333         case K_PAUSE:
  1334             keymap[i] = SDLK_PAUSE;
  1335             break;
  1336 
  1337         case 127:
  1338             keymap[i] = SDLK_BACKSPACE;
  1339             break;
  1340 
  1341         default:
  1342             break;
  1343         }
  1344     }
  1345 }
  1346 
  1347 static SDL_keysym *
  1348 TranslateKey(int scancode, SDL_keysym * keysym)
  1349 {
  1350     /* Set the keysym information */
  1351     keysym->scancode = scancode;
  1352     keysym->sym = keymap[scancode];
  1353     keysym->mod = KMOD_NONE;
  1354 
  1355     /* If UNICODE is on, get the UNICODE value for the key */
  1356     keysym->unicode = 0;
  1357     if (SDL_TranslateUNICODE) {
  1358         int map;
  1359         SDLMod modstate;
  1360 
  1361         modstate = SDL_GetModState();
  1362         map = 0;
  1363         if (modstate & KMOD_SHIFT) {
  1364             map |= (1 << KG_SHIFT);
  1365         }
  1366         if (modstate & KMOD_CTRL) {
  1367             map |= (1 << KG_CTRL);
  1368         }
  1369         if (modstate & KMOD_LALT) {
  1370             map |= (1 << KG_ALT);
  1371         }
  1372         if (modstate & KMOD_RALT) {
  1373             map |= (1 << KG_ALTGR);
  1374         }
  1375         if (KTYP(vga_keymap[map][scancode]) == KT_LETTER) {
  1376             if (modstate & KMOD_CAPS) {
  1377                 map ^= (1 << KG_SHIFT);
  1378             }
  1379         }
  1380         if (KTYP(vga_keymap[map][scancode]) == KT_PAD) {
  1381             if (modstate & KMOD_NUM) {
  1382                 keysym->unicode = KVAL(vga_keymap[map][scancode]);
  1383             }
  1384         } else {
  1385             keysym->unicode = KVAL(vga_keymap[map][scancode]);
  1386         }
  1387     }
  1388     return (keysym);
  1389 }
  1390 
  1391 /* vi: set ts=4 sw=4 expandtab: */