我正在使用PTY库在ruby中编写终端模拟器。 /dev/tty0
是连接到键盘的设备文件。我像这样产生shell:
shell = PTY.spawn 'env TERM=ansi COLUMNS=63 LINES=21 sh -i < /dev/tty0'
它主要起作用,但是当在shell中启动子进程时,shell[0]
不会将键盘输入输出到该子进程。例如:当我通过"cat\nasdf"
发送shell[1]
时,"cat"
会通过shell[0]
返回,但"asdf"
则不会。为什么会发生这种情况,我该如何解决?
修改的:
这是我的代码。 ChumbyScreen
是一个外部模块,用于控制我为此编写的嵌入式设备的屏幕(称为“Chumby”)。 write
方法在屏幕上放置一个字符。
require 'pty'
def handle_escape(io)
actions = 'ABCDEFGHJKSTfmnsulh'
str, action = '', nil
loop do
c = io.read(1)
if actions.include? c
action = c
break
else
str += c
end
end
case action
when 'J'
ChumbyScreen.x = 0
end
end
system '[ -e /dev/tty0 ] || mknod /dev/tty0 c 4 0'
shell = PTY.spawn 'env TERM=ansi COLUMNS=63 LINES=21 sh -i < /dev/tty0'
loop do
c = shell[0].read(1)
if c == "\e"
c2 = shell[0].read(1)
if c2 == '['
handle_escape shell[0]
next
else
c += c2
end
end
ChumbyScreen.write c
end
在阅读了shodanex的回答后,我尝试了这个:
require 'pty'
def handle_escape(io)
actions = 'ABCDEFGHJKSTfmnsulh'
str, action = '', nil
loop do
c = io.read(1)
if actions.include? c
action = c
break
else
str += c
end
end
case action
when 'J'
ChumbyScreen.x = 0
end
end
system '[ -e /dev/tty0 ] || mknod /dev/tty0 c 4 0'
shell = PTY.spawn 'env TERM=ansi COLUMNS=63 LINES=21 sh -i'
Thread.new do
k = open '/dev/tty0', File::RDONLY
loop do
shell[1].write k.read(1)
end
end.priority = 1
loop do
c = shell[0].read(1)
if c == "\e"
c2 = shell[0].read(1)
if c2 == '['
handle_escape shell[0]
next
else
c += c2
end
end
ChumbyScreen.write c
end
它有效,但我输入的字符在我按下回车之前不显示。它必须以某种方式缓冲线 - 我如何通过它? Control-C和Control-D也不做任何事情。我需要他们发送eof并终止进程。
答案 0 :(得分:2)
tty输入模式默认为线路输入,因此在输出之前不会看到任何内容 换行。
我建议使用strace来调试此类行为。通过这种方式,您可以看到系统调用,例如,查看是否在等待更多输入的读取时被阻止等等。
当你不使用'&lt; / dev / tty0',它确实有效,对吗? 基本上,你想要的是对人物的回应。如果您执行以下操作:
shell = PTY.spawn 'env TERM=ansi COLUMNS=63 LINES=21 sh -i'
shell[1].puts("cat\nasdf")
s = shell[0].read(16)
puts s
你使用以下方法来处理这个过程:
strace -ff -o test.log -e trace=read,write ./testr.rb
在输出中,您将看到asdf两次。 但是如果你看一下strace代码,就会发现cat子进程只写了一次asdf,而它的父进程,即shell,从不写asdf。
那么为什么有两个'asdf'输出?因为tty层正在做本地回声。因此,当您在shell中键入内容时,它会转到pty和pty驱动程序:
那么当你做sh -i </dev/tty0
时会发生什么?来自键盘的字符将回显到/ dev / tty0,而不是回显到shell的输出。
shell没有做任何回声,tty层是,所以你要做的就是下面的(把它作为伪代码,我不能胜任红宝石):
# Emulate terminal behavior with pty
shell = PTY.spawn 'env TERM=ansi COLUMNS=63 LINES=21 sh -i'
keyboard = open(/dev/tty0)
input = keyboard.read()
shell[1].write(input)
puts shell[0].read(...)
现在,如果你想要一些交互式的东西,你需要在原始模式下配置/ dev / tty0,并使用select来知道什么时候你可以不受阻塞地读取,以及何时有可用于输出的数据。
要在原始模式下配置tty,您可以尝试使用
stty -F /dev/tty0 -cooked