diff --git a/src/main/kotlin/app/termora/PtyConnectorReader.kt b/src/main/kotlin/app/termora/PtyConnectorReader.kt index f92e906..faf8010 100644 --- a/src/main/kotlin/app/termora/PtyConnectorReader.kt +++ b/src/main/kotlin/app/termora/PtyConnectorReader.kt @@ -3,6 +3,7 @@ package app.termora import app.termora.terminal.PtyConnector import app.termora.terminal.Terminal import kotlinx.coroutines.delay +import org.slf4j.LoggerFactory import javax.swing.SwingUtilities import kotlin.time.Duration.Companion.milliseconds @@ -11,9 +12,14 @@ class PtyConnectorReader( private val terminal: Terminal, ) { + companion object { + private val log = LoggerFactory.getLogger(PtyConnectorReader::class.java) + } + suspend fun start() { var i: Int val buffer = CharArray(1024 * 8) + while ((ptyConnector.read(buffer).also { i = it }) != -1) { if (i == 0) { delay(10.milliseconds) @@ -22,6 +28,10 @@ class PtyConnectorReader( val text = String(buffer, 0, i) SwingUtilities.invokeLater { terminal.write(text) } } + + if (log.isDebugEnabled) { + log.debug("PtyConnectorReader stopped") + } } } \ No newline at end of file diff --git a/src/main/kotlin/app/termora/PtyHostTerminalTab.kt b/src/main/kotlin/app/termora/PtyHostTerminalTab.kt index 19c7e14..e9f0548 100644 --- a/src/main/kotlin/app/termora/PtyHostTerminalTab.kt +++ b/src/main/kotlin/app/termora/PtyHostTerminalTab.kt @@ -27,6 +27,10 @@ abstract class PtyHostTerminalTab( TerminalPanelFactory.getInstance(windowScope).createTerminalPanel(terminal, ptyConnectorDelegate) protected val ptyConnectorFactory get() = PtyConnectorFactory.getInstance(windowScope) + init { + terminal.getTerminalModel().setData(DataKey.PtyConnector, ptyConnectorDelegate) + } + override fun start() { coroutineScope.launch(Dispatchers.IO) { diff --git a/src/main/kotlin/app/termora/terminal/ControlSequenceIntroducerProcessor.kt b/src/main/kotlin/app/termora/terminal/ControlSequenceIntroducerProcessor.kt index 2107083..2318342 100644 --- a/src/main/kotlin/app/termora/terminal/ControlSequenceIntroducerProcessor.kt +++ b/src/main/kotlin/app/termora/terminal/ControlSequenceIntroducerProcessor.kt @@ -1,5 +1,6 @@ package app.termora.terminal +import app.termora.assertEventDispatchThread import org.slf4j.LoggerFactory import kotlin.math.max import kotlin.math.min @@ -13,7 +14,6 @@ class ControlSequenceIntroducerProcessor(terminal: Terminal, reader: TerminalRea companion object { private val log = LoggerFactory.getLogger(ControlSequenceIntroducerProcessor::class.java) - private val styles = hashMapOf() } // 非法字符,需要重排序 @@ -175,8 +175,9 @@ class ControlSequenceIntroducerProcessor(terminal: Terminal, reader: TerminalRea } } - // TODO Device Status Report (DSR). + // Device Status Report (DSR). 'n' -> { + processDeviceStatusReport() } // ECSI Ps J Erase in Display (ED), VT100. @@ -464,6 +465,33 @@ class ControlSequenceIntroducerProcessor(terminal: Terminal, reader: TerminalRea 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 */ @@ -580,7 +608,7 @@ class ControlSequenceIntroducerProcessor(terminal: Terminal, reader: TerminalRea 25 -> { terminalModel.setData(DataKey.ShowCursor, enable) 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 -> { if (log.isWarnEnabled) { - log.warn("Unknown SGR: $args") + log.warn("Unknown SGR: $mode") } } } diff --git a/src/main/kotlin/app/termora/terminal/DataKey.kt b/src/main/kotlin/app/termora/terminal/DataKey.kt index 5dd9dd2..8e99c93 100644 --- a/src/main/kotlin/app/termora/terminal/DataKey.kt +++ b/src/main/kotlin/app/termora/terminal/DataKey.kt @@ -180,6 +180,11 @@ class DataKey(val clazz: KClass) { * CSI Ps SP q Set cursor style (DECSCUSR), VT520. */ val CursorStyle = DataKey(app.termora.terminal.CursorStyle::class) + + /** + * Pty Connector + */ + val PtyConnector = DataKey(app.termora.terminal.PtyConnector::class) } } diff --git a/src/main/kotlin/app/termora/terminal/PtyProcessConnector.kt b/src/main/kotlin/app/termora/terminal/PtyProcessConnector.kt index 6d2b582..852c6e7 100644 --- a/src/main/kotlin/app/termora/terminal/PtyProcessConnector.kt +++ b/src/main/kotlin/app/termora/terminal/PtyProcessConnector.kt @@ -2,6 +2,7 @@ package app.termora.terminal import com.pty4j.PtyProcess import com.pty4j.WinSize +import org.apache.commons.io.IOUtils import java.io.InputStreamReader import java.nio.charset.Charset import java.nio.charset.StandardCharsets @@ -33,6 +34,7 @@ class PtyProcessConnector(private val process: PtyProcess, private val charset: } override fun close() { + IOUtils.closeQuietly(reader) process.destroyForcibly() }