mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-13 22:46:06 +09:00
keyboard input to use properly open/closed input stream
This commit is contained in:
@@ -9,6 +9,7 @@ import net.torvald.tsvm.peripheral.PeriBase
|
|||||||
import org.luaj.vm2.LuaValue
|
import org.luaj.vm2.LuaValue
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
import java.io.PrintStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
@@ -68,9 +69,14 @@ class VM(
|
|||||||
|
|
||||||
internal fun getIO(): IOSpace = peripheralTable[0].peripheral as IOSpace
|
internal fun getIO(): IOSpace = peripheralTable[0].peripheral as IOSpace
|
||||||
|
|
||||||
lateinit var printStream: OutputStream
|
//lateinit var printStream: OutputStream
|
||||||
lateinit var errorStream: OutputStream
|
//lateinit var errorStream: OutputStream
|
||||||
lateinit var inputStream: InputStream
|
//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 {
|
init {
|
||||||
peripheralTable[0] = PeripheralEntry(
|
peripheralTable[0] = PeripheralEntry(
|
||||||
|
|||||||
@@ -44,9 +44,9 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
|
|||||||
batch.projectionMatrix = camera.combined
|
batch.projectionMatrix = camera.combined
|
||||||
Gdx.gl20.glViewport(0, 0, appConfig.width, appConfig.height)
|
Gdx.gl20.glViewport(0, 0, appConfig.width, appConfig.height)
|
||||||
|
|
||||||
vm.printStream = gpu.getPrintStream()
|
vm.getPrintStream = { gpu.getPrintStream() }
|
||||||
vm.errorStream = gpu.getErrorStream()
|
vm.getErrorStream = { gpu.getErrorStream() }
|
||||||
vm.inputStream = gpu.getInputStream()
|
vm.getInputStream = { gpu.getInputStream() }
|
||||||
|
|
||||||
// TEST PRG
|
// TEST PRG
|
||||||
vmRunner = VMRunnerFactory(vm, "js")
|
vmRunner = VMRunnerFactory(vm, "js")
|
||||||
|
|||||||
@@ -15,24 +15,25 @@ class VMJSR223Delegate(val vm: VM) {
|
|||||||
|
|
||||||
fun print(s: String) {
|
fun print(s: String) {
|
||||||
//print("[Nashorn] $s")
|
//print("[Nashorn] $s")
|
||||||
vm.printStream.write(s.toByteArray())
|
vm.getPrintStream().write(s.toByteArray())
|
||||||
}
|
}
|
||||||
fun println(s: String) {
|
fun println(s: String) {
|
||||||
//println("[Nashorn] $s")
|
//println("[Nashorn] $s")
|
||||||
vm.printStream.write((s + '\n').toByteArray())
|
vm.getPrintStream().write((s + '\n').toByteArray())
|
||||||
}
|
}
|
||||||
fun println() = print('\n')
|
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
|
* Read series of key inputs until Enter/Return key is pressed
|
||||||
*/
|
*/
|
||||||
fun read(): String {
|
fun read(): String {
|
||||||
|
val inputStream = vm.getInputStream()
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
var key: Int
|
var key: Int
|
||||||
do {
|
do {
|
||||||
key = readKey()
|
key = inputStream.read()
|
||||||
|
|
||||||
if ((key == 8 && sb.isNotEmpty()) || key in 0x20..0x7E) {
|
if ((key == 8 && sb.isNotEmpty()) || key in 0x20..0x7E) {
|
||||||
this.print("${key.toChar()}")
|
this.print("${key.toChar()}")
|
||||||
@@ -45,6 +46,7 @@ class VMJSR223Delegate(val vm: VM) {
|
|||||||
} while (key != 13 && key != 10)
|
} while (key != 13 && key != 10)
|
||||||
this.println()
|
this.println()
|
||||||
|
|
||||||
|
inputStream.close()
|
||||||
return sb.toString()
|
return sb.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -368,7 +368,7 @@ class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Compa
|
|||||||
|
|
||||||
private lateinit var PRINTSTREAM_INSTANCE: OutputStream
|
private lateinit var PRINTSTREAM_INSTANCE: OutputStream
|
||||||
private lateinit var ERRORSTREAM_INSTANCE: OutputStream
|
private lateinit var ERRORSTREAM_INSTANCE: OutputStream
|
||||||
private lateinit var INPUTSTREAM_INSTANCE: InputStream
|
//private lateinit var INPUTSTREAM_INSTANCE: InputStream
|
||||||
|
|
||||||
override fun getPrintStream(): OutputStream {
|
override fun getPrintStream(): OutputStream {
|
||||||
try {
|
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 {
|
override fun getInputStream(): InputStream {
|
||||||
try {
|
return object : InputStream() {
|
||||||
return INPUTSTREAM_INSTANCE
|
|
||||||
}
|
|
||||||
catch (e: UninitializedPropertyAccessException) {
|
|
||||||
INPUTSTREAM_INSTANCE = object : InputStream() {
|
|
||||||
|
|
||||||
override fun read(): Int {
|
init {
|
||||||
var key: Byte
|
vm.getIO().mmio_write(38L, 1)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
|
|||||||
private var mouseY: Short = 0
|
private var mouseY: Short = 0
|
||||||
private var mouseDown = false
|
private var mouseDown = false
|
||||||
|
|
||||||
|
private var keyboardInputRequested = false
|
||||||
|
|
||||||
override fun peek(addr: Long): Byte? {
|
override fun peek(addr: Long): Byte? {
|
||||||
return mmio_read(addr)
|
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 32..33 -> (mouseX.toInt() shr (adi - 32).times(8)).toByte()
|
||||||
in 34..35 -> (mouseY.toInt() shr (adi - 34).times(8)).toByte()
|
in 34..35 -> (mouseY.toInt() shr (adi - 34).times(8)).toByte()
|
||||||
36L -> if (mouseDown) 1 else 0
|
36L -> if (mouseDown) 1 else 0
|
||||||
37L -> keyboardBuffer.removeHead() ?: -1
|
37L -> keyboardBuffer.removeTail() ?: -1
|
||||||
|
38L -> if (keyboardInputRequested) 1 else 0
|
||||||
else -> -1
|
else -> -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,6 +49,11 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
|
|||||||
val adi = addr.toInt()
|
val adi = addr.toInt()
|
||||||
val bi = byte.toInt().and(255)
|
val bi = byte.toInt().and(255)
|
||||||
when (addr) {
|
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 {
|
override fun keyTyped(p0: Char): Boolean {
|
||||||
try {
|
if (keyboardInputRequested) {
|
||||||
keyboardBuffer.appendTail(p0.toByte())
|
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 {
|
override fun scrolled(p0: Int): Boolean {
|
||||||
|
|||||||
@@ -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
|
// even if overflowing is enabled, appending at tail causes head element to be altered, therefore such action
|
||||||
// must be blocked by throwing overflow error
|
// 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) {
|
if (overflow) {
|
||||||
throw StackOverflowError()
|
throw StackOverflowError()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,13 +43,16 @@ Endianness: little
|
|||||||
|
|
||||||
MMIO
|
MMIO
|
||||||
|
|
||||||
0..31: Raw Keyboard Buffer read. Won't shift the key buffer
|
0..31 RO: Raw Keyboard Buffer read. Won't shift the key buffer
|
||||||
32..33: Mouse X pos
|
32..33 RO: Mouse X pos
|
||||||
34..35: Mouse Y pos
|
34..35 RO: Mouse Y pos
|
||||||
36: Mouse down? (1 for TRUE, 0 for FALSE)
|
36 RO: Mouse down? (1 for TRUE, 0 for FALSE)
|
||||||
37: Read/Write single key input. Key buffer will be shifted. Manual writing is
|
37 RW: Read/Write single key input. Key buffer will be shifted. Manual writing is
|
||||||
usually unnecessary as such action must be automatically managed via LibGDX
|
usually unnecessary as such action must be automatically managed via LibGDX
|
||||||
input processing.
|
input processing.
|
||||||
|
38 RW: Request keyboard input be read. Write nonzero value to enable, write zero to
|
||||||
|
close it. Keyboard buffer will be cleared whenever request is received, so
|
||||||
|
MAKE SURE YOU REQUEST THE KEY INPUT ONLY ONCE!
|
||||||
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user