hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/kernel/input.rv
blob: fe25c8189145d6e11d9b062afc4305c8966312f5 (plain)
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
# keyboard scancode table
# ts is not a good way to write a driver lmao
const KBD       = "  1234567890-=  qwertyuiop[]  asdfghjkl;'` \\zxcvbnm,./    "
# same layout, shifted. index 42 (left shift) / 54 (right shift) stay blank
const KBD_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 = { line = "", shift = :false }

# decode one scancode to a character string, or :nil for releases / modifiers /
# unmapped keys. this is the only scancode decoder now, used by both the shell
# and the read() syscall
fn decode_key(code) do
  if code == 0x2a or code == 0x36 do shell.shift = :true  return :nil end # shift down
  if code == 0xaa or code == 0xb6 do shell.shift = :false return :nil end # shift up
  if code >= 128 return :nil            # other releases
  if code == 28 return "\n"             # enter
  if code == 14 return "\x08"           # backspace
  if code < 2 return :nil
  if code >= KBD:len() return :nil
  const ch = if shell.shift KBD_SHIFT[code] else KBD[code]
  if ch == " " and code != 0x39 return :nil # blank cells = modifiers/unmapped
  ch
end

global on_key = fn(code) do
  const ch = decode_key(code)
  if ch == :nil return :nil
  # a process blocked in read() gets first dibs, if it takes the byte, the shell
  # doesnt see it (the process echoes its own input via write())
  if stdin_deliver(ch:ascii()) return :nil
  # otherwise the shells line editor
  if ch == "\n" do puts("\n") run(shell.line) shell.line = "" return :nil end
  if ch == "\x08" do
    if shell.line:len() > 0 do shell.line = shell.line:sub(0, shell.line:len() - 1) puts("\x08 \x08") end
    return :nil
  end
  shell.line ~= ch
  puts(ch)
end