# Wrappers around keyboard primitives that take a 'keyboard' object and are thus
# easier to test.
container keyboard [ # can't think of another word like screen/display, so real and fake keyboards use the same name
index:number
data:address:array:character
]
recipe init-fake-keyboard [
default-space:address:array:location <- new location:type, 30:literal
result:address:keyboard <- new keyboard:type
buf:address:address:array:character <- get-address result:address:keyboard/deref, data:offset
#? $start-tracing #? 1
buf:address:address:array:character/deref <- next-ingredient
#? $stop-tracing #? 1
idx:address:number <- get-address result:address:keyboard/deref, index:offset
idx:address:number/deref <- copy 0:literal
reply result:address:keyboard
]
recipe read-key [
default-space:address:array:location <- new location:type, 30:literal
x:address:keyboard <- next-ingredient
{
break-unless x:address:keyboard
idx:address:number <- get-address x:address:keyboard/deref, index:offset
buf:address:array:character <- get x:address:keyboard/deref, data:offset
max:number <- length buf:address:array:character/deref
{
done?:boolean <- greater-or-equal idx:address:number/deref, max:number
break-unless done?:boolean
reply 0:literal/eof, 1:literal/found, x:address:keyboard/same-as-ingredient:0
}
c:character <- index buf:address:array:character/deref, idx:address:number/deref
idx:address:number/deref <- add idx:address:number/deref, 1:literal
reply c:character, 1:literal/found, x:address:keyboard/same-as-ingredient:0
}
# real keyboard input is infrequent; avoid polling it too much
switch
c:character, found?:boolean <- read-key-from-keyboard
reply c:character, found?:boolean, x:address:keyboard/same-as-ingredient:0
]
recipe wait-for-key [
default-space:address:array:location <- new location:type, 30:literal
x:address:keyboard <- next-ingredient
{
break-unless x:address:keyboard
# on fake keyboards 'wait-for-key' behaves just like 'read-key'
c:character, x:address:keyboard <- read-key x:address:keyboard
reply c:character, x:address:keyboard/same-as-ingredient:0
}
c:character <- wait-for-key-from-keyboard
reply c:character, x:address:keyboard/same-as-ingredient:0
]
recipe send-keys-to-channel [
default-space:address:array:location <- new location:type, 30:literal
keyboard:address <- next-ingredient
chan:address:channel <- next-ingredient
screen:address <- next-ingredient
{
c:character, found?:boolean <- read-key keyboard:address
loop-unless found?:boolean
#? print-integer screen:address, c:character #? 1
print-character screen:address, c:character
chan:address:channel <- write chan:address:channel, c:character
# todo: eof
loop
}
]