feat: Device Status Report (DSR)

This commit is contained in:
hstyi
2025-01-22 15:31:15 +08:00
committed by hstyi
parent d5157d3a16
commit d6de0922c6
5 changed files with 53 additions and 4 deletions

View File

@@ -3,6 +3,7 @@ package app.termora
import app.termora.terminal.PtyConnector import app.termora.terminal.PtyConnector
import app.termora.terminal.Terminal import app.termora.terminal.Terminal
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import org.slf4j.LoggerFactory
import javax.swing.SwingUtilities import javax.swing.SwingUtilities
import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.milliseconds
@@ -11,9 +12,14 @@ class PtyConnectorReader(
private val terminal: Terminal, private val terminal: Terminal,
) { ) {
companion object {
private val log = LoggerFactory.getLogger(PtyConnectorReader::class.java)
}
suspend fun start() { suspend fun start() {
var i: Int var i: Int
val buffer = CharArray(1024 * 8) val buffer = CharArray(1024 * 8)
while ((ptyConnector.read(buffer).also { i = it }) != -1) { while ((ptyConnector.read(buffer).also { i = it }) != -1) {
if (i == 0) { if (i == 0) {
delay(10.milliseconds) delay(10.milliseconds)
@@ -22,6 +28,10 @@ class PtyConnectorReader(
val text = String(buffer, 0, i) val text = String(buffer, 0, i)
SwingUtilities.invokeLater { terminal.write(text) } SwingUtilities.invokeLater { terminal.write(text) }
} }
if (log.isDebugEnabled) {
log.debug("PtyConnectorReader stopped")
}
} }
} }

View File

@@ -27,6 +27,10 @@ abstract class PtyHostTerminalTab(
TerminalPanelFactory.getInstance(windowScope).createTerminalPanel(terminal, ptyConnectorDelegate) TerminalPanelFactory.getInstance(windowScope).createTerminalPanel(terminal, ptyConnectorDelegate)
protected val ptyConnectorFactory get() = PtyConnectorFactory.getInstance(windowScope) protected val ptyConnectorFactory get() = PtyConnectorFactory.getInstance(windowScope)
init {
terminal.getTerminalModel().setData(DataKey.PtyConnector, ptyConnectorDelegate)
}
override fun start() { override fun start() {
coroutineScope.launch(Dispatchers.IO) { coroutineScope.launch(Dispatchers.IO) {

View File

@@ -1,5 +1,6 @@
package app.termora.terminal package app.termora.terminal
import app.termora.assertEventDispatchThread
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
@@ -13,7 +14,6 @@ class ControlSequenceIntroducerProcessor(terminal: Terminal, reader: TerminalRea
companion object { companion object {
private val log = LoggerFactory.getLogger(ControlSequenceIntroducerProcessor::class.java) private val log = LoggerFactory.getLogger(ControlSequenceIntroducerProcessor::class.java)
private val styles = hashMapOf<TextStyle, TextStyle>()
} }
// 非法字符,需要重排序 // 非法字符,需要重排序
@@ -175,8 +175,9 @@ class ControlSequenceIntroducerProcessor(terminal: Terminal, reader: TerminalRea
} }
} }
// TODO Device Status Report (DSR). // Device Status Report (DSR).
'n' -> { 'n' -> {
processDeviceStatusReport()
} }
// ECSI Ps J Erase in Display (ED), VT100. // ECSI Ps J Erase in Display (ED), VT100.
@@ -464,6 +465,33 @@ class ControlSequenceIntroducerProcessor(terminal: Terminal, reader: TerminalRea
return false return false
} }
private fun processDeviceStatusReport() {
assertEventDispatchThread()
if (args.startsWithQuestionMark()) {
if (log.isWarnEnabled) {
log.warn("Don't support DEC-specific Device Report Status")
}
return
}
if (!terminalModel.hasData(DataKey.PtyConnector)) {
return
}
val ptyConnector = terminalModel.getData(DataKey.PtyConnector)
val m = args.first()
if (m == '6') {
val position = terminal.getCursorModel().getPosition()
ptyConnector.write("${ControlCharacters.ESC}[${position.y};${position.x}R")
} else if (m == '5') {
ptyConnector.write("${ControlCharacters.ESC}[0n")
}
}
/** /**
* https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-?-Pm-h.1D0E * https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-?-Pm-h.1D0E
*/ */
@@ -580,7 +608,7 @@ class ControlSequenceIntroducerProcessor(terminal: Terminal, reader: TerminalRea
25 -> { 25 -> {
terminalModel.setData(DataKey.ShowCursor, enable) terminalModel.setData(DataKey.ShowCursor, enable)
if (log.isDebugEnabled) { if (log.isDebugEnabled) {
log.debug("Blinking cursor $enable") log.debug("Hide cursor (DECTCEM) $enable")
} }
} }
@@ -929,7 +957,7 @@ class ControlSequenceIntroducerProcessor(terminal: Terminal, reader: TerminalRea
else -> { else -> {
if (log.isWarnEnabled) { if (log.isWarnEnabled) {
log.warn("Unknown SGR: $args") log.warn("Unknown SGR: $mode")
} }
} }
} }

View File

@@ -180,6 +180,11 @@ class DataKey<T : Any>(val clazz: KClass<T>) {
* CSI Ps SP q Set cursor style (DECSCUSR), VT520. * CSI Ps SP q Set cursor style (DECSCUSR), VT520.
*/ */
val CursorStyle = DataKey(app.termora.terminal.CursorStyle::class) val CursorStyle = DataKey(app.termora.terminal.CursorStyle::class)
/**
* Pty Connector
*/
val PtyConnector = DataKey(app.termora.terminal.PtyConnector::class)
} }
} }

View File

@@ -2,6 +2,7 @@ package app.termora.terminal
import com.pty4j.PtyProcess import com.pty4j.PtyProcess
import com.pty4j.WinSize import com.pty4j.WinSize
import org.apache.commons.io.IOUtils
import java.io.InputStreamReader import java.io.InputStreamReader
import java.nio.charset.Charset import java.nio.charset.Charset
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
@@ -33,6 +34,7 @@ class PtyProcessConnector(private val process: PtyProcess, private val charset:
} }
override fun close() { override fun close() {
IOUtils.closeQuietly(reader)
process.destroyForcibly() process.destroyForcibly()
} }