📄 kbd.c
字号:
/* nothing */;
/* test controller, expect 0x00 if successful */
DEBUG(printf("\n controller self-test");)
Result=_kbdWriteRead(_KBD_CMD_REG, _KBD_CCMD_TEST2, 1,
(u8 *)"\x00");
if(Result != 0)
{ static const char *Line[2]={ "clock", "data" };
static const char *Stuck[2]={ "low", "high" };
printf(" *** interface test failed, ");
Result--;
if(Result > 3)
printf("cause unknown\n");
else printf("%s line stuck %s\n", Line[Result >> 1],
Stuck[Result & 1]);
BAIL: crite(Flags); /* restore previous interrupt mask */
return(-1); }
/* enable keyboard interface on controller. Controller commands
(_KBD_CCMD_nnn) may return a data byte, but do not return an ACK */
_kbdWrite(_KBD_CMD_REG, _KBD_CCMD_ENABLE);
/* reset keyboard (selects scancode set 2), expect 0xFA and 0xAA */
DEBUG(printf("\n resetting keyboard");)
Result=_kbdWriteRead(_KBD_DATA_REG, _KBD_KCMD_RESET, 2,
(u8 *)"\xFA\xAA");
if(Result != 0)
goto BAIL;
/* test keyboard, expect 0x55 if successful */
DEBUG(printf("\n keyboard self-test");)
Result=_kbdWriteRead(_KBD_CMD_REG, _KBD_CCMD_TEST1, 1,
(u8 *)"\x55");
if(Result != 0)
goto BAIL;
/* disable keyboard before programming it, expect 0xFA (ACK) */
DEBUG(printf("\n disable");)
Result=_kbdWriteRead(_KBD_DATA_REG, _KBD_KCMD_DIS, 1,
(u8 *)"\xFA");
if(Result != 0)
goto BAIL;
/* disable AT-to-XT keystroke conversion, disable PS/2 mouse,
set SYS bit, and Enable Keyboard Interrupt */
_kbdWrite(_KBD_CMD_REG, _KBD_CCMD_WRCMDB);
_kbdWrite(_KBD_DATA_REG, _KBD_CB_INIT); /* DMS, SYS, EKI */
/* program desired scancode set, expect 0xFA (ACK)... */
DEBUG(printf("\n programming scancode set %u", ScanCodeSet);)
Result=_kbdWriteRead(_KBD_DATA_REG, _KBD_KCMD_SCSET, 1,
(u8 *)"\xFA");
if(Result != 0)
goto BAIL;
/* ...send scancode set value, expect 0xFA (ACK) */
Result=_kbdWriteRead(_KBD_DATA_REG, ScanCodeSet, 1,
(u8 *)"\xFA");
if(Result != 0)
goto BAIL;
/* make all keys typematic (auto-repeat) and make-break. This may work
only with scancode set 3, I'm not sure. Expect 0xFA (ACK) */
DEBUG(printf("\n making all keys typematic and make-break");)
Result=_kbdWriteRead(_KBD_DATA_REG, _KBD_KCMD_TMB, 1,
(u8 *)"\xFA");
// -----------------------------
// if(Result != 0) goto BAIL;
/* set typematic delay as short as possible;
repeat as fast as possible, expect ACK... */
DEBUG(printf("\n setting fast typematic mode");)
Result=_kbdWriteRead(_KBD_DATA_REG, _KBD_KCMD_TYPEM, 1,
(u8 *)"\xFA");
// ----------------------------
//if(Result != 0) goto BAIL;
/* ...typematic control byte (0 corresponds to MODE CON RATE=30 DELAY=1),
expect 0xFA (ACK) */
Result=_kbdWriteRead(_KBD_DATA_REG, 0, 1,
(u8 *)"\xFA");
if(Result != 0)
goto BAIL;
/* enable keyboard, expect 0xFA (ACK) */
DEBUG(printf("\n enable");)
Result=_kbdWriteRead(_KBD_DATA_REG, _KBD_KCMD_EN, 1,
(u8 *)"\xFA");
if(Result != 0)
goto BAIL;
printf("\n scancode set 3 driver activated\n");
/* restore previous interrupt mask */
crite(Flags);
return(0); }
/*****************************************************************************
name: irq1
action: IRQ1 (INT 9) interrupt handler (keyboard);
puts scancode in Keystrokes queue (unless it's full)
*****************************************************************************/
static void interrupt _irq1(__CPPARGS)
{ u8 Code;
Code=inportb(_KBD_DATA_REG);
if(inq(&(_Con.Keystrokes), Code) != 0)
/* full queue, beep or something */;
outportb(0x20, 0x20); } /* send EOI to 8259 interrupt controller */
/*****************************************************************************
name: my_getch
action: waits for keypress, converts raw set 3 scancodes to
extended ASCII
returns:extended ASCII value
*****************************************************************************/
int my_getch(console *_Con)
{/* convert raw set 3 scancodes to ASCII, no Shift
A-Z and a-z are in the "wrong" maps (this slightly simplifies the
conversion logic for Ctrl), but we fix that below */
static const u16 Map[]={
/* 00 */0, 0, 0, 0, 0, 0, 0, K_F1,
/* 08 */0x1B, 0, 0, 0, 0, 0x09, '`', K_F2,
/* 11 is left Ctrl; 12 is left Shift; 14 is CapsLock */
/* 10 */0, 0, 0, 0, 0, 'Q', '1', K_F3,
/* 19 is left Alt */
/* 18 */0, 0, 'Z', 'S', 'A', 'W', '2', K_F4,
/* 20 */0, 'C', 'X', 'D', 'E', '4', '3', K_F5,
/* 28 */0, ' ', 'V', 'F', 'T', 'R', '5', K_F6,
/* 30 */0, 'N', 'B', 'H', 'G', 'Y', '6', K_F7,
/* 39 is right Alt */
/* 38 */0, 0, 'M', 'J', 'U', '7', '8', K_F8,
/* 40 */0, ',', 'K', 'I', 'O', '0', '9', K_F9,
/* 48 */0, '.', '/', 'L', ';', 'P', '-', K_F10,
/* 50 */0, 0, '\'', 0, '[', '=', K_F11, K_PRNT,
/* 58 is right Ctrl; 59 is right Shift; 5F is Scroll Lock */
/* 58 */0, 0, 0x0D, ']', '\\', 0, K_F12, 0,
/* 60 */K_DN, K_LFT, K_PAUSE,K_UP, K_DEL, K_END, 0x08, K_INS,
/* 68 */0, K_END, K_RT, K_LFT, K_HOME, K_PGDN, K_HOME, K_PGUP,
/* 76 is Num Lock */
/* 70 */K_INS, K_DEL, K_DN, '5', K_RT, K_UP, 0, '/',
/* 78 */0, 0x0D, K_PGDN, 0, '+', K_PGUP, '*', 0,
/* 80 */0, 0, 0, 0, '-', 0, 0, 0,
/* 88 */0, 0, 0, K_LWIN, K_RWIN, K_MENU, 0, 0 };
/* convert raw set 3 scancodes to ASCII with Shift */
static const u16 ShiftMap[]={
/* 00 */0, 0, 0, 0, 0, 0, 0, K_F1,
/* 08 */0x1B, 0, 0, 0, 0, 0x09, '~', K_F2,
/* 10 */0, 0, 0, 0, 0, 'q', '!', K_F3,
/* 18 */0, 0, 'z', 's', 'a', 'w', '@', K_F4,
/* 20 */0, 'c', 'x', 'd', 'e', '$', '#', K_F5,
/* 28 */0, ' ', 'v', 'f', 't', 'r', '%', K_F6,
/* 30 */0, 'n', 'b', 'h', 'g', 'y', '^', K_F7,
/* 38 */0, 0, 'm', 'j', 'u', '&', '*', K_F8,
/* 40 */0, '<', 'k', 'i', 'o', ')', '(', K_F9,
/* 48 */0, '>', '?', 'l', ':', 'p', '_', K_F10,
/* 50 */0, 0, '"', 0, '{', '+', K_F11, K_PRNT,
/* 58 */0, 0, 0x0D, '}', '|', 0, K_F12, 0,
/* 60 */K_DN, K_LFT, K_PAUSE,K_UP, K_DEL, K_END, 0x08, K_INS,
/* 68 */0, '1', K_RT, '4', '7', K_PGDN, K_HOME, K_PGUP,
/* 70 */'0', '.', '2', '5', '6', '8', 0, '/',
/* 78 */0, 0x0D, '3', 0, '+', '9', '*', 0,
/* 80 */0, 0, 0, 0, '-', 0, 0, 0,
/* 88 */0, 0, 0, K_LWIN, K_RWIN, K_MENU, 0, 0 };
while(1)
{ short Code, RetVal;
bool SawBreakCode;
SawBreakCode=false;
do
/* get scancode
xxx - should yield to OS if no scancode available */
{ do Code=deq(&(_Con->Keystrokes));
while(Code < 0);
/* step 0: raw set 3 scancodes */
if(Code == 0xF0)
SawBreakCode=true;}
while(Code == 0xF0);
if(SawBreakCode)
Code=-Code;
/* step 1: raw scancodes, negated if break code. Good for e.g. video games
Alt pressed = fire weapon, Alt released = cease fire
set "bucky bits" (Alt, Ctrl, and Shift) */
if(Code == RK_LEFT_ALT || Code == RK_RIGHT_ALT)
{ _Con->KbdStatus |= KBD_BUCKY_ALT;
continue; }
if(Code == -RK_LEFT_ALT || Code == -RK_RIGHT_ALT)
{ _Con->KbdStatus &= ~KBD_BUCKY_ALT;
continue; }
if(Code == RK_LEFT_CTRL || Code == RK_RIGHT_CTRL)
{ _Con->KbdStatus |= KBD_BUCKY_CTRL;
continue; }
if(Code == -RK_LEFT_CTRL || Code == -RK_RIGHT_CTRL)
{ _Con->KbdStatus &= ~KBD_BUCKY_CTRL;
continue; }
if(Code == RK_LEFT_SHIFT || Code == RK_RIGHT_SHIFT)
{ _Con->KbdStatus |= KBD_BUCKY_SHIFT;
continue; }
if(Code == -RK_LEFT_SHIFT || Code == -RK_RIGHT_SHIFT)
{ _Con->KbdStatus &= ~KBD_BUCKY_SHIFT;
continue; }
/* not interested in break codes other than Ctrl, Alt, Shift */
if(Code < 0)
continue;
/* Scroll Lock, Num Lock, and Caps Lock set the LEDs */
if(Code == RK_SCROLL_LOCK)
{ _Con->KbdStatus ^= KBD_BUCKY_SCRL;
goto LEDS; }
if(Code == RK_NUM_LOCK)
{ _Con->KbdStatus ^= KBD_BUCKY_NUM;
goto LEDS; }
if(Code == RK_CAPS_LOCK)
{ _Con->KbdStatus ^= KBD_BUCKY_CAPS;
LEDS: _kbdWrite(_KBD_DATA_REG, _KBD_KCMD_LEDS);
/* clever choice of KBD_BUCKY_SCRL, etc. makes this work */
_kbdWrite(_KBD_DATA_REG,
(_Con->KbdStatus >> 10) & 7);
continue; }
/* ignore invalid scan codes */
if(Code >= 0x90)
continue;
RetVal=Map[Code];
/* defective keyboard? more than 104 keys? */
if(RetVal == 0)
continue;
/* merge bucky bits with raw scan code
(no, don't do this, we still need Code)
// Code |= (_Con->KbdStatus & KBD_BUCKY_ANY);
/* step 2: raw scancodes with bucky bits. Good for e.g. user-interface
Alt+BackSpace = undo, Shift+Alt+BackSpace = redo
Using tables for scancode-to-ASCII conversion would be more flexible,
but take more memory. With 5 bucky bits (Ctrl, Shift, Alt, NumLock, and
CapsLock), it would take 32 tables, 144 entries each (one entry for
each scancode), 2 bytes/entry == 9216 bytes.
Alt pressed? there is no ASCII equivalent
just return mapped scancode with bucky bits */
if((_Con->KbdStatus & KBD_BUCKY_ALT) != 0)
RetVal |= (_Con->KbdStatus & KBD_BUCKY_ANY);
/* Ctrl pressed... */
else if((_Con->KbdStatus & KBD_BUCKY_CTRL) != 0)
/* ...Ctrl @A-Z[\]^_ return 0-31 */
{ if(RetVal >= '@' && RetVal <= '_')
RetVal=RetVal - '@';
/* ...anything else: return mapped scancode with bucky bits */
else RetVal |= (_Con->KbdStatus & KBD_BUCKY_ANY); }
/* Shift pressed... */
else if((_Con->KbdStatus & KBD_BUCKY_SHIFT) != 0)
/* ...ASCII: use alternate map to convert Code to RetVal */
{ if(RetVal >= ' ' && RetVal <= '~')
RetVal=ShiftMap[Code];
/* ...non-ASCII: return mapped scancode with bucky bits */
else RetVal |= (_Con->KbdStatus & KBD_BUCKY_ANY); }
/* no Alt, no Ctrl, no Shift: get return value from Map[] unless
1. NumLock is on
2. the key pressed is on the numeric keypad
in which case, return value comes from ShiftMap[] instead. Got that? */
else if(((_Con->KbdStatus & KBD_BUCKY_NUM) != 0)
&& RetVal >= RK_END_1)
RetVal=ShiftMap[Code];
/* somehow, after all this, we got an invalid key... */
if(RetVal == 0)
continue;
/* CapsLock affects only A-Z
could use tolower() and toupper() here if you want to drag in ctype.h
Logic is backwards to get proper A-Z value from Map[] or ShiftMap[] */
if((_Con->KbdStatus & KBD_BUCKY_CAPS) == 0)
{ if(RetVal >= 'a' && RetVal <= 'z')
RetVal=RetVal - 'a' + 'A';
else if(RetVal >= 'A' && RetVal <= 'Z')
RetVal=RetVal - 'A' + 'a'; }
/* ASCII at last... */
return(RetVal); }}
/*****************************************************************************
name: main
*****************************************************************************/
#define BUF_SIZE 512
int main(void)
{ u8 Buffer[BUF_SIZE];
int Result, Temp;
union REGS Regs;
vector Vector9;
/* make sure it's really DOS */
Regs.x.ax=0x1600;
int86(0x2F, &Regs, &Regs);
if(Regs.h.al != 0 && Regs.h.al != 0x80)
{ printf("Detected Windows version ");
if(Regs.h.al == 0x01 || Regs.h.al == 0xFF)
printf("2.x");
else printf("%u.%u\n", Regs.h.al, Regs.h.ah);
printf("This keyboard driver/demo code will not work "
"under Windows\n");
return(-1); }
/* try the scancode set 3 keyboard driver */
if(kbdInit(3) != 0)
return(2);
/* init Con */
_Con.Keystrokes.Data=Buffer;
_Con.Keystrokes.Size=BUF_SIZE;
/* set new IRQ 9 (keyboard) interrupt handler */
SAVE_VECT(9, Vector9);
SET_VECT(9, _irq1);
/* demo */
printf("(Press Esc to quit this demo)\n");
do
{
Temp=my_getch(&_Con);
if(Temp < 0x100)
putchar(Temp);
else
printf("<%04X>", Temp);
printf("key = <%04X>\n", Temp);
fflush(stdout);
}while(Temp != '\x1B');
/* restore original keyboard interrupt vector */
RESTORE_VECT(9, Vector9);
/* go back to scancode set 1 or 2 */
Temp=1;
DEBUG(printf("programming scancode set %u\n", Temp);)
Result=_kbdWriteRead(_KBD_DATA_REG, _KBD_KCMD_SCSET, 1,
(u8 *)"\xFA");
if(Result == 0)
/* ...send scancode set value, expect 0xFA (ACK) */
{ Result=_kbdWriteRead(_KBD_DATA_REG, Temp, 1,
(u8 *)"\xFA"); }
return(0); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -