mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-11 15:24:05 +09:00
working print() sans screen scroll
This commit is contained in:
@@ -7,7 +7,7 @@ import sun.nio.ch.DirectBuffer
|
|||||||
class GraphicsJSR223Delegate(val vm: VM) {
|
class GraphicsJSR223Delegate(val vm: VM) {
|
||||||
|
|
||||||
private fun getFirstGPU(): GraphicsAdapter? {
|
private fun getFirstGPU(): GraphicsAdapter? {
|
||||||
return vm.peripheralTable[vm.findPeribyType("gpu") ?: return null].peripheral as? GraphicsAdapter
|
return vm.findPeribyType(VM.PERITYPE_TERM)?.peripheral as? GraphicsAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resetPalette() {
|
fun resetPalette() {
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import net.torvald.tsvm.firmware.Firmware.Companion.toLuaValue
|
|||||||
import net.torvald.tsvm.peripheral.IOSpace
|
import net.torvald.tsvm.peripheral.IOSpace
|
||||||
import net.torvald.tsvm.peripheral.PeriBase
|
import net.torvald.tsvm.peripheral.PeriBase
|
||||||
import org.luaj.vm2.LuaValue
|
import org.luaj.vm2.LuaValue
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
@@ -64,6 +66,10 @@ class VM(
|
|||||||
|
|
||||||
val peripheralTable = Array(8) { PeripheralEntry() }
|
val peripheralTable = Array(8) { PeripheralEntry() }
|
||||||
|
|
||||||
|
lateinit var printStream: OutputStream
|
||||||
|
lateinit var errorStream: OutputStream
|
||||||
|
lateinit var inputStream: InputStream
|
||||||
|
|
||||||
init {
|
init {
|
||||||
peripheralTable[0] = PeripheralEntry(
|
peripheralTable[0] = PeripheralEntry(
|
||||||
"io",
|
"io",
|
||||||
@@ -77,9 +83,9 @@ class VM(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun findPeribyType(searchTerm: String): Int? {
|
fun findPeribyType(searchTerm: String): PeripheralEntry? {
|
||||||
for (i in 0..7) {
|
for (i in 0..7) {
|
||||||
if (peripheralTable[i].type == searchTerm) return i
|
if (peripheralTable[i].type == searchTerm) return peripheralTable[i]
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -100,7 +106,7 @@ class VM(
|
|||||||
val HW_RESERVE_SIZE = 1024.kB()
|
val HW_RESERVE_SIZE = 1024.kB()
|
||||||
val USER_SPACE_SIZE = 8192.kB()
|
val USER_SPACE_SIZE = 8192.kB()
|
||||||
|
|
||||||
const val PERITYPE_GRAPHICS = "gpu"
|
const val PERITYPE_TERM = "gpu"
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun translateAddr(addr: Long): Pair<Any?, Long> {
|
internal fun translateAddr(addr: Long): Pair<Any?, Long> {
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import com.badlogic.gdx.graphics.OrthographicCamera
|
|||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import net.torvald.tsvm.peripheral.GraphicsAdapter
|
import net.torvald.tsvm.peripheral.GraphicsAdapter
|
||||||
import kotlin.coroutines.CoroutineContext
|
import java.io.InputStream
|
||||||
import kotlin.coroutines.suspendCoroutine
|
import java.io.OutputStream
|
||||||
|
|
||||||
class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter() {
|
class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter() {
|
||||||
|
|
||||||
@@ -28,9 +28,9 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
|
|||||||
gpu = GraphicsAdapter(lcdMode = false)
|
gpu = GraphicsAdapter(lcdMode = false)
|
||||||
|
|
||||||
vm.peripheralTable[1] = PeripheralEntry(
|
vm.peripheralTable[1] = PeripheralEntry(
|
||||||
VM.PERITYPE_GRAPHICS,
|
VM.PERITYPE_TERM,
|
||||||
gpu,
|
gpu,
|
||||||
256.kB(),
|
GraphicsAdapter.VRAM_SIZE,
|
||||||
16,
|
16,
|
||||||
0
|
0
|
||||||
)
|
)
|
||||||
@@ -42,6 +42,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.errorStream = gpu.getErrorStream()
|
||||||
|
//inputStream = gpu.getInputStream()
|
||||||
|
|
||||||
// TEST PRG
|
// TEST PRG
|
||||||
vmRunner = VMRunnerFactory(vm, "js")
|
vmRunner = VMRunnerFactory(vm, "js")
|
||||||
@@ -244,7 +247,7 @@ while (true) {
|
|||||||
for (var k = 0; k < 2560; k++) {
|
for (var k = 0; k < 2560; k++) {
|
||||||
vm.poke(-(253952 + k + 1) - hwoff, -2); // transparent
|
vm.poke(-(253952 + k + 1) - hwoff, -2); // transparent
|
||||||
vm.poke(-(253952 + 2560 + k + 1) - hwoff, -1); // white
|
vm.poke(-(253952 + 2560 + k + 1) - hwoff, -1); // white
|
||||||
vm.poke(-(253952 + 2560*2 + k + 1) - hwoff, Math.round(Math.random() * 255));
|
/*vm.poke(-(253952 + 2560*2 + k + 1) - hwoff, Math.round(Math.random() * 255));*/
|
||||||
}
|
}
|
||||||
|
|
||||||
rng = inthash(rng);
|
rng = inthash(rng);
|
||||||
@@ -255,7 +258,7 @@ while (true) {
|
|||||||
}
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
private val gpuTestPaletteJs = "eval('${jscode.replace(Regex("//[^\\n]*"), "").replace('\n', ' ')}')"
|
private val gpuTestPaletteJs = "function print(s){vm.print(s)}eval('${jscode.replace(Regex("//[^\\n]*"), "").replace('\n', ' ')}')"
|
||||||
|
|
||||||
|
|
||||||
private val gpuTestPaletteJava = """
|
private val gpuTestPaletteJava = """
|
||||||
|
|||||||
@@ -13,4 +13,13 @@ class VMJSR223Delegate(val vm: VM) {
|
|||||||
fun malloc(size: Int) = vm.malloc(size)
|
fun malloc(size: Int) = vm.malloc(size)
|
||||||
fun free(ptr: Int) = vm.free(ptr)
|
fun free(ptr: Int) = vm.free(ptr)
|
||||||
|
|
||||||
|
fun print(s: String) {
|
||||||
|
//println("[Nashorn] $s")
|
||||||
|
vm.printStream.write((s + '\n').toByteArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class VMSerialDebugger(val vm: VM) {
|
||||||
|
fun print(s: String) = System.out.println(s)
|
||||||
}
|
}
|
||||||
@@ -52,6 +52,7 @@ object VMRunnerFactory {
|
|||||||
bind.put("graphics", GraphicsJSR223Delegate(vm))
|
bind.put("graphics", GraphicsJSR223Delegate(vm))
|
||||||
//bind.put("poke", { a: Long, b: Byte -> vm.poke(a, b) }) // kts: lambda does not work...
|
//bind.put("poke", { a: Long, b: Byte -> vm.poke(a, b) }) // kts: lambda does not work...
|
||||||
//bind.put("nanotime", { System.nanoTime() })
|
//bind.put("nanotime", { System.nanoTime() })
|
||||||
|
bind.put("serial", VMSerialDebugger(vm))
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun executeCommand(command: String) {
|
override suspend fun executeCommand(command: String) {
|
||||||
|
|||||||
@@ -1,13 +1,27 @@
|
|||||||
package net.torvald.tsvm.peripheral
|
package net.torvald.tsvm.peripheral
|
||||||
|
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements standard TTY that can interpret some of the ANSI escape sequences
|
* Implements standard TTY that can interpret some of the ANSI escape sequences
|
||||||
|
*
|
||||||
|
* A paper tty must be able to implemented by extending this class (and butchering some of the features), of which it
|
||||||
|
* sets limits on some of the functions (notably 'setCursorPos')
|
||||||
*/
|
*/
|
||||||
abstract class GlassTty(val TEXT_ROWS: Int, val TEXT_COLS: Int) {
|
abstract class GlassTty(val TEXT_ROWS: Int, val TEXT_COLS: Int) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (x, y)
|
||||||
|
*/
|
||||||
abstract fun getCursorPos(): Pair<Int, Int>
|
abstract fun getCursorPos(): Pair<Int, Int>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Think of it as a real paper tty;
|
||||||
|
* setCursorPos must "wrap" the cursor properly when x-value goes out of screen bound.
|
||||||
|
* For y-value, only when y < 0, set y to zero and don't care about the y-value goes out of bound.
|
||||||
|
*/
|
||||||
abstract fun setCursorPos(x: Int, y: Int)
|
abstract fun setCursorPos(x: Int, y: Int)
|
||||||
|
|
||||||
abstract var rawCursorPos: Int
|
abstract var rawCursorPos: Int
|
||||||
@@ -19,6 +33,23 @@ abstract class GlassTty(val TEXT_ROWS: Int, val TEXT_COLS: Int) {
|
|||||||
|
|
||||||
abstract fun putChar(x: Int, y: Int, text: Byte, foreColour: Byte = ttyFore.toByte(), backColour: Byte = ttyBack.toByte())
|
abstract fun putChar(x: Int, y: Int, text: Byte, foreColour: Byte = ttyFore.toByte(), backColour: Byte = ttyBack.toByte())
|
||||||
|
|
||||||
|
fun writeOut(char: Byte) {
|
||||||
|
val printable = acceptChar(char)
|
||||||
|
|
||||||
|
if (printable) {
|
||||||
|
val (x, y) = getCursorPos()
|
||||||
|
putChar(x, y, char)
|
||||||
|
setCursorPos(x + 1, y) // should automatically wrap and advance a line for out-of-bound x-value
|
||||||
|
}
|
||||||
|
|
||||||
|
// deal with y-axis out-of-bounds
|
||||||
|
val (cx, cy) = getCursorPos()
|
||||||
|
if (cy >= TEXT_ROWS) {
|
||||||
|
scrollUp(cy - TEXT_ROWS + 1)
|
||||||
|
setCursorPos(cx, TEXT_ROWS - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var ttyEscState = TTY_ESC_STATE.INITIAL
|
private var ttyEscState = TTY_ESC_STATE.INITIAL
|
||||||
private val ttyEscArguments = Stack<Int>()
|
private val ttyEscArguments = Stack<Int>()
|
||||||
/**
|
/**
|
||||||
@@ -52,11 +83,14 @@ abstract class GlassTty(val TEXT_ROWS: Int, val TEXT_COLS: Int) {
|
|||||||
|
|
||||||
when (ttyEscState) {
|
when (ttyEscState) {
|
||||||
TTY_ESC_STATE.INITIAL -> {
|
TTY_ESC_STATE.INITIAL -> {
|
||||||
if (char == ESC) {
|
when (char) {
|
||||||
ttyEscState = TTY_ESC_STATE.ESC
|
ESC -> ttyEscState = TTY_ESC_STATE.ESC
|
||||||
}
|
LF -> crlf()
|
||||||
else {
|
BS -> backspace()
|
||||||
return true
|
TAB -> insertTab()
|
||||||
|
BEL -> ringBell()
|
||||||
|
in 0x00.toByte()..0x1F.toByte() -> return false
|
||||||
|
else -> return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TTY_ESC_STATE.ESC -> {
|
TTY_ESC_STATE.ESC -> {
|
||||||
@@ -170,6 +204,8 @@ abstract class GlassTty(val TEXT_ROWS: Int, val TEXT_COLS: Int) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
abstract fun resetTtyStatus()
|
abstract fun resetTtyStatus()
|
||||||
abstract fun cursorUp(arg: Int = 1)
|
abstract fun cursorUp(arg: Int = 1)
|
||||||
abstract fun cursorDown(arg: Int = 1)
|
abstract fun cursorDown(arg: Int = 1)
|
||||||
@@ -180,15 +216,31 @@ abstract class GlassTty(val TEXT_ROWS: Int, val TEXT_COLS: Int) {
|
|||||||
abstract fun cursorX(arg: Int = 1) // aka Cursor Horizintal Absolute
|
abstract fun cursorX(arg: Int = 1) // aka Cursor Horizintal Absolute
|
||||||
abstract fun eraseInDisp(arg: Int = 0)
|
abstract fun eraseInDisp(arg: Int = 0)
|
||||||
abstract fun eraseInLine(arg: Int = 0)
|
abstract fun eraseInLine(arg: Int = 0)
|
||||||
|
/** New lines are added at the bottom */
|
||||||
abstract fun scrollUp(arg: Int = 1)
|
abstract fun scrollUp(arg: Int = 1)
|
||||||
|
/** New lines are added at the top */
|
||||||
abstract fun scrollDown(arg: Int = 1)
|
abstract fun scrollDown(arg: Int = 1)
|
||||||
abstract fun sgrOneArg(arg: Int = 0)
|
abstract fun sgrOneArg(arg: Int = 0)
|
||||||
abstract fun sgrTwoArg(arg1: Int, arg2: Int)
|
abstract fun sgrTwoArg(arg1: Int, arg2: Int)
|
||||||
abstract fun sgrThreeArg(arg1: Int, arg2: Int, arg3: Int)
|
abstract fun sgrThreeArg(arg1: Int, arg2: Int, arg3: Int)
|
||||||
|
/** The values are one-based
|
||||||
|
* @param arg1 y-position (row)
|
||||||
|
* @param arg2 x-position (column) */
|
||||||
abstract fun cursorXY(arg1: Int, arg2: Int)
|
abstract fun cursorXY(arg1: Int, arg2: Int)
|
||||||
abstract fun ringBell()
|
abstract fun ringBell()
|
||||||
abstract fun insertTab()
|
abstract fun insertTab()
|
||||||
|
abstract fun crlf()
|
||||||
|
abstract fun backspace()
|
||||||
|
|
||||||
|
abstract fun getPrintStream(): OutputStream
|
||||||
|
abstract fun getErrorStream(): OutputStream
|
||||||
|
abstract fun getInputStream(): InputStream
|
||||||
|
|
||||||
|
private val CR = 0x0D.toByte()
|
||||||
|
private val LF = 0x0A.toByte()
|
||||||
|
private val TAB = 0x09.toByte()
|
||||||
|
private val BS = 0x08.toByte()
|
||||||
|
private val BEL = 0x07.toByte()
|
||||||
private val ESC = 0x1B.toByte()
|
private val ESC = 0x1B.toByte()
|
||||||
|
|
||||||
private enum class TTY_ESC_STATE {
|
private enum class TTY_ESC_STATE {
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ import net.torvald.tsvm.AppLoader
|
|||||||
import net.torvald.tsvm.VM
|
import net.torvald.tsvm.VM
|
||||||
import net.torvald.tsvm.kB
|
import net.torvald.tsvm.kB
|
||||||
import sun.nio.ch.DirectBuffer
|
import sun.nio.ch.DirectBuffer
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.io.PrintStream
|
||||||
import kotlin.experimental.and
|
import kotlin.experimental.and
|
||||||
|
|
||||||
class GraphicsAdapter(val lcdMode: Boolean = false) : GlassTty(Companion.TEXT_ROWS, Companion.TEXT_COLS), PeriBase {
|
class GraphicsAdapter(val lcdMode: Boolean = false) : GlassTty(Companion.TEXT_ROWS, Companion.TEXT_COLS), PeriBase {
|
||||||
@@ -58,8 +61,28 @@ class GraphicsAdapter(val lcdMode: Boolean = false) : GlassTty(Companion.TEXT_RO
|
|||||||
set(value) { spriteAndTextArea.setShort(memTextCursorPosOffset, value.toShort()) }
|
set(value) { spriteAndTextArea.setShort(memTextCursorPosOffset, value.toShort()) }
|
||||||
|
|
||||||
override fun getCursorPos() = rawCursorPos % TEXT_COLS to rawCursorPos / TEXT_COLS
|
override fun getCursorPos() = rawCursorPos % TEXT_COLS to rawCursorPos / TEXT_COLS
|
||||||
|
/**
|
||||||
|
* Think of it as a real paper tty;
|
||||||
|
* setCursorPos must "wrap" the cursor properly when x-value goes out of screen bound.
|
||||||
|
* For y-value, only when y < 0, set y to zero and don't care about the y-value goes out of bound.
|
||||||
|
*/
|
||||||
override fun setCursorPos(x: Int, y: Int) {
|
override fun setCursorPos(x: Int, y: Int) {
|
||||||
rawCursorPos = toTtyTextOffset(x, y)
|
var newx = x
|
||||||
|
var newy = y
|
||||||
|
|
||||||
|
if (newx >= TEXT_COLS) {
|
||||||
|
newx = 0
|
||||||
|
newy += 1
|
||||||
|
}
|
||||||
|
else if (newx < 0) {
|
||||||
|
newx = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newy < 0) {
|
||||||
|
newy = 0 // DON'T SCROLL when cursor goes ABOVE the screen
|
||||||
|
}
|
||||||
|
|
||||||
|
rawCursorPos = toTtyTextOffset(newx, newy)
|
||||||
}
|
}
|
||||||
private fun toTtyTextOffset(x: Int, y: Int) = y * TEXT_COLS + x
|
private fun toTtyTextOffset(x: Int, y: Int) = y * TEXT_COLS + x
|
||||||
|
|
||||||
@@ -80,6 +103,7 @@ class GraphicsAdapter(val lcdMode: Boolean = false) : GlassTty(Companion.TEXT_RO
|
|||||||
// -1 is preferred because it points to the colour CLEAR, and it's constant.
|
// -1 is preferred because it points to the colour CLEAR, and it's constant.
|
||||||
spriteAndTextArea.fillWith(-1)
|
spriteAndTextArea.fillWith(-1)
|
||||||
|
|
||||||
|
setCursorPos(0, 0)
|
||||||
|
|
||||||
println(framebuffer.pixels.limit())
|
println(framebuffer.pixels.limit())
|
||||||
}
|
}
|
||||||
@@ -194,6 +218,157 @@ class GraphicsAdapter(val lcdMode: Boolean = false) : GlassTty(Companion.TEXT_RO
|
|||||||
spriteAndTextArea[memTextOffset + textOff] = text
|
spriteAndTextArea[memTextOffset + textOff] = text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun cursorUp(arg: Int) {
|
||||||
|
val (x, y) = getCursorPos()
|
||||||
|
setCursorPos(x, y - arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun cursorDown(arg: Int) {
|
||||||
|
val (x, y) = getCursorPos()
|
||||||
|
val newy = y + arg
|
||||||
|
setCursorPos(x, if (newy >= TEXT_ROWS) TEXT_ROWS - 1 else newy)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun cursorFwd(arg: Int) {
|
||||||
|
val (x, y) = getCursorPos()
|
||||||
|
setCursorPos(x + arg, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun cursorBack(arg: Int) {
|
||||||
|
val (x, y) = getCursorPos()
|
||||||
|
setCursorPos(x - arg, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun cursorNextLine(arg: Int) {
|
||||||
|
val (_, y) = getCursorPos()
|
||||||
|
val newy = y + arg
|
||||||
|
setCursorPos(0, if (newy >= TEXT_ROWS) TEXT_ROWS - 1 else newy)
|
||||||
|
if (newy >= TEXT_ROWS) {
|
||||||
|
scrollUp(newy - TEXT_ROWS + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun cursorPrevLine(arg: Int) {
|
||||||
|
val (_, y) = getCursorPos()
|
||||||
|
setCursorPos(0, y - arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun cursorX(arg: Int) {
|
||||||
|
val (_, y) = getCursorPos()
|
||||||
|
setCursorPos(arg, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun eraseInDisp(arg: Int) {
|
||||||
|
when (arg) {
|
||||||
|
else -> TODO()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun eraseInLine(arg: Int) {
|
||||||
|
when (arg) {
|
||||||
|
else -> TODO()
|
||||||
|
} }
|
||||||
|
|
||||||
|
/** New lines are added at the bottom */
|
||||||
|
override fun scrollUp(arg: Int) {
|
||||||
|
//TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
/** New lines are added at the top */
|
||||||
|
override fun scrollDown(arg: Int) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sgrOneArg(arg: Int) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sgrTwoArg(arg1: Int, arg2: Int) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sgrThreeArg(arg1: Int, arg2: Int, arg3: Int) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The values are one-based
|
||||||
|
* @param arg1 y-position (row)
|
||||||
|
* @param arg2 x-position (column) */
|
||||||
|
override fun cursorXY(arg1: Int, arg2: Int) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun ringBell() {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun insertTab() {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun crlf() {
|
||||||
|
val (_, y) = getCursorPos()
|
||||||
|
val newy = y + 1
|
||||||
|
setCursorPos(0, if (newy >= TEXT_ROWS) TEXT_ROWS - 1 else newy)
|
||||||
|
if (newy >= TEXT_ROWS) scrollUp(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun backspace() {
|
||||||
|
val (x, y) = getCursorPos()
|
||||||
|
putChar(x, y, 0x20.toByte())
|
||||||
|
setCursorPos(x - 1, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var PRINTSTREAM_INSTANCE: OutputStream
|
||||||
|
private lateinit var ERRORSTREAM_INSTANCE: OutputStream
|
||||||
|
private lateinit var INPUTSTREAM_INSTANCE: InputStream
|
||||||
|
|
||||||
|
override fun getPrintStream(): OutputStream {
|
||||||
|
try {
|
||||||
|
return PRINTSTREAM_INSTANCE
|
||||||
|
}
|
||||||
|
catch (e: UninitializedPropertyAccessException) {
|
||||||
|
PRINTSTREAM_INSTANCE = object : OutputStream() {
|
||||||
|
override fun write(p0: Int) {
|
||||||
|
writeOut(p0.toByte())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PRINTSTREAM_INSTANCE
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getErrorStream(): OutputStream {
|
||||||
|
try {
|
||||||
|
return ERRORSTREAM_INSTANCE
|
||||||
|
}
|
||||||
|
catch (e: UninitializedPropertyAccessException) {
|
||||||
|
ERRORSTREAM_INSTANCE = object : OutputStream() {
|
||||||
|
private val SGI_RED = byteArrayOf(0x1B, 0x5B, 0x33, 0x31, 0x6D)
|
||||||
|
private val SGI_RESET = byteArrayOf(0x1B, 0x5B, 0x6D)
|
||||||
|
|
||||||
|
override fun write(p0: Int) {
|
||||||
|
SGI_RED.forEach { writeOut(it) }
|
||||||
|
writeOut(p0.toByte())
|
||||||
|
SGI_RESET.forEach { writeOut(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun write(p0: ByteArray) {
|
||||||
|
SGI_RED.forEach { writeOut(it) }
|
||||||
|
p0.forEach { writeOut(it) }
|
||||||
|
SGI_RESET.forEach { writeOut(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERRORSTREAM_INSTANCE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getInputStream(): InputStream {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
framebuffer.dispose()
|
framebuffer.dispose()
|
||||||
rendertex.dispose()
|
rendertex.dispose()
|
||||||
|
|||||||
Reference in New Issue
Block a user