hos/kernel/char/keyboard.c

194 lines
5.7 KiB
C

// 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"
#include "functions.h"
#include "lang/conv.h" // asciiSwitchCase()
#include "kout.h"
#include "console.h"
#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 (kbdScan >= 0x3B && kbdScan <= 0x40)
console_activate(kbdScan - 0x3A);
}
//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;
}