From 5d5576c07789f7b8e3b56dfa67664ac016c91965 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sat, 20 Dec 2025 11:17:50 +0900 Subject: [PATCH] fix: mmio-based readKey() having delayed event because of race condition --- .../src/net/torvald/tsvm/VMJSR223Delegate.kt | 20 +++++++------------ .../net/torvald/tsvm/peripheral/IOSpace.kt | 14 ++++++++----- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/tsvm_core/src/net/torvald/tsvm/VMJSR223Delegate.kt b/tsvm_core/src/net/torvald/tsvm/VMJSR223Delegate.kt index 9341a5b..e55ec4a 100644 --- a/tsvm_core/src/net/torvald/tsvm/VMJSR223Delegate.kt +++ b/tsvm_core/src/net/torvald/tsvm/VMJSR223Delegate.kt @@ -208,25 +208,19 @@ class VMJSR223Delegate(private val vm: VM) { * ^A-^Z: 1 through 26 */ fun readKey(): Int { - val inputStream = vm.getInputStream() - var key: Int = inputStream.read() - inputStream.close() - return key - - // impl that doesn't rely on InputStream - // fixme it's causing event-wise delay - /*vm.getIO().let { - it.mmio_write(38, 1) + // MMIO-based implementation that can be replicated by JS via MMIO read/writes + vm.getIO().let { + it.mmio_write(38, 1) // Set keyboardInputRequested = true (also clears buffer) vm.isIdle.set(true) - while (it.mmio_read(49L) == 0.toByte()) { + while (it.mmio_read(49L) == 0.toByte()) { // Wait for keyPushed flag Thread.sleep(6L) } vm.isIdle.set(false) - it.mmio_write(38, 0) - return it.mmio_read(37L)!!.toUint() - }*/ + it.mmio_write(38, 0) // Clear keyboardInputRequested + return it.mmio_read(37L)!!.toUint() // Read and remove key from buffer + } } /** diff --git a/tsvm_core/src/net/torvald/tsvm/peripheral/IOSpace.kt b/tsvm_core/src/net/torvald/tsvm/peripheral/IOSpace.kt index 3e2ca8b..0a220c1 100644 --- a/tsvm_core/src/net/torvald/tsvm/peripheral/IOSpace.kt +++ b/tsvm_core/src/net/torvald/tsvm/peripheral/IOSpace.kt @@ -99,7 +99,11 @@ class IOSpace(val vm: VM) : PeriBase("io"), InputProcessor { in 32..33 -> (mouseX.toInt() shr (adi - 32).times(8)).toByte() in 34..35 -> (mouseY.toInt() shr (adi - 34).times(8)).toByte() 36L -> mouseDown.toInt().toByte() - 37L -> keyboardBuffer.removeTail() ?: -1 + 37L -> { + val key = keyboardBuffer.removeTail() ?: -1 + keyPushed = !keyboardBuffer.isEmpty // Clear flag when buffer becomes empty + key + } 38L -> keyboardInputRequested.toInt().toByte() 39L -> rawInputFunctionLatched.toInt().toByte() in 40..47 -> keyEventBuffers[adi - 40] @@ -174,6 +178,7 @@ class IOSpace(val vm: VM) : PeriBase("io"), InputProcessor { keyboardInputRequested = (byte.isNonZero()) if (keyboardInputRequested) { keyboardBuffer.clear() + keyPushed = false // Reset flag when buffer is cleared vm.isIdle.set(true) } else @@ -344,14 +349,11 @@ class IOSpace(val vm: VM) : PeriBase("io"), InputProcessor { override fun keyTyped(p0: Char): Boolean { if (keyboardInputRequested && p0.toInt() > 0) { //println("[IO] key typed = ${p0.toInt()}") - keyPushed = true keyboardBuffer.appendHead(p0.toByte()) - Thread.sleep(6L) - keyPushed = false + keyPushed = true // Set after append; cleared when buffer is emptied via mmio_read(37) return true } else { - keyPushed = false return false } } @@ -389,11 +391,13 @@ class IOSpace(val vm: VM) : PeriBase("io"), InputProcessor { if (keyboardInputRequested) { if (p0 in Input.Keys.A..Input.Keys.Z && (Gdx.input.isKeyPressed(Input.Keys.CONTROL_LEFT) || Gdx.input.isKeyPressed(Input.Keys.CONTROL_RIGHT))) { keyboardBuffer.appendHead((p0 - 28).toByte()) + keyPushed = true } else { specialKeys[p0]?.let { //println("[IO] key special = ${it.toUInt()}") keyboardBuffer.appendHead(it) + keyPushed = true } } return true