📄 kbd_ttyscan.c
字号:
/*
* Copyright (c) 2000 Greg Haerr <greg@censoft.com>
*
* Microwindows /dev/tty console scancode keyboard driver for Linux
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <linux/keyboard.h>
#include <linux/kd.h>
#include <linux/vt.h>
#include "device.h"
#include "fb.h"
#define KEYBOARD "/dev/tty" /* console kbd to open*/
static int TTY_Open(KBDDEVICE *pkd);
static void TTY_Close(void);
static void TTY_GetModifierInfo(MWKEYMOD *modifiers, MWKEYMOD *curmodifiers);
static int TTY_Read(MWKEY *kbuf, MWKEYMOD *modifiers, MWSCANCODE *scancode);
KBDDEVICE kbddev = {
TTY_Open,
TTY_Close,
TTY_GetModifierInfo,
TTY_Read,
NULL
};
#define RELEASED 0
#define PRESSED 1
static int fd; /* file descriptor for keyboard */
static struct termios old; /* original terminal modes */
static int old_kbd_mode;
static unsigned char key_state[MWKEY_LAST]; /* FIXME - make sparse array */
static MWKEYMOD key_modstate;
/* kernel unicode tables per shiftstate and scancode*/
#define NUM_VGAKEYMAPS (1<<KG_CAPSSHIFT) /* kernel key maps*/
static unsigned short os_keymap[NUM_VGAKEYMAPS][NR_KEYS];
/* PC scancode -> Microwindows key value mapping for non-Linux kernel values*/
static MWKEY keymap[128] = {
MWKEY_UNKNOWN, MWKEY_ESCAPE, '1', '2', '3', /* 0*/
'4', '5', '6', '7', '8', /* 5*/
'9', '0', '-', '=', MWKEY_BACKSPACE, /* 10*/
MWKEY_TAB, 'q', 'w', 'e', 'r', /* 15*/
't', 'y', 'u', 'i', 'o', /* 20*/
'o', '[', ']', MWKEY_ENTER, MWKEY_LCTRL, /* 25*/
'a', 's', 'd', 'f', 'g', /* 30*/
'h', 'j', 'k', 'l', ';', /* 35*/
'\'', '`', MWKEY_LSHIFT, '\\', 'z', /* 40*/
'x', 'c', 'v', 'b', 'n', /* 45*/
'm', ',', '.', '/', MWKEY_RSHIFT, /* 50*/
MWKEY_KP_MULTIPLY, MWKEY_LALT, ' ', MWKEY_CAPSLOCK, MWKEY_F1, /* 55*/
MWKEY_F2, MWKEY_F3, MWKEY_F4, MWKEY_F5, MWKEY_F6, /* 60*/
MWKEY_F7, MWKEY_F8, MWKEY_F9, MWKEY_F10, MWKEY_NUMLOCK, /* 65*/
MWKEY_SCROLLOCK, MWKEY_KP7, MWKEY_KP8, MWKEY_KP9, MWKEY_KP_MINUS, /* 70*/
MWKEY_KP4, MWKEY_KP5, MWKEY_KP6, MWKEY_KP_PLUS, MWKEY_KP1, /* 75*/
MWKEY_KP2, MWKEY_KP3, MWKEY_KP0, MWKEY_KP_PERIOD, MWKEY_UNKNOWN, /* 80*/
MWKEY_UNKNOWN, MWKEY_UNKNOWN, MWKEY_F11, MWKEY_F12, MWKEY_UNKNOWN, /* 85*/
MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_UNKNOWN, /* 90*/
MWKEY_UNKNOWN, MWKEY_KP_ENTER, MWKEY_RCTRL, MWKEY_KP_DIVIDE,MWKEY_PRINT,/* 95*/
MWKEY_RALT, MWKEY_BREAK, MWKEY_HOME, MWKEY_UP, MWKEY_PAGEUP, /* 100*/
MWKEY_LEFT, MWKEY_RIGHT, MWKEY_END, MWKEY_DOWN, MWKEY_PAGEDOWN, /* 105*/
MWKEY_INSERT, MWKEY_DELETE, MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_UNKNOWN, /* 110*/
MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_PAUSE, /* 115*/
MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_UNKNOWN, /* 120*/
MWKEY_LMETA, MWKEY_RMETA, MWKEY_MENU /* 125*/
};
static MWBOOL UpdateKeyState(int pressed, MWKEY mwkey);
static void UpdateLEDState(MWKEYMOD modstate);
static MWKEY TranslateScancode(int scancode, MWKEYMOD modstate);
static void LoadKernelKeymaps(int fd);
static MWBOOL switch_vt(unsigned short which);
/*
* Open the keyboard.
* This is real simple, we just use a special file handle
* that allows non-blocking I/O, and put the terminal into
* character mode.
*/
static int
TTY_Open(KBDDEVICE *pkd)
{
char *env;
int i;
int ledstate = 0;
struct termios new;
/* Open "CONSOLE" or /dev/tty device*/
if(!(env = getenv("CONSOLE")))
fd = open(KEYBOARD, O_NONBLOCK);
else
fd = open(env, O_NONBLOCK);
if (fd < 0)
return -1;
/* Save previous settings*/
if (ioctl(fd, KDGKBMODE, &old_kbd_mode) < 0) {
perror("KDGKMODE");
goto err;
}
if (tcgetattr(fd, &old) < 0)
goto err;
/* Set medium-raw keyboard mode */
new = old;
/* ISIG and BRKINT must be set otherwise '2' is ^C (scancode 3)!!*/
new.c_lflag &= ~(ICANON | ECHO | ISIG);
new.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON
| BRKINT);
new.c_cc[VMIN] = 0;
new.c_cc[VTIME] = 0;
if (tcsetattr(fd, TCSAFLUSH, &new) < 0) {
TTY_Close();
return -1;
}
if (ioctl(fd, KDSKBMODE, K_MEDIUMRAW) < 0) {
TTY_Close();
return -1;
}
/* Load OS keymappings*/
LoadKernelKeymaps(fd);
/* Initialize keyboard state*/
key_modstate = MWKMOD_NONE;
for (i=0; i<MWKEY_LAST; ++i)
key_state[i] = RELEASED;
/* preset CAPSLOCK and NUMLOCK from startup LED state*/
if (ioctl(fd, KDGETLED, &ledstate) == 0) {
if (ledstate & LED_CAP) {
key_modstate |= MWKMOD_CAPS;
key_state[MWKEY_CAPSLOCK] = PRESSED;
}
if (ledstate & LED_NUM) {
key_modstate |= MWKMOD_NUM;
key_state[MWKEY_NUMLOCK] = PRESSED;
}
}
UpdateLEDState(key_modstate);
return fd;
err:
close(fd);
fd = -1;
return -1;
}
/*
* Close the keyboard.
* This resets the terminal modes.
*/
static void
TTY_Close(void)
{
int ledstate = 0x80000000L;
if (fd >= 0) {
/* revert LEDs to follow key modifiers*/
if (ioctl(fd, KDSETLED, ledstate) < 0)
perror("KDSETLED");
/* reset terminal mode*/
if (ioctl(fd, KDSKBMODE, old_kbd_mode) < 0)
perror("KDSKBMODE");
tcsetattr(fd, TCSAFLUSH, &old);
close(fd);
}
fd = -1;
}
/*
* Return the possible modifiers and current modifiers for the keyboard.
*/
static void
TTY_GetModifierInfo(MWKEYMOD *modifiers, MWKEYMOD *curmodifiers)
{
if (modifiers)
*modifiers = MWKMOD_CTRL | MWKMOD_SHIFT | MWKMOD_ALT |
MWKMOD_META | MWKMOD_ALTGR | MWKMOD_CAPS | MWKMOD_NUM;
if (curmodifiers)
*curmodifiers = key_modstate;
}
/*
* This reads one keystroke from the keyboard, and the current state of
* the modifier keys (ALT, SHIFT, etc). Returns -1 on error, 0 if no data
* is ready, 1 on a keypress, and 2 on keyrelease.
* This is a non-blocking call.
*/
static int
TTY_Read(MWKEY *kbuf, MWKEYMOD *modifiers, MWSCANCODE *pscancode)
{
int cc; /* characters read */
int pressed;
int scancode;
MWKEY mwkey;
unsigned char buf[128];
cc = read(fd, buf, 1);
if (cc > 0) {
pressed = (*buf & 0x80) ? RELEASED: PRESSED;
scancode = *buf & 0x7f;
mwkey = keymap[scancode];
/**if(pressed) {
printf("scan %02x really: %08x\n", *buf&0x7F, *buf);
printf("mwkey: %02x (%c)\n", mwkey, mwkey);
}**/
/* Handle Alt-FN for vt switch */
switch (mwkey) {
case MWKEY_F1:
case MWKEY_F2:
case MWKEY_F3:
case MWKEY_F4:
case MWKEY_F5:
case MWKEY_F6:
case MWKEY_F7:
case MWKEY_F8:
case MWKEY_F9:
case MWKEY_F10:
case MWKEY_F11:
case MWKEY_F12:
if (key_modstate & MWKMOD_ALT) {
if (switch_vt(mwkey-MWKEY_F1+1)) {
mwkey = MWKEY_REDRAW;
}
}
break;
/* Fall through to normal processing */
default:
/* update internal key states*/
if (!UpdateKeyState(pressed, mwkey))
return 0;
/* mwkey is 0 if only a modifier is hit */
if(mwkey != MWKEY_LCTRL &&
mwkey != MWKEY_RCTRL &&
mwkey != MWKEY_LALT &&
mwkey != MWKEY_RALT &&
mwkey != MWKEY_RSHIFT &&
mwkey != MWKEY_LSHIFT) {
/* translate scancode to key value*/
mwkey = TranslateScancode(scancode, key_modstate);
} else {
//printf("Modifier only\n");
//mwkey = 0;
}
/* XXX Hack to get scancodes to come out the same as
everything else */
switch(scancode) {
case 0x1: /* esc */
case 0x29: /* ` */
case 0x2 ... 0xe: /* 1 - BackSpace */
case 0xf ... 0x1b: /* TAB - ] */
case 0x2b: /* \ */
case 0x3a: /* Caps-Lock */
case 0x1e ... 0x28: /* a - ' */
case 0x1c: /* Enter */
case 0x2a: /* LShift */
case 0x2c ... 0x35: /* z - / */
case 0x36: /* RShift */
case 0x1d: /* LCtrl */
//case 0x7d: /* LWin */
case 0x38: /* LAlt */
case 0x39: /* Space */
//case 0x64: /* RAlt */
//case 0x7e: /* RWin */
//case 0x7f: /* Win-PopupMenu */
//case 0x61: /* RCtrl */
//case 0x63: /* SysReq */
//case 0x46: /* Scroll Lock */
//case 0x77: /* Pause/Break */
scancode += 8;
break;
case 0x6e: /* Insert */
scancode -= 0x4;
break;
case 0x66: /* Home */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -