web-dev-qa-db-ja.com

'backward-kill-line'をCtrl + Shift + Backspaceにキーバインドする方法は?

zsh kill Ctrl + Backspace、Ctrl + Delete の回答を使用して、次のキーバインディングを構成しました。

  • Ctrl+Backspace:現在のWordの先頭まで削除します。
  • Ctrl+Delete:現在のWordの終わりまで削除します。
  • Ctrl+Shift+Delete:行末まで削除します。

これは、次のコマンドを使用して実行されています。

$ bindkey -M emacs '^[[3;5~' kill-Word
$ bindkey -M emacs '^H' backward-kill-Word 
$ bindkey -M emacs '^[[3;6~' kill-line  

キー(つまり、^[[3;5~部分)をエンコードする方法を知るために、私は答えに詳述されている「トリック」を使用しました: "タイプ Ctrl+CCtrl+Delete システムの値を確認する」

問題

バインドしたい Ctrl+Shift+Backspacebackward-kill-lineコマンドに移動します(つまり、カーソルと行の先頭の間のすべてを削除します)。

しかし、私がタイプするとき Ctrl+CCtrl+Shift+Backspace、プロンプトには^Hのみが表示されます—つまり、と同じキーの組み合わせ Ctrl+Backspace

1
ebosi

お使いの端末は、同じエスケープシーケンスを送信します Ctrl+Shift+Backspace はどうかと言うと Ctrl+Backspace、したがって、zshが2つを区別する方法はありません。唯一の解決策は、さまざまなエスケープシーケンスを送信するように端末を構成することです。すべての端末がこれを許可しているわけではありません。

Xterm、rxvt、iTerm2、Emacs termなどの一部の端末では、各キーコードのエスケープシーケンスを手動で構成できます。端末のドキュメントを参照してください。

たとえば、xtermの場合、以下のスニペットを.Xresourcesに配置できます。 xrdb -merge ~/.Xresourcesでロードします。多くの環境では、ログイン時にこれが読み込まれます。そうでない場合は、このコマンドをX11スタートアップファイルに追加します。

XTerm.VT100.translations: #override \
    Ctrl Shift <Key>BackSpace: string("\033[27;6;8~") \n

次に、このエスケープシーケンスを使用できます¹:

bindkey -M emacs '^[[27;6;8~' backward-kill-Word 

Gnome-terminal、Guake、Terminatorなど、 vte に基づく端末では、運が悪いです。キーバインディングを構成する方法はありません。 彼らは特定のキーのアドホックサポートを追加することをいとわないかもしれません しかし。

¹ xtermのmodifyOtherKeysモード と互換性があるようにこのシーケンスを選択しました。通常はmodifyOtherKeysを有効にすることをお勧めします。これはほとんど下位互換性がありますが、必要な特定のキーコードはレベル2でのみ有効になり、対処するのが面倒です(たとえば、Ctrl +文字が送信されない対応する制御文字)。

X11ターミナルエミュレータを使用する場合 Ctrl+Shift+Backspace と同じものを送信します Backspace そしてそれはそれを変更する方法を提供しません(そしてあなたが必死なら)、ダーティハックとしてあなたはターミナルエミュレータとXサーバー間の通信をハイジャックすることができます、そして例えば置き換える Backspace (キーコード22)と F12 (キーボード96)X11イベントメッセージで、次の場合にターミナルエミュレータに送信されます。 Backspace が押されている間 Shift そして Ctrl 開催中です。

ちなみに、zshは、UnixドメインとTCPソケットAPIを組み込んでいるため、比較的簡単です。以下のスクリプトを次のように実行します。

that-script guake

そして、あなたの~/.zshrcに追加します

if [ -n "$WRAPPED_DISPLAY" ]; then
  export DISPLAY="$WRAPPED_DISPLAY"
  unset DISPLAY
fi

(その端末内で開始された他のアプリケーションがそのラッパーを通過するのを避けるため)。

そしてバインド:

bindkey -M emacs '^[[24;6~' backward-kill-Word

ここで、\e[24;6~は、を押したときに送信されるシーケンスです。 Ctrl+Shift+F12 VTEと少なくともxtermでは。

#! /bin/zsh -

die() {
  (($# == 0)) || print -ru2 -- "$@"
  exit 1
}

case $DISPLAY in
  (:<->(.<->|))
    mode=unix;;
  ((localhost|127.0.0.1|"[::1]"):<->(.<->|))
    mode=tcp
    zmodload zsh/net/tcp || die;;
  (*)
    die "Unsupported display: $DISPLAY";;
esac

conn=${DISPLAY##*:}
port=${conn%%.*}
screennumber=${conn#$port}
(($# > 0)) || argv=(gnome-terminal --wait)

unset -v listen_fd
typeset -A clients

tcp_connect() ztcp -v localhost $((port + 6000))
unix_connect() zsocket /tmp/.X11-unix/X$port

zmodload zsh/net/socket || die
zmodload zsh/system || die
zmodload zsh/zselect || die

new_port=20
until
  new_socket_path=/tmp/.X11-unix/X$new_port
  zsocket -l $new_socket_path 2> /dev/null
do
  ((new_port++))
done
listen_fd=$REPLY

unset -v pid
trap '
  kill "$pid" 2> /dev/null
  wait "$pid"; ret=$?
  rm -f $new_socket_path
  exit "$ret"' EXIT INT TERM HUP
{
  coproc {
    export WRAPPED_DISPLAY=$DISPLAY DISPLAY=:$new_port$screennumber
    xauth list "$WRAPPED_DISPLAY" |
      awk '{$1 = "add " ENVIRON["DISPLAY"];print}' |
      xauth -q -
    "$@" <&3 3>&1 >&4 4>&- {listen_fd}<&-
  }
} 3<&0 4>&1
pid=$!
exec {child_monitor}<&p
coproc :

LC_ALL=C
set -o extendedglob

tear() {
  exec {1}>&- {2}>&-
  unset "clients[$1]"
}

typeset -A ready
while zselect -A ready -r $listen_fd $child_monitor ${(kv)clients}; do
  [[ $ready[$child_monitor] ]] && exit
  if [[ $ready[$listen_fd] ]]; then
    zsocket -a $listen_fd || die
    fd=$REPLY
    ${mode}_connect || die
    clients[$fd]=$REPLY
  fi
  for client server (${(kv)clients}) {
    for from fdin fdout (
      client $client $server
      server $server $client
    ) if [[ $ready[$fdin] ]]; then
        if sysread -s 65536 -i $fdin buf; then
          if [[ $from = server ]]; then
            if [[ $buf[1,2] = $'\x23\x83' ]]; then
              offsets=(9 17 73) # Generic XInputExtension Event 
            else
              offsets=(1 2 29)  # Normal Event
            fi
            if
              [[ $buf[offsets[1]] = ($'\x2'|$'\x3') ]] && # KeyPress or KeyRelease
                [[ $buf[offsets[2]] = $'\x16' ]] && # keycode 22, Backspace
                printf -v modifiers %d "'$buf[offsets[3]]" &&
                ((modifiers & 5 == 5)) # Shift+Ctrl
            then
              buf[offsets[2]]=$'\x60' # keycode 96, F12
            fi
          fi
          syswrite -o $fdout -- $buf || tear $client $server
        else
          tear $client $server
        fi
      fi
  }
done

そこでは完全なX11プロトコルの解釈を行っておらず、keypressイベントが完全なメッセージとして表示されると想定していることに注意してください。端末がすでにXサーバーとの通信でビジー状態のときにそのキーの組み合わせを押すと、それを見逃す可能性があります。また、すべてのX11トラフィックがzsh(パフォーマンスを目的とした言語ではなくシェル)で記述されたラッパーを通過する必要があるため、パフォーマンスにも影響します。

1