keyboard input to use properly open/closed input stream

This commit is contained in:
minjaesong
2020-05-15 17:13:56 +09:00
parent e486d8dce4
commit 772354d2d1
7 changed files with 65 additions and 38 deletions

View File

@@ -9,6 +9,7 @@ import net.torvald.tsvm.peripheral.PeriBase
import org.luaj.vm2.LuaValue
import java.io.InputStream
import java.io.OutputStream
import java.io.PrintStream
import java.util.*
import kotlin.math.ceil
import kotlin.random.Random
@@ -68,9 +69,14 @@ class VM(
internal fun getIO(): IOSpace = peripheralTable[0].peripheral as IOSpace
lateinit var printStream: OutputStream
lateinit var errorStream: OutputStream
lateinit var inputStream: InputStream
//lateinit var printStream: OutputStream
//lateinit var errorStream: OutputStream
//lateinit var inputStream: InputStream // InputStream should not be a singleton, as it HAS TO open and close the stream.
// Printstreams don't need that so they're singleton.
var getPrintStream: () -> OutputStream = { TODO() }
var getErrorStream: () -> OutputStream = { TODO() }
var getInputStream: () -> InputStream = { TODO() }
init {
peripheralTable[0] = PeripheralEntry(

View File

@@ -44,9 +44,9 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
batch.projectionMatrix = camera.combined
Gdx.gl20.glViewport(0, 0, appConfig.width, appConfig.height)
vm.printStream = gpu.getPrintStream()
vm.errorStream = gpu.getErrorStream()
vm.inputStream = gpu.getInputStream()
vm.getPrintStream = { gpu.getPrintStream() }
vm.getErrorStream = { gpu.getErrorStream() }
vm.getInputStream = { gpu.getInputStream() }
// TEST PRG
vmRunner = VMRunnerFactory(vm, "js")

View File

@@ -15,24 +15,25 @@ class VMJSR223Delegate(val vm: VM) {
fun print(s: String) {
//print("[Nashorn] $s")
vm.printStream.write(s.toByteArray())
vm.getPrintStream().write(s.toByteArray())
}
fun println(s: String) {
//println("[Nashorn] $s")
vm.printStream.write((s + '\n').toByteArray())
vm.getPrintStream().write((s + '\n').toByteArray())
}
fun println() = print('\n')
fun readKey() = vm.inputStream.read()
//fun readKey() = vm.inputStream.read()
/**
* Read series of key inputs until Enter/Return key is pressed
*/
fun read(): String {
val inputStream = vm.getInputStream()
val sb = StringBuilder()
var key: Int
do {
key = readKey()
key = inputStream.read()
if ((key == 8 && sb.isNotEmpty()) || key in 0x20..0x7E) {
this.print("${key.toChar()}")
@@ -45,6 +46,7 @@ class VMJSR223Delegate(val vm: VM) {
} while (key != 13 && key != 10)
this.println()
inputStream.close()
return sb.toString()
}
}

View File

@@ -368,7 +368,7 @@ class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Compa
private lateinit var PRINTSTREAM_INSTANCE: OutputStream
private lateinit var ERRORSTREAM_INSTANCE: OutputStream
private lateinit var INPUTSTREAM_INSTANCE: InputStream
//private lateinit var INPUTSTREAM_INSTANCE: InputStream
override fun getPrintStream(): OutputStream {
try {
@@ -412,27 +412,32 @@ class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Compa
}
}
/**
* As getting the keyboard input now requires proper open and closing, the inputstream cannot be a singleton, unlike
* the printstream.
*/
override fun getInputStream(): InputStream {
try {
return INPUTSTREAM_INSTANCE
}
catch (e: UninitializedPropertyAccessException) {
INPUTSTREAM_INSTANCE = object : InputStream() {
return object : InputStream() {
override fun read(): Int {
var key: Byte
do {
Thread.sleep(4L) // if spinning rate is too fast, this function fail.
// Possible cause: Input event handling of GDX is done on separate thread
key = vm.getIO().mmio_read(37L)!!
} while (key == (-1).toByte())
//println("[stdin] key = $key")
return key.toInt().and(255)
}
init {
vm.getIO().mmio_write(38L, 1)
}
return INPUTSTREAM_INSTANCE
override fun read(): Int {
var key: Byte
do {
Thread.sleep(4L) // if spinning rate is too fast, this function fail.
// Possible cause: Input event handling of GDX is done on separate thread
key = vm.getIO().mmio_read(37L)!!
} while (key == (-1).toByte())
//println("[stdin] key = $key")
return key.toInt().and(255)
}
override fun close() {
vm.getIO().mmio_write(38L, 0)
}
}
}

View File

@@ -22,6 +22,8 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
private var mouseY: Short = 0
private var mouseDown = false
private var keyboardInputRequested = false
override fun peek(addr: Long): Byte? {
return mmio_read(addr)
}
@@ -37,7 +39,8 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
in 32..33 -> (mouseX.toInt() shr (adi - 32).times(8)).toByte()
in 34..35 -> (mouseY.toInt() shr (adi - 34).times(8)).toByte()
36L -> if (mouseDown) 1 else 0
37L -> keyboardBuffer.removeHead() ?: -1
37L -> keyboardBuffer.removeTail() ?: -1
38L -> if (keyboardInputRequested) 1 else 0
else -> -1
}
}
@@ -46,6 +49,11 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
val adi = addr.toInt()
val bi = byte.toInt().and(255)
when (addr) {
37L -> keyboardBuffer.appendHead(byte)
38L -> {
keyboardInputRequested = (byte != 0.toByte())
if (keyboardInputRequested) keyboardBuffer.clear()
}
}
}
@@ -67,11 +75,13 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
}
override fun keyTyped(p0: Char): Boolean {
try {
keyboardBuffer.appendTail(p0.toByte())
if (keyboardInputRequested) {
keyboardBuffer.appendHead(p0.toByte())
return true
}
else {
return false
}
catch (e: StackOverflowError) { /* if stack overflow, simply stop reading more keys */ }
return true
}
override fun scrolled(p0: Int): Boolean {

View File

@@ -84,6 +84,7 @@ class CircularArray<T>(val size: Int, val overwriteOnOverflow: Boolean): Iterabl
// even if overflowing is enabled, appending at tail causes head element to be altered, therefore such action
// must be blocked by throwing overflow error
// if you think this behaviour is wrong, you're confusing appendHead() with appendTail(). Use appendHead() and removeTail()
if (overflow) {
throw StackOverflowError()
}