mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 02:12:58 +08:00
feat: telnet character mode
This commit is contained in:
@@ -2,18 +2,15 @@ package app.termora.plugin.internal.telnet
|
||||
|
||||
import app.termora.*
|
||||
import app.termora.account.AccountOwner
|
||||
import app.termora.keymgr.KeyManager
|
||||
import app.termora.plugin.internal.BasicProxyOption
|
||||
import com.formdev.flatlaf.FlatClientProperties
|
||||
import com.formdev.flatlaf.extras.components.FlatComboBox
|
||||
import com.formdev.flatlaf.ui.FlatTextBorder
|
||||
import com.jgoodies.forms.builder.FormBuilder
|
||||
import com.jgoodies.forms.layout.FormLayout
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Component
|
||||
import java.awt.KeyboardFocusManager
|
||||
import java.awt.Window
|
||||
import java.awt.event.ComponentAdapter
|
||||
import java.awt.event.ComponentEvent
|
||||
import java.nio.charset.Charset
|
||||
@@ -25,7 +22,6 @@ class TelnetHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPan
|
||||
// telnet 不支持代理密码
|
||||
private val proxyOption = BasicProxyOption(authenticationTypes = listOf())
|
||||
private val terminalOption = TerminalOption()
|
||||
private val owner: Window get() = SwingUtilities.getWindowAncestor(this)
|
||||
|
||||
init {
|
||||
addOption(generalOption)
|
||||
@@ -69,7 +65,10 @@ class TelnetHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPan
|
||||
env = terminalOption.environmentTextArea.text,
|
||||
startupCommand = terminalOption.startupCommandTextField.text,
|
||||
serialComm = serialComm,
|
||||
extras = mutableMapOf("backspace" to (terminalOption.backspaceComboBox.selectedItem as Backspace).name)
|
||||
extras = mutableMapOf(
|
||||
"backspace" to (terminalOption.backspaceComboBox.selectedItem as Backspace).name,
|
||||
"character-at-a-time" to (terminalOption.characterAtATimeTextField.selectedItem?.toString() ?: "false")
|
||||
)
|
||||
)
|
||||
|
||||
return Host(
|
||||
@@ -108,6 +107,8 @@ class TelnetHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPan
|
||||
terminalOption.startupCommandTextField.text = host.options.startupCommand
|
||||
terminalOption.backspaceComboBox.selectedItem =
|
||||
Backspace.valueOf(host.options.extras["backspace"] ?: Backspace.Delete.name)
|
||||
terminalOption.characterAtATimeTextField.selectedItem =
|
||||
host.options.extras["character-at-a-time"]?.toBooleanStrictOrNull() ?: false
|
||||
|
||||
}
|
||||
|
||||
@@ -186,7 +187,6 @@ class TelnetHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPan
|
||||
val usernameTextField = OutlineTextField(128)
|
||||
val hostTextField = OutlineTextField(255)
|
||||
val passwordTextField = OutlinePasswordField(255)
|
||||
val publicKeyComboBox = OutlineComboBox<String>()
|
||||
val remarkTextArea = FixedLengthTextArea(512)
|
||||
val authenticationTypeComboBox = FlatComboBox<AuthenticationType>()
|
||||
|
||||
@@ -198,30 +198,6 @@ class TelnetHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPan
|
||||
private fun initView() {
|
||||
add(getCenterComponent(), BorderLayout.CENTER)
|
||||
|
||||
publicKeyComboBox.isEditable = false
|
||||
|
||||
publicKeyComboBox.renderer = object : DefaultListCellRenderer() {
|
||||
override fun getListCellRendererComponent(
|
||||
list: JList<*>?,
|
||||
value: Any?,
|
||||
index: Int,
|
||||
isSelected: Boolean,
|
||||
cellHasFocus: Boolean
|
||||
): Component {
|
||||
var text = StringUtils.EMPTY
|
||||
if (value is String) {
|
||||
text = KeyManager.getInstance().getOhKeyPair(value)?.name ?: text
|
||||
}
|
||||
return super.getListCellRendererComponent(
|
||||
list,
|
||||
text,
|
||||
index,
|
||||
isSelected,
|
||||
cellHasFocus
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
authenticationTypeComboBox.renderer = object : DefaultListCellRenderer() {
|
||||
override fun getListCellRendererComponent(
|
||||
list: JList<*>?,
|
||||
@@ -340,6 +316,7 @@ class TelnetHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPan
|
||||
val charsetComboBox = JComboBox<String>()
|
||||
val backspaceComboBox = JComboBox<Backspace>()
|
||||
val startupCommandTextField = OutlineTextField()
|
||||
val characterAtATimeTextField = YesOrNoComboBox()
|
||||
val environmentTextArea = FixedLengthTextArea(2048)
|
||||
|
||||
|
||||
@@ -355,6 +332,7 @@ class TelnetHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPan
|
||||
backspaceComboBox.addItem(Backspace.Backspace)
|
||||
backspaceComboBox.addItem(Backspace.VT220)
|
||||
|
||||
characterAtATimeTextField.selectedItem = false
|
||||
|
||||
environmentTextArea.setFocusTraversalKeys(
|
||||
KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
|
||||
@@ -409,6 +387,8 @@ class TelnetHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPan
|
||||
.add(charsetComboBox).xy(3, rows).apply { rows += step }
|
||||
.add("${I18n.getString("termora.new-host.terminal.backspace")}:").xy(1, rows)
|
||||
.add(backspaceComboBox).xy(3, rows).apply { rows += step }
|
||||
.add("${I18n.getString("termora.new-host.terminal.character-mode")}:").xy(1, rows)
|
||||
.add(characterAtATimeTextField).xy(3, rows).apply { rows += step }
|
||||
.add("${I18n.getString("termora.new-host.terminal.startup-commands")}:").xy(1, rows)
|
||||
.add(startupCommandTextField).xy(3, rows).apply { rows += step }
|
||||
.add("${I18n.getString("termora.new-host.terminal.env")}:").xy(1, rows)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package app.termora.plugin.internal.telnet
|
||||
|
||||
import app.termora.terminal.StreamPtyConnector
|
||||
import org.apache.commons.io.IOUtils
|
||||
import org.apache.commons.net.telnet.TelnetClient
|
||||
import org.apache.commons.net.telnet.TelnetOption
|
||||
import org.apache.commons.net.telnet.WindowSizeOptionHandler
|
||||
@@ -9,18 +10,27 @@ import java.nio.charset.Charset
|
||||
|
||||
class TelnetStreamPtyConnector(
|
||||
private val telnet: TelnetClient,
|
||||
private val charset: Charset
|
||||
) :
|
||||
StreamPtyConnector(telnet.inputStream, telnet.outputStream) {
|
||||
private val reader = InputStreamReader(telnet.inputStream, getCharset())
|
||||
private val charset: Charset,
|
||||
private val characterMode: Boolean,
|
||||
) : StreamPtyConnector(telnet.inputStream, telnet.outputStream) {
|
||||
|
||||
private val reader = InputStreamReader(telnet.inputStream, charset)
|
||||
|
||||
|
||||
override fun read(buffer: CharArray): Int {
|
||||
return reader.read(buffer)
|
||||
}
|
||||
|
||||
override fun write(buffer: ByteArray, offset: Int, len: Int) {
|
||||
output.write(buffer, offset, len)
|
||||
output.flush()
|
||||
if (characterMode) {
|
||||
for (i in offset until len + offset) {
|
||||
output.write(byteArrayOf(buffer[i]))
|
||||
output.flush()
|
||||
}
|
||||
} else {
|
||||
output.write(buffer, offset, len)
|
||||
output.flush()
|
||||
}
|
||||
}
|
||||
|
||||
override fun resize(rows: Int, cols: Int) {
|
||||
@@ -33,10 +43,13 @@ class TelnetStreamPtyConnector(
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
IOUtils.closeQuietly(input)
|
||||
IOUtils.closeQuietly(output)
|
||||
telnet.disconnect()
|
||||
}
|
||||
|
||||
override fun getCharset(): Charset {
|
||||
return charset
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import java.net.InetSocketAddress
|
||||
import java.net.Proxy
|
||||
import java.nio.charset.Charset
|
||||
|
||||
|
||||
class TelnetTerminalTab(
|
||||
windowScope: WindowScope, host: Host,
|
||||
) : PtyHostTerminalTab(windowScope, host) {
|
||||
@@ -32,12 +33,18 @@ class TelnetTerminalTab(
|
||||
)
|
||||
}
|
||||
|
||||
val characterMode = host.options.extras["character-at-a-time"]?.toBooleanStrictOrNull() ?: false
|
||||
|
||||
val termtype = host.options.envs()["TERM"] ?: "xterm-256color"
|
||||
val ttopt = TerminalTypeOptionHandler(termtype, false, false, true, false)
|
||||
val echoopt = EchoOptionHandler(false, true, false, true)
|
||||
val gaopt = SuppressGAOptionHandler(true, true, true, true)
|
||||
val wsopt = WindowSizeOptionHandler(winSize.cols, winSize.rows, true, false, true, false)
|
||||
val bopt = SimpleOptionHandler(TelnetOption.BINARY, true, false, true, false)
|
||||
val fcopt = SimpleOptionHandler(TelnetOption.REMOTE_FLOW_CONTROL, true, true, false, false)
|
||||
|
||||
telnet.addOptionHandler(bopt)
|
||||
telnet.addOptionHandler(fcopt)
|
||||
telnet.addOptionHandler(ttopt)
|
||||
telnet.addOptionHandler(echoopt)
|
||||
telnet.addOptionHandler(gaopt)
|
||||
@@ -45,6 +52,7 @@ class TelnetTerminalTab(
|
||||
|
||||
telnet.connect(host.host, host.port)
|
||||
telnet.keepAlive = true
|
||||
telnet.tcpNoDelay = characterMode
|
||||
|
||||
val encoder = terminal.getKeyEncoder()
|
||||
if (encoder is KeyEncoderImpl) {
|
||||
@@ -56,7 +64,8 @@ class TelnetTerminalTab(
|
||||
}
|
||||
}
|
||||
|
||||
return ptyConnectorFactory.decorate(TelnetStreamPtyConnector(telnet, telnet.charset))
|
||||
|
||||
return ptyConnectorFactory.decorate(TelnetStreamPtyConnector(telnet, telnet.charset, characterMode))
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -182,6 +182,7 @@ termora.new-host.proxy=Proxy
|
||||
termora.new-host.terminal=${termora.settings.terminal}
|
||||
termora.new-host.terminal.encoding=Encoding
|
||||
termora.new-host.terminal.backspace=Backspace
|
||||
termora.new-host.terminal.character-mode=Character-at-a-time
|
||||
termora.new-host.terminal.heartbeat-interval=Heartbeat Interval
|
||||
termora.new-host.terminal.startup-commands=Startup Command
|
||||
termora.new-host.terminal.env=Environment
|
||||
|
||||
@@ -174,6 +174,7 @@ termora.new-host.proxy=代理
|
||||
termora.new-host.terminal=${termora.settings.terminal}
|
||||
termora.new-host.terminal.encoding=编码
|
||||
termora.new-host.terminal.backspace=退格键
|
||||
termora.new-host.terminal.character-mode=单字符模式
|
||||
termora.new-host.terminal.heartbeat-interval=心跳间隔
|
||||
termora.new-host.terminal.startup-commands=启动命令
|
||||
termora.new-host.terminal.env=环境
|
||||
|
||||
@@ -172,6 +172,7 @@ termora.new-host.proxy=代理
|
||||
termora.new-host.terminal=${termora.settings.terminal}
|
||||
termora.new-host.terminal.encoding=編碼
|
||||
termora.new-host.terminal.backspace=退格鍵
|
||||
termora.new-host.terminal.character-mode=單字元模式
|
||||
termora.new-host.terminal.startup-commands=啟動命令
|
||||
termora.new-host.terminal.heartbeat-interval=心跳間隔
|
||||
termora.new-host.terminal.env=環境
|
||||
|
||||
Reference in New Issue
Block a user