Menu

Terminal.appがダメなのでiTermをいじる

 LeopardのTerminal.appをしばらく使っているうちに、こいつは使えない代物だと分かった。

 まず、「○」とか「△」とかの記号を倍幅文字と認識してくれない。これは再描画しても直らないのでTigerのTerminal.appよりひどい。もしかすると、日本語フォントの記号グリフに沿った文字幅情報を含むエンコーディング定義を追加することできれいに対処できるのかもしれないが、その方法は未調査。ていうか、こんなのデベロッパープレビュー段階で気づかなかったんだろうか。Appleには日本人ハッカーはいないの?

 二番目に、CommandキーをMetaキーとして使えないのが不便。TigerではAPE+Cmd2Optでなんとかなったが、今のところLeopardには対応していない。ていうかCmd2Optの配布物ってWeb Archive等を漁らないと手に入らなかった気がする。なんにせよ、Emacs使いにとってMetaキーが左下のちっこいOptionキーひとつというのは致命的だ。小指をつって死ねと言うに等しい。小指が休職したら、Ctrl+[で亀のようなもたもた人生を遅れというのか。

 あと、ANSIカラーを調整できないので目に優しくない。頼みの綱はTerminalColorsだが、作者のサイトを見るとLeopardのTerminal.appに対応するのは当分先になりそうだ。

 どうにかしようにもソースがない。じゃあソースがあるものをいじろう、ということでiTermに手を入れました。まず、第一の記号問題を解決するパッチがこれ。

Index: NSStringITerm.m
===================================================================
RCS file: /cvsroot/iterm/iTerm/NSStringITerm.m,v
retrieving revision 1.8
diff -u -r1.8 NSStringITerm.m
--- NSStringITerm.m	13 Nov 2006 08:01:04 -0000	1.8
+++ NSStringITerm.m	5 Nov 2007 14:04:20 -0000
@@ -286,6 +286,8 @@
 	0xfffd,
 };
 
+static int isJapaneseEnvironment = -1;
+
 
 @implementation NSString (iTerm)
 
@@ -296,8 +298,22 @@
 
 + (BOOL)isDoubleWidthCharacter:(unichar)unicode encoding:(NSStringEncoding) e
 {
-	if (unicode <= 0xa0 || (unicode>0x452 && unicode <0x200f))
-		return NO;
+    if (unicode <= 0xa0 || (unicode>0x452 && unicode <0x200f))
+        return NO;
+
+    if (isJapaneseEnvironment < 0) {
+        const char ja_JP[] = "ja_JP.";
+        const char *lang = getenv("LANG");
+
+        if (lang != NULL && strlen(lang) > sizeof(ja_JP) - 1 && !strncmp(lang, ja_JP, sizeof(ja_JP) - 1))
+            isJapaneseEnvironment = YES;
+        else
+            isJapaneseEnvironment = NO;
+    }
+
+    if (isJapaneseEnvironment && unicode >= 0x2000)
+        return YES;
+
     /*
      unicode character width check
      see. http://www.unicode.org

かなり手抜きながら、LANGja_JPっぽいときはU+2000以上の文字は倍幅とみなすものだ。

 次に第二のCommandキーをMetaキーにするパッチがこれ。

Index: iTermApplication.m
===================================================================
RCS file: /cvsroot/iterm/iTerm/iTermApplication.m,v
retrieving revision 1.10
diff -u -r1.10 iTermApplication.m
--- iTermApplication.m	7 Nov 2006 08:03:08 -0000	1.10
+++ iTermApplication.m	5 Nov 2007 13:51:06 -0000
@@ -43,6 +43,10 @@
 	id aWindow;
 	PseudoTerminal *currentTerminal;
 	PTYSession *currentSession;
+	unsigned int modflag;
+	unichar unicode;
+	NSString *keystr;
+	NSEvent *newEvent;
 
 
 	if([anEvent type] == NSKeyDown)
@@ -57,16 +61,42 @@
 			currentSession = [currentTerminal currentSession];
 
 			if([currentSession hasKeyMappingForEvent: anEvent highPriority: YES])
+			{
 				[currentSession keyDown: anEvent];
-			else
-				[super sendEvent: anEvent];
-		}
-		else
-		   [super sendEvent: anEvent];
+				return;
+			}
+
+			modflag = [anEvent modifierFlags];
+
+			if ((modflag & NSCommandKeyMask)) {
+				keystr  = [anEvent characters];
+				unicode = [keystr length] > 0 ? [keystr characterAtIndex : 0] : 0;
 
+				switch (unicode)
+				{
+					case 0x20:						// Switch Input Source
+					case NSCarriageReturnCharacter:	// Enter Full Screen
+						break;
+
+					default:
+						newEvent = [NSEvent keyEventWithType: [anEvent type]
+											location: [anEvent locationInWindow]
+											modifierFlags: ((modflag - NSCommandKeyMask) | NSAlternateKeyMask)
+											timestamp: [anEvent timestamp]
+											windowNumber: [anEvent windowNumber]
+											context: [anEvent context]
+											characters: keystr
+											charactersIgnoringModifiers: [anEvent charactersIgnoringModifiers]
+											isARepeat: [anEvent isARepeat]
+											keyCode: [anEvent keyCode]];
+						[currentSession keyDown: newEvent];
+						return;
+				}
+			}
+		}
 	}
-	else
-		[super sendEvent: anEvent];
+
+	[super sendEvent: anEvent];
 }
 
 @end

これは、一部の組合せを除き、CommandキーをOptionキーと同一視させる修正。もちろん、Keyboard Profileの「Option Key as」でOptionキーをMetaキーにしないと無意味だ。ふつうは日本語を直接入力したいだろうから、そこの設定は「Meta」ではなく「+Esc」にするだろう。

 なお、第三の色問題はiTermには存在しない。Display Profileでいじれるから。

 iTermのサイトからCVSでソースを取ってきて上のパッチを当て、好みに応じていじってビルドしてください。特にどのCommandキーショートカットを生かすかの部分は人それぞれのはず。ビルド方法は、iTerm.xcodeprojを開いてビルドボタンを押すだけ。Xcodeは最新版(Tigerなら2.5, Leopardなら3.0)にしておいた方がいい。Tiger 10.4.10 + Xcode 2.4だとうまくビルドできなかった。

 何か情報があれば寄せてください。みんな我慢しているのか、他にいい選択肢があって俺が知らないだけなのか、いつも不思議なんだよね。

 次に続く。

12 Replies to “Terminal.appがダメなのでiTermをいじる”

  1. 下記のURLの “Terminal 2 Release Notes” を参照してください。
    U+25B3(WHITE UP-POINTING TRIANGLE)やU+25EF(LARGE CIRCLE)のように文字幅が Ambiguous に分類される文字は文字幅を Narrow として扱うと記載されています。
    http://developer.apple.com/releasenotes/DeveloperTools/RN-Terminal/index.html
    尚、xterm の -cjk_width に相当するようなオプションは、探した限りでは見つかりませんでした。
    記号が重なって表示される件は、wcwidth()とTerminal.appは記号を Narrow として扱っているが、表示する時に(いわゆる)全角のグリフしか見つけられなかったという状況のようですから、これがもし修正されれば(いわゆる)半角で欠けずに表示されるようになるでしょう。
    要するに
    「ギリシャ文字やキリル文字が全角で表示されないと使いにくいと感じるお客様は、Terminal.app 以外のアプリをご利用ください」
    という話のようですね。

  2. なるほど。調べが足りなかった。
    ambiguousはwideと見なすというオプションが欲しいですね。
    ASCIIフォントからグリフを取得してその幅から…というのが利けばいいのだけど、それだとASCIIフォントに入ってしまっているグリフが常に優先されてしまうという問題がある。
    WindowsのFontLinkもASCII(というか先に指定したもの)優先なので、自分で好きなASCII & non-ASCIIフォントを合成したものを作ったりしています。
    FontForgeを使うと簡単。
    Ttyアプリケーションについては、個別に教える必要あり。
    以下が参考になります。
    http://d.hatena.ne.jp/macks/20061001

  3. そうか。MacPortsを見忘れたのはうかつでした。
    いつまでもパッチ・パッチじゃ面倒なのでsubmitしちゃいましたが、フォローがあればお願いします。
    http://sourceforge.net/tracker/?func=detail&aid=1826692&group_id=67789&atid=518973
    http://sourceforge.net/tracker/?func=detail&aid=1826697&group_id=67789&atid=518973
    KeyRemap4MacBookの情報もありがとうございます。さっそく試してみます。

  4. どうもありがとうございます。
    私の読み方が合っていれば、その実装と私のパッチの実装とで挙動に差はないのではないかと思います。
    というのも、mk_wcwidth_cjk()はnon-spacing characterかどうかも調べていますが、結局iTerm本体が幅1と2にしか対応していないので、幅0のケースを捨てているからです。
    また、そのパッチだとCJKエンコーディングかどうかの判定をしていないので、CJK friendlyな代わりにWestern unfriendlyな気がします。
    ということで、non-spacing charactersに対応するまでは私のパッチを使ってもらうように依頼してもいいでしょうか?
    (落としどころを伝えないと取り込んでもらえないので)

  5. おまかせいたします。ひとつ質問があります。
    エンコーディングがUTF-8の場合に
    ロケールを見ているようですが、
    これは一般的な方法なのでしょうか?

  6. そこはただの手抜きです。本当は、上のissueのdescriptionにも書いた通り、non-ASCIIフォントがCJK用なのかどうかを見るべきなのだと思います。プロファイルごとにCJKだったりそうでなかったりする使い方は当然あるので。
    フォントやグリフの情報を取って残る不具合を直すのは別途やろうと思っているので、とりあえずのその場しのぎです。

  7. はじめまして。emacs使いにとってはTerminal.app + Cmd2optついでにVisorがないとなかなかLeopardにアップグードできません。ところでCmd2OptってWeb上にありますかね?探してもぜんぜん見つからないんで

コメントを残す

メールアドレスが公開されることはありません。