247 lines
6.7 KiB
C
247 lines
6.7 KiB
C
// keyboard.c
|
|
// Author: Josh Holtrop
|
|
// Created: 04/17/03
|
|
// Modified: 03/02/04
|
|
|
|
#include "hos_defines.h"
|
|
#include "keyboard.h"
|
|
|
|
#define KBD_BUFFER_LENGTH 64
|
|
|
|
byte kbdFlags = 0; //holds current keyboard flags - caps/num/scroll/shift/ctrl/alt
|
|
byte kbdAscii = 0; //holds ASCII value of a key pressed
|
|
byte kbdScan = 0; //holds the keyboard scan code of a key pressed
|
|
|
|
dword 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
|
|
byte kbdExt = 0; //# of extended key codes left to input
|
|
byte kbdExt2 = 0; //# of 2nd-set-extended key codes left to input
|
|
byte 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
|
|
//nul esc bksp tab lctl lsft rsft lalt caps F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 numScrlNumPad------- unknown---- F11 F12 unknown....
|
|
const byte SCAN2ASCII[128] = "\000\0331234567890-=\010\011qwertyuiop[]\n\001asdfghjkl;'`\001\\zxcvbnm,./\001*\001 \001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001-\001\001\001+\001\001\001\001\001\002\002\002\001\001\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002";
|
|
const byte SCAN2ASCIISHIFT[128] = "\000\033!@#$%^&*()_+\010\011QWERTYUIOP{}\n\001ASDFGHJKL:\"~\001|ZXCVBNM<>?\001*\001 \001\001\001\001\001\001\001\001\001\001\001\001\001789-456+1230.\002\002\002\001\001\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002";
|
|
|
|
//====FUNCTIONS:
|
|
// The Keyboard Interrupt Service Routine
|
|
void isr_keyboard()
|
|
{
|
|
kbdScan = inportb(0x60);
|
|
//printf("\nKEYBOARD INTERRUPT: 0x%x", kbdScan);
|
|
byte inState = inportb(0x61);
|
|
outportb(0x61, inState|0x80);
|
|
outportb(0x61, inState);
|
|
|
|
//printf("IRQ 1: %x\n", kbdScan);
|
|
|
|
if (kbdScan == 0xFA) //250 //ACKnowledge
|
|
{
|
|
//printf("KBD_ACK 0x%x!\n", ackReason);
|
|
if (ackReason == 0xED) //reset LEDs
|
|
{
|
|
outportb(0x60, (kbdFlags & 0x07));
|
|
}
|
|
ackReason = 0;
|
|
}
|
|
if (kbdScan == 224) //extended key
|
|
{
|
|
kbdExt = 1;
|
|
eoi();
|
|
return;
|
|
}
|
|
if (kbdScan == 225) //2nd-set-extended key
|
|
{
|
|
kbdExt2 = 2;
|
|
eoi();
|
|
return;
|
|
}
|
|
|
|
//====handle control keys::
|
|
kbdAscii = 2;
|
|
switch (kbdScan) //control keys
|
|
{
|
|
case KBD_SCAN_LSHIFT:
|
|
kbdFlags |= KBD_SHIFT;
|
|
kbdAscii = 1;
|
|
break;
|
|
case KBD_SCAN_RSHIFT:
|
|
kbdFlags |= KBD_SHIFT;
|
|
kbdAscii = 1;
|
|
break;
|
|
case KBD_SCAN_LCTRL:
|
|
kbdFlags |= KBD_CTRL;
|
|
kbdAscii = 1;
|
|
break;
|
|
case KBD_SCAN_LALT:
|
|
kbdFlags |= KBD_ALT;
|
|
kbdAscii = 1;
|
|
break;
|
|
|
|
case KBD_SCAN_LSHIFT + KBD_SCAN_RELEASED:
|
|
kbdFlags &= (KBD_SHIFT ^ 0xFF);
|
|
kbdAscii = 1;
|
|
break;
|
|
case KBD_SCAN_RSHIFT + KBD_SCAN_RELEASED:
|
|
kbdFlags &= (KBD_SHIFT ^ 0xFF);
|
|
kbdAscii = 1;
|
|
break;
|
|
case KBD_SCAN_LCTRL + KBD_SCAN_RELEASED:
|
|
kbdFlags &= (KBD_CTRL ^ 0xFF);
|
|
kbdAscii = 1;
|
|
break;
|
|
case KBD_SCAN_LALT + KBD_SCAN_RELEASED:
|
|
kbdFlags &= (KBD_ALT ^ 0xFF);
|
|
kbdAscii = 1;
|
|
break;
|
|
|
|
case KBD_SCAN_CAPS+KBD_SCAN_RELEASED:
|
|
kbdFlags ^= KBD_CAPS;
|
|
kbdAscii = 1;
|
|
kbd_resetLEDs(); //update LEDs
|
|
break;
|
|
case KBD_SCAN_SCROLL+KBD_SCAN_RELEASED:
|
|
kbdFlags ^= KBD_SCROLL;
|
|
kbdAscii = 1;
|
|
kbd_resetLEDs(); //update LEDs
|
|
break;
|
|
case KBD_SCAN_NUM+KBD_SCAN_RELEASED:
|
|
kbdFlags ^= KBD_NUM;
|
|
kbdAscii = 1;
|
|
kbd_resetLEDs(); //update LEDs
|
|
break;
|
|
}
|
|
if (kbdAscii == 1)
|
|
{
|
|
if (kbdExt > 0)
|
|
kbdExt--;
|
|
eoi();
|
|
return;
|
|
}
|
|
//====determine ASCII value of key::
|
|
if (kbdExt > 0) //extended key, kbdScan holds extended key
|
|
{
|
|
kbdExt--;
|
|
kbdAscii = 1;
|
|
switch (kbdScan)
|
|
{
|
|
case KBD_SCANE_ENTER:
|
|
kbdAscii = '\n'; break;
|
|
case 53: // '/' character (divide on numpad)
|
|
kbdAscii = '/'; break;
|
|
}
|
|
}
|
|
else if (kbdExt2 > 0) //extended key 2
|
|
{
|
|
kbdExt2--;
|
|
// if (kbdScan == 69) // (pause|break)
|
|
// kbdAscii = 2; //flag ascii value of 1 means control character (pausebreak)
|
|
// else
|
|
kbdAscii = 2; //flag ascii value of 2 means ignore key (or unknown value)
|
|
}
|
|
else //not an extended key
|
|
{
|
|
// if letter key
|
|
if (((kbdScan >= 16) && (kbdScan <= 25)) || ((kbdScan >= 30) && (kbdScan <= 38)) || ((kbdScan >= 44) && (kbdScan <= 50)))
|
|
{
|
|
// if caps and shift are different (either one pressed, not both)
|
|
if (((kbdFlags & KBD_SHIFT) != 0) & ((kbdFlags & KBD_CAPS) != 0))
|
|
kbdAscii = SCAN2ASCII[kbdScan & 0x7F];
|
|
else if (((kbdFlags & KBD_SHIFT) == 0) & ((kbdFlags & KBD_CAPS) == 0))
|
|
kbdAscii = SCAN2ASCII[kbdScan & 0x7F];
|
|
else
|
|
kbdAscii = SCAN2ASCIISHIFT[kbdScan & 0x7F];
|
|
}
|
|
// if numpad key
|
|
else if ((kbdScan >= 71) && (kbdScan <= 83))
|
|
{
|
|
// if numlock on
|
|
if (kbdFlags & KBD_NUM)
|
|
kbdAscii = SCAN2ASCIISHIFT[kbdScan & 0x7F];
|
|
else
|
|
kbdAscii = SCAN2ASCII[kbdScan & 0x7F];
|
|
}
|
|
// other key
|
|
else
|
|
{
|
|
if ((kbdFlags & KBD_SHIFT) != 0)
|
|
kbdAscii = SCAN2ASCIISHIFT[kbdScan & 0x7F];
|
|
else
|
|
kbdAscii = SCAN2ASCII[kbdScan & 0x7F];
|
|
}
|
|
}
|
|
|
|
//====do something with key::
|
|
// printf("kbdScan == %d\nkbdAscii == %d\nkbdFlags == %d\n", kbdScan, kbdAscii, kbdFlags);
|
|
if ((kbdScan == 83) && (kbdFlags & KBD_CTRL) && (kbdFlags & KBD_ALT))
|
|
{
|
|
printf("Initiating reboot.");
|
|
restart();
|
|
}
|
|
if (kbdAscii == 2) //unknown key / ignore key
|
|
{
|
|
eoi();
|
|
return;
|
|
}
|
|
if (kbdScan < KBD_SCAN_RELEASED) //a key was pressed, save it
|
|
{
|
|
if (kbdBufferLen >= KBD_BUFFER_LENGTH) //no key slots available
|
|
{
|
|
eoi();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
kbdBuffer[(kbdBufferStart+kbdBufferLen++)%KBD_BUFFER_LENGTH] = (dword) ((kbdFlags << 16) | (kbdScan << 8) | kbdAscii);
|
|
// printf("S:%d\tL:%d\tR:%x\n", kbdBufferStart, kbdBufferLen, kbdBuffer[kbdBufferStart]);
|
|
}
|
|
}
|
|
|
|
eoi();
|
|
|
|
}
|
|
|
|
//Gets a key from the buffer, returns 0 if no keys available, returns immediately
|
|
dword kbdGetKey()
|
|
{
|
|
if (kbdBufferLen == 0) //buffer empty
|
|
return 0;
|
|
dword 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
|
|
dword kbdWaitKey()
|
|
{
|
|
for (;;)
|
|
{
|
|
if (kbdBufferLen != 0) //buffer empty
|
|
break;
|
|
}
|
|
dword 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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|