home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / D / SVGALIB / SVGALIB1.TAR / svgalib / src / keyboard / keyboard.c next >
Encoding:
C/C++ Source or Header  |  1994-12-31  |  9.5 KB  |  383 lines

  1. /* Keyboard library functions */
  2. /* H. Hanemaayer (hhanemaa@cs.ruu.nl) */
  3.  
  4. /*
  5.  * Keyboard I/O based on showkey.c from kbd-0.84 package.
  6.  *
  7.  * This is an initial version, it isn't very safe yet since it only catches
  8.  * sigsegv.
  9.  */
  10.  
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <unistd.h>
  14. #include <string.h>
  15. #include <signal.h>
  16. #include <sys/ioctl.h>
  17. #include <fcntl.h>
  18. #include <termios.h>
  19. #include <linux/kd.h>
  20. /* linux/keyboard.h defines NR_KEYS and some scancode-like constants, so it */
  21. /* should also be useful for svgalib programs using the keyboard. It misses */
  22. /* a few KERNEL ifdefs around kernel data structures though. */
  23. #include <linux/keyboard.h>
  24. #include <sys/vt.h>
  25. #include <vga.h>
  26. #include "../libvga.h"
  27. #include "vgakeyboard.h"
  28.  
  29.  
  30. static void (*__keyboard_eventhandler)( int, int );
  31.  
  32.  
  33. static struct sigaction oldsiga_segv, oldsiga_kill;
  34. static struct termios oldkbdtermios, newkbdtermios;
  35. static int oldkbmode;
  36. static int kbd_fd;
  37. static void (*currentinthandler)();
  38. static void (*currentsegvhandler)();
  39. static void (*currentkillhandler)();
  40. static int ctrl_c_state_c, ctrl_c_state_control;
  41. static int alt_state, functionkey_state;
  42.  
  43. #if 0
  44. static void inthandler() {
  45.     keyboard_close();
  46.     sigaction(SIGINT, &oldsiga, NULL);
  47.     raise(SIGINT);
  48. }
  49. #endif
  50.  
  51. static void handle_segv() {
  52.     /* Hope this still works (the critical thing is probably that */
  53.     /* oldkbmode is not overwritten). */
  54.     keyboard_close();
  55.     /* restore old interrupt */
  56.     sigaction(SIGSEGV, &oldsiga_segv, NULL);
  57.     raise(SIGSEGV);
  58. }
  59.  
  60. static void handle_kill() {
  61.     keyboard_close();
  62.     /* restore old interrupt */
  63.     sigaction(SIGKILL, &oldsiga_kill, NULL);
  64.     raise(SIGKILL);
  65. }
  66.  
  67. static void ctrl_c_pressed() {
  68.     keyboard_close();
  69.     raise(SIGINT);
  70. }
  71.  
  72. static void default_handler( int, int );
  73.  
  74. int keyboard_init_return_fd() {
  75.     struct sigaction siga;
  76.  
  77.     currentinthandler = NULL;
  78.     currentsegvhandler = NULL;
  79.     currentkillhandler = NULL;
  80.  
  81.     /* Install default keyboard handler. */
  82.      __keyboard_eventhandler = default_handler;
  83.  
  84.     if (__svgalib_console_fd != -1)
  85.         kbd_fd = __svgalib_console_fd;
  86.     else
  87.         /* svgalib has not already opened the console at */
  88.         /* initialization. */
  89.         if ((kbd_fd = open("/dev/console", O_RDONLY)) < 0) {
  90.             printf("svgalib (keyboard): cannot open /dev/console.\n");
  91.             return -1;
  92.         }
  93.  
  94.     if (ioctl(kbd_fd, KDGKBMODE, &oldkbmode)) {
  95.         printf("svgalib: cannot get keyboard mode.\n");
  96.         return -1;
  97.     }
  98.  
  99.     tcgetattr(kbd_fd, &oldkbdtermios);
  100.     newkbdtermios = oldkbdtermios;
  101.  
  102.     newkbdtermios.c_lflag = newkbdtermios.c_lflag & ~ (ICANON | ECHO | ISIG);
  103.     newkbdtermios.c_cc[VMIN] = 0;    /* Making these 0 seems to have the */
  104.     newkbdtermios.c_cc[VTIME] = 0;    /* desired effect. */
  105.  
  106.     tcsetattr(kbd_fd, TCSAFLUSH, &newkbdtermios);
  107.  
  108.     ioctl(kbd_fd, KDSKBMODE, K_MEDIUMRAW);
  109.  
  110.     keyboard_clearstate();
  111.  
  112.     /* Install segv handler. */
  113.     /* We probably need to catch a host of other signals also if */
  114.     /* we don't want the keyboard to die in any circumstances. */
  115.     currentsegvhandler = handle_segv;
  116.     siga.sa_handler = handle_segv;
  117.     siga.sa_flags = 0;
  118.     siga.sa_mask = 0;
  119.     sigaction(SIGSEGV, &siga, &oldsiga_segv);
  120.     currentkillhandler = handle_kill;
  121.     siga.sa_handler = handle_kill;
  122.     sigaction(SIGKILL, &siga, &oldsiga_kill);
  123.  
  124.     return kbd_fd;    /* OK, return fd. */
  125. }
  126.  
  127. /* Old compatible init function. */
  128.  
  129. int keyboard_init() {
  130.     if (keyboard_init_return_fd() == -1)
  131.         return -1;
  132.     else
  133.         return 0;
  134. }
  135.  
  136. void keyboard_close() {
  137.     ioctl(kbd_fd, KDSKBMODE, oldkbmode);
  138.     tcsetattr(kbd_fd, 0, &oldkbdtermios);
  139.  
  140.     if (kbd_fd != __svgalib_console_fd)
  141.         /* Close the console if it was opened in keyboard_init, */
  142.         /* rather than vga_init. */
  143.         close(kbd_fd);
  144.     if (currentsegvhandler != NULL)
  145.         /* Restore old interrupt. */
  146.         sigaction(SIGSEGV, &oldsiga_segv, NULL);
  147.     if (currentkillhandler != NULL)
  148.         /* Restore old interrupt. */
  149.         sigaction(SIGKILL, &oldsiga_kill, NULL);
  150. #if 0
  151.     if (currentinthandler != NULL)
  152.         /* Restore old interrupt. */
  153.         sigaction(SIGINT, &oldsiga, NULL);
  154. #endif
  155. }
  156.  
  157. /* For now, we assume there's no console switching. */
  158. /* (Actually, there won't be any unless we catch the console switching */
  159. /* keys). */
  160.  
  161. #define KBDREADBUFFERSIZE 32
  162.  
  163. static int keyboard_getevents( int wait ) {
  164. /* Read keyboard device, and handle events. */
  165. /* If wait == 1, process at least one event and return. */
  166. /* If wait == 0, handle all accumulated events; return 0 if no events */
  167. /* were handled, 1 otherwise. */
  168. /* Wait mode doesn't seem to work very well; the keyboard repeat delay is */
  169. /* present. I don't understand fcntl. */
  170.     static unsigned char buf[KBDREADBUFFERSIZE];
  171.     static int kfdmode = 0;    /* 1 = DELAY, 0 = NDELAY */
  172.     int bytesread, i;
  173.     int eventhandled;
  174.  
  175.     eventhandled = 0;
  176.  
  177. again:
  178.     if (kfdmode == 1) {    /* This only happens for wait == 1. */
  179.         struct termios kbdtermios;
  180.         int flags;
  181.         /* We don't want to wait, set NDELAY mode. */
  182.         fcntl(kbd_fd, F_GETFL, &flags);
  183.         fcntl(kbd_fd, F_SETFL, flags | O_NDELAY);
  184.  
  185.         #if 0
  186.         tcgetattr(kbd_fd, &kbdtermios);
  187.         kbdtermios.c_lflag = kbdtermios.c_lflag & ~ (ICANON | ECHO | ISIG);
  188.         kbdtermios.c_cc[VMIN] = 0;
  189.         kbdtermios.c_cc[VTIME] = 0;
  190.         tcsetattr(kbd_fd, TCSANOW, &kbdtermios);
  191.         #endif
  192.  
  193.         kfdmode = 0;
  194.     }
  195.     bytesread = read(kbd_fd, buf, KBDREADBUFFERSIZE);
  196.  
  197.     if (wait == 1 && bytesread < 1) {
  198.         struct termios kbdtermios;
  199.         int flags;
  200.         /* We already handled an event, no need to wait for another. */
  201.         if (eventhandled)
  202.             return 1;
  203.         /* Wait mode, we'll sleep on reads. */
  204.         fcntl(kbd_fd, F_GETFL, &flags);
  205.         fcntl(kbd_fd, F_SETFL, flags & ~O_NDELAY);
  206.  
  207.         #if 0
  208.         tcgetattr(kbd_fd, &kbdtermios);
  209.         kbdtermios.c_lflag = kbdtermios.c_lflag & ~ (ICANON | ECHO | ISIG);
  210.         kbdtermios.c_cc[VMIN] = 0;
  211.         kbdtermios.c_cc[VTIME] = 0;
  212.         tcsetattr(kbd_fd, TCSANOW, &kbdtermios);
  213.         #endif
  214.  
  215.         kfdmode = 1;
  216.         bytesread = read(kbd_fd, buf, 1);
  217.     }
  218.  
  219.     if (wait == 0 && bytesread < 1)
  220.         return eventhandled;
  221.  
  222.     if (bytesread >= 1)
  223.         eventhandled = 1;
  224.  
  225.     for (i = 0; i < bytesread; i++) {
  226.         /* Check for ctrl-c. */
  227.         if ((buf[i] & 0x7f) == SCANCODE_C)
  228.             if (buf[i] & 0x80)
  229.                 ctrl_c_state_c = 0;
  230.             else
  231.                 ctrl_c_state_c = 1;
  232.         if ((buf[i] & 0x7f) == SCANCODE_LEFTCONTROL
  233.         || (buf[i] & 0x7f) == SCANCODE_RIGHTCONTROL)
  234.             if (buf[i] & 0x80)
  235.                 ctrl_c_state_control = 0;
  236.             else
  237.                 ctrl_c_state_control = 1;
  238.         if ((buf[i] & 0x7f) == SCANCODE_LEFTALT
  239.         || (buf[i] & 0x7f) == SCANCODE_RIGHTALT)
  240.             if (buf[i] & 0x80)
  241.                 alt_state = 0;
  242.             else
  243.                 alt_state = 1;
  244.         if ((buf[i] & 0x7f) >= SCANCODE_F1
  245.         && (buf[i] & 0x7f) <= SCANCODE_F10)
  246.             if (buf[i] & 0x80)
  247.                 functionkey_state &= ~(1 << ((buf[i] & 0x7f)
  248.                     - SCANCODE_F1));
  249.             else
  250.                 functionkey_state |= 1 << ((buf[i] & 0x7f)
  251.                     - SCANCODE_F1);
  252.         if (ctrl_c_state_control && ctrl_c_state_c)
  253.             ctrl_c_pressed();
  254.         if (alt_state && functionkey_state) {
  255.             /* VT switch. */
  256.             int j, vt;
  257.             for (j = 0; j < 10; j++)
  258.                 if (functionkey_state & (1 << i)) {
  259.                     vt = i + 1;
  260.                     break;
  261.                 }
  262.  
  263.             /*
  264.              * This will generate a signal catched by
  265.              * svgalib to restore textmode.
  266.              */
  267.             ioctl(__svgalib_tty_fd, VT_ACTIVATE, vt);
  268.             return 1;
  269.         }
  270.         __keyboard_eventhandler(buf[i] & 0x7f,
  271.             (buf[i] & 0x80) ? KEY_EVENTRELEASE : KEY_EVENTPRESS);
  272.     }
  273.  
  274.     /* Handle other events that have accumulated. */
  275.     goto again;
  276. }
  277.  
  278. int keyboard_update() {
  279.     return keyboard_getevents(0);    /* Don't wait. */
  280. }
  281.  
  282. void keyboard_waitforupdate() {
  283.     keyboard_getevents(1);        /* Wait for event. */
  284.     return;
  285. }
  286.  
  287. void keyboard_seteventhandler( void (*handler)( int, int ) ) {
  288.     __keyboard_eventhandler = handler;
  289. }
  290.  
  291.  
  292.  
  293. /* Default event handler. */
  294.  
  295. void keyboard_setdefaulteventhandler() {
  296.     __keyboard_eventhandler = default_handler;
  297. }
  298.  
  299. static unsigned char state[NR_KEYS];    /* NR_KEYS is defined in linux/keyboard.h */
  300. static int translatemode = 0;
  301.  
  302. static int checkscancode( int scancode ) {
  303.     if (scancode < 0 || scancode >= NR_KEYS) {
  304.         printf("svgalib: keyboard scancode out of range (%d).\n",
  305.             scancode);
  306.         return 1;
  307.     }
  308.     return 0;
  309. }
  310.  
  311. static void default_handler( int scancode, int newstate ) {
  312.     if (checkscancode(scancode))
  313.         return;
  314.     if (translatemode & TRANSLATE_CURSORKEYS)
  315.         /* Map cursor key block to keypad cursor keys. */
  316.         switch (scancode) {
  317.          case SCANCODE_CURSORBLOCKUP :
  318.             scancode = SCANCODE_CURSORUP; break;
  319.          case SCANCODE_CURSORBLOCKLEFT :
  320.             scancode = SCANCODE_CURSORLEFT; break;
  321.         case SCANCODE_CURSORBLOCKRIGHT :
  322.             scancode = SCANCODE_CURSORRIGHT; break;
  323.         case SCANCODE_CURSORBLOCKDOWN :
  324.             scancode = SCANCODE_CURSORDOWN; break;
  325.         }
  326.     if (translatemode & TRANSLATE_DIAGONAL) {
  327.         /* Translate diagonal keypad keys to two keypad cursor keys. */
  328.         switch (scancode) {
  329.         case SCANCODE_CURSORUPLEFT :
  330.             state[SCANCODE_CURSORUP] = newstate;
  331.             state[SCANCODE_CURSORLEFT] = newstate;
  332.             return;
  333.         case SCANCODE_CURSORUPRIGHT :
  334.             state[SCANCODE_CURSORUP] = newstate;
  335.             state[SCANCODE_CURSORRIGHT] = newstate;
  336.             return;
  337.         case SCANCODE_CURSORDOWNLEFT :
  338.             state[SCANCODE_CURSORDOWN] = newstate;
  339.             state[SCANCODE_CURSORLEFT] = newstate;
  340.             return;
  341.         case SCANCODE_CURSORDOWNRIGHT :
  342.             state[SCANCODE_CURSORDOWN] = newstate;
  343.             state[SCANCODE_CURSORRIGHT] = newstate;
  344.             return;
  345.         }
  346.     }
  347.     if ((translatemode & TRANSLATE_KEYPADENTER) && scancode ==
  348.     SCANCODE_KEYPADENTER)
  349.         scancode = SCANCODE_ENTER;
  350.  
  351. #if 0    /* This happens very often. */
  352.     if (state[scancode] == newstate) {
  353.         printf("svgalib: keyboard event does not match (scancode = %d)\n",
  354.             scancode);
  355.         return;
  356.     }
  357. #endif    
  358.     state[scancode] = newstate;
  359. }
  360.  
  361. void keyboard_clearstate() {
  362.     int i;
  363.     memset(state, 0, NR_KEYS);
  364.     ctrl_c_state_c = 0;
  365.     ctrl_c_state_control = 0;
  366.     alt_state = 0;
  367.     functionkey_state = 0;
  368. }
  369.  
  370. int keyboard_keypressed( int scancode ) {
  371.     if (checkscancode(scancode))
  372.         return 0;
  373.     return state[scancode];
  374. }
  375.  
  376. char *keyboard_getstate() {
  377.     return state;
  378. }
  379.  
  380. void keyboard_translatekeys( int mode ) {
  381.     translatemode = mode;
  382. }
  383.