# adapted from illwill's examples/keycodes.nim
import std/[math, os, strformat, times]
import std/[atomics, strutils]
import illwill, nimler
var
uiThread: Thread[void]
gLastKeyPressed: Atomic[Key]
stopFlag: Atomic[bool]
gLastKeypressed.store(Key.None)
stopFlag.store(false)
proc controlC {.noconv.} =
gLastKeyPressed.store(Key.CtrlC)
proc updateScreen(tb: var TerminalBuffer) =
let
x1 = 3
y1 = 1
x2 = max(tb.width-4, x1)
y2 = max(tb.height-2, y1)
fillChars = "|/-\\"
let t = epochTime()
let ch = fillChars[((t * 5) mod fillChars.len.float).int]
tb.setForegroundColor(fgBlack, bright=true)
tb.fill(x1,y1, x2, y2, $ch)
tb.setForegroundColor(fgWhite)
tb.drawRect(x1, y1, x2, y2)
tb.setForegroundColor(fgWhite, bright=true)
tb.write(x1+1, y1+1, "Press keys/key combinations on the keyboard to view their keycode")
tb.write(x1+1, y1+2, "Press Q, Esc or Ctrl-C to quit")
tb.write(x1+1, y1+4, "Resize the terminal window and see what happens :)")
let
text = " Key pressed: "
tx = max(x1 + ((x2 - x1 - text.len) / 2).int, 0)
ty = max(y1 + ((y2 - y1) / 2).int, 0)
tb.setBackgroundColor(bgRed)
tb.setForegroundColor(fgYellow)
tb.drawRect(tx-1, ty-1, tx + text.len, ty+1, doubleStyle=true)
tb.write(tx, ty, text)
tb.setForegroundColor(fgWhite, bright=true)
tb.write(tx+14, ty, $gLastKeyPressed.load)
proc main() {.thread.} =
illwillInit(fullscreen=true)
setControlCHook(controlC)
hideCursor()
defer:
illwillDeinit()
showCursor()
while not(stopFlag.load):
var tb = newTerminalBuffer(terminalWidth(), terminalHeight())
let key = getKey()
case key
of Key.None: discard
else: gLastKeyPressed.store(key)
tb.updateScreen()
tb.display()
sleep(50)
using
env: ptr ErlNifEnv
argc: cint
argv: ptr UncheckedArray[ErlNifTerm]
proc lastKey(env, argc, argv): ErlNifTerm {.nif, arity: 0, dirtyIo.} =
env.toTerm(ErlAtom($gLastKeyPressed.load))
proc start(env, argc, argv): ErlNifTerm {.nif, arity: 0, dirtyIo.} =
createThread uiThread, main
env.toTerm(ErlAtom("ok"))
proc setKey(env, argc, argv): ErlNifTerm {.nif, arity: 1, dirtyIo.} =
var key = Key.None
let arg = fromTerm(env, argv[0], ErlAtom)
if not(arg.isSome):
env.toTerm(ErlAtom("what"))
else:
try:
key = parseEnum[Key](arg.unsafeGet().string)
except ValueError:
discard
if key != Key.None:
gLastKeyPressed.store(key)
env.toTerm(ErlAtom("ok"))
else:
env.toTerm(ErlAtom("error"))
proc stop(env, argc, argv): ErlNifTerm {.nif, arity: 0, dirtyIo.} =
stopFlag.store(true)
joinThread uiThread
env.toTerm(ErlAtom("ok"))
exportNifs "keycodes", [start, lastKey, setKey, stop]