ncurses アプリケーションから呼び出されたスクリプトの出力内のエスケープ シーケンス

ncurses アプリケーションから呼び出されたスクリプトの出力内のエスケープ シーケンス

現在、ホームサーバーの tmux セッションで、mcabber を Jabber クライアント (ncurses を使用) として実行しています。ローカルでは、文字エスケープ シーケンスによる growl 通知のトリガーをサポートする iTerm2 をターミナル エミュレーターとして実行しています。

注:echoこの質問の はすべて、 bash および GNU の 、printf %bまたは のように機能します。echo -eecho

たとえば、echo "\e]9;foobar\007"iTerm2 は「foobar」というテキストを含む Growl メッセージを送信します。

ただし、tmux セッションでは、エスケープ シーケンスが消費されます。そのため、独自の文字エスケープ シーケンスを\Ptmux次のように使用できます。

echo "\ePtmux;\e\e]9;foobar\007\e\\"

これにより、tmux セッション内から growl メッセージがトリガーされます。

ただし、新しいメッセージが受信されたときに起動される mcabber イベント スクリプトでこれを使用すると、エコーが間違った端末に送信されたかのように通知がトリガーされません。

これは、スクリプトをトリガーする mcabber が ncurses アプリケーションであるため、通常の bash スクリプトからの出力が失われ、iTerm 2 がそれを認識できないことに関係していると思います。

私はまた、私が発見したいくつかのアイデアに従ってエコーする前に、smcupを呼び出して成功しませんでした

tput smcup
echo "\ePtmux;\e\e]9;$FROM: $MSG\007\e\\"
tput rmcup

問題は「実際のターミナル ウィンドウ」に戻ることではなく、出力を ncurses ウィンドウに向けることにあるため、これは機能しないと思われます。

これについて何かアイデアはありますか?

答え1

イベントスクリプトが「グロウラー」メッセージを送信できない理由は、mcabber標準入力を閉じ、出力イベントコマンドを実行するとエラーストリームが発生します。これは次のようになります。hooks.c:

  if ((pid=fork()) == -1) {
    scr_LogPrint(LPRINT_LOGNORM, "Fork error, cannot launch external command.");
    g_free(datafname);
    return;   
  }    
  if (pid == 0) { // child
    // Close standard file descriptors
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);
    if (execl(extcmd, extcmd, arg_type, arg_info, bjid, arg_data,
              (char *)NULL) == -1) {
      // scr_LogPrint(LPRINT_LOGNORM, "Cannot execute external command.");
      exit(1);
    }
  }
  g_free(datafname);

これにより、イベントスクリプトは、mcabber

メッセージを傍受する特別なncursesモードはありません(結局のところtmuxすでにechoterminfo アプリケーションとして実行中)。おそらく、 (できればprintf) を にリダイレクトすることで問題を回避できるでしょう/dev/tty。たとえば、

#!/bin/sh
printf '\033Ptmux;\033\033]9;foobar\007\033\\' >/dev/tty

答え2

tmux および screen プログラムは、エスケープ シーケンスを直接渡しません。アプリケーションに 1 種類のターミナル (screen ターミナル タイプ) を提示し、それ自体が別のターミナルに対する ncurses アプリケーションです。実質的には、ターミナル トランスレータのようなものです。つまり、"screen" ターミナル タイプのシーケンスを消費 (または破棄) し、表示されるバッファーを作成します。次に、それらのバッファー変更イベントを取得し、現在使用しているターミナルの種類を使用して現在のバッファーを表示します。そのため、元のアプリと表示ターミナルは分離されています。

答え3

たとえば次のようなものを置くとします...

export "PTTY=$(tty)"

.../etc/profileその後、新しい-lOginシェルを呼び出すたびに(これは、新しいターミナル ウィンドウを開いたときに通常発生することです)tmuxその環境変数は、そのすべての子プロセス(そのすべての子を含む)で使用できるようになります。

これにより、次のことが可能になります...

printf '\033]9;foobar\007' >"$PTTY"

...これにより、pty現在のシェルと使用しているターミナル エミュレーターの間に存在する可能性のあるすべてのレイヤーをスキップします。

答え4

bash スクリプトからの出力が失われることが問題である場合は、リダイレクトによって解決できます。

echo "\ePtmux;\e\e]9;foobar\007\e\" > /dev/tty

しかし、実際の問題は、echo -ebash が文字列内のエスケープ シーケンスを処理できるように、 を使用する必要があるということだと思います。

関連情報