1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
# keyboard scancode table
# ts is not a good way to write a driver lmao
const KEYMAP = " 1234567890-= qwertyuiop[] asdfghjkl;'` \\zxcvbnm,./ "
const KEYMAP_SHIFT = " !@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"~ |ZXCVBNM<>? "
# 8259 pic
fn pic_remap() do
outb(0x20, 0x11) outb(0xa0, 0x11)
outb(0x21, 0x20) outb(0xa1, 0x28)
outb(0x21, 0x04) outb(0xa1, 0x02)
outb(0x21, 0x01) outb(0xa1, 0x01)
outb(0x21, 0xff) outb(0xa1, 0xff)
end
fn pic_unmask(line)
outb(0x21, inb(0x21) band (255 bxor (1 shl line)))
# 8253/8254 pit channel 0, mode 3 (square wave)
# divisor 11931 -> ~100 hz (1193182 / 11931)
# the isr just counts ticks
fn pit_init() do
outb(0x43, 0x36)
outb(0x40, 11931 band 0xff)
outb(0x40, (11931 shr 8) band 0xff)
end
# she stroke my keys till i handle
# no fr this is just a key stroke handler
global shell = { shift = :false, extended = :false, ctrl = :false }
fn decode_key(code) -> string | :nil do
# shift down
if code == 0x2a or code == 0x36 do
shell.shift = :true
return :nil
end
# shift up
if code == 0xaa or code == 0xb6 do
shell.shift = :false
return :nil
end
# ctrl down
if code == 0x1d do
shell.ctrl = :true
return :nil
end
# ctrl up
if code == 0x9d do
shell.ctrl = :false
return :nil
end
# other releases
if (code >= 128)
return :nil
# enter
if (code == 28)
return "\n"
# backspace
if code == 14 do
if shell.ctrl do
return "\x7f"
end
return "\x08"
end
if (code < 2)
return :nil
if (code >= KEYMAP:len())
return :nil
const character = if (shell.shift) KEYMAP_SHIFT[code] else KEYMAP[code]
# blank cells = modifiers/unmapped
if (character == " " and code != 0x39)
return :nil
if (shell.ctrl)
return string.of_ascii(character:ascii() band 0x1f)
return character
end
global on_key = fn(code) do
if code == 0xe0 do
shell.extended = :true
return :nil
end
if shell.extended do
shell.extended = :false
let final = 0
match code
| 0x48 => final = 65 # up
| 0x50 => final = 66 # down
| 0x4d => final = 67 # right
| 0x4b => final = 68 # left
| 0x47 => final = 72 # home
| 0x4f => final = 70 # end
| _ => :nil
if final != 0 do
tty:feed(27) tty:feed(91) tty:feed(final)
end
return :nil
end
const character = decode_key(code)
if (character == :nil)
return :nil
tty:feed(character:ascii())
end
|