ZealOS/src/Kernel/SerialDev/Keyboard.ZC

569 lines
13 KiB
HolyC
Executable File

asm {
NORMAL_KEY_SCAN_DECODE_TABLE::
DU8 0, CH_ESC, "1234567890-=", CH_BACKSPACE, '\t';
DU8 "qwertyuiop[]", '\n', 0, "as";
DU8 "dfghjkl;'\`", 0, "\\zxcv";
DU8 "bnm,./", 0, '*', 0, CH_SPACE, 0, 0, 0, 0, 0, 0;
DU8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0, 0, '+', 0;
SHIFT_KEY_SCAN_DECODE_TABLE::
DU8 0, CH_SHIFT_ESC, "!@#$$%^&*()_+", CH_BACKSPACE, '\t';
DU8 "QWERTYUIOP{}", '\n', 0, "AS";
DU8 "DFGHJKL:\"~", 0, "|ZXCV";
DU8 "BNM<>?", 0, '*', 0, CH_SPACE, 0, 0, 0, 0, 0, 0;
DU8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0, 0, '+', 0;
CTRL_KEY_SCAN_DECODE_TABLE::
DU8 0, CH_ESC, "1234567890-=", CH_BACKSPACE, '\t';
DU8 CH_CTRLQ, CH_CTRLW, CH_CTRLE, CH_CTRLR, CH_CTRLT, CH_CTRLY, CH_CTRLU, CH_CTRLI, CH_CTRLO,
CH_CTRLP, "[]", '\n', 0, CH_CTRLA, CH_CTRLS;
DU8 CH_CTRLD, CH_CTRLF, CH_CTRLG, CH_CTRLH, CH_CTRLJ, CH_CTRLK, CH_CTRLL,
";'\`", 0, "\\", CH_CTRLZ, CH_CTRLX, CH_CTRLC, CH_CTRLV;
DU8 CH_CTRLB, CH_CTRLN, CH_CTRLM, ",./", 0, '*', 0, CH_SPACE, 0, 0, 0, 0, 0, 0;
DU8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0, 0, '+', 0;
}
U0 KbdCmdSend(I64 port, U8 val)
{
F64 timeout = tS + 0.125;
while (tS < timeout)
{
if (!(InU8(KBD_CTRL) & 2))
{
OutU8(port, val);
return;
}
}
throw;
}
I64 KbdCmdRead()
{
F64 timeout = tS + 0.125;
while (tS < timeout)
if (InU8(KBD_CTRL) & 1)
return InU8(KBD_PORT);
throw;
}
U0 KbdCmdFlush()
{
F64 timeout = tS + 0.03;
while (tS < timeout)
InU8(KBD_PORT);
}
U0 KbdLEDsSet(I64 sc)
{
U8 v = 0;
BEqual(&v, 0, Bt(&sc, SCf_SCROLL));
BEqual(&v, 1, Bt(&sc, SCf_NUM));
BEqual(&v, 2, Bt(&sc, SCf_CAPS));
try
{
KbdCmdSend(KBD_PORT, 0xED);
KbdCmdSend(KBD_PORT, v);
}
catch
Fs->catch_except = TRUE;
}
U0 KbdMouseCmdAck(...)
{
I64 i, ack, timeout;
for (i = 0; i < argc; i++)
{
timeout = 5;
do
{
ack = 0;
try
{
KbdCmdSend(KBD_CTRL, 0xD4);
KbdCmdSend(KBD_PORT, argv[i]);
ack = KbdCmdRead;
}
catch
{
KbdCmdFlush;
Fs->catch_except = TRUE;
}
}
while (ack != 0xFA && --timeout);
if (!timeout)
throw;
}
}
U0 KbdTypeMatic(U8 delay)
{//Set speed of repeated keys.
try
{
KbdCmdSend(KBD_CTRL, 0xA7); //Disable Mouse
KbdCmdSend(KBD_CTRL, 0xAE); //Enable Keyboard
KbdCmdSend(KBD_PORT, 0xF3);
KbdCmdSend(KBD_PORT, delay);//Typematic rate
KbdCmdSend(KBD_CTRL, 0xA8); //Enable Mouse
}
catch
{
KbdCmdFlush;
Fs->catch_except = TRUE;
}
}
I64 Char2ScanCode(I64 ch, I64 sc_flags=0)
{//ASCII value to scan code (Slow).
I64 i;
U8 *table;
if (sc_flags)
{
table = NORMAL_KEY_SCAN_DECODE_TABLE;
if (sc_flags & SCF_CTRL || ch < 26)
table = CTRL_KEY_SCAN_DECODE_TABLE;
else if (sc_flags & SCF_SHIFT || 'A' <= ch <= 'Z')
{
if (!(sc_flags & SCF_CAPS))
table = SHIFT_KEY_SCAN_DECODE_TABLE;
}
else
{
if (sc_flags & SCF_CAPS)
table = SHIFT_KEY_SCAN_DECODE_TABLE;
}
for (i = 0; i < 0x50; i++)
if (table[i] == ch)
return i | sc_flags;
return sc_flags;
}
else
{
table = NORMAL_KEY_SCAN_DECODE_TABLE;
for (i = 0; i < 0x50; i++)
if (table[i] == ch)
return i;
table = SHIFT_KEY_SCAN_DECODE_TABLE;
for (i = 0; i < 0x50; i++)
if (table[i] == ch)
return i | SCF_SHIFT;
table = CTRL_KEY_SCAN_DECODE_TABLE;
for (i = 0; i < 0x50; i++)
if (table[i] == ch)
return i | SCF_CTRL;
return 0;
}
}
U8 ScanCode2Char(I64 sc)
{//Scan code to ASCII value.
U8 *table = NORMAL_KEY_SCAN_DECODE_TABLE;
if (sc & SCF_E0_PREFIX)
return 0;
if (sc & SCF_CTRL)
table = CTRL_KEY_SCAN_DECODE_TABLE;
else if (sc & SCF_SHIFT)
{
if (!(sc & SCF_CAPS))
table = SHIFT_KEY_SCAN_DECODE_TABLE;
}
else
{
if (sc & SCF_CAPS)
table = SHIFT_KEY_SCAN_DECODE_TABLE;
}
sc &= 0x7F;
if (sc >= 0x50)
return 0;
else
return table[sc];
}
U8 scan_code_map[0x100] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, SC_SHIFT, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, SC_ENTER, SC_CTRL, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0x35, 0, 0, SC_ALT, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, SC_HOME, SC_CURSOR_UP, SC_PAGE_UP, 0, SC_CURSOR_LEFT, 0, SC_CURSOR_RIGHT, 0, SC_END,
SC_CURSOR_DOWN, SC_PAGE_DOWN, SC_INS, SC_DELETE, 0, 0, 0, 0, 0, 0, 0, 0, SC_GUI, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
U8 num_lock_map[0x100] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, SC_SHIFT, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 0, 5, 6, 7, 0, 2,
3, 4, 11, 0x34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, SC_ENTER, SC_CTRL, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0x35, 0, 0, SC_ALT, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, SC_HOME, SC_CURSOR_UP, SC_PAGE_UP, 0, SC_CURSOR_LEFT, 0, SC_CURSOR_RIGHT, 0, SC_END,
SC_CURSOR_DOWN, SC_PAGE_DOWN, SC_INS, SC_DELETE, 0, 0, 0, 0, 0, 0, 0, 0, SC_GUI, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
U8 *Char2KeyName(I64 ch, Bool include_ctrl=TRUE)
{//ASCII value to key name.
I64 i;
U8 buf[STR_LEN];
if (ch <= CH_SPACE)
{
switch [ch]
{
case '\n':
StrCopy(buf, "ENTER");
break;
case CH_BACKSPACE:
StrCopy(buf, "BACKSPACE");
break;
case '\t':
StrCopy(buf, "TAB");
break;
case CH_ESC:
StrCopy(buf, "ESC");
break;
case CH_SHIFT_ESC:
StrCopy(buf, "SHIFT_ESC");
break;
case 0: //nobound switch
case 29:
case 30:
*buf = 0;
break;
case CH_SPACE:
StrCopy(buf, "SPACE");
break;
default:
if (include_ctrl)
StrCopy(buf, "CTRL ");
buf[i = StrLen(buf)] = ch - 1 + 'a';
buf[i + 1] = 0;
break;
}
}
else if (Bt(char_bmp_printable, ch))
{
*buf = ch;
buf[1] = 0;
}
else
*buf = 0;
return StrNew(buf);
}
U8 *ScanCode2KeyName(I64 sc)
{//Scan code to key name.
I64 ch;
U8 buf[STR_LEN], *st;
*buf = 0;
if (sc & SCF_CTRL)
CatPrint(buf, "CTRL ");
if (sc & SCF_ALT)
CatPrint(buf, "ALT ");
if (sc & SCF_SHIFT)
CatPrint(buf, "SHIFT ");
if (sc & SCF_NO_SHIFT)
CatPrint(buf, " ");
if (ch = ScanCode2Char(sc & 255))
{
st = Char2KeyName(ch, FALSE);
StrCopy(buf + StrLen(buf), st);
Free(st);
}
else
{
switch (sc & 255)
{
case SC_BACKSPACE: CatPrint(buf, "BACK"); break;
case SC_CAPS: CatPrint(buf, "CAPS"); break;
case SC_NUM: CatPrint(buf, "NUM"); break;
case SC_SCROLL: CatPrint(buf, "SCROLL"); break;
case SC_CURSOR_UP: CatPrint(buf, "UP"); break;
case SC_CURSOR_DOWN: CatPrint(buf, "DOWN"); break;
case SC_CURSOR_LEFT: CatPrint(buf, "LEFT"); break;
case SC_CURSOR_RIGHT: CatPrint(buf, "RIGHT"); break;
case SC_PAGE_UP: CatPrint(buf, "PAGE_UP"); break;
case SC_PAGE_DOWN: CatPrint(buf, "PAGE_DOWN"); break;
case SC_HOME: CatPrint(buf, "HOME"); break;
case SC_END: CatPrint(buf, "END"); break;
case SC_INS: CatPrint(buf, "INS"); break;
case SC_DELETE: CatPrint(buf, "DELETE"); break;
case SC_F1: CatPrint(buf, "F1"); break;
case SC_F2: CatPrint(buf, "F2"); break;
case SC_F3: CatPrint(buf, "F3"); break;
case SC_F4: CatPrint(buf, "F4"); break;
case SC_F5: CatPrint(buf, "F5"); break;
case SC_F6: CatPrint(buf, "F6"); break;
case SC_F7: CatPrint(buf, "F7"); break;
case SC_F8: CatPrint(buf, "F8"); break;
case SC_F9: CatPrint(buf, "F9"); break;
case SC_F10: CatPrint(buf, "F10"); break;
case SC_F11: CatPrint(buf, "F11"); break;
case SC_F12: CatPrint(buf, "F12"); break;
case SC_GUI: CatPrint(buf, "WINDOWS"); break;
case SC_PRINTSCREEN1: CatPrint(buf, "PRINTSCREEN1"); break;
case SC_PRINTSCREEN2: CatPrint(buf, "PRINTSCREEN2"); break;
}
}
return StrNew(buf);
}
U0 KbdBuildSC(U8 raw_byte, Bool in_irq, U8 *_last_raw_byte, I64 *_last_sc)
{
I64 ch, sc_flags, sc, sc2, sc_raw, new_key_f;
Bool set_LEDs = FALSE;
if (raw_byte == 0xE0)
{
*_last_sc &= ~0x1FF;
*_last_raw_byte = raw_byte;
return;
}
sc = raw_byte;
BEqual(&sc, SCf_E0_PREFIX, *_last_raw_byte == 0xE0);
BEqual(&sc, SCf_KEY_UP, raw_byte & 0x80);
*_last_raw_byte = raw_byte;
sc_flags = _last_sc->u32[0] & ~0x1FF;
sc_raw = sc;
if (sc_flags & SCF_NUM)
{
if (sc2 = num_lock_map[sc.u8[0]])
sc.u8[0] = sc2;
}
else
{
if (sc2 = scan_code_map[sc.u8[0]])
sc.u8[0] = sc2;
}
new_key_f = SCF_NEW_KEY;
if (sc & SCF_KEY_UP)
switch (sc & ~SCF_KEY_UP)
{
case SC_SHIFT: sc_flags &= ~SCF_SHIFT; break;
case SC_CTRL: sc_flags &= ~SCF_CTRL; break;
case SC_ALT: sc_flags &= ~SCF_ALT; break;
case SC_DELETE: sc_flags &= ~SCF_DELETE; break;
case SC_INS: sc_flags &= ~SCF_INS; break;
case SC_CAPS: sc_flags ^= SCF_CAPS; set_LEDs=TRUE; break;
case SC_NUM: sc_flags ^= SCF_NUM; set_LEDs=TRUE; break;
case SC_SCROLL: sc_flags ^= SCF_SCROLL; set_LEDs=TRUE; break;
}
else
switch (sc)
{
case SC_SHIFT:
if (Bts(&sc_flags, SCf_SHIFT))
new_key_f = 0;
break;
case SC_CTRL:
if (Bts(&sc_flags, SCf_CTRL))
new_key_f = 0;
break;
case SC_ALT:
if (Bts(&sc_flags, SCf_ALT))
new_key_f = 0;
break;
case SC_DELETE:
sc_flags |= SCF_DELETE;
break;
case SC_INS:
sc_flags |= SCF_INS;
break;
}
sc_flags |= new_key_f;
sc = sc_flags | sc | (sc_flags | sc_raw) << 32;
if (sc_flags & SCF_CTRL && sc_flags & SCF_ALT)
{
if (!(sc & SCF_KEY_UP))
{
if (sc & 255 == SC_DELETE && !(sc_flags & SCF_SHIFT))
CtrlAltDel(sc);
else
{
ch = ScanCode2Char(sc & 255);
if ('a' <= ch <= 'z')
{
sc &= ~(SCF_NEW_KEY | SCF_NEW_KEY << 32);
ch -= 'a';
kbd.last_down_scan_code = sc;
if (keydev.fp_ctrl_alt_cbs[ch] &&
Bt(&keydev.ctrl_alt_in_irq_flags, ch) == in_irq &&
(!(sc_flags & SCF_SHIFT) &&
keydev.ctrl_alt_no_shift_descs[ch]) || sc_flags & SCF_SHIFT && keydev.ctrl_alt_shift_descs[ch])
(*keydev.fp_ctrl_alt_cbs[ch])(sc);
}
}
}
}
if (set_LEDs && !in_irq)
KbdLEDsSet(sc);
*_last_sc = sc;
}
U0 KbdPacketRead()
{
static U8 last_raw_byte = 0;
static I64 last_sc = 0;
U8 raw_byte;
if (TSCGet>kbd.timestamp + counts.time_stamp_freq >> 3)
FifoU8Flush(kbd.fifo);
kbd.timestamp = TSCGet;
raw_byte = InU8(KBD_PORT);
KbdBuildSC(raw_byte, TRUE, &last_raw_byte, &last_sc);
if (!FifoU8Count(kbd.fifo))
{
FifoU8Insert(kbd.fifo, raw_byte);
if (raw_byte != 0xE0)
{
while (FifoU8Remove(kbd.fifo, &raw_byte))
FifoU8Insert(kbd.fifo2, raw_byte);
}
}
else
{
FifoU8Insert(kbd.fifo, raw_byte);
while (FifoU8Remove(kbd.fifo, &raw_byte))
FifoU8Insert(kbd.fifo2, raw_byte);
}
}
interrupt U0 IRQKbd()
{
CLD
OutU8(PIC_1, PIC_EOI);
kbd.irqs_working = TRUE;
if (mouse_hard.install_in_progress)
{
kbd.reset = TRUE;
return;
}
keydev.ctrl_alt_ret_addr = RBPGet()(I64) + 8;
KbdPacketRead;
}
U0 KbdInit()
{
try
{
KbdCmdFlush;
KbdCmdSend(KBD_CTRL, 0xA7); //Disable Mouse
KbdCmdSend(KBD_CTRL, 0xAE); //Enable Keyboard
KbdCmdSend(KBD_PORT, 0xF0);
KbdCmdSend(KBD_PORT, 0x02);
KbdLEDsSet(kbd.scan_code);
}
catch
{
KbdCmdFlush;
Fs->catch_except = TRUE;
}
IntEntrySet(0x21, &IRQKbd);
OutU8(PIC_1_DATA, InU8(PIC_1_DATA) & ~2);
}
U0 KbdHandler()
{
static U8 last_raw_byte = 0;
U8 raw_byte;
FifoU8Remove(kbd.fifo2, &raw_byte);
KbdBuildSC(raw_byte, FALSE, &last_raw_byte, &kbd.scan_code);
if (raw_byte == 0xE0)
{
FifoU8Remove(kbd.fifo2, &raw_byte);
KbdBuildSC(raw_byte, FALSE, &last_raw_byte, &kbd.scan_code);
}
if (Btr(&kbd.scan_code, SCf_NEW_KEY))
{
kbd.new_key_timestamp = kbd.timestamp;
Btr(&kbd.scan_code, 32 + SCf_NEW_KEY);
FifoI64Ins(kbd.scan_code_fifo, kbd.scan_code);
kbd.count++;
if (!(kbd.scan_code & SCF_KEY_UP))
{
kbd.last_down_scan_code = kbd.scan_code;
Bts(kbd.down_bitmap, kbd.scan_code.u8[0]);
Bts(kbd.down_bitmap2, kbd.scan_code.u8[4]);
}
else
{
Btr(kbd.down_bitmap, kbd.scan_code.u8[0]);
Btr(kbd.down_bitmap2, kbd.scan_code.u8[4]);
}
}
}
I64 KbdMessagesQueue()
{
I64 arg1, arg2, message_code = MESSAGE_NULL;
CTask *task_focus;
if (task_focus = sys_focus_task)
{
while (FifoI64Remove(kbd.scan_code_fifo, &arg2))
{
arg1 = ScanCode2Char(arg2);
if (arg2 & SCF_KEY_UP)
{
TaskMessage(task_focus, 0, MESSAGE_KEY_UP, arg1, arg2, 0);
message_code = MESSAGE_KEY_UP;
}
else
{
TaskMessage(task_focus, 0, MESSAGE_KEY_DOWN, arg1, arg2, 0);
message_code = MESSAGE_KEY_DOWN;
}
}
}
return message_code;
}
I64 KbdMouseEventTime()
{//Timestamp of last key or mouse event.
if (mouse_hard.timestamp > kbd.timestamp)
return mouse_hard.timestamp;
else
return kbd.new_key_timestamp;
}