rcmdnk's blog

前回 コマンドラインで文字化けしてたのは\M-c.inputrcで設定してたからだ、 という話を書きましたが、 ついでにメタキーやらエスケープ入力やらを少し調べたので まとめておきたいと思います。

MacのiTerm(ターミナル)でのメタキー、エスケープシーケンスの設定

まず、Macの場合ちょっと特殊なので、iTerm(ここではiTerm2)等で メタキープレフィックス状態やエスケープシーケンスを送る方法をまとめておきます。

iTerm(ターミナル.appでも一緒) ではCommandキー()との同時押しはターミナルに直接送られないで、 アプリケーションのショートカットとなるので +f はサーチウィンドウが開いてしまいます。

これに対処するにはいくつか方法がありますが、 まずはiTerm自体でキー直接送るよう、設定をする方法があります。

Preferences Profiles Keysの項目で、上の図の様に +f に対して Send Escape Sequence+fと言う様に設定します。 これで+f を押すとESC fが送らる様になるので コマンドライン上で1単語進める様になります。

ターミナル.appでも 環境設定 設定 キーボードに 同じ様な設定項目があるので、同様に設定出来ます。

また、上の図の下の方を見るとOption()の設定が NormalMeta+Escのうちから選べる様になっているので、 Metaを選べばメタキー、+Escを選べば入力キーと共にエスケープシーケンス (上のCommandに対するのと同様の働き)、

として働かす事が出来ます。

また、もしKeyRemap4MacBook1 を使っているなら下のような設定を入れておけば直接 +ESC に置き換えてやることもできます。 (沢山入れたい時はこちらの方が楽。)

terminal_escape_sequence.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<item>
  <name>Command + (f, b, d, y, Ctrl-y, Ctrl-h, &lt;, &gt; c, u, ., _, ) to ESC + * </name>
  <identifier>private.iterm2.escape_sequenceidentifier>
  <only>TERMINAL</only>
  <autogen>
    __KeyToKey__ KeyCode::F,
    MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_COMMAND|ModifierFlag::NONE,
    KeyCode::ESCAPE, KeyCode::F
  </autogen>
  <autogen>
    __KeyToKey__ KeyCode::B,
    MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_COMMAND|ModifierFlag::NONE,
    KeyCode::ESCAPE, KeyCode::B
  </autogen>
  <autogen>
    __KeyToKey__ KeyCode::D,
    MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_COMMAND|ModifierFlag::NONE,
    KeyCode::ESCAPE, KeyCode::D
  </autogen>
  <autogen>
    __KeyToKey__ KeyCode::Y,
    MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_COMMAND|ModifierFlag::NONE,
    KeyCode::ESCAPE, KeyCode::Y
  </autogen>
</item>

メタプレフィックスとエスケープシーケンス、それからAltキー

前置きが長くなりましたが、本題へ。

そもそもメタプレフィックス(\M-、メタキーと同時押し)と エスケープシーケンス(\e、ESCを押して一旦離して次のキーを押す) が全く一緒だと思ってたんですが 基本的には区別されます。

以下に行く前に取り敢えず前回の設定の

set convert-meta off
set input-meta on
set output-meta on

は設定してあることを前提とします。(convert-metaはすぐに変えますが。)

convert-metaonの場合

前回で設定したconvert-metaoffでなくonになっていると メタキープレフィックスがエスケープシーケンスと区別されなくなります。

これは、まず

  • メタキーが8bit目を1にするためのキーであること。

一方

  • convert-metaonである場合、8bit目が1のキー入力が来た時は 8bit目を落として、ESCを先に1回押した状態、と同じにする。
  • さらにこのようなESC+*の状態をメタキープレフィックス状態と同値とみなす様になる。

ということから結果的に\M-f\efの様なキーを全く同一とみなす様になります。 (この辺理解がちょっと怪しい…)

実際にset convert-meta on.inputrcで設定した場合、 まず、bind -p等とすると設定されている項目は\C-等Control関係のものなどのものに混じって \M-f等、メタキープレフィックスな状態だけが表示されます。

MacのiTerm上では、 +f+f (これらについては上にあるように設定してあるとします)、 及びESCf は全て初期設定の1単語進む(forward-word)、の動きをします。 Windows/Linuxでも AltfESCf が同様に動作します。

ここで、

$ bind '"\ef":backward-word'

としても

$ bind '"\M-f":backward-word'

としても、いずれの場合でも全てのキーが1単語戻る、の動作をするように変更されます。

また、bind -p|grep backward-wordで確認すると、上記両方共設定した場合でも

$ bind '"\M-f":backward-word'
$ bind '"\ef":backward-word'
$ `bind -p|grep backward`
"\M-f": backward-word

の様に\M-fしか表示されません。試しに違う設定を入れてみれば

$ bind '"\M-f":backward-char'
$ bind '"\ef":backward-word'
$ `bind -p|grep backward`
"\M-f": backward-word

$ bind '"\ef":backward-word'
$ bind '"\M-f":backward-char'
$ `bind -p|grep backward`
"\M-f": backward-char

の様に\ef\M-fのいずれか後で設定した物がbindの\M-fの結果として 表示される事が分かります(上の表示は必要ない出力は省いています。)。

convert-metaoffの場合

convert-metaoffの場合、\M-fESC fは区別されます。

まず、bind -pなどとすると\eの項目だけで\M-となっているものはありません。

ここでキーを試して見ると、Macでの +fESCf、 また Windows/Linuxでの AltfESCf は1単語進む(forward-word)、の動きをします。

一方、Macでメタキーとして設定した +f だけは forward-wordの動きはせず文字化けしたものを表示したりします。

従ってメタキープレフィックスな状態とエスケープシーケンスが区別されていて、 さらにAltキーはメタキーとしてではなく、エスケープシーケンスを作る様に 働く事が分かります。 AltについてはCygwinやらLinuxでのxterm等で試しましたが、 試した限りでは全てエスケープシーケンス的に動いています。 (ここが意外だった所。ターミナルやその他の環境によって もしかしたら違うのかもしれません。)

次に、bindでキー変更してみると、

$ bind '"\ef":backward-word'

とした場合は+f以外のキーが

$ bind '"\M-f":backward-word'

とした場合は+fだけが変更されます。

bind -Pとすると

$ bind -P |grep backword-word
"\eb": backward-word
"\ef": backward-word
"*": backward-word

の様な感じで、最後の文字化け(*としてある)部分が\M-fです。 (文字化け部分はfのコード(01100110)の8bit目が1になったもの。)

input-meta/output-metaについて

input-metaoffの場合、端末がサポートして居ない場合、 8bit目を落とします。onだと端末の状況関係なく8bit目も受け入れます。 手元の環境ではこの設定はoffにしても影響が出るものはありませんでした。 この値は古くはmeta-flagと言う名前で定義されていましたが、 この名前は現在はinput-metaと同義で、 input-metaで定義してもbind -v等で見るとき等はinput-metaの値として反映されます。

output-metaonの時には出力時に8bit目が1の入力を直接表示し、 offの時はメタプレフィックスエスケープシーケンスとして表示します。 output-metaoffにしてさらにconvert-metaoffにした状態で +f を打つと\346と表示され、 これは11100110(fのコードの8bit目を1にしたもの)の8進法表示になってる 事が確認出来ます。(メタキーが8bit目を1にしたことを確認出来る。)

Emacsでのキーバインド

Emacsにおいては少なくとも初期設定のままでは エスケープシーケンスのみが有効でメタキーは効きませんでした。

キーバインドで

(define-key global-map "\M-f" 'backward-word)

と書こうが、

(define-key global-map "\ef" 'backward-word)

と書こうが+f は1単語戻る、になりましたが、 +f は何故かAを出力するだけでした 2

Happy Hacking Keyboardのメタキー?

HHKにはモードを変更してスペースの両端にあるキーを変更できたりするんですが、 両端にあるダイヤモンド型のマークの有るキーが Wikipediaの メタキーのページ で紹介されているので違いがあるかな、と思ったんですが、 このキーは何も機能しない様でした。

HHKモード にして、キー自体が送られていることはyamyの スキャンコードの機能で確かめました。 コード自体は以前も調べたのですが、左右がそれぞれ0x7b0x79です。 これらは日本語配列キーボードの無変換、変換に当たるキーコードなので、 この部分だけは日本語配列と同じ Alt-無変換-Space-変換 Alt の状態になっているわけですね。

というわけで、未だメタキーを直接送れるキーボードがあるかどうか自体が謎。 (WikiのAltの歴史 なんかを見てもメタキーの存在はもう無い感じですかね…?)

Sponsored Links
  1. 現在は Karabiner-Elements に名前が変わっています。

  2. .emacsを数年ぶりにいじる上、昔の設定を消していたのでどうやるか 分からなくて調べた…

Sponsored Links

« コマンドラインでの文字化け解決?: '\M-c'とは... ターミナルキーバインドの設定等 »

}