5

NCURSES プログラムと対話しようとしています。

例として、私は GNU Screen を使用しており、内部で aptitude を実行しています。(代わりに mc で試すことができます。)

以下のプログラムは、私のセッションに接続するために -x で screen セッションを開始します。

下向き矢印と上向き矢印を押してナビゲートしたい。

終了するために「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. なぜ適切ではないのか疑問に思っています。TERM=xterm を TERM=ansi に変更して修正しました。なぜ xterm が機能しないのか、いまだに困惑しています。

4

3 に答える 3

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'

于 2013-06-12T15:04:58.460 に答える
2

特定の端末機能のコードを取得する良い方法は、オプション付きtputの特定の端末タイプのコマンドを使用することです。-T

Python では、cursesモジュールを使用して正しいコードを取得します。

from curses import *
setupterm('xterm')

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

を起動すると、利用可能な機能について読むことができますman terminfo。上記の例は、目的のキー コードを取得するsavetty()前後にsetupterm必要にresetty()なる場合があります。そうしないと、端末が悪い状態のままになる可能性があります。Cでは、エラー時に端末をリセットするために、いくつかの終了ハンドラにもそれを含めるのは良いことでしたが、Pythonモジュールはそれを独自に処理する場合があります。

この方法は、端末コードをハードコーディングするのとは対照的に、xtermのterminfoが現在の Linux ディストリビューションのものとは異なる可能性があるシステム間で移植できるという利点があります。

于 2013-06-13T15:42:09.977 に答える