一部のCommand+?だけをMeta+?として使うKeyRemap4MacBookパッチ
先日、アルミになった新MacBookを買いました。やはり新しいマシンはウキウキしますね。僕は今までTigerで耐えてきたので、これが初Leopardです。LeopardのTerminal.appは十分使い物になると聞いていたので、早速試してみることにしました。
ところで、僕はCommandキー(日本語キーボードなら英数キー)がMetaの意味になる端末エミュレータでないとストレスで死んでしまうのですが、これは標準のTerminal.appの機能では実現できません。僕の実現したい環境は次の通りです。
- Terminal.app以外
- CommandキーはCommandキーとして利用したい。
- Terminal.app
- Command+FなどはOption+Fにして、シェルにMetaとして渡したい(シェル上で1単語分カーソルを進める)。でも、Command+V(ペースト)やCommand+T(新規タブ作成)など、Terminal.appの機能はそのまま使いたい。
補足しておきますと、多くのシェルではMeta+B,Meta+Fで単語1個分カーソルを前後に移動するといったEmacs風の操作が可能で、シェル上での作業を効率化できます。僕はこれに依存しきっており、使えないとイライラするというわけです。(参考記事:「シェルの操作にAltキーを使おう」)
このわがままを実現する方法ですが、僕はキー割当変更ソフトKeyRemap4MacBookにパッチを当てて解決しました。このパッチはTerminal.appだけでなく、iTermに対しても有効です。
パッチの紹介
今回作ったパッチは、特定のキーとCommandが同時に押された場合にCommandをOptionに置き換えるものです。どんなキーの組み合わせの場合に置き換えるかは下記のようにメニュー形式で選ぶことができます。「Remap Emacs-like Meta key」以下の部分が今回追加した項目です。
僕はCommand+{B,F,D,P,N,W,X}の7つのキーの組み合わせについてはシェルにmeta+{B,F,D,P,N,W,X}として渡しています。また、iTermを併用したい場合のために、Optionではなくescを送るような設定も作ってみました。これで本当に不便が無いかどうか、しばらく実験してみます。
それにしてもKeyRemap4MacBookは素晴らしいツールです。Macを買ってきたら真っ先にインストールしたいソフトウェアの一つではないでしょうか。また、開発環境のXcodeがOSの付属品として無料で手に入るのはMacOSXのナイスな点と言えるでしょう。誰でも気軽に「ちょっとパッチ当ててみるか」と試せるのは実に良い環境ですよね。
パッチの中身
KeyRemap4MacBook 5.1.0に対するパッチを別サーバにアップロードしました(KeyRemap4MacBook-5.1.0-hnw-patch-20081202.txt)。同じ内容を下記にも貼付けておきます。開発バージョンでは既に取り込まれている修正も含んでいます。
diff -ru KeyRemap4MacBook-5.1.0.orig/files/prefpane/checkbox.xml KeyRemap4MacBook-5.1.0/files/prefpane/checkbox.xml --- KeyRemap4MacBook-5.1.0.orig/files/prefpane/checkbox.xml 2008-05-20 21:00:48.000000000 +0900 +++ KeyRemap4MacBook-5.1.0/files/prefpane/checkbox.xml 2008-12-02 08:21:01.000000000 +0900 @@ -1018,6 +1018,40 @@ <name>Remap Command_L to Option_L</name> <sysctl>remap.app_term_commandL2optionL</sysctl> </item> + <item> + <name>Remap Emacs-like Meta key</name> + <list> + <item> + <name>Use Escape instead of Option</name> + <appendix>(with below configurations)</appendix> + <sysctl>remap.app_term_emacslike_meta_option2escape</sysctl> + </item> + <item> + <name>Remap Command_L+[BFD] to Option_L+[BFD]</name> + <sysctl>remap.app_term_emacslike_meta_commandLbfd2optionLbfd</sysctl> + </item> + <item> + <name>Remap Command_L+[PN] to Option_L+[PN]</name> + <sysctl>remap.app_term_emacslike_meta_commandLpn2optionLpn</sysctl> + </item> + <item> + <name>Remap Command_L+W to Option_L+W</name> + <sysctl>remap.app_term_emacslike_meta_commandLw2optionLw</sysctl> + </item> + <item> + <name>Remap Command_L+X to Option_L+X</name> + <sysctl>remap.app_term_emacslike_meta_commandLx2optionLx</sysctl> + </item> + <item> + <name>Remap Command_L+V to Option_L+V</name> + <sysctl>remap.app_term_emacslike_meta_commandLv2optionLv</sysctl> + </item> + <item> + <name>Remap Command_L+Q to Option_L+Q</name> + <sysctl>remap.app_term_emacslike_meta_commandLq2optionLq</sysctl> + </item> + </list> + </item> </list> </item> </list> diff -ru KeyRemap4MacBook-5.1.0.orig/src/core/kext/RemapUtil.cpp KeyRemap4MacBook-5.1.0/src/core/kext/RemapUtil.cpp --- KeyRemap4MacBook-5.1.0.orig/src/core/kext/RemapUtil.cpp 2008-05-20 20:58:26.000000000 +0900 +++ KeyRemap4MacBook-5.1.0/src/core/kext/RemapUtil.cpp 2008-12-02 08:03:33.000000000 +0900 @@ -871,6 +871,14 @@ } void + FireFunc::firefunc_before_escape(const RemapParams ¶ms) + { + unsigned int flags = allFlagStatus.makeFlags(params); + listFireExtraKey.add(FireExtraKey::TYPE_BEFORE, KeyEvent::DOWN, flags, KeyCode::ESCAPE, CharCode::ESCAPE); + listFireExtraKey.add(FireExtraKey::TYPE_BEFORE, KeyEvent::UP, flags, KeyCode::ESCAPE, CharCode::ESCAPE); + } + + void FireFunc::firefunc_space(const RemapParams ¶ms) { unsigned int flags = allFlagStatus.makeFlags(params); diff -ru KeyRemap4MacBook-5.1.0.orig/src/core/kext/RemapUtil.hpp KeyRemap4MacBook-5.1.0/src/core/kext/RemapUtil.hpp --- KeyRemap4MacBook-5.1.0.orig/src/core/kext/RemapUtil.hpp 2008-05-20 20:56:52.000000000 +0900 +++ KeyRemap4MacBook-5.1.0/src/core/kext/RemapUtil.hpp 2008-12-02 08:07:54.000000000 +0900 @@ -259,6 +259,7 @@ void firefunc_commandSpace(const RemapParams ¶ms); void firefunc_enter(const RemapParams ¶ms); void firefunc_escape(const RemapParams ¶ms); + void firefunc_before_escape(const RemapParams ¶ms); void firefunc_space(const RemapParams ¶ms); void firefunc_emacsmode_controlK(const RemapParams ¶ms, bool first = false); void firefunc_emacsmode_ex_controlU(const RemapParams ¶ms); diff -ru KeyRemap4MacBook-5.1.0.orig/src/core/kext/remap.cpp KeyRemap4MacBook-5.1.0/src/core/kext/remap.cpp --- KeyRemap4MacBook-5.1.0.orig/src/core/kext/remap.cpp 2008-05-25 23:46:19.000000000 +0900 +++ KeyRemap4MacBook-5.1.0/src/core/kext/remap.cpp 2008-12-02 08:08:44.000000000 +0900 @@ -1862,6 +1862,54 @@ } } + void + remap_app_term_emacslike_meta(const RemapParams ¶ms) + { + static ModifierCanceling mc_commandL; + + if (! config.remap_app_term_emacslike_meta_commandLbfd2optionLbfd && + ! config.remap_app_term_emacslike_meta_commandLpn2optionLpn && + ! config.remap_app_term_emacslike_meta_commandLw2optionLw && + ! config.remap_app_term_emacslike_meta_commandLx2optionLx && + ! config.remap_app_term_emacslike_meta_commandLv2optionLv && + ! config.remap_app_term_emacslike_meta_commandLq2optionLq) return; + + if (! (params.activeApplicationInfo)->is_terminal) return; + + if (allFlagStatus.commandL.isHeldDown()) { + bool cancel_command = false; + + if ((config.remap_app_term_emacslike_meta_commandLbfd2optionLbfd && + (*(params.key) == KeyCode::B || *(params.key) == KeyCode::F || + *(params.key) == KeyCode::D)) || + (config.remap_app_term_emacslike_meta_commandLpn2optionLpn && + (*(params.key) == KeyCode::P || *(params.key) == KeyCode::N)) || + (config.remap_app_term_emacslike_meta_commandLw2optionLw && + *(params.key) == KeyCode::W) || + (config.remap_app_term_emacslike_meta_commandLx2optionLx && + *(params.key) == KeyCode::X) || + (config.remap_app_term_emacslike_meta_commandLv2optionLv && + *(params.key) == KeyCode::V) || + (config.remap_app_term_emacslike_meta_commandLq2optionLq && + *(params.key) == KeyCode::Q)) { + + if (!config.remap_app_term_emacslike_meta_option2escape) { + allFlagStatus.optionL.temporary_increase(); + } + // cancel command_L + mc_commandL.keyRelease(params, ModifierFlag::COMMAND_L); + + // メモ:COMMAND_Lを離した後でescのdown/upをする意図。コードが汚くて悲しい。 + if (config.remap_app_term_emacslike_meta_option2escape && + *(params.eventType) == KeyEvent::DOWN) { + FireFunc::firefunc_before_escape(params); + } + return; + } + } + mc_commandL.restore(params, ModifierFlag::COMMAND_L); + } + // ---------------------------------------- void remap_qwerty2colemak(const RemapParams ¶ms) @@ -2631,6 +2679,7 @@ // ---------------------------------------- remap_app_vm_commandspace2optionbackquote(params); remap_app_finder_return2commandO(params); + remap_app_term_emacslike_meta(params); // ---------------------------------------- remap_qwerty2colemak(params); diff -ru KeyRemap4MacBook-5.1.0.orig/src/core/server/getActiveApplicationName.m KeyRemap4MacBook-5.1.0/src/core/server/getActiveApplicationName.m --- KeyRemap4MacBook-5.1.0.orig/src/core/server/getActiveApplicationName.m 2008-04-15 01:30:18.000000000 +0900 +++ KeyRemap4MacBook-5.1.0/src/core/server/getActiveApplicationName.m 2008-12-02 08:43:11.000000000 +0900 @@ -1,6 +1,6 @@ #include <sys/types.h> #include <stdio.h> -#import <Appkit/Appkit.h> +#import <AppKit/AppKit.h> void getActiveApplicationName(char *buffer, size_t len) diff -ru KeyRemap4MacBook-5.1.0.orig/src/core/server/server.cpp KeyRemap4MacBook-5.1.0/src/core/server/server.cpp --- KeyRemap4MacBook-5.1.0.orig/src/core/server/server.cpp 2008-05-20 20:46:13.000000000 +0900 +++ KeyRemap4MacBook-5.1.0/src/core/server/server.cpp 2008-12-02 08:49:33.000000000 +0900 @@ -206,7 +206,8 @@ reply->is_vi = true; } if (strcmp(applicationName, "com.apple.Terminal") == 0 || - strcmp(applicationName, "iTerm") == 0) { + strcmp(applicationName, "iTerm") == 0 || + strcmp(applicationName, "net.sourceforge.iTerm") == 0) { reply->is_terminal = true; } if (strcmp(applicationName, "com.vmware.fusion") == 0 ||
参考にしたページ
- KeyRemap4MacBook > ソースコード
KeyRemap4MacBookのソースパッケージを取得し、パッチを作る方法が書いてあります。 - KeyRemap4MacBookのSemicolon to Returnを改良 - jimo/memo
KeyRemap4MacBookをmakeした際に「Appkit/Appkit.hが無いよ」と怒られて悩みましたが、ここを見て解決できました。 - シェルの操作にAltキーを使おう
僕が会社ブログに書いた記事ですが、コマンドライン編集時にはmeta+d(WindowsならAlt+d)などが強力ですよ、という紹介記事です。