// keyboard.c // Author: Josh Holtrop // Created: 04/17/03 // Modified: 08/16/04 #include "hos_defines.h" #include "char/keyboard.h" #include "sys/io.h" // inportb, outportb #include "functions.h" #include "lang/conv.h" // asciiSwitchCase() #include "kout.h" #include "display.h" // display_activate() #define KBD_BUFFER_LENGTH 64 u8_t kbdFlags = 0; // holds current keyboard flags - caps/num/scroll/shift/ctrl/alt u8_t lastWasE0 = 0; // was the last byte 0x0E ? u32_t kbdBuffer[KBD_BUFFER_LENGTH]; // a buffer for all keypresses int kbdBufferStart = 0; // position of next key in buffer int kbdBufferLen = 0; // number of keys left in the buffer u8_t rawIgnore = 0; // how many signals to blatantly ignore u8_t ackReason = 0; // used to record the reason why we would get an acknowledge byte (0xFA) //these arrays convert a keyboard scan code to an ASCII character value const u8_t SCAN2ASCII[129] = // for normal keys "\000\0331234567890-=\010\011" // null,esc,1234567890-=,bksp,tab "qwertyuiop[]\n\000as" // qwertyuiop[],enter,lctrl,as "dfghjkl;'`\000\\zxcv" // dfghjkl;'`,lshift,\zxcv "bnm,./\000*\000 \000\000\000\000\000\000" // bnm,./,rshift,*,alt,space,caps,f1,f2,f3,f4,f5 "\000\000\000\000\000\000\000\000\000\000-\000\000\000+\000" // f6,f7,f8,f9,f10,num,scrl,home,up,pgup,dash,left,center,right,plus,end "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" // down,pgdn,ins,del,?,?,?,f11,f12,?,?,winL,winR,menu,?,? "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" // ? "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; // ? const u8_t SCAN2ASCII2[129] = // for shifted or numlocked keys "\000\033!@#$%^&*()_+\010\011" // null,esc,!@#$%^&*()_+,bksp,tab "QWERTYUIOP{}\n\000AS" // QWERTYUIOP{},enter,lctrl,AS "DFGHJKL:\"~\000|ZXCV" // DFGHJKL:"~,lshift,|ZXCV "BNM<>?\000*\000 \000\000\000\000\000\000" // BNM<>?,rshift,*,alt,space,caps,f1,f2,f3,f4,f5 "\000\000\000\000\000\000\000789-456+1" // f6,f7,f8,f9,f10,num,scrl,789-456+1 "230.\000\000\000\000\000\000\000\000\000\000\000\000" // 230.,?,?,?,f11,f12,?,?,winL,winR,menu,?,? "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" // ? "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; // ? // The Keyboard Interrupt Service Routine void isr_keyboard() { u8_t kbdScan = inportb(0x60); u8_t inState = inportb(0x61); outportb(0x61, inState|0x80); outportb(0x61, inState); if (kbdScan == 0xFA) //250 // ACKnowledge { //printf("KBD_ACK 0x%x!\n", ackReason); switch (ackReason) { case 0xED: // reset LEDs outportb(0x60, (kbdFlags & 0x07)); break; } ackReason = 0; } if (rawIgnore) // ignore keycodes { rawIgnore--; return; } if (lastWasE0 && (kbdScan == 0x2A || kbdScan == 0xAA)) // ignore extended "shift" { lastWasE0 = 0; return; } if (kbdScan == 0xE0) // 0xE0 == extended key { lastWasE0 = 1; return; } if (kbdScan == 0xE1) // 0xE1 == 2nd-set-extended key { rawIgnore = 2; return; } switch (kbdScan) // handle control keys { case KBD_SCAN_LSHIFT: kbdFlags |= KBDF_SHIFT; break; case KBD_SCAN_RSHIFT: kbdFlags |= KBDF_SHIFT; break; case KBD_SCAN_CTRL: kbdFlags |= KBDF_CTRL; break; case KBD_SCAN_ALT: kbdFlags |= KBDF_ALT; break; case KBD_SCAN_LSHIFT + KBD_SCAN_RELEASED: kbdFlags &= (KBDF_SHIFT ^ 0xFF); break; case KBD_SCAN_RSHIFT + KBD_SCAN_RELEASED: kbdFlags &= (KBDF_SHIFT ^ 0xFF); break; case KBD_SCAN_CTRL + KBD_SCAN_RELEASED: kbdFlags &= (KBDF_CTRL ^ 0xFF); break; case KBD_SCAN_ALT + KBD_SCAN_RELEASED: kbdFlags &= (KBDF_ALT ^ 0xFF); break; case KBD_SCAN_CAPS+KBD_SCAN_RELEASED: kbdFlags ^= KBDF_CAPS; kbd_resetLEDs(); // update LEDs break; case KBD_SCAN_SCROLL+KBD_SCAN_RELEASED: kbdFlags ^= KBDF_SCROLL; kbd_resetLEDs(); // update LEDs break; case KBD_SCAN_NUM+KBD_SCAN_RELEASED: kbdFlags ^= KBDF_NUM; kbd_resetLEDs(); // update LEDs break; } u8_t kbdAscii; // shift or (numlock and key from numpad) if ( (kbdFlags & KBDF_SHIFT) || ((kbdFlags & KBDF_NUM) && (kbdScan >= 71) && (kbdScan <= 83)) ) kbdAscii = SCAN2ASCII2[kbdScan & 0x7F]; else // normal key kbdAscii = SCAN2ASCII[kbdScan & 0x7F]; if (kbdFlags & KBDF_CAPS) kbdAscii = asciiSwitchCase(kbdAscii); // won't affect non-letter characters //====do something with key:: // kprintf("kbdScan = \e[31;1m0x%x\e[0m\tkbdAscii = \e[1;32m0x%x\e[0m (\e[35m%c\e[0m)\tkbdFlags = \e[34m0x%x\e[0m\n", kbdScan, kbdAscii, kbdAscii, kbdFlags); if ((kbdScan == 83) && (kbdFlags & KBDF_CTRL) && (kbdFlags & KBDF_ALT)) { kprintf("Initiating reboot."); restart(); } if (kbdScan & KBD_SCAN_RELEASED) kbdAscii = 0; if (kbdBufferLen < KBD_BUFFER_LENGTH) //no key slots available kbdBuffer[(kbdBufferStart+kbdBufferLen++)%KBD_BUFFER_LENGTH] = (u32_t) ((kbdFlags << 16) | (kbdScan << 8) | kbdAscii); if (kbdAscii) kprintf("%c", kbdAscii); // if (kbdFlags & KBDF_ALT) // { if (kbdScan >= 0x3B && kbdScan <= 0x44) display_activate(kbdScan - 0x3B); if (kbdScan >= 0x57 && kbdScan <= 0x58) display_activate(kbdScan - 0x4D); // } } //Gets a key from the buffer, returns 0 if no keys available, returns immediately u32_t kbdGetKey() { if (kbdBufferLen == 0) // buffer empty return 0; u32_t retVal = kbdBuffer[kbdBufferStart]; kbdBufferStart++; kbdBufferLen--; if (kbdBufferStart >= KBD_BUFFER_LENGTH) kbdBufferStart = 0; return retVal; } //Gets a key from the buffer, if no keys available, waits for one to be entered u32_t kbdWaitKey() { for (;;) { if (kbdBufferLen != 0) // buffer empty break; } u32_t retVal = kbdBuffer[kbdBufferStart]; kbdBufferStart++; kbdBufferLen--; if (kbdBufferStart >= KBD_BUFFER_LENGTH) kbdBufferStart = 0; return retVal; } //Resets the keyboard LEDs to reflect the current state of the num lock, caps lock, and scroll lock bits void kbd_resetLEDs() { outportb(0x60, 0xED); ackReason = 0xED; }