問題の背景を理解している人は本編に飛んでください。
(追記: 投稿して満足したところで、もっとずっと簡単な方法を発見してしまった。むなしい。 ~/Library/KeyBindings/DefaultKeyBinding.dict によるキーバインドの変更)
想定する環境
この問題への対応は、環境依存性が高いですので、最初にこの記事が前提とする環境を書いておきます。
- macOS 10.13 (Mojave)
- MacBook (JISキーボード)
- Karabiner-Elements 12.9.0
- Emacs 26 for Mac OS X (パッチ無し)
背景
JISキーボードには \ (バックスラッシュ) のキーがありません。UNIXユーザ、プログラマにとって、これは大変不便です。
一方、JISキーボードには ¥ (円記号) のキーがあります。¥ (円記号; U+00A5) は呪われた文字です。
Windowsでは、¥ (円記号) と \ (バックスラッシュ)が同一視されることが多いようですが、これらは元々 JIS X 0201 と US-ASCII という別の文字集合に属するもので、同一視がそもそも間違っています。MS-DOSが採用したMS漢字コードにおいて、1バイト文字として表現されるのは US-ASCII でなく JIS X 0201 であったが、テキストファイルだけからどちらの文字集合であるかは区別できないため、C言語のソースコードなどで使われる \ (バックスラッシュ)は画面上では ¥ (円記号)のように文字化けしてしまっていました。この現象を正しく文字化けと認識せず、\ (バックスラッシュ)を ¥ (円記号)と読み換えようなどと、対応をなあなあにして来たことが、我が国にとって永遠の禍根を残すことになります。
macOSは ¥ (円記号) と \ (バックスラッシュ)を区別します。したがって、JISキーボード上の ¥ (円記号) のキーを押すと ¥ (円記号) が入力されます。これはたいへん正しい処理ですが、実用的には不便です。¥ (円記号; U+00A5) は実際にはほとんど使用されておらず、逆に \ (バックスラッシュ)はUNIXやプログラミングでは最も重要な文字の1つだからです。
ことえり、そして Google 日本語入力には、¥キーで入力する文字をバックスラッシュ (\) に変更する機能があります。したがって、これらの機能で満足できる人はこの記事を読む必要がありません。
Karabiner-Elementsで¥キーの挙動を変更する
原理的には、Karabiner-Elements で "International 3" (¥キーに対応)を \ キーに変更するだけで良さそうですが、私の環境ではうまく行きませんでした。Karabiner-ElementsでJISキーボードがUSキーボードとして認識される問題のように見えますが、Country codeを45にしても変化ありません。
JISキーボードでは、Option+¥ で \ (バックスラッシュ)を入力することができます。そこで、以下のようにして¥キーを押すとOption+¥が押されたようにします。
(参考: JIS配列のMacで、バックスラッシュをさくっと入力する方法(JetBrainsのIDE対応)
- Karabiner-Elements の Complex modifications タブから Add rule ボタンを押す
- Import more rules from internet (open a web browser) ボタンを押す
- "Swap ¥ and \ always on JIS Keyboards" というルールを Import する
- Change ¥ to Alt+¥ ルールを Enable する
Emacsの設定
上記設定で大概はOKですが、Emacsでは駄目です。¥キーを押しても "M-¥ is undefined" と叱られてしまいます。
¥キーで \ (バックスラッシュ)が入るようにするためには、init.el の中で次のように設定します。なお、私のように ns-command-modifier と ns-alternate-modifier を設定して Command キーと Option キーを入れ換えている人は、M-¥ でなく s-¥ としてください。
(define-key global-map [?\M-¥] [?\\])
実はこれだけではまだ不十分で、インクリメンタルサーチがうまく動きません。インクリメンタルサーチを使っていない人(いないと思うが…)以外は、以下の設定も追加しましょう。
(defun isearch-add-backslash()
(interactive)
(isearch-printing-char ?\\ 1))
(define-key isearch-mode-map [?\M-¥] 'isearch-add-backslash)
これですっきり。コーディングもはかどりますね。