📄 sdl_fbevents.c
字号:
/* SDL - Simple DirectMedia Layer Copyright (C) 1997-2006 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Sam Lantinga slouken@libsdl.org*/#include "SDL_config.h"/* Handle the event stream, converting console events into SDL events */#include <stdio.h>#include <sys/types.h>#include <sys/time.h>#include <sys/ioctl.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <limits.h>/* For parsing /proc */#include <dirent.h>#include <ctype.h>#include <linux/vt.h>#include <linux/kd.h>#include <linux/keyboard.h>#include "SDL_timer.h"#include "SDL_mutex.h"#include "../SDL_sysvideo.h"#include "../../events/SDL_sysevents.h"#include "../../events/SDL_events_c.h"#include "SDL_fbvideo.h"#include "SDL_fbevents_c.h"#include "SDL_fbkeys.h"#include "SDL_fbelo.h"#ifndef GPM_NODE_FIFO#define GPM_NODE_FIFO "/dev/gpmdata"#endif/*#define DEBUG_KEYBOARD*//*#define DEBUG_MOUSE*//* The translation tables from a console scancode to a SDL keysym */#define NUM_VGAKEYMAPS (1<<KG_CAPSSHIFT)static Uint16 vga_keymap[NUM_VGAKEYMAPS][NR_KEYS];static SDLKey keymap[128];static Uint16 keymap_temp[128]; /* only used at startup */static SDL_keysym *TranslateKey(int scancode, SDL_keysym *keysym);/* Ugh, we have to duplicate the kernel's keysym mapping code... Oh, it's not so bad. :-) FIXME: Add keyboard LED handling code */static void FB_vgainitkeymaps(int fd){ struct kbentry entry; int map, i; /* Don't do anything if we are passed a closed keyboard */ if ( fd < 0 ) { return; } /* Load all the keysym mappings */ for ( map=0; map<NUM_VGAKEYMAPS; ++map ) { SDL_memset(vga_keymap[map], 0, NR_KEYS*sizeof(Uint16)); for ( i=0; i<NR_KEYS; ++i ) { entry.kb_table = map; entry.kb_index = i; if ( ioctl(fd, KDGKBENT, &entry) == 0 ) { /* fill keytemp. This replaces SDL_fbkeys.h */ if ( (map == 0) && (i<128) ) { keymap_temp[i] = entry.kb_value; } /* The "Enter" key is a special case */ if ( entry.kb_value == K_ENTER ) { entry.kb_value = K(KT_ASCII,13); } /* Handle numpad specially as well */ if ( KTYP(entry.kb_value) == KT_PAD ) { switch ( entry.kb_value ) { case K_P0: case K_P1: case K_P2: case K_P3: case K_P4: case K_P5: case K_P6: case K_P7: case K_P8: case K_P9: vga_keymap[map][i]=entry.kb_value; vga_keymap[map][i]+= '0'; break; case K_PPLUS: vga_keymap[map][i]=K(KT_ASCII,'+'); break; case K_PMINUS: vga_keymap[map][i]=K(KT_ASCII,'-'); break; case K_PSTAR: vga_keymap[map][i]=K(KT_ASCII,'*'); break; case K_PSLASH: vga_keymap[map][i]=K(KT_ASCII,'/'); break; case K_PENTER: vga_keymap[map][i]=K(KT_ASCII,'\r'); break; case K_PCOMMA: vga_keymap[map][i]=K(KT_ASCII,','); break; case K_PDOT: vga_keymap[map][i]=K(KT_ASCII,'.'); break; default: break; } } /* Do the normal key translation */ if ( (KTYP(entry.kb_value) == KT_LATIN) || (KTYP(entry.kb_value) == KT_ASCII) || (KTYP(entry.kb_value) == KT_LETTER) ) { vga_keymap[map][i] = entry.kb_value; } } } }}int FB_InGraphicsMode(_THIS){ return((keyboard_fd >= 0) && (saved_kbd_mode >= 0));}int FB_EnterGraphicsMode(_THIS){ struct termios keyboard_termios; /* Set medium-raw keyboard mode */ if ( (keyboard_fd >= 0) && !FB_InGraphicsMode(this) ) { /* Switch to the correct virtual terminal */ if ( current_vt > 0 ) { struct vt_stat vtstate; if ( ioctl(keyboard_fd, VT_GETSTATE, &vtstate) == 0 ) { saved_vt = vtstate.v_active; } if ( ioctl(keyboard_fd, VT_ACTIVATE, current_vt) == 0 ) { ioctl(keyboard_fd, VT_WAITACTIVE, current_vt); } } /* Set the terminal input mode */ if ( tcgetattr(keyboard_fd, &saved_kbd_termios) < 0 ) { SDL_SetError("Unable to get terminal attributes"); if ( keyboard_fd > 0 ) { close(keyboard_fd); } keyboard_fd = -1; return(-1); } if ( ioctl(keyboard_fd, KDGKBMODE, &saved_kbd_mode) < 0 ) { SDL_SetError("Unable to get current keyboard mode"); if ( keyboard_fd > 0 ) { close(keyboard_fd); } keyboard_fd = -1; return(-1); } keyboard_termios = saved_kbd_termios; keyboard_termios.c_lflag &= ~(ICANON | ECHO | ISIG); keyboard_termios.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON); keyboard_termios.c_cc[VMIN] = 0; keyboard_termios.c_cc[VTIME] = 0; if (tcsetattr(keyboard_fd, TCSAFLUSH, &keyboard_termios) < 0) { FB_CloseKeyboard(this); SDL_SetError("Unable to set terminal attributes"); return(-1); } /* This will fail if we aren't root or this isn't our tty */ if ( ioctl(keyboard_fd, KDSKBMODE, K_MEDIUMRAW) < 0 ) { FB_CloseKeyboard(this); SDL_SetError("Unable to set keyboard in raw mode"); return(-1); } if ( ioctl(keyboard_fd, KDSETMODE, KD_GRAPHICS) < 0 ) { FB_CloseKeyboard(this); SDL_SetError("Unable to set keyboard in graphics mode"); return(-1); } /* Prevent switching the virtual terminal */ ioctl(keyboard_fd, VT_LOCKSWITCH, 1); } return(keyboard_fd);}void FB_LeaveGraphicsMode(_THIS){ if ( FB_InGraphicsMode(this) ) { ioctl(keyboard_fd, KDSETMODE, KD_TEXT); ioctl(keyboard_fd, KDSKBMODE, saved_kbd_mode); tcsetattr(keyboard_fd, TCSAFLUSH, &saved_kbd_termios); saved_kbd_mode = -1; /* Head back over to the original virtual terminal */ ioctl(keyboard_fd, VT_UNLOCKSWITCH, 1); if ( saved_vt > 0 ) { ioctl(keyboard_fd, VT_ACTIVATE, saved_vt); } }}void FB_CloseKeyboard(_THIS){ if ( keyboard_fd >= 0 ) { FB_LeaveGraphicsMode(this); if ( keyboard_fd > 0 ) { close(keyboard_fd); } } keyboard_fd = -1;}int FB_OpenKeyboard(_THIS){ /* Open only if not already opened */ if ( keyboard_fd < 0 ) { static const char * const tty0[] = { "/dev/tty0", "/dev/vc/0", NULL }; static const char * const vcs[] = { "/dev/vc/%d", "/dev/tty%d", NULL }; int i, tty0_fd; /* Try to query for a free virtual terminal */ tty0_fd = -1; for ( i=0; tty0[i] && (tty0_fd < 0); ++i ) { tty0_fd = open(tty0[i], O_WRONLY, 0); } if ( tty0_fd < 0 ) { tty0_fd = dup(0); /* Maybe stdin is a VT? */ } ioctl(tty0_fd, VT_OPENQRY, ¤t_vt); close(tty0_fd); if ( (geteuid() == 0) && (current_vt > 0) ) { for ( i=0; vcs[i] && (keyboard_fd < 0); ++i ) { char vtpath[12]; SDL_snprintf(vtpath, SDL_arraysize(vtpath), vcs[i], current_vt); keyboard_fd = open(vtpath, O_RDWR, 0);#ifdef DEBUG_KEYBOARD fprintf(stderr, "vtpath = %s, fd = %d\n", vtpath, keyboard_fd);#endif /* DEBUG_KEYBOARD */ /* This needs to be our controlling tty so that the kernel ioctl() calls work */ if ( keyboard_fd >= 0 ) { tty0_fd = open("/dev/tty", O_RDWR, 0); if ( tty0_fd >= 0 ) { ioctl(tty0_fd, TIOCNOTTY, 0); close(tty0_fd); } } } } if ( keyboard_fd < 0 ) { /* Last resort, maybe our tty is a usable VT */ struct vt_stat vtstate; keyboard_fd = open("/dev/tty", O_RDWR); if ( ioctl(keyboard_fd, VT_GETSTATE, &vtstate) == 0 ) { current_vt = vtstate.v_active; } else { current_vt = 0; } }#ifdef DEBUG_KEYBOARD fprintf(stderr, "Current VT: %d\n", current_vt);#endif saved_kbd_mode = -1; /* Make sure that our input is a console terminal */ { int dummy; if ( ioctl(keyboard_fd, KDGKBMODE, &dummy) < 0 ) { close(keyboard_fd); keyboard_fd = -1; SDL_SetError("Unable to open a console terminal"); } } /* Set up keymap */ FB_vgainitkeymaps(keyboard_fd); } return(keyboard_fd);}static enum { MOUSE_NONE = -1, MOUSE_MSC, /* Note: GPM uses the MSC protocol */ MOUSE_PS2, MOUSE_IMPS2, MOUSE_MS, MOUSE_BM, MOUSE_ELO, MOUSE_TSLIB, NUM_MOUSE_DRVS} mouse_drv = MOUSE_NONE;void FB_CloseMouse(_THIS){#if SDL_INPUT_TSLIB if (ts_dev != NULL) { ts_close(ts_dev); ts_dev = NULL; mouse_fd = -1; }#endif /* SDL_INPUT_TSLIB */ if ( mouse_fd > 0 ) { close(mouse_fd); } mouse_fd = -1;}/* Returns processes listed in /proc with the desired name */static int find_pid(DIR *proc, const char *wanted_name){ struct dirent *entry; int pid; /* First scan proc for the gpm process */ pid = 0; while ( (pid == 0) && ((entry=readdir(proc)) != NULL) ) { if ( isdigit(entry->d_name[0]) ) { FILE *status; char path[PATH_MAX]; char name[PATH_MAX]; SDL_snprintf(path, SDL_arraysize(path), "/proc/%s/status", entry->d_name); status=fopen(path, "r"); if ( status ) { name[0] = '\0'; fscanf(status, "Name: %s", name); if ( SDL_strcmp(name, wanted_name) == 0 ) { pid = SDL_atoi(entry->d_name); } fclose(status); } } } return pid;}/* Returns true if /dev/gpmdata is being written to by gpm */static int gpm_available(char *proto, size_t protolen){ int available; DIR *proc; int pid; int cmdline, len, arglen; char path[PATH_MAX]; char args[PATH_MAX], *arg; /* Don't bother looking if the fifo isn't there */#ifdef DEBUG_MOUSE fprintf(stderr,"testing gpm\n");#endif if ( access(GPM_NODE_FIFO, F_OK) < 0 ) { return(0); } available = 0; proc = opendir("/proc"); if ( proc ) { char raw_proto[10] = { '\0' }; char repeat_proto[10] = { '\0' }; while ( !available && (pid=find_pid(proc, "gpm")) > 0 ) { SDL_snprintf(path, SDL_arraysize(path), "/proc/%d/cmdline", pid); cmdline = open(path, O_RDONLY, 0); if ( cmdline >= 0 ) { len = read(cmdline, args, sizeof(args)); arg = args; while ( len > 0 ) { arglen = SDL_strlen(arg)+1;#ifdef DEBUG_MOUSE fprintf(stderr,"gpm arg %s len %d\n",arg,arglen);#endif if ( SDL_strcmp(arg, "-t") == 0) { /* protocol string, keep it for later */ char *t, *s; t = arg + arglen; s = SDL_strchr(t, ' '); if (s) *s = 0; SDL_strlcpy(raw_proto, t, SDL_arraysize(raw_proto)); if (s) *s = ' '; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -