iTerm2のCUI版emacsでcontrol+記号とShiftキーバインドが入力できない問題について

2023年3月28日
thumbnail
iTerm2上のemacsは基本的にcontrol + 記号のキーバインドが使えません。 詳しいことはこちらの記事に書かれています。
どうやらコントロールキーが制御できるASCIIの範囲が決まっているからっぽいです。
もう1つのC-S-アルファベットキーが使えないのは別の問題でCUI版のemacsでは使えません。例えばC-vキーバインドもC-S-vキーバインドもemacsには同じC-vとして処理されてしまうからです。
さまざまなサイトを閲覧してどうにかこの2つのバインドに対処したので紹介します。

Control + 記号キーバインド

iTerm2では直接control + 記号のキーバインドは打てません。そこで、emacsのevent-apply-controll-modifierを使ってあたかもcontrol + 記号を打ったようにします。たとえばC-x @ cを押してからrを押すと、C-rを押したのと同じことになります。
これを使えば記号を含めたキーバインドが可能になります。C-. を実現するならC-x @ c .とすれば実行できます。
毎回C-x @ c .と入力するのは大変なので、iTerm2のグローバルショートカットキーでHexコード送信を割り当てて、C-.と打ったらemacsにはC-x @ c .を送信すれば、C-.のキーバインドが使えます。
article image

iTerm2のキー設定

iTerm2を開いて、上のメニューから「iTerm2」から「Preferences...」を選びます。「Keys」を選び、+ボタンを押します。
article image
試しにC-.を追加します。「keyboard shortcut」のフィールドがアクティブな状態で control + .を打ち込みます。打ち込むと^.になります。プルダウンメニューから「Send Hex Code」を選びます。新しく出てきたテキストフィールドに以下を記述します。
18 40 63 2e
article image
18 40 63 2eHex codeはこの様に対応しいて、C-x @ c .を表しています。
18 = C-x
40 = @
63 = c
2e = .
その他のキーバインドは以下の様になっています。
ショートカットキー  Hex code
C-,              18 40 63 2c
C-.              18 40 63 2e
C-:              18 40 63 3a
C-;              18 40 63 3b
C-<              18 40 63 3c
C->              18 40 63 3e
例外的に、C-<Control + Shift + <C->Control + Shift + >で登録します。
article image
上の画像を見てもわかる様に、違っているのは最後のhex codeだけです。 他にもC-(C-/を割り当てたい方は以下のサイトの表から16進数のhex codeを参照してください。

emacsで記号文字キーバインドを割り当てる

試しに、先ほど設定したC-.にキーバインドを割り当てます。 ファイルのパスを表示する関数を作りショートカットを割り当ています。 emacsの設定ファイルを開きます。
emacs ~/.emacs.d/init.el
以下を書き込みます。
(defun show-file-name ()
"Show the full path file name in the minibuffer."
(interactive)
(message (buffer-file-name)))
(global-set-key (kbd "C-.") 'show-file-name)
保存して、設定ファイルを再読み込みします。
M-x eval-buffer
ファイル名を表示するC-.を実行しすると、エコーエリアにファイル名が表示されます。
article image
キーボードで入力したC-.がiTerm2でC-x @ c .に変換されemacs上でキーバインドが機能したことをあらわしています。

Control + Shift +アルファベットバインド

最初にも書いたように、C-S-fみたいなシフトを使ったキーバインドはCUI版のemacsではC-fと処理されてしまいます。shiftキーを別のバインドとして使うにはトリックが必要です。event-apply-control-super-modifier関数を作成し、event-apply-shift-modifier を上書きして、iTerm2の入力はC-S-fになりますがemacs内部ではC-s-fとして処理させます。C-s-fはControl + super + fを表しており、スーパーキーを押しているという体に変換します。
とりあえず、C-s-fを利用できるようにします。init.el に独自に作成したevent-apply-control-super-modifier関数を加えます。作成した関数でevent-apply-shift-modifierを上書きします。本来はC-x @ Sevent-apply-shift-modifierが処理するところをcontrol + superにしてしまいます。
(defun event-apply-control-super-modifier (ignore-prompt)
  "\\\\Add the Control+Shift modifier to the following event.
For example, type \\\\[event-apply-control-shift-modifier] SPC to enter Control-Shift-SPC."
  (vector (event-apply-modifier
           (event-apply-modifier (read-event) 'control 26 "C-")
           'super 23 "s-")))
(define-key function-key-map (kbd "C-x @ S") 'event-apply-control-super-modifier)
ちなみに上のコードのsuper 23 "s-"はここを参照しています。
Emacs側でC-s-fを使う準備が整いました。iTerm2で記号のキーバインドでやったようにHexコードを送る設定を加えます。
18 40 53 66Hex codeはこの様に対応しいて、C-x @ S fを表しています。
18 = C-x
40 = @
53 = S
66 = f
article image
動作確認で、上で作ったshow-file-nameC-s-fにバインドします。
(global-set-key (kbd "C-s-f") 'show-file-name)
article image
上の画像はC-h kC-s-fをタイプしてcontrol + Shift + fC-s-fとして処理されているのを確認しています。

まとめ

この方法でより多くのショートカットキーを簡単なキーバインドで定義できるようになりました。emacsを使った素早いコーディングが可能になりますね。
profile image
Ted
大学でコンセンサスアルゴリズムを研究。卒業後ベンチャー企業に入社してフルスタックでWebサービスを開発。現在は大手IT企業に転職し、プログラミングを行っている。AIにプログラマーの仕事を奪って欲しいと願っている。