diff options
author | Can | 2025-01-26 18:11:07 +0100 |
---|---|---|
committer | Can | 2025-01-26 18:11:07 +0100 |
commit | ba86b9db29b1cbf3bebea70d98655967ba9da770 (patch) | |
tree | 0d77f6687e069e290ce97ccafa77c3e914b28b53 /src | |
parent | 1eaabb587a10bad0799360f056d8fa74aa02aa6a (diff) |
added keyboard support
Diffstat (limited to 'src')
-rw-r--r-- | src/cpu.effekt | 60 | ||||
-rw-r--r-- | src/renderer.effekt | 1 | ||||
-rw-r--r-- | src/renderers/js.effekt | 21 |
3 files changed, 69 insertions, 13 deletions
diff --git a/src/cpu.effekt b/src/cpu.effekt index 4a18d22..f347ddd 100644 --- a/src/cpu.effekt +++ b/src/cpu.effekt @@ -21,7 +21,27 @@ extern io def getNow(): Int = jsWeb "Date.now()" interface CPU { def initCPU(rom: ByteArray): Unit def cycleCPU(): Unit + } +def convertKey(key: String): Int = key match { + case "1" => 1 + case "2" => 2 + case "3" => 3 + case "4" => 12 + case "q" => 4 + case "w" => 5 + case "e" => 6 + case "r" => 13 + case "a" => 7 + case "s" => 8 + case "d" => 9 + case "f" => 14 + case "z" => 10 + case "x" => 0 + case "c" => 11 + case "v" => 15 + case _ => -1 +} def makeCPU() {r: Renderer} = { // Initialize the RAM @@ -33,7 +53,6 @@ def makeCPU() {r: Renderer} = { var delay: Byte in global = 0.toByte() // Delay timer var sound: Byte in global = 0.toByte() // Sound timer - var pc: Int in global = 512 // Program counter var sp: Byte in global = 0.toByte() // Stack pointer // After checking the implementation of queue in Effekt, I realized that it also works as a stack, so I will use it as a stack @@ -47,16 +66,27 @@ def makeCPU() {r: Renderer} = { new CPU { def initCPU(rom: ByteArray) = { ram.init(rom) - r.fill("black") + r.clear() } def cycleCPU() = { val currentTime = getNow() + var key: Int = -1 // Key pressed + if (currentTime - last_key_update_time >= 16) { // 60Hz key updates + // Update keys + val key_ = r.getKeyPressed().getOrElse { "P" } + if (key_ != "P") { + last_key_update_time = currentTime + key = convertKey(key_) + r.log("Key pressed: " ++ show(key)) + } + } + if (currentTime - last_instruction_run_time >= 2) { // ~500Hz val h = ram.getAddr(pc) val l = ram.getAddr(pc + 1) val inst = bitwiseOr(bitwiseShl(h.toInt(), 8), l.toInt()) - // r.log("PC: " ++ show(pc)) - // r.log("Instruction: " ++ show(inst)) + r.log("PC: " ++ show(pc)) + r.log("Instruction: " ++ show(inst)) // Decode val opcode = bitwiseShr(bitwiseAnd(inst, 61440), 12) @@ -225,16 +255,21 @@ def makeCPU() {r: Renderer} = { pc = pc + 2 } case 14 => { + r.log("nn: " ++ show(nn)) nn match { - // Skip next instruction if key with the value of VX is pressed + // Skip next instruction if key with the value of VX is not pressed case 161 => { - // TODO: missing keyboard input - () + r.log("Key: " ++ show(key) ++ " VX: " ++ show(v.unsafeGet(x))) + if (key != -1 && key != v.unsafeGet(x).toInt()) { + pc = pc + 2 + } } - // Skip next instruction if key with the value of VX is not pressed + // Skip next instruction if key with the value of VX is pressed case 158 => { - // TODO: missing keyboard input - () + r.log("Key: " ++ show(key) ++ " VX: " ++ show(v.unsafeGet(x))) + if (key != -1 && key == v.unsafeGet(x).toInt()) { + pc = pc + 2 + } } } else { r.log("Unknown Instruction: " ++ show(inst)) @@ -248,8 +283,9 @@ def makeCPU() {r: Renderer} = { } // Wait for a key press, store the value of the key in VX case 10 => { - // TODO: missing keyboard input - () + if (key != -1) { + v.set(x, key.toByte()) + } } // SET delay timer = VX case 21 => { diff --git a/src/renderer.effekt b/src/renderer.effekt index 358272b..b4d5343 100644 --- a/src/renderer.effekt +++ b/src/renderer.effekt @@ -16,4 +16,5 @@ interface Renderer { def get(x: Int, y: Int): Bool def update(f: () => Unit at {io, global}): Unit def log(msg: String): Unit + def getKeyPressed(): Option[String] } diff --git a/src/renderers/js.effekt b/src/renderers/js.effekt index ab7cc53..4aea494 100644 --- a/src/renderers/js.effekt +++ b/src/renderers/js.effekt @@ -14,6 +14,7 @@ extern io def loadRom(): ByteArray = jsWeb "rom ? rom : new Uint8Array(0)" extern io def requestAnimationFrame {callback: () => Unit}: Unit = jsWeb "requestAnimationFrame(() => $effekt.runToplevel((ks) => ${box callback}(ks)))" extern jsWeb """ let rom = undefined; + let key = undefined; // Global Log Function function log(msg) { const message = new Date().toLocaleTimeString() + ' - ' + msg + ' \n' @@ -28,6 +29,12 @@ extern jsWeb """ document.getElementById('start').removeAttribute('disabled'); }); } + + function keyRegister() { + document.addEventListener('keydown', (event) => { + window.key = event.key; + }); + } """ val pageContent = """ @@ -70,7 +77,7 @@ val width = 640 val height = 320 val scale = 10 -extern io def renderPage(content: String): Unit = jsWeb "document.write(${content}); romCheck();" +extern io def renderPage(content: String): Unit = jsWeb "document.write(${content}); romCheck(); keyRegister();" // Initialize the screen def init(run: (ByteArray) => Unit at {io, global}) = { renderPage(pageContent) @@ -126,6 +133,14 @@ extern io def update(f: () => Unit at {io, global}): Unit = jsWeb """ }, 1000 / 120); """ +extern io def getKeyPressed(): String = jsWeb """ + (() => { + const key = window.key; + window.key = undefined; + return key; + })(); +""" + namespace JSRenderer { // make JS Renderer def makeRenderer: Renderer = new Renderer { @@ -136,5 +151,9 @@ namespace JSRenderer { def log(msg: String) = log(msg) def fill(color: String) = fill(color) def get(x: Int, y: Int) = get(x, y) + def getKeyPressed() = { + val key = getKeyPressed() + undefinedToOption(key) + } } } |