mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 02:12:58 +08:00
feat: Device Status Report (DSR)
This commit is contained in:
@@ -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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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) {
|
||||||
|
|
||||||
|
|||||||
@@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user