📄 keyboard.c
字号:
/* Keyboard library functions *//* H. Hanemaayer (hhanemaa@cs.ruu.nl) *//* Apr 03 1998: Added fake mouse event and some cleanup by 101 (Attila Lendvai) e-mail: 101@kempelen.inf.bme.hu *//* * May 28 1998: Changed __keyboard_eventhandler to * __svgalib_keyboard_eventhandler and made non-static to allow for fake * keyboard events for the wheelmice (Brion Vibber <brion@pobox.com>) * * July 3 1998: Added keyboard remapping support - brion*//* * Keyboard I/O based on showkey.c from kbd-0.84 package. * This is an initial version, it isn't very safe yet since it only catches * sigsegv.*//* #define DEBUG_KEYBOARD */#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <signal.h>#include <sys/ioctl.h>#include <fcntl.h>#include <termios.h>#include <linux/kd.h>/* linux/keyboard.h defines NR_KEYS and some scancode-like constants, so it *//* should also be useful for svgalib programs using the keyboard. It misses *//* a few KERNEL ifdefs around kernel data structures though. */#include <linux/keyboard.h>#include <sys/vt.h>/* Needed to check uid of keymap files */#include <sys/stat.h>#include <unistd.h>#include <vga.h>#include "../libvga.h"#include "vgakeyboard.h"#include "driver.h"void (*__svgalib_keyboard_eventhandler) (int, int);static struct termios oldkbdtermios, newkbdtermios;static int oldkbmode;/* vga.c needs to check that: */int __svgalib_kbd_fd = -1; /* nowadays merely used as a flag */static int c_state, ctrl_state, alt_state, functionkey_state, win_state;static int translatemode = 0;static unsigned char state[NR_KEYS]; /* NR_KEYS is defined in linux/keyboard.h */static int keymap[NR_KEYS];static int usekeymap = 0; /* If nonzero, we translate scancodes */static int rootkeymaps = 0; /* If nonzero, only load keymaps owned by root */static char keynames[NR_KEYS][MAX_KEYNAME_LEN] = { /* The default US QWERTY layout */ "", "Escape", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "zero", "minus", "equal", "Delete", "Tab", "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "bracketleft", "bracketright", "Return", "Control", "a", "s", "d", "f", "g", "h", "j", "k", "l", "semicolon", "apostrophe", "grave", "Shift", "backslash", "z", "x", "c", "v", "b", "n", "m", "comma", "period", "slash", "Shift", "KP_Multiply", "Alt", "space", "Caps_Lock", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "Num_Lock", "Scroll_Lock", "KP_7", "KP_8", "KP_9", "KP_Subtract", "KP_4", "KP_5", "KP_6", "KP_Add", "KP_1", "KP_2", "KP_3", "KP_0", "KP_Period", "Last_Console", "", "less", "F11", "F12", "", "", "", "", "", "", "", "KP_Enter", "Control", "KP_Divide", "Control_backslash", "AltGr", "Break", "Find", "Up", "Prior", "Left", "Right", "Select", "Down", "Next", "Insert", "Remove", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""};static void default_handler(int, int);static char *kbd_load_keymap(char *ptr);static void kbd_update_keymap(void);static int kbd_mapkey(int inscancode);static struct FakeMouseEvent { int data; short type; short flags; int scancode; char keyname[MAX_KEYNAME_LEN];} **fake_mouse_events = 0;/* Number of events per scancode */static short *fme_numberof = 0;/* Number of scancodes used */static int fme_used = 0;/* Fake event flags */#define FMEF_TRIGGERED 1 /* Triggered, */#define FMEF_AT_PRESS 2 /* Request at press (or if false at release)*/#define FMEF_AT_BOTH 4 /* Request at press/release too */#define FMEF_REPEAT 8 /* Keep on sending fake events */#define FME_TYPE_BUTTON 1#define FME_TYPE_DELTAX 2#define FME_TYPE_DELTAY 3#define FME_TYPE_DELTAZ 4#define FME_TYPE_IGNOREX 5#define FME_TYPE_IGNOREY 6#define FME_TYPE_IGNOREZ 7#define FME_TYPE_BUTTON1 8#define FME_TYPE_BUTTON2 9#define FME_TYPE_BUTTON3 10static int expand_events(int n) { struct FakeMouseEvent *newptr = 0;/* int n; */ if ( ! fake_mouse_events) {#ifdef DEBUG_KEYBOARD fprintf(stderr," Allocating space for FMEs...\n");#endif if ( (fake_mouse_events = malloc(sizeof(void *) * NR_KEYS)) == 0) { error: fputs("svgalib: keyboard-config: out of memory ?! Fake mouse events might be disabled !", stderr); return 0; } else { if ( (fme_numberof = malloc(sizeof(short) * NR_KEYS)) == 0) { free(fake_mouse_events); fake_mouse_events = 0; goto error; } memset(fake_mouse_events, 0, sizeof(void *) * NR_KEYS); memset(fme_numberof, 0, sizeof(short) * NR_KEYS); } }#ifdef DEBUG_KEYBOARD fprintf(stderr," Expanding FME #%d... ", n);#endif if ( (newptr = realloc(fake_mouse_events[n], sizeof(struct FakeMouseEvent) * ++fme_numberof[n])) != 0 ) {#ifdef DEBUG_KEYBOARD fprintf(stderr,"it's all good.\n");#endif fake_mouse_events[n] = newptr; return 1; } else { goto error; }}static char *kbd_config_options[] = { "kbd_fake_mouse_event", "kbd_keymap", "kbd_only_root_keymaps", NULL};static char *kbd_process_option(int option, int mode) { char *ptr; short type = 0; short ignore_type = 0; short flags = FMEF_AT_PRESS; int data = 0; int scancode = 0; int event_ok = 0; int n = 0; struct FakeMouseEvent *event; char keyname[MAX_KEYNAME_LEN]; switch (option) { case 0: /* kbd_fake_mouse_event */ if ( (ptr = strtok(NULL, " ")) == 0) { param_needed: fprintf(stderr, "svgalib: kbd-config: too few parameters for \'%s\'\n", kbd_config_options[option]); return ptr; } else if ( (scancode = __svgalib_mapkeyname(ptr)) == -1) { fprintf(stderr, "svgalib: kbd-config: \'%s\' is not a valid scancode\n", ptr); return ptr; } strncpy(keyname, ptr, MAX_KEYNAME_LEN); /* Find the event for this key if there is one*/#ifdef DEBUG_KEYBOARD fprintf(stderr," Looking for fme for key \'%s\'... ", keyname);#endif for(n = 0; n < fme_used; n++) if(strcmp(fake_mouse_events[n]->keyname, keyname) == 0) break; if(n == fme_used) fme_used++;#ifdef DEBUG_KEYBOARD fprintf(stderr," found at #%d.\n", n);#endif read_event: if ( (ptr = strtok(NULL, " ")) == 0) { if ( event_ok ) break; else goto param_needed; } if ( ! strcasecmp(ptr, "both")) { flags |= FMEF_AT_BOTH; goto read_event; } else if ( ! strcasecmp(ptr, "up")) { flags &= ~FMEF_AT_PRESS; flags &= ~FMEF_AT_BOTH; goto read_event; } else if ( ! strcasecmp(ptr, "down")) { flags |= FMEF_AT_PRESS; flags &= ~FMEF_AT_BOTH; goto read_event; } else if ( ! strcasecmp(ptr, "repeat")) { flags |= FMEF_REPEAT; goto read_event; } else if ( ! strcasecmp(ptr, "discrete")) { flags &= ~FMEF_REPEAT; goto read_event; } else if ( ! strcasecmp(ptr, "button")) { type = FME_TYPE_BUTTON; if ( (ptr = strtok(NULL, " ")) == 0) goto param_needed; if ( (data = atoi(ptr)) == 0 || data > 10) { fprintf(stderr, "svgalib: kbd-config: \'%s\' is not a valid mouse button\n", ptr); return ptr; } store_event:#ifdef DEBUG_KEYBOARD printf(" Fake Mouse Event: scancode: %ld; type: %ld; data: %ld; flags: %ld\n", (long)scancode, (long)type, (long)data, (long)flags);#endif if ( ! expand_events(n)) return ptr; event = &fake_mouse_events[n][fme_numberof[n] - 1]; event -> type = type; event -> flags = flags; event -> data = data; event -> scancode = scancode; strcpy(event -> keyname, keyname); event_ok = 1; goto read_event; } else if ( ! strcasecmp(ptr, "deltax")) { type = FME_TYPE_DELTAX; ignore_type = FME_TYPE_IGNOREX; process_delta: if ( (ptr = strtok(NULL, " ")) == 0) goto param_needed; if ( ! strcasecmp(ptr, "off")) { type = ignore_type; data = 1; goto store_event; } else if ( ! strcasecmp(ptr, "on")) { type = ignore_type; data = 0; goto store_event; } else if ( (data = atoi(ptr)) == 0) { fprintf(stderr, "svgalib: kbd-config: \'%s\' is not a valid delta\n", ptr); return ptr; } goto store_event; } else if ( ! strcasecmp(ptr, "deltay")) { type = FME_TYPE_DELTAY; ignore_type = FME_TYPE_IGNOREY; goto process_delta; } else if ( ! strcasecmp(ptr, "deltaz")) { type = FME_TYPE_DELTAZ; ignore_type = FME_TYPE_IGNOREZ; goto process_delta; } else if ( ! strcasecmp(ptr, "button1")) { type = FME_TYPE_BUTTON1; process_button: if ( (ptr = strtok(NULL, " ")) == 0) goto param_needed; if ( ! strcasecmp(ptr, "pressed")) { data = 1; } else if ( ! strcasecmp(ptr, "released")) { data = 0; } else { fprintf(stderr, "svgalib: kbd-config: \'%s\' is not a legal parameter for command " "\'button[123]\'. Should be either \'pressed\' or \'released\'\n", ptr); return ptr; } goto store_event; } else if ( ! strcasecmp(ptr, "button2")) { type = FME_TYPE_BUTTON2; goto process_button; } else if ( ! strcasecmp(ptr, "button3")) { type = FME_TYPE_BUTTON3; goto process_button; } else if ( ! event_ok) { fprintf(stderr, "svgalib: kbd-config: illegal mouse event: \'%s\'\n", ptr); return ptr; } else return ptr; break; case 1: /* kbd_keymap */ if ( (ptr = strtok(NULL, " ")) == 0 ) { goto param_needed; } else if(kbd_load_keymap(ptr)) return ptr; break; case 2: /* kbd_only_root_keymaps */#ifdef DEBUG_KEYBOARD fprintf(stderr, " Setting rootkeymaps to 1.\n");#endif rootkeymaps = 1; break; } return strtok(NULL, " ");};int keyboard_init_return_fd(void) { char *ptr; keyboard_translatekeys(translatemode); /* Honour 'nosigint' setting */ /* Install default keyboard handler. */ __svgalib_keyboard_eventhandler = default_handler; __svgalib_open_devconsole(); __svgalib_kbd_fd = __svgalib_tty_fd; /* We are initialized. */ if (ioctl(__svgalib_kbd_fd, KDGKBMODE, &oldkbmode)) { printf("svgalib: cannot get keyboard mode.\n"); return -1; } tcgetattr(__svgalib_kbd_fd, &oldkbdtermios); newkbdtermios = oldkbdtermios; newkbdtermios.c_lflag &= ~(ICANON | ECHO | ISIG); newkbdtermios.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON); newkbdtermios.c_cc[VMIN] = 0; /* Making these 0 seems to have the */ newkbdtermios.c_cc[VTIME] = 0; /* desired effect. */ tcsetattr(__svgalib_kbd_fd, TCSAFLUSH, &newkbdtermios); ioctl(__svgalib_kbd_fd, KDSKBMODE, K_MEDIUMRAW); keyboard_clearstate(); __svgalib_read_options(kbd_config_options, kbd_process_option); /* Check SVGALIB_KEYMAP env var */ if ( (ptr = getenv("SVGALIB_KEYMAP")) != 0) { kbd_load_keymap(ptr); } return __svgalib_kbd_fd; /* OK, return fd. */}/* Old compatible init function. */int keyboard_init(void){ if (keyboard_init_return_fd() == -1) return -1; else return 0;}void keyboard_close(void) { if (__svgalib_kbd_fd < 0) return; if (fake_mouse_events) { int i; for (i = 0; i < NR_KEYS; i++) { if (fake_mouse_events[i]) free(fake_mouse_events[i]); } free(fake_mouse_events); fake_mouse_events = NULL; } ioctl(__svgalib_kbd_fd, KDSKBMODE, oldkbmode); tcsetattr(__svgalib_kbd_fd, 0, &oldkbdtermios); __svgalib_kbd_fd = -1;}/* For now, we assume there's no console switching. *//* (Actually, there won't be any unless we catch the console switching *//* keys). */#define KBDREADBUFFERSIZE 32static int keyboard_getevents(int wait){/* Read keyboard device, and handle events. *//* If wait == 1, process at least one event and return. *//* If wait == 0, handle all accumulated events; return 0 if no events *//* were handled, 1 otherwise. *//* Wait mode doesn't seem to work very well; the keyboard repeat delay is *//* present. I don't understand fcntl. */ static unsigned char buf[KBDREADBUFFERSIZE]; static int kfdmode = 0; /* 1 = DELAY, 0 = NDELAY */ int bytesread, i; int eventhandled; eventhandled = 0; again: if (kfdmode == 1) { /* This only happens for wait == 1. */#if 0 struct termios kbdtermios;#endif int flags; /* We don't want to wait, set NDELAY mode. */ fcntl(__svgalib_kbd_fd, F_GETFL, &flags); fcntl(__svgalib_kbd_fd, F_SETFL, flags | O_NDELAY);#if 0 tcgetattr(__svgalib_kbd_fd, &kbdtermios); kbdtermios.c_lflag = kbdtermios.c_lflag & ~(ICANON | ECHO | ISIG); kbdtermios.c_cc[VMIN] = 0; kbdtermios.c_cc[VTIME] = 0; tcsetattr(__svgalib_kbd_fd, TCSANOW, &kbdtermios);#endif kfdmode = 0; } bytesread = read(__svgalib_kbd_fd, buf, KBDREADBUFFERSIZE); if (wait == 1 && bytesread < 1) {#if 0 struct termios kbdtermios;#endif int flags; /* We already handled an event, no need to wait for another. */ if (eventhandled) return 1; /* Wait mode, we'll sleep on reads. */ fcntl(__svgalib_kbd_fd, F_GETFL, &flags); fcntl(__svgalib_kbd_fd, F_SETFL, flags & ~O_NDELAY);#if 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -