iTerm2でSwapOptCmdが使えるようにしてみた

2011/03/19追記
iTerm2-alpha17からModifierキーがカスタマイズできるようになったみたいです!
SwapOptCmdと同じ動作を実現するには
iTerm > Preferences… > Keyboard で Left Command Key を Left Option にして,Left Option Key を Left Command にして,Global Shortcut Keys で Do Not Remap Modifiers に Command + Space を追加します.
簡単ですねっ!!

Mac ユーザーで iTerm を使ってる人はちらほらいるんじゃないかと思うんですが,いつの間にか後継の iTerm2 がアルファ版でリリースされていたようですね.
使用メモリが少なくなったらしいですし(あまり気にしてないので未確認),ショートカットキーの割り当ての自由度も上がってるのでなかなか良いです.

なんちゃって Emacs ユーザーの私としては Command キーが Meta キーとして使えないと苦痛でしょうがないので iTerm では SwapOptCmd を使って Option キーと Command キーを入れ替えてました.
っで,iTerm と同じように iTerm2 にも SwapOptCmd を適用しようとしても Command キーが Meta キーとして認識されないんですね…
というのも,iTerm2 alpha14 から 左Option と 右Option を別に扱ってるからです.

そこで iTerm2 でも SwapOptCmd が使えるように patch を作成しました.

SOCPlugin.patch

--- SOCPlugin.m.org	2011-02-05 11:41:23.000000000 +0900
+++ SOCPlugin.m	2011-02-05 11:34:51.000000000 +0900
@@ -17,6 +17,8 @@
 //
 
 #import <objc/runtime.h>
+#define LEFT_OPTION  0x080120
+#define LEFT_COMMAND 0x100108
 
 @interface NSApplication (Replace)
 - (void)replace_sendEvent: (NSEvent*)event;
@@ -45,8 +47,8 @@
 	NSEventType type = [event type];
 	if (type == NSKeyDown || type == NSKeyUp) {
 		NSUInteger flags = [event modifierFlags];
-		if ((flags & (NSAlternateKeyMask | NSCommandKeyMask)) ==
-			NSCommandKeyMask) {
+		if ((flags & LEFT_COMMAND) ==
+			LEFT_COMMAND) {
 #ifndef REPLACE_ALL_KEYS
 			if ([event keyCode] == 49) {
 				/* command+space */
@@ -54,16 +56,16 @@
 				return;
 			}
 #endif
-			flags &= ~NSCommandKeyMask;
-			flags |= NSAlternateKeyMask;
+			flags &= ~LEFT_COMMAND;
+			flags |= LEFT_OPTION;
 			[self sendSwapEvent: event modifierFlags: flags];
 			return;
 		}
-		if ((flags & (NSAlternateKeyMask | NSCommandKeyMask)) ==
-			NSAlternateKeyMask) {
+		if ((flags & LEFT_OPTION) ==
+			LEFT_OPTION) {
 			NSUInteger flags = [event modifierFlags];
-			flags &= ~NSAlternateKeyMask;
-			flags |= NSCommandKeyMask;
+			flags &= ~LEFT_OPTION;
+			flags |= LEFT_COMMAND;
 			[self sendSwapEvent: event modifierFlags: flags];
 			return;
 		}

Modifier の種類のフラグとして modifierFlags (NSUint) の上位2バイトが与えられてるみたいなんで,このフラグをいじりたければ NSAlternateKeyMask や NSCommandKeyMask でいじれるんですが,左Option か 右Option かなどの情報が 下位2バイトに与えられてるのでここもいじる必要があります.ということでいじってます.

パッチを当ててSwapOptCmdを設置するまで

  1. まずSwapOptCmdのソース (SwapOptCmd-source.tar.gz) をダウンロードして展開します.
    $ wget https://sites.google.com/a/yedo.com/www/swapoptcmd/SwapOptCmd-source.tar.gz -O SwapOptCmd-source.tar.gz
    $ tar xvf SwapOptCmd-source.tar.gz
    $ cd SwapOptCmd
    
  2. 次に先程のパッチを当てます
    $ patch -p0 <SOCPlugin.patch
    
  3. Xcodeでビルドします.
    $ open -a Xcode SwapOptCmd.xcodeproj
    

    Build > Build や Command + B でビルドできます.
    Active Configuration を Debug から Release にした方がいいのかもしれませんが,今回初めて Xcode を立ち上げたぐらいなんでよくわかりません…
    とりあえず Release にしておきましょうか.

  4. iTerm2で使えるように build/Release/SwapOptCmd.bundle/Contents/Info.plist の array に次の内容を追加します.(見ればわかると思います)
         <dict>
             <key>BundleIdentifier</key>
             <string>com.googlecode.iterm2</string>
         </dict>
    
  5. SwapOptCmdを設置します.
    $ cp -r build/Release/SwapOptCmd.bundle ~/Library/Application\ Support/SIMBL/Plugins/
    

補足1

SwapOptCmd は元々 Terminal.app のために作られたものなので iTerm2 での動作は保証していません.
SwapOptCmd は sendEvent を上書きすることでキーを入れ替えてるみたいですが,iTerm2 も sendEvent を上書きしてるみたいなんで,iTerm2 の所望の動作が得られなくなる可能性があります.
むしろソースコードをパッと見た感じ iTerm2 では Modifier の設定を変更できるみたいなので SwapOptCmd は必要ないかもしれません.
でも設定の変更の仕方はわかりません…

補足2

SwapOptCmdを使うと Ctrl と Meta (Command) の同時押しが認識されなくなります.
SwapOptCmdを使わずに Ctrl と Meta (Option) の同時押しをした場合と全く同じ modifierFlags を送るようにしてもダメだったので,一体どうすればいいんですかね…