先日、アルミになった新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)などが強力ですよ、という紹介記事です。
