如何与假装成终端的子进程进行交互?

时间:2013-06-09 02:18:04

标签: python twisted

我正在尝试与NCURSES计划互动。

作为一个例子,我正在使用GNU Screen并在内部运行aptitude。 (你可以用mc来试试。)

以下程序使用-x启动屏幕会话以连接到我的会话。

我想通过按向下箭头和向上箭头来导航。

如果我发送'q'退出,我会在其他屏幕会话中弹出一个框。

我需要做些什么才能获得箭头键等特殊键?

目前似乎忽略了我发送的VT102序列。

from twisted.internet import protocol, reactor

class MyPP(protocol.ProcessProtocol):
    def connectionMade(self):
        reactor.callLater(1.0, self.foo)

    def foo(self):
        self.transport.write('\033[B')

    def processExited(self, reason):
        print "processExited, status %s" % (reason.value.exitCode,)

    def outReceived(self, data):
        print data

    def errReceived(self, data):
        print "errReceived!", data

pp = MyPP()
command = ['screen', '-x']
reactor.spawnProcess(pp, command[0], command, {'TERM':'xterm'}, usePTY=True)

reactor.run()

更新

  1. Ted告诉我用ESC [A(向上)和ESC [B(向下)与bash一起行走在命令历史中。

  2. 想知道为什么在aptitude中我没有将TERM = xterm更改为TERM = ansi修复它。为什么xterm不起作用仍困扰着我。

3 个答案:

答案 0 :(得分:2)

  

我已将TERM = xterm更改为TERM = ansi修复了它。为什么xterm没有   工作仍困扰着我。

使用Ubuntu 13.04,看起来ansixterm控件代码不完全相同。

$ infocmp ansi | grep cud
        cr=^M, cub=\E[%p1%dD, cub1=\E[D, cud=\E[%p1%dB, cud1=\E[B,
        kcud1=\E[B, kcuf1=\E[C, kcuu1=\E[A, khome=\E[H, kich1=\E[L,

$ infocmp xterm | grep cud
        cud=\E[%p1%dB, cud1=^J, cuf=\E[%p1%dC, cuf1=\E[C,
        kcub1=\EOD, kcud1=\EOB, kcuf1=\EOC, kcuu1=\EOA,

...所以看起来您需要发送字符串'\033OB'来模拟带有xterm的向下箭头。

以下代码适用于我......

import subprocess
import os
import time

# Set TERM=xterm in case it isn't already
os.environ['TERM'] = 'xterm'

# Spawn aptitude
p = subprocess.Popen('aptitude', stdin=subprocess.PIPE)

# Wait for a bit to let it load from cache
time.sleep(5)

# Control it using xterm control codes
p.stdin.write('\033OB') # arrow down
time.sleep(1)
p.stdin.write('\033OB') # arrow down
time.sleep(1)
p.stdin.write('\033OA') # arrow up
time.sleep(1)
p.stdin.write('\033OA') # arrow up
time.sleep(1)
p.stdin.write('q')      # quit
time.sleep(1)
p.stdin.write('y')      # confirm

......虽然它在完成后搞砸了我的终端,所以我不得不这样做......

$ stty sane

...让它再次运作。


<强>更新

刚刚找到了确定正确控制代码的更简单方法。如果您加载vi,请进入插入模式,然后按CTRL-V,然后按您想要模拟的密钥,它会显示从终端发送的文字字符串。

例如......

Down Arrow: ^[OB

Page Up: ^[[5~

...其中^[CTRL-[,即'\033'

答案 1 :(得分:2)

获取特定终端功能代码的一种好方法是使用tput命令,对于某些具有-T选项的特定终端类型。

在Python中,使用curses模块获取正确的代码:

from curses import *
setupterm('xterm')

key_up = tigetstr("kcuul")
key_down = tigetstr("kcudl")

您可以通过启动man terminfo来了解可用功能。在获得您感兴趣的密钥代码后,上述示例可能需要savetty()之前的setuptermresetty()。否则,您的终端可能会留在错误的中州。在C中,最好在某些退出处理程序中使用它,以便在出错时重置终端,但Python模块可以自己处理它。

与硬编码终端代码相比,此方法具有可在系统之间移植的优势,其中 xterm terminfo 可能与当前Linux发行版上的 terminfo 不同

答案 2 :(得分:0)

像Pexpect这样的东西可能在这里很有用:

https://pypi.python.org/pypi/pexpect

它是Expect的python实现,它基本上监视输入并基于模式执行操作,就像一个人坐在那里与应用程序交互一样。