Home や End キーが機能しない

提供: ArchWiki
2022年1月28日 (金) 12:40時点におけるKusanaginoturugi (トーク | 投稿記録)による版 (→‎TERM: add == Shell prompt ==)
ナビゲーションに移動 検索に移動

コマンドラインプログラムでは、Home や End キーがうまく動作しないということがよくあります。キーが押されたときにターミナルエミュレータはマルチ文字エスケープコードを送信しているわけですが、(シェルなどの) プログラムがエスケープコードを正しく解釈できていないためです。問題が起こっているプログラムの設定を変更して、特定のエスケープコードを受信したときに適切な動作をするように設定することで問題は解決します。したがって、解決方法はプログラムによってそれぞれ異なります。

多数のプログラムに影響を与える問題から順々に確認していってください。

TERM

キーが機能しない理由としては TERM 環境変数の上書きが一番トップにきます。近代的なターミナルは TERM 変数を勝手に設定してくれるので、プログラムの設定に入る前に、間違って TERM 変数を上書きしてしまってないか確認してください (例えば、~/.bashrc など)。TERM を手動で設定してはいけません。ターミナルに任せましょう。

ターミナルによって設定される TERM の値が気にくわない場合 (例えば 'xterm-256color' と設定して欲しいのに 'xterm' となってしまう場合)、TERM 変数を変えなくても上書きできる方法がターミナルに用意されていることがあります。

xterm や urxvt の場合、X resources で設定できます:

XTerm*termName: xterm-256color
...
URxvt*termName: rxvt-unicode

Screen の場合、~/.screenrc で設定できます:

term screen-256color

Tmux の場合、~/.tmux.conf で設定できます:

set -g default-terminal screen-256color

Shell prompt

Another possible reason for misbehaving Home and End keys is malformed custom shell prompt. The shell tries to calculate actual length of the prompt contained in PS1 environment variable, but if PS1 contains some escape sequences (e.g. for colored text), shell may assume that they are actual printable characters with non-zero length. This will obviously result in text rendering mistakes.

この記事またはセクションは加筆を必要としています。
理由: The following instructions are Bash-specific. Add instructions for other shells, e.g. Zsh%{...%}. (議論: トーク:Home や End キーが機能しない#)

To avoid that, you should enclose your non-printable stuff in PS1 with \[ and \] so that shell can understand that it is actually non-printable. For example, this line in your .bashrc

PS1="\e[32m\u \e[34m\w \e[37m\$ \e[0m"

should become this:

PS1="\[\e[32m\]\u \[\e[34m\]\w \[\e[37m\]\$ \[\e[0m\]"

For more info, please refer to Bash/Prompt customization.

Readline

コマンドラインアプリケーションはキーボード入力を読み込むために大抵 Readline ライブラリを使っています。よって、多くの場合 Readline を正しく設定すれば Home と End の問題は解決です。Readline は曖昧なキーのマッピングを /etc/inputrc (全ユーザー共通) と ~/.inputrc (各ユーザー個別) で管理しています。

デフォルトの /etc/inputrc では、Home/End のエスケープコードを処理するように以下の記述がされています:

"\e[1~": beginning-of-line
"\e[4~": end-of-line
"\e[7~": beginning-of-line
"\e[8~": end-of-line
"\eOH": beginning-of-line
"\eOF": end-of-line
"\e[H": beginning-of-line
"\e[F": end-of-line

キーが機能しない場合、おそらくターミナルが送信しているエスケープコードが上記のリストに含まれていません。まずは送信されているエスケープコードを確認してください。Readline の "quoted-insert" というコマンドを使ったり showkey --scancodes コマンドを実行することで確認できます。quoted-insert を呼び出すデフォルトのキーバインドは Ctrl+V です。

例えば、ターミナルの中で、以下の順番でキーボードから入力を行えば:

  1. Ctrl+V
  2. Home
  3. Spacebar
  4. Ctrl+V
  5. End

以下のような出力が得られます:

$ ^[[1~ ^[[4~

^[ はエスケープ文字です。つまり、上記の場合、Home キーのエスケープコードは [1~ で End キーのエスケープコードは [4~ です。Readline のデフォルト設定にエスケープコードが記述されていない場合、以下のように追加してください:

"\e[1~": beginning-of-line
"\e[4~": end-of-line

Readline ではエスケープ文字を表すのに \e を使用するので注意してください。

Terminfo

Readline を使用しないプログラム (例: ncurses) については、terminfo を編集することでターミナルに送信されるエスケープコードを変更することができます。

まず既存の terminfo をファイルに保存:

infocmp $TERM >terminfo.src

そして作成されたファイルを編集してエスケープコードを変更。例えば khome と kend を変更した場合:

khome=\E[1~, kend=\E[4~,
警告: 他のキーが同じエスケープシーケンスを使っていないことをよく確認してください。

その後新しい terminfo をコンパイル (~/.terminfo ディレクトリに保存されます):

tic terminfo.src

最後にシェルの環境変数を使って新しい terminfo を指定:

export TERMINFO=~/.terminfo

他のアプリケーション

上記の方法で問題が解決しない場合、おそらくシステム共通の問題というよりは特定のプログラム限定の問題です。それぞれのプログラムのドキュメントを参照して対処してください。以下はよく使われているプログラムにおける修正方法です。

Lynx

Readline で使用するのと同じ quoted-insert 文字列を使ってキーバインドを追加できます。ただしエスケープ文字として \033 を使用します:

lynx.cfg
setkey "\033[1~" HOME
setkey "\033[4~" END

URxvt/Rxvt

Lynx と同じフォーマットのエスケープシーケンスを使って X resources にエスケープコードのバインドを追加:

URxvt.keysym.Home: \033[1~
URxvt.keysym.End: \033[4~
URxvt.keysym.KP_Home: \033[1~
URxvt.keysym.KP_End:  \033[4~

KP_Home と KP_End はテンキーの Home と End キーです。上記の設定で URxvt の中で動作するプログラム (例: Nano) の問題が解決されることもあります。

また、/etc/inputrc に以下のセクションを追加することでも修正できます:

# those two are for rxvt
"\e[7~":beginning-of-line
"\e[8~":end-of-line

Zsh

terminfo データベースを使って正しいキーバインドを設定してください。

~/.zshrc
bindkey "${terminfo[khome]}" beginning-of-line
bindkey "${terminfo[kend]}" end-of-line

詳しくは Zsh#キーバインドzshwiki: bindkeys を参照。

Less

lesskey を使って設定ファイルを作成し Readline の時と同じエスケープコードを設定してください:

$ lesskey -o .less -
#command
\e[4~ goto-end
\e[1~ goto-line

あるいは xterm の場合、別のエスケープコードを使う必要があります:

$ lesskey -o .less -
#command
\eOF goto-end
\eOH goto-line