[aquaskk-changes 329] CVS update: AquaSKK

Tomotaka SUWA t-suw****@users*****
2007年 8月 16日 (木) 19:58:18 JST


Index: AquaSKK/AsciiConversionMode.cpp
diff -u AquaSKK/AsciiConversionMode.cpp:1.7.2.4 AquaSKK/AsciiConversionMode.cpp:1.7.2.5
--- AquaSKK/AsciiConversionMode.cpp:1.7.2.4	Sat Feb  3 17:52:48 2007
+++ AquaSKK/AsciiConversionMode.cpp	Thu Aug 16 19:58:18 2007
@@ -1,5 +1,5 @@
 /*
-  $Id: AsciiConversionMode.cpp,v 1.7.2.4 2007/02/03 08:52:48 t-suwa Exp $
+  $Id: AsciiConversionMode.cpp,v 1.7.2.5 2007/08/16 10:58:18 t-suwa Exp $
 
   MacOS X implementation of the SKK input method.
 
@@ -33,7 +33,8 @@
 
 AsciiConversionMode::AsciiConversionMode(ParentInputMode& src)
     :ChildInputMode(src),
-     word_register_mode(NULL),
+     word_register_mode(0),
+     old_word_register_mode(0),
      status(STATUS_NULL),
      show_cands_window_after_Nth_cand(5),
      completion_mode(false),
@@ -42,9 +43,8 @@
 }
 
 AsciiConversionMode::~AsciiConversionMode() {
-    if(word_register_mode) {
-	delete word_register_mode;
-    }
+    delete word_register_mode;
+    delete old_word_register_mode;
 }
 
 void AsciiConversionMode::start() {
@@ -61,12 +61,12 @@
 bool AsciiConversionMode::handleInputChar(SKKChar skkchar) {
     if(word_register_mode) {
 	word_register_mode->handleInput(skkchar);
-	return false; // WordRegisterMode::handleInput()‚ª‰½‚ð•Ô‚»‚¤‚Æ‚àŠm’è‚Í‚µ‚È‚¢B
+	return false; // WordRegisterMode::handleInput()が何を返そうとも確定はしない。
     }
 
     if(SKKConfig::AbbrevNextKey() == skkchar) {
 	if(status == STATUS_WHITE && completion_mode) {
-	    // ŽŸ‚ÌŒó•â‚ցBÅŒã‚܂ōs‚Á‚½‚çÅ‰‚É–ß‚éB
+	    // 次の候補へ。最後まで行ったら最初に戻る。
 	    current_completion_index++;
 	    if (current_completion_index >= completions.size()) {
 		current_completion_index = 0;
@@ -78,7 +78,7 @@
 
     if(SKKConfig::AbbrevPrevKey() == skkchar) {
 	if(status == STATUS_WHITE && completion_mode) {
-	    // ‘O‚ÌŒó•â‚ցBÅ‰‚܂ōs‚Á‚½‚çÅŒã‚É–ß‚éB
+	    // 前の候補へ。最初まで行ったら最後に戻る。
 	    if(current_completion_index == 0) {
 		current_completion_index = completions.size() - 1;
 	    } else {
@@ -89,14 +89,14 @@
 	}
     }
 
-    // tab,ƒsƒŠƒIƒh,ƒJƒ“ƒ}ˆÈŠO‚Ì‚¢‚©‚Ȃ镶Žš‚ª“ü—Í‚³‚ê‚Ä‚à•âŠ®ƒ‚[ƒh‚𔲂¯‚éB
+    // tab,ピリオド,カンマ以外のいかなる文字が入力されても補完モードを抜ける。
     completion_mode = false;
 
     if(SKKConfig::ToggleKanaKey() == skkchar) {
 	if(status == STATUS_BLACK || status == STATUS_BLACK_WITH_WINDOW) {
-	    // Œ»Ý‚ÌŒó•â‚ðŠm’èB
-	    // 1) •½‰¼–¼ƒ‚[ƒh‚È‚ç‘SŠp•Ð‰¼–¼ƒ‚[ƒh‚Ö
-	    // 2) ‚»‚êˆÈŠO‚Ȃ畽‰¼–¼ƒ‚[ƒh‚Ö
+	    // 現在の候補を確定。
+	    // 1) 平仮名モードなら全角片仮名モードへ
+	    // 2) それ以外なら平仮名モードへ
 	    parent->setEnabledKanjiMode(false);
 	    if(parent->isHiraganaInputMode()) {
 		parent->goZenKataInputMode();
@@ -109,7 +109,7 @@
 
     if(SKKConfig::PrevKouhoKey() == skkchar) {
 	if(status == STATUS_BLACK) {
-	    // ˆê‚‘O‚ÌŒó•â‚ցBÅ‰‚ÌŒó•â‚¾‚Á‚½‚灤ƒ‚[ƒh‚Ö–ß‚éB
+	    // 一つ前の候補へ。最初の候補だったら▽モードへ戻る。
 	    if(current_candidate_index > 0) {
 		current_candidate_index--;
 	    } else {
@@ -118,17 +118,17 @@
 	    return false;
 	}
 	else if(status == STATUS_BLACK_WITH_WINDOW) {
-	    // delete‚ª‰Ÿ‚³‚ꂽ‚à‚Ì‚ÆŒ©˜ô‚·
+	    // deleteが押されたものと見做す
 	    handleBackSpace();
 	    return false;
 	}
-	// ‚»‚êˆÈŠO‚È‚ç‘f’Ê‚è
+	// それ以外なら素通り
     }
 
     if(SKKConfig::PurgeFromJisyoKey() == skkchar) {
 	if(status == STATUS_BLACK) {
-	    // íœƒvƒƒ“ƒvƒg‚ðo‚·B‚±‚Ì•ÏŠ·‚ªŽÀ‚̓†[ƒU[Ž«‘‚ɍڂÁ‚Ä‚¢‚È‚©‚Á‚½‚Æ‚µ‚Ä‚à
-	    // –Ê“|‚È‚Ì‚Å‚»‚ÌŽ–‚ð‚í‚´‚í‚´Šm”F‚µ‚È‚¢B—v–]‚Å‚à‚ ‚ê‚Εʂ¾‚ªB
+	    // 削除プロンプトを出す。この変換が実はユーザー辞書に載っていなかったとしても
+	    // 面倒なのでその事をわざわざ確認しない。要望でもあれば別だが。
 	    status = STATUS_PROMPT;
 	    prompt_type = PROMPT_DELETE_FROM_USER_DIC;
 	    prompt_input.clear();
@@ -144,7 +144,7 @@
 
     if(SKKConfig::ToggleKatakanaKey() == skkchar) {
 	if(status == STATUS_WHITE) {
-	    // ”¼Šp‰p”Žš‚ð‘SŠp‰p”Žš‚É•ÏŠ·‚µ‚Ä‚©‚çŠm’肵‚ďI—¹
+	    // 半角英数字を全角英数字に変換してから確定して終了
 	    parent->fix(ZenAscInputMode::convert(index));
 
 	    parent->setEnabledAsciiConversionMode(false);
@@ -153,9 +153,9 @@
 	    return false;
 	}
 	if(status == STATUS_BLACK || status == STATUS_BLACK_WITH_WINDOW) {
-	    // Œ»Ý‚ÌŒó•â‚ðŠm’肵‚Ä‚©‚çA
-	    // 1) ”¼Šp•Ð‰¼–¼ƒ‚[ƒh‚Ȃ畽‰¼–¼ƒ‚[ƒh‚Ö
-	    // 2) ‚»‚êˆÈŠO‚Ȃ甼Šp•Ð‰¼–¼‰¼–¼ƒ‚[ƒh‚Ö
+	    // 現在の候補を確定してから、
+	    // 1) 半角片仮名モードなら平仮名モードへ
+	    // 2) それ以外なら半角片仮名仮名モードへ
 	    parent->setEnabledAsciiConversionMode(false);
 	    if (parent->isHanKataInputMode()) {
 		parent->goHiraganaInputMode();
@@ -167,12 +167,12 @@
     }
 
     if(SKKConfig::KakuteiKey() == skkchar) {
-	return true; // Šm’è‚Ì‚Ý
+	return true; // 確定のみ
     }
 
     if(SKKConfig::LatinModeKey() == skkchar || SKKConfig::Jisx0208LatinModeKey() == skkchar) {
 	if(status == STATUS_BLACK) {
-	    // ‚»‚ꂼ‚ê‚ðŠm’肵‚Ä”¼Šp/‘SŠp‰p”Žšƒ‚[ƒh‚ցB
+	    // それぞれを確定して半角/全角英数字モードへ。
 	    if(SKKConfig::LatinModeKey() == skkchar) {
 		parent->goHanAscInputMode();
 	    } else {
@@ -180,7 +180,14 @@
 	    }
 	    return true;
 	}
-	// ¤ƒ‚[ƒh‚âŒó•â‘I‘ð‰æ–Ê‚È‚ç‘f’Ê‚èB
+	// ▽モードや候補選択画面なら素通り。
+    }
+
+    if(SKKConfig::SetHenkanPointKey() == skkchar) {
+	if(status == STATUS_BLACK || status == STATUS_BLACK_WITH_WINDOW) {
+	    parent->fix(getStringToFix());
+	    return parent->handleInput(skkchar);
+	}
     }
 
     if(SKKConfig::SetHenkanPointKey() == skkchar) {
@@ -201,67 +208,67 @@
     if(SKKConfig::NextKouhoKey() == skkchar) {
 	if(status == STATUS_WHITE) {
 	    if(index.length() == 0) {
-		// I—¹
+		// 終了
 		parent->setEnabledAsciiConversionMode(false);
 		parent->display(CppCFString());
 		initialize();
 		return false;
 	    }
 
-	    // ŽI‚É–â‚¢‡‚킹
+	    // 鯖に問い合わせ
 	    askServerTheCandidates();
 
 	    if(candidates.size() > 0) {
-		// Œó•â‚ª‘¶Ý‚µ‚½B¥ƒ‚[ƒh‚ցB
+		// 候補が存在した。▼モードへ。
 		status = STATUS_BLACK;
-		current_candidate_index = 0; // Å‰‚ÌŒó•âB
+		current_candidate_index = 0; // 最初の候補。
 	    } else {
-		// ˆê‚‚àŒó•â‚ª–³‚¢B’PŒê“o˜^ŠJŽnB
+		// 一つも候補が無い。単語登録開始。
 		startRegisteringWord();
 	    }
 	}
 	else if(status == STATUS_BLACK) {
-	    // ŽŸ‚ÌŒó•â‚Ö
+	    // 次の候補へ
 	    current_candidate_index++;
 
-	    if(current_candidate_index >= candidates.size()) { // I‚í‚è‚܂ōs‚Á‚½‚ç’PŒê“o˜^ŠJŽnB
+	    if(current_candidate_index >= candidates.size()) { // 終わりまで行ったら単語登録開始。
 		startRegisteringWord();
 	    }
 	    else if(current_candidate_index >= show_cands_window_after_Nth_cand - 1) {
-		// ‚±‚êˆÈ~‚̃[ƒe[ƒVƒ‡ƒ“‚ÅŒó•â‘I‘ðƒEƒCƒ“ƒhƒE‚ð•\Ž¦‚·‚éB
+		// これ以降のローテーションで候補選択ウインドウを表示する。
 		status = STATUS_BLACK_WITH_WINDOW;
 		openCandidatesWindow();
 	    }
 	}
 	else if(status == STATUS_BLACK_WITH_WINDOW) {
 	    if(candidates_window_current_frame < candidates_window_num_of_frames - 1) {
-		// ÅŒã‚̃tƒŒ[ƒ€‚Å‚È‚¯‚ê‚΁AŽŸ‚̃tƒŒ[ƒ€‚֍s‚­B
+		// 最後のフレームでなければ、次のフレームへ行く。
 		goToNextCandidatesFrame();
 	    } else {
-		// ÅŒã‚̃tƒŒ[ƒ€‚¾‚Á‚½‚çA’PŒê“o˜^‚ðŠJŽnB
+		// 最後のフレームだったら、単語登録を開始。
 		closeCandidatesWindow();
 		startRegisteringWord();
 	    }
 	}
     } else {
 	if(status == STATUS_WHITE) {
-	    // index‚É‚½‚¾’ljÁB
+	    // indexにただ追加。
 	    index += skkchar;
 	}
 	else if(status == STATUS_BLACK) {
-	    // Œ»Ý‚ÌŒó•â‚ðŠm’肵‚ďˆ—‚ðŒp‘±
+	    // 現在の候補を確定して処理を継続
 	    parent->fix(getStringToFix());
 	    return parent->handleInput(skkchar);
 	}
 	else if(status == STATUS_BLACK_WITH_WINDOW) {
-	    // asdfjkli1ƒtƒŒ[ƒ€“–‚½‚è‚ÌŒó•â”‚ª7‚æ‚菭‚È‚¯‚ê‚΂±‚ê‚àŒ¸‚éBj‚Ì•¶Žš‚Å‚ ‚ê‚Î
-	    // ‚»‚ÌŒó•â‚ð‚½‚¾Šm’è‚·‚éB
-	    // ‚»‚¤‚Å‚È‚¯‚ê‚ÎŒ»Ý‚ÌŒó•â‚ð‚½‚¾Šm’è‚·‚éB
+	    // asdfjkl(1フレーム当たりの候補数が7より少なければこれも減る。)の文字であれば
+	    // その候補をただ確定する。
+	    // そうでなければ現在の候補をただ確定する。
 	    int cand_index = CppCFString("asdfjkl").substring(0, candidates_window_cands_per_frame).indexOf(skkchar);
 	    if(cand_index != -1) {
 		unsigned new_index = current_candidate_index + cand_index;
 		if(new_index < candidates.size()) {
-		    // ‚±‚̃Cƒ“ƒfƒBƒbƒNƒX‚ª‹–‚³‚ê‚é‚È‚çŠm’èB
+		    // このインディックスが許されるなら確定。
 		    current_candidate_index = new_index;
 		    return true;
 		}
@@ -269,7 +276,7 @@
 	    return false;
 	}
 	else if(status == STATUS_PROMPT) {
-	    // ‚»‚Ì‚Ü‚Üprompt_input‚ɒljÁB
+	    // そのままprompt_inputに追加。
 	    prompt_input += skkchar;
 	}
     }
@@ -284,7 +291,7 @@
 bool AsciiConversionMode::handleBackSpace() {
     if(word_register_mode) {
 	word_register_mode->handleBackSpace();
-	return true; // WordRegisterMode::handleBackSpace()‚ª‰½‚ð•Ô‚»‚¤‚Æ‚à–{•¶‚͏Á‚³‚È‚¢B
+	return true; // WordRegisterMode::handleBackSpace()が何を返そうとも本文は消さない。
     }
 
     if(status == STATUS_NULL) {
@@ -292,32 +299,32 @@
     }
 
     if(status == STATUS_WHITE) {
-	// index‚ª‹ó‚Ȃ珉Šú‰»‚µ‚ďI—¹
-	// ‹ó‚Å‚È‚¯‚ê‚Îindex‚̍Ōã‚Ì•¶Žš‚ðÁ‚·B
+	// indexが空なら初期化して終了
+	// 空でなければindexの最後の文字を消す。
 	if(index.length() == 0) {
 	    parent->setEnabledAsciiConversionMode(false);
 	    parent->display(CppCFString());
 	    initialize();
 	} else {
-	    completion_mode = false; // •âŠ®ƒ‚[ƒh‚¾‚Á‚½ê‡‚͕⊮ƒ‚[ƒh‚𔲂¯‚éB
+	    completion_mode = false; // 補完モードだった場合は補完モードを抜ける。
 	    index.eraseLast(1);
 	}
     }
     else if(status == STATUS_BLACK) {
-	// Œ»Ý‚ÌŒó•â‚ðŠm’肵‚ĈꕶŽšíœ
+	// 現在の候補を確定して一文字削除
 	CppCFString str(getStringToFix());
 	str.eraseLast(1);
 	parent->fix(str);
 	parent->display(CppCFString());
     }
     else if(status == STATUS_BLACK_WITH_WINDOW) {
-	// Å‰‚̃tƒŒ[ƒ€‚È‚çA¥ƒ‚[ƒh‚Ö–ß‚é
-	// ‚»‚¤‚Å‚È‚¯‚ê‚ΑO‚̃tƒŒ[ƒ€‚ցB
+	// 最初のフレームなら、▼モードへ戻る
+	// そうでなければ前のフレームへ。
 	if(candidates_window_current_frame == 0) {
-	    // ƒEƒCƒ“ƒhƒE‚ðŠJ‚­‘O‚É–ß‚·
+	    // ウインドウを開く前に戻す
 	    current_candidate_index = show_cands_window_after_Nth_cand - 2;
 
-	    // ƒEƒCƒ“ƒhƒE‚ð•Â‚¶‚éB
+	    // ウインドウを閉じる。
 	    closeCandidatesWindow();
 
 	    status = STATUS_BLACK;
@@ -326,7 +333,7 @@
 	}
     }
     else if(status == STATUS_PROMPT) {
-	// prompt_input‚ª‹ó‚Å‚È‚¯‚ê‚΍Ōã‚Ì•¶Žš‚ðÁ‚·B
+	// prompt_inputが空でなければ最後の文字を消す。
 	if(prompt_input.length() > 0) {
 	    prompt_input.eraseLast(1);
 	}
@@ -339,23 +346,23 @@
 	word_register_mode->handleReturn();
 
 	if(word_register_mode) {
-	    // handleReturn‚©‚çwordRegistrationFinished‚ªŒÄ‚΂ꂽ‚çword_register_mode‚Í”jŠü‚³‚ê‚邽‚߁B
+	    // handleReturnからwordRegistrationFinishedが呼ばれたらword_register_modeは破棄されるため。
 	    word_register_mode->redisplay();
 	}
 
-	return true; // í‚Étrue‚ð•Ô‚·B
+	return true; // 常にtrueを返す。
     }
 
     if(status == STATUS_PROMPT) {
 	switch(prompt_type) {
 	case PROMPT_DELETE_FROM_USER_DIC: {
-	    // prompt_input‚ªyes‚È‚çíœ‚µ‚ÄSTATUS_WHITE‚É–ß‚éB
-	    // ‚»‚êˆÈŠO‚È‚çSTATUS_BLACK‚É–ß‚éB
+	    // prompt_inputがyesなら削除してSTATUS_WHITEに戻る。
+	    // それ以外ならSTATUS_BLACKに戻る。
 	    if(prompt_input == "yes") {
-		// íœ
+		// 削除
 		makeServerRemoveWord();
 
-		// STATUS_WHITE‚Ö
+		// STATUS_WHITEへ
 		status = STATUS_WHITE;
 	    } else {
 		status = STATUS_BLACK;
@@ -370,8 +377,8 @@
     }
 
     if(ClientConfiguration::theInstance().isSkkEggLikeNewline()) {
-	// skk-egglike-newlineƒ‚[ƒh‚È‚çAŽ©—Í‚ÅŠm’肳‚¹‚Ä‚©‚珉Šú‰»‚µ‚Ätrue‚ð•Ô‚·B
-	// ŽI‚É‘—M
+	// skk-egglike-newlineモードなら、自力で確定させてから初期化してtrueを返す。
+	// 鯖に送信
 	parent->fix(getStringToFix());
 	return true;
     } else {
@@ -381,15 +388,15 @@
 
 bool AsciiConversionMode::handleArrow(SKKChar skkchar) {
     if(word_register_mode) {
-	return word_register_mode->handleArrow(skkchar); // ˆÏ÷
+	return word_register_mode->handleArrow(skkchar); // 委譲
     }
     
     if(status == STATUS_BLACK || status == STATUS_BLACK_WITH_WINDOW) {
-	// Œ»Ý‚ÌŒó•â‚ðŠm’è‚·‚é
+	// 現在の候補を確定する
 	parent->fix(getStringToFix());
     }
     
-    // ƒAƒXƒL[•ÏŠ·ƒ‚[ƒh‚ðI—¹‚·‚éB
+    // アスキー変換モードを終了する。
     parent->setEnabledAsciiConversionMode(false);
     initialize();
     return false;
@@ -400,18 +407,18 @@
 	return word_register_mode->handleCg();
     }
     
-    // •½‰¼–¼ƒCƒ“ƒvƒbƒgƒ‚[ƒh‚ÌhandleCg‚ðŒÄ‚сAgetStringToFix()‚àŒÄ‚Ô‚ªAŒÄ‚Ô‚¾‚¯B
+    // 平仮名インプットモードのhandleCgを呼び、getStringToFix()も呼ぶが、呼ぶだけ。
     parent->getCurrentInputMode().handleCg();
     parent->getCurrentInputMode().getStringToFix();
     
     if(status == STATUS_WHITE) {
-	// ƒAƒXƒL[•ÏŠ·ƒ‚[ƒhI—¹
+	// アスキー変換モード終了
 	parent->setEnabledAsciiConversionMode(false);
 	initialize();
     }
     else if(status == STATUS_BLACK || status == STATUS_BLACK_WITH_WINDOW) {
-	// okuri‚ª‹ó‚È‚çSTATUS_WHITE_ROOT‚ցB‚»‚¤‚Å‚È‚¯‚ê‚ÎSTATUS_WHITE_OKURI‚ցB
-	// ƒEƒCƒ“ƒhƒE‚ªŠJ‚©‚ê‚Ä‚¢‚½‚ç•Â‚¶‚éB
+	// okuriが空ならSTATUS_WHITE_ROOTへ。そうでなければSTATUS_WHITE_OKURIへ。
+	// ウインドウが開かれていたら閉じる。
 	if(status == STATUS_BLACK_WITH_WINDOW) {
 	    closeCandidatesWindow();
 	}
@@ -436,17 +443,17 @@
     
     if(status == STATUS_WHITE) {
 	if(completion_mode) {
-	    // ŽŸ‚ÌŒó•â‚ցBÅŒã‚܂ōs‚Á‚½‚çÅ‰‚É–ß‚éB
+	    // 次の候補へ。最後まで行ったら最初に戻る。
 	    current_completion_index++;
 	    if(current_completion_index >= completions.size()) {
 		current_completion_index = 0;
 	    }
 	    index = completions[current_completion_index];
 	} else {
-	    // ŽI‚É–â‚¢‡‚킹‚éB
+	    // 鯖に問い合わせる。
 	    askServerTheCompletions();
 
-	    // •âŠ®‚ÌŒó•â‚ª‚ ‚ê‚Ε⊮ŠJŽnB–³‚¯‚ê‚Ή½‚à‚¹‚¸‚É–ß‚éB
+	    // 補完の候補があれば補完開始。無ければ何もせずに戻る。
 	    if(completions.size() > 0) {
 		completion_mode = true;
 		index = completions[0];
@@ -461,72 +468,78 @@
 void AsciiConversionMode::terminate() {
     if(word_register_mode) {
 	word_register_mode->terminate();
+	resetRegistrationMode();
     }
 
-    parent->fix(getStringToFix()); // Šm’è‚·‚é
+    parent->fix(getStringToFix()); // 確定する
     parent->setEnabledAsciiConversionMode(false);
     initialize();
 }
 
+// 直前の単語登録モードを削除し、現在の単語登録モードを退避する
+void AsciiConversionMode::resetRegistrationMode() {
+    delete old_word_register_mode;
+    old_word_register_mode = word_register_mode;
+    word_register_mode = 0;
+}
+
 void AsciiConversionMode::wordRegistrationFinished() {
     if(word_register_mode) {
 	CppCFString content = word_register_mode->getContent();
 	if(content.length() > 0) {
-	    // ŽI‚É‘—M
+	    // 鯖に送信
 	    sendWordToServerToRegister(index,content);
 
-	    // Šm’è
+	    // 確定
 	    parent->fix(content);
 
-	    // I—¹
+	    // 終了
 	    parent->setEnabledAsciiConversionMode(false);
 	    initialize();
 	} else {
 	    status = STATUS_WHITE;
 	}
 
-	delete word_register_mode;
-	word_register_mode = NULL;
+	resetRegistrationMode();
 	parent->updatePencilMenuIcon();
     }
 }
 
 void AsciiConversionMode::wordRegistrationCanceled() {
-    delete word_register_mode;
-    word_register_mode = NULL;
+    resetRegistrationMode();
     parent->updatePencilMenuIcon();
     
     if(status == STATUS_WHITE) {
 	// do nothing
     }
     else if(status == STATUS_BLACK) {
-	current_candidate_index = candidates.size() - 1; // ÅŒã‚ÌŒó•â‚ցB
+	current_candidate_index = candidates.size() - 1; // 最後の候補へ。
     }
     else if(status == STATUS_BLACK_WITH_WINDOW) {
-	// ƒEƒCƒ“ƒhƒE‚ðŠJ‚¢‚čŌã‚̃tƒŒ[ƒ€‚ðo‚·
-	current_candidate_index = show_cands_window_after_Nth_cand - 1; // goToNextCandidatesFrame()‚Å‚¸‚ê‚éB
+	// ウインドウを開いて最後のフレームを出す
+	current_candidate_index = show_cands_window_after_Nth_cand - 1; // goToNextCandidatesFrame()でずれる。
 	openCandidatesWindow(OpenReverse);
     }
 }
 
 CppCFString AsciiConversionMode::getStringToDisplay() {
     if(word_register_mode) {
-	// –³Ž‹‚³‚¹‚éB‚³‚à‚È‚¢‚Ɛ܊pWordRegisterMode‚ªÝ’肵‚½•¶Žš‚ð’ׂµ‚Ä‚µ‚Ü‚¤B
+	// 無視させる。さもないと折角WordRegisterModeが設定した文字を潰してしまう。
 	return CppCFString().append(kIgnoreThis);
     }
     
     if(status == STATUS_WHITE) {
-	// ¤index
+	// â–½index
 	return CppCFString().append(0x25bd).append(index);
     }
     else if(status == STATUS_BLACK || status == STATUS_BLACK_WITH_WINDOW) {
 	CppCFString str(convertNumeric(numconv_, candidates[current_candidate_index]));
 
-	// ¥Œ»Ý‚ÌŒó•â
+	// ▼現在の候補
 	return CppCFString().append(0x25bc).append(str);
     }
     else if(status == STATUS_PROMPT) {
-	// [ƒvƒƒ“ƒvƒg][“ü—Í]
+	// [プロンプト][入力]
 	return CppCFString('[').append(prompt).append("][").append(prompt_input).append(kCaret).append(']');
     } else {
 	return CppCFString().append(kIgnoreThis);
@@ -541,24 +554,24 @@
     else if(status == STATUS_BLACK) {
 	result = convertNumeric(numconv_, candidates[current_candidate_index]);
 
-	// ŽI‚É‘—M
+	// 鯖に送信
 	sendCurrentCandidateToServerToRegister();
     }
     else if(status == STATUS_BLACK_WITH_WINDOW) {
 	result = convertNumeric(numconv_, candidates[current_candidate_index]);
 
-	// ŽI‚É‘—M
+	// 鯖に送信
 	sendCurrentCandidateToServerToRegister();
 
-	// ƒEƒCƒ“ƒhƒE‚ð•Â‚¶‚éB
+	// ウインドウを閉じる。
 	closeCandidatesWindow();
     }
     else /* if (status == STATUS_NULL) */ {
 	result = CppCFString().append(kIgnoreThis);
     }
     
-    // ‚±‚ꂪŒÄ‚΂ꂽ‚Æ‚¢‚¤‚±‚Æ‚Ífix‚³‚ê‚é‚Æ‚¢‚¤‚±‚ƂȂ̂ŃAƒXƒL[•ÏŠ·ƒ‚[ƒhI—¹B
-    // ‰Šú‰»‚·‚éB
+    // これが呼ばれたということはfixされるということなのでアスキー変換モード終了。
+    // 初期化する。
     parent->setEnabledAsciiConversionMode(false);
     initialize();
     
@@ -580,14 +593,14 @@
 
     str.append(index);
 
-    // ahya@¨@-ahya
+    // ahya → -ahya
     CppCFData query;
     query.own(str.toCFData());
 
     current_candidate_index = 0;
     ::askServerTheCandidates(query, candidates);
 
-    // ”’l•ÏŠ·‚ª—LŒø‚©H
+    // 数値変換が有効か?
     if(ClientConfiguration::theInstance().useNumericConversion() &&
        numconv_.Setup(index.toStdString(kCFStringEncodingUTF8))) {
 	CppCFString normalized(numconv_.NormalizedKey().c_str(), kCFStringEncodingUTF8);
@@ -603,7 +616,7 @@
 }
 
 void AsciiConversionMode::askServerTheCompletions() {
-    // ŽI‚ɐq‚Ë‚é
+    // 鯖に尋ねる
     CppCFData cfdata_query;
     cfdata_query.own(index.toCFData());
 
@@ -612,16 +625,16 @@
 }
 
 void AsciiConversionMode::sendCurrentCandidateToServerToRegister() {
-    // ŽI‚É‘—M
+    // 鯖に送信
     sendWordToServerToRegister(index,candidates[current_candidate_index]);
 }
 
 void AsciiConversionMode::makeServerRemoveWord() {
     CppCFString query;
-    // ahya i߁Í߁j@¨@-ahya i߁Í߁j
+    // ahya (゚∀゚) → -ahya (゚∀゚)
     query.append('-').append(index).append(SKK_MSG_DELIMITER).append(candidates[current_candidate_index]);
     
-    // ŽI‚É“n‚·
+    // 鯖に渡す
     CppCFData cfdata_query;
     cfdata_query.own(query.toCFData());
     ::makeServerRemoveWord(cfdata_query);
@@ -645,45 +658,35 @@
 }
 
 void AsciiConversionMode::goToNextCandidatesFrame() {
-    // ƒEƒCƒ“ƒhƒEID(UInt16)‚ðŠÜ‚ÞCFData‚ðì¬‚µAŽI‚Ö‘—‚éB
+    // ウインドウID(UInt16)を含むCFDataを作成し、鯖へ送る。
     CppCFData reply(ServerConnectionFactory::theInstance().newConnection().
 		    send(kSKKCandidatesWindowNext, newCFDataRefWithWindowID(candidates_window_id),
 			 kAquaSKKServerRunLoopMode));
 
-    // Œ»Ý‚̃tƒŒ[ƒ€”ԍ†‚ðƒCƒ“ƒNƒŠƒƒ“ƒg
+    // 現在のフレーム番号をインクリメント
     ++ candidates_window_current_frame;
 
-    // Œ»Ý‚ÌŒó•â”ԍ†‚ðƒtƒŒ[ƒ€“–‚½‚è‚ÌŒó•â”•ª‘‚â‚·B
+    // 現在の候補番号をフレーム当たりの候補数分増やす。
     current_candidate_index += candidates_window_cands_per_frame;
     candidates_window_cands_per_frame = CFSwapInt16BigToHost(reply.getUInt16(0));
 }
 
 void AsciiConversionMode::goToPrevCandidatesFrame() {
-    // ƒEƒCƒ“ƒhƒEID(UInt16)‚ðŠÜ‚ÞCFData‚ðì¬‚µAŽI‚Ö‘—‚éB
+    // ウインドウID(UInt16)を含むCFDataを作成し、鯖へ送る。
     CppCFData reply(ServerConnectionFactory::theInstance().newConnection().
 		    send(kSKKCandidatesWindowPrev, newCFDataRefWithWindowID(candidates_window_id),
 			 kAquaSKKServerRunLoopMode));
 
-    // Œ»Ý‚̃tƒŒ[ƒ€”ԍ†‚ðƒfƒNƒŠƒƒ“ƒg
+    // 現在のフレーム番号をデクリメント
     -- candidates_window_current_frame;
 
-    // Œ»Ý‚ÌŒó•â”ԍ†‚ðƒtƒŒ[ƒ€“–‚½‚è‚ÌŒó•â”•ªŒ¸‚ç‚·B
+    // 現在の候補番号をフレーム当たりの候補数分減らす。
     candidates_window_cands_per_frame = CFSwapInt16BigToHost(reply.getUInt16(0));
     current_candidate_index -= candidates_window_cands_per_frame;
 }
 
-void AsciiConversionMode::suspendCandidatesWindow() {
-    ServerConnectionFactory::theInstance().newConnection().
-	send(kSKKSuspendCandidatesWindow, newCFDataRefWithWindowID(candidates_window_id));
-}
-
-void AsciiConversionMode::resumeCandidatesWindow() {
-    ServerConnectionFactory::theInstance().newConnection().
-	send(kSKKResumeCandidatesWindow, newCFDataRefWithWindowID(candidates_window_id));
-}
-
 void AsciiConversionMode::closeCandidatesWindow() {
-    // ƒEƒCƒ“ƒhƒEID(UInt16)‚ðŠÜ‚ÞCFData‚ðì¬‚µAŽI‚Ö‘—‚éB
+    // ウインドウID(UInt16)を含むCFDataを作成し、鯖へ送る。
     ServerConnectionFactory::theInstance().newConnection().
 	send(kSKKCloseCandidatesWindow, newCFDataRefWithWindowID(candidates_window_id));
 }
Index: AquaSKK/AsciiConversionMode.h
diff -u AquaSKK/AsciiConversionMode.h:1.5.2.1 AquaSKK/AsciiConversionMode.h:1.5.2.2
--- AquaSKK/AsciiConversionMode.h:1.5.2.1	Sat Feb  3 16:53:29 2007
+++ AquaSKK/AsciiConversionMode.h	Thu Aug 16 19:58:18 2007
@@ -1,5 +1,5 @@
 /*
-  $Id: AsciiConversionMode.h,v 1.5.2.1 2007/02/03 07:53:29 t-suwa Exp $
+  $Id: AsciiConversionMode.h,v 1.5.2.2 2007/08/16 10:58:18 t-suwa Exp $
 
   MacOS X implementation of the SKK input method.
 
@@ -38,35 +38,36 @@
     NumericConverter numconv_;
 
 protected:
-    static const int STATUS_NULL = 0; // ƒAƒXƒL[•ÏŠ·ƒ‚[ƒh‚É‚È‚Á‚Ä‚¢‚È‚¢ó‘ԁBæ“ª‚Ɂ¤‚à¥‚à–³‚¢B
-    static const int STATUS_WHITE = 1; // ¤ƒ‚[ƒh
-    static const int STATUS_BLACK = 2; // ¥ƒ‚[ƒh
-    static const int STATUS_BLACK_WITH_WINDOW = 3; // ¥ƒ‚[ƒh‚ŁAŒó•â‘I‘ðƒEƒCƒ“ƒhƒE‚ªŠJ‚¢‚Ä‚¢‚éB
-    static const int STATUS_PROMPT = 4; // ƒvƒƒ“ƒvƒg‚ðo‚µ‚Ä‚¢‚éB
+    static const int STATUS_NULL = 0; // アスキー変換モードになっていない状態。先頭に▽も▼も無い。
+    static const int STATUS_WHITE = 1; // ▽モード
+    static const int STATUS_BLACK = 2; // ▼モード
+    static const int STATUS_BLACK_WITH_WINDOW = 3; // ▼モードで、候補選択ウインドウが開いている。
+    static const int STATUS_PROMPT = 4; // プロンプトを出している。
 
-    WordRegisterMode* word_register_mode; // NULL‚Å‚È‚¢Žž‚Í’PŒê“o˜^ƒ‚[ƒh‚ª‹N“®’†B
+    WordRegisterMode* word_register_mode; // NULLでない時は単語登録モードが起動中。
+    WordRegisterMode* old_word_register_mode; // 直前まで有効だった単語登録モード
 
     int status;
-    CppCFString index; // Œ©o‚µŒê
+    CppCFString index; // 見出し語
 
-    static const int PROMPT_DELETE_FROM_USER_DIC = 1; // ƒ†[ƒU[Ž«‘‚©‚ç’PŒê‚ðíœ
-    int prompt_type; // ƒvƒƒ“ƒvƒg‚ÌŽí—ށB
-    CppCFString prompt; // ƒvƒƒ“ƒvƒg
-    CppCFString prompt_input; // ƒvƒƒ“ƒvƒg‚Ƀ†[ƒU[‚ª“ü—Í‚µ‚½•¶Žš—ñ
-
-    std::vector<CppCFString> candidates; // ‘S‚Ä‚ÌŒó•â
-    unsigned current_candidate_index; // Œ»Ý‚ÌŒó•â”ԍ†
-
-    unsigned show_cands_window_after_Nth_cand; // ‰½ŒÂ–ڈȍ~‚ÌŒó•â‚ðŒó•â‘I‘ðƒEƒCƒ“ƒhƒE‚É•\Ž¦‚·‚é‚©B
-
-    unsigned candidates_window_id; // status‚ªSTATUS_BLACK_WITH_WINDOW‚Ì‚Æ‚«AŒó•â‘I‘ðƒEƒCƒ“ƒhƒE‚ÌIDB
-    unsigned candidates_window_current_frame; // Œó•â‘I‘ðƒEƒCƒ“ƒhƒE‚ÌŒ»Ý‚̃tƒŒ[ƒ€
-    unsigned candidates_window_cands_per_frame; // Œó•â‘I‘ðƒEƒCƒ“ƒhƒE‚Ì1ƒtƒŒ[ƒ€“–‚½‚è‚ÌŒó•â”
-    unsigned candidates_window_num_of_frames; // Œó•â‘I‘ðƒEƒCƒ“ƒhƒE‚̃tƒŒ[ƒ€”
-
-    bool completion_mode; // Œ©o‚µŒê•âŠ®ƒ‚[ƒhB‚±‚̃‚[ƒh‚ł̓sƒŠƒIƒh‚ƃJƒ“ƒ}‚ª•âŠ®‚Ì‘€ì‚ÉŽg‚í‚ê‚éB
-    std::vector<CppCFString> completions; // •âŠ®‚ÌŒó•â
-    unsigned current_completion_index; // Œ»Ý‚̕⊮‚ÌŒó•â”ԍ†
+    static const int PROMPT_DELETE_FROM_USER_DIC = 1; // ユーザー辞書から単語を削除
+    int prompt_type; // プロンプトの種類。
+    CppCFString prompt; // プロンプト
+    CppCFString prompt_input; // プロンプトにユーザーが入力した文字列
+
+    std::vector<CppCFString> candidates; // 全ての候補
+    unsigned current_candidate_index; // 現在の候補番号
+
+    unsigned show_cands_window_after_Nth_cand; // 何個目以降の候補を候補選択ウインドウに表示するか。
+
+    unsigned candidates_window_id; // statusがSTATUS_BLACK_WITH_WINDOWのとき、候補選択ウインドウのID。
+    unsigned candidates_window_current_frame; // 候補選択ウインドウの現在のフレーム
+    unsigned candidates_window_cands_per_frame; // 候補選択ウインドウの1フレーム当たりの候補数
+    unsigned candidates_window_num_of_frames; // 候補選択ウインドウのフレーム数
+
+    bool completion_mode; // 見出し語補完モード。このモードではピリオドとカンマが補完の操作に使われる。
+    std::vector<CppCFString> completions; // 補完の候補
+    unsigned current_completion_index; // 現在の補完の候補番号
 
     bool henkanModeStatus;
 
@@ -78,16 +79,15 @@
     virtual void openCandidatesWindow(OpenDirection mode = OpenNormal);
     virtual void goToPrevCandidatesFrame();
     virtual void goToNextCandidatesFrame();
-    virtual void suspendCandidatesWindow();
-    virtual void resumeCandidatesWindow();
     virtual void closeCandidatesWindow();
     virtual void initialize();
+    virtual void resetRegistrationMode();
 	
 public:
     AsciiConversionMode(class ParentInputMode& parent);
     virtual ~AsciiConversionMode();
 
-    virtual void start(); // ‚±‚ꂪŒÄ‚΂ê‚é‚Ɓ¤ƒ‚[ƒh‚É‚È‚éB
+    virtual void start(); // これが呼ばれると▽モードになる。
     virtual bool handleInput(SKKChar skkchar);
     virtual bool handleBackSpace();
     virtual bool handleReturn();
@@ -99,8 +99,8 @@
     virtual CppCFString getStringToDisplay();
     virtual CppCFString getStringToFix();
 
-    virtual void wordRegistrationFinished(); // WordRegisterModeê—pB
-    virtual void wordRegistrationCanceled(); // WordRegisterModeê—pB
+    virtual void wordRegistrationFinished(); // WordRegisterMode専用。
+    virtual void wordRegistrationCanceled(); // WordRegisterMode専用。
 };
 
 #endif	// INC__AsciiConversionMode__
Index: AquaSKK/BIMClientServer.h
diff -u AquaSKK/BIMClientServer.h:1.6.2.1 AquaSKK/BIMClientServer.h:1.6.2.2
--- AquaSKK/BIMClientServer.h:1.6.2.1	Sat Feb  3 16:53:29 2007
+++ AquaSKK/BIMClientServer.h	Thu Aug 16 19:58:18 2007
@@ -1,5 +1,5 @@
 /*
-  $Id: BIMClientServer.h,v 1.6.2.1 2007/02/03 07:53:29 t-suwa Exp $
+  $Id: BIMClientServer.h,v 1.6.2.2 2007/08/16 10:58:18 t-suwa Exp $
 
   MacOS X implementation of the SKK input method.
 
@@ -24,29 +24,27 @@
 #ifndef INC__BIMClientServer__
 #define INC__BIMClientServer__
 
-// ƒRƒ“ƒ|[ƒlƒ“ƒg‚̃oƒ“ƒhƒ‹–¼
+// コンポーネントのバンドル名
 #define kIMBundleIdentifier "jp.sourceforge.AquaSKKInputMethod"
 
-// ƒT[ƒo[–¼
-//#define kBasicServerName "\pAquaSKKServer.app"
+// サーバー名
 #define kCSTR_SKKServerName "AquaSKKServer.app"
 
-// ƒT[ƒo[ƒ|[ƒg–¼
+// サーバーポート名
 #define kBasicServerPortName "jp.sourceforge.AquaSKKServer"
 
-// ƒT[ƒo[‚Ì RunLoopMode
+// サーバーの RunLoopMode
 #define	kAquaSKKServerRunLoopMode	CFSTR("AquaSKK::ServerRunLoopMode")
 
-// ƒNƒ‰ƒCƒAƒ“ƒg‚Ì RunLoopMode
+// クライアントの RunLoopMode
 #define	kAquaSKKClientRunLoopMode	CFSTR("AquaSKK::ClientRunLoopMode")
 
-// ƒNƒ‰ƒCƒAƒ“ƒg¨ŽI‚ւ̃ƒbƒZ[ƒW‚Ì‘—M‚ŁAcontent‚̐擪‚É•t‚­ƒwƒbƒ_B
+// クライアント→鯖へのメッセージの送信で、contentの先頭に付くヘッダ。
 struct BasicMessageHeader {
     ProcessSerialNumber		fProcessSerialNumber;
 };
-typedef struct BasicMessageHeader BasicMessageHeader;
 
-// TSM‚©‚çî•ñ‚ðˆø‚«o‚·Žž‚ÉŽg—p‚·‚é\‘¢‘́B
+// TSMから情報を引き出す時に使用する構造体。
 struct OffsetToPosParams {
     long			fRefCon;
     long			fTextOffset;
@@ -70,46 +68,75 @@
 
 typedef SInt32 BasicMessageID;
 
-// ƒƒbƒZ[ƒW‚Ì‹æØ‚蕶Žš
-#define	SKK_MSG_DELIMITER	(0x0b) /* ‚’¼ƒ^ƒu */
+// メッセージの区切り文字
+#define	SKK_MSG_DELIMITER	(0x0b) // 垂直タブ
 
-enum { // ƒNƒ‰ƒCƒAƒ“ƒg‚©‚çŽI‚ւ̃ƒbƒZ[ƒW
-    kBasicMessageActivated			= 100,	// SKK‚ªƒAƒNƒeƒBƒu‚É‚È‚Á‚½B
-    kBasicMessageDeactivated			= 101,	// SKK‚ªƒAƒNƒeƒBƒu‚Å‚È‚­‚È‚Á‚½B
-    kBasicMessageHidePalettes			= 102,	// ƒpƒŒƒbƒg‚ð‰B‚·‚悤ATSM‚ÉŽwŽ¦‚³‚ꂽ
-	
-    kSKKMessageSearch = 200, // ŒŸõBƒNƒGƒŠ‚ÌŒ`Ž®‚ÍUniChar‚Ì”z—ñ‚ŗႦ‚΁u+‚½‚Æe ‚¦v‚âu-‚Í‚¢‚ꂁvB
-    // ‘—‚艼–¼‚ª‚ ‚ê‚ΐ擪‚ª+A–³‚¯‚ê‚Î-B‘—‚艼–¼‚ª‚ ‚éê‡‚Í”¼ŠpƒXƒy[ƒX‚Å‹æØ‚ç‚ê‚Ä‚¢‚éB
-    // ƒŒƒXƒ|ƒ“ƒX‚͗Ⴆ‚΁u—Ⴆ šg‚¦vu”z—ñ ”r—ñv‚̂悤‚É”¼ŠpƒXƒy[ƒX‚Å‹æØ‚ç‚ê‚Ä‚¢‚éB
-    kSKKCreateCandidatesWindow = 201, // Œó•â‘I‘ð‰æ–Ê‚ð•\Ž¦B
-    // ƒNƒGƒŠ‚ÌŒ`Ž®‚Í
-    // +0	•\Ž¦‚·‚ׂ«xÀ•W(QuickDrawÀ•W)	•„†•t‚«2ƒoƒCƒg®”
-    // +2	•\Ž¦‚·‚ׂ«yÀ•W(QuickDrawÀ•W)	•„†•t‚«2ƒoƒCƒg®”
-    // +4	Œó•â(Œãq)						UniChar”z—ñ
-    // Œó•â:uˆ¢ ˆŸ ˜± —gv‚̂悤‚ÉŠ¿Žš‚Ì•”•ª‚𔼊pƒXƒy[ƒX‚Å‹æØ‚Á‚Ä•À‚ׂ½‚à‚́B
+enum { // クライアントから鯖へのメッセージ
+    // SKKがアクティブになった
+    kBasicMessageActivated = 100,
+
+    // SKKがアクティブでなくなった
+    kBasicMessageDeactivated = 101,
+
+    // パレットを隠すよう、TSMに指示された
+    kBasicMessageHidePalettes = 102,
+
+    // 検索:クエリの形式はUniCharの配列で例えば「+たとe え」や「-はいれつ」
+    // 送り仮名があれば先頭が+、無ければ-
+    // 送り仮名がある場合は SKK_MSG_DELIMITER で区切られている
+    // レスポンスは例えば「配列 排列」のように SKK_MSG_DELIMITER で区切られている
+    kSKKMessageSearch = 200,
+
+    // 候補選択画面を表示
+    // クエリの形式は
+    // +0	表示すべきx座標(QuickDraw座標)	符号付き2バイト整数
+    // +2	表示すべきy座標(QuickDraw座標)	符号付き2バイト整数
+    // +4	候補(後述)			UniChar配列
+    // 候補:「阿 亜 亞 揚」のように漢字の部分を SKK_MSG_DELIMITER で区切って並べたもの。
     //
-    // ƒŒƒXƒ|ƒ“ƒX‚Í
-    // +0	Œó•â‘I‘ð‰æ–ÊID				•„†–³‚µ2ƒoƒCƒg®”
-    // +2	1ƒtƒŒ[ƒ€‚É•\Ž¦‚·‚éŒó•â‚̐”	•„†–³‚µ2ƒoƒCƒg®”
-    // +4	ƒtƒŒ[ƒ€”					•„†–³‚µ2ƒoƒCƒg®”
-    // Œv6ƒoƒCƒgB
-    kSKKCandidatesWindowNext = 202, // Žw’肵‚½Œó•â‘I‘ð‰æ–Ê‚ðŽŸ‚ÖƒXƒNƒ[ƒ‹BƒNƒGƒŠ‚Í2ƒoƒCƒg‚ÌŒó•â‘I‘ð‰æ–ÊIDBƒŒƒXƒ|ƒ“ƒX–³‚µB
-    kSKKCandidatesWindowPrev = 203, // ‘O‚ÖƒXƒNƒ[ƒ‹BŒã‚ÍNext‚Æ“¯‚¶B
-    kSKKCloseCandidatesWindow = 204, // •Â‚¶‚éBŒã‚ÍNext‚Æ“¯‚¶B
-    kSKKRegisterThisToUserDic = 205, // ƒ†[ƒU[Ž«‘‚Ö‚Ì“o˜^BƒNƒGƒŠ‚ÌŒ`Ž®‚ÍUniChar‚Ì”z—ñ‚ŁA
-    // —Ⴆ‚΁u+‚½‚Æe ‚¦ —ávu-‚Í‚¢‚ê‚ ”z—ñv‚Æ‚È‚Á‚Ä‚¢‚éBƒŒƒXƒ|ƒ“ƒX‚Í–³‚¢B
-    kSKKRemoveThisFromUserDic = 206, // ƒ†[ƒU[Ž«‘‚©‚çíœBƒNƒGƒŠ‚ÌŒ`Ž®‚ÍkSKKRegisterThisToUserDic‚Æ“¯‚¶B
-    kSKKSuspendCandidatesWindow = 207,
-    kSKKResumeCandidatesWindow = 208,
-
-    kSKKShowAboutBox = 300, // AboutBox‚ð•\Ž¦‚·‚éBƒŒƒXƒ|ƒ“ƒX‚Í–³‚¢B
-    kSKKShowPreferencesBox = 301, // ŠÂ‹«Ý’èƒEƒCƒ“ƒhƒE‚ð•\Ž¦‚·‚éBƒŒƒXƒ|ƒ“ƒX‚Í–³‚¢B
-    kSKKShowWordRegistrationBox = 302, // ’PŒê“o˜^ƒEƒCƒ“ƒhƒE‚ð•\Ž¦‚·‚éBƒŒƒXƒ|ƒ“ƒX‚Í–³‚¢B
+    // レスポンスは
+    // +0	候補選択画面ID			符号無し2バイト整数
+    // +2	1フレームに表示する候補の数	符号無し2バイト整数
+    // +4	フレーム数			符号無し2バイト整数
+    kSKKCreateCandidatesWindow = 201,
+
+    // 指定した候補選択画面を次へスクロール
+    // クエリは2バイトの候補選択画面 ID
+    kSKKCandidatesWindowNext = 202,
+
+    // 前へスクロール
+    kSKKCandidatesWindowPrev = 203,
+
+    // 閉じる
+    kSKKCloseCandidatesWindow = 204,
+
+    // ユーザー辞書への登録
+    // クエリの形式はUniCharの配列で、
+    // 例えば「+たとe え 例」「-はいれつ 配列」となっている
+    kSKKRegisterThisToUserDic = 205,
+
+    // ユーザー辞書から削除
+    // クエリの形式はkSKKRegisterThisToUserDicと同じ
+    kSKKRemoveThisFromUserDic = 206,
+	
+    // AboutBoxを表示する(レスポンス無)
+    kSKKShowAboutBox = 300,
+
+    // 環境設定ウインドウを表示(レスポンス無)
+    kSKKShowPreferencesBox = 301,
+
+    // 単語登録ウインドウを表示(レスポンス無)
+    kSKKShowWordRegistrationBox = 302,
+	
+    // 補完の候補を検索
+    // クエリの形式はUniCharの配列で例えば「ほ」など
+    // レスポンスは「ほか ほかん」のように SKK_MSG_DELIMITER で区切られた見出し語のリスト
+    kSKKFetchCompletions = 400,
 
-    kSKKFetchCompletions = 400, // •âŠ®‚ÌŒó•â‚ðŒŸõBƒNƒGƒŠ‚ÌŒ`Ž®‚ÍUniChar‚Ì”z—ñ‚ŁA
-    // —Ⴆ‚΁u‚فvBƒŒƒXƒ|ƒ“ƒX‚́u‚Ù‚© ‚Ù‚©‚ñv‚̂悤‚É”¼ŠpƒXƒy[ƒX‚Å‹æØ‚ç‚ꂽŒ©o‚µŒê‚̃ŠƒXƒgB
+    // トグル変換の見出し語を登録
+    kSKKRegisterToggleEntry = 401,
 
-    kBasicMessageIsSkkEggLikeNewline = 500,	// 
+    kBasicMessageIsSkkEggLikeNewline = 500,
     kBasicMessageIsNumericKeypad_HalfWidth = 501,
     kBasicMessageIsAsciiModeStartup = 502,
     kBasicMessageUseNumericConversion = 503,
@@ -117,7 +144,7 @@
     kBasicMessage__EOF
 };
 
-// ƒT[ƒo[‚©‚çƒNƒ‰ƒCƒAƒ“ƒg‚Ö‚Ì’Ê’mƒƒbƒZ[ƒW
+// サーバーからクライアントへの通知メッセージ
 enum {
     kSKKClientConfigurationModified = 100
 };
Index: AquaSKK/CandidatesManager.h
diff -u AquaSKK/CandidatesManager.h:1.4.2.1 AquaSKK/CandidatesManager.h:1.4.2.2
--- AquaSKK/CandidatesManager.h:1.4.2.1	Sat Feb  3 16:53:29 2007
+++ AquaSKK/CandidatesManager.h	Thu Aug 16 19:58:18 2007
@@ -1,5 +1,5 @@
 /*
-  $Id: CandidatesManager.h,v 1.4.2.1 2007/02/03 07:53:29 t-suwa Exp $
+  $Id: CandidatesManager.h,v 1.4.2.2 2007/08/16 10:58:18 t-suwa Exp $
 
   MacOS X implementation of the SKK input method.
 
@@ -39,8 +39,6 @@
     unsigned createAndShow(SInt16 qd_x, SInt16 qd_y, const CppCFString& candidates, bool showLast = false);
     void windowNext(unsigned int window_id);
     void windowPrev(unsigned int window_id);
-    void suspendWindow(unsigned int window_id);
-    void resumeWindow(unsigned int window_id);
     void closeWindow(unsigned int window_id);
     CandidatesWindowController* getWindowController(unsigned window_id);
 };
Index: AquaSKK/CandidatesManager.mm
diff -u AquaSKK/CandidatesManager.mm:1.6.2.1 AquaSKK/CandidatesManager.mm:1.6.2.2
--- AquaSKK/CandidatesManager.mm:1.6.2.1	Sat Feb  3 16:53:29 2007
+++ AquaSKK/CandidatesManager.mm	Thu Aug 16 19:58:18 2007
@@ -1,5 +1,5 @@
 /* -*- objc -*-
-  $Id: CandidatesManager.mm,v 1.6.2.1 2007/02/03 07:53:29 t-suwa Exp $
+  $Id: CandidatesManager.mm,v 1.6.2.2 2007/08/16 10:58:18 t-suwa Exp $
 	
   MacOS X implementation of the SKK input method.
 
@@ -103,18 +103,6 @@
     [cand_windows[window_id] showPrevFrame];
 }
 
-void CandidatesManager::suspendWindow(unsigned int window_id) {
-    CandidatesWindowController* cwc = cand_windows[window_id];
-
-    [[cwc window] orderOut:nil];
-}
-
-void CandidatesManager::resumeWindow(unsigned int window_id) {
-    CandidatesWindowController* cwc = cand_windows[window_id];
-
-    [[cwc window] orderFront:nil];
-}
-
 void CandidatesManager::closeWindow(unsigned int window_id) {
     CandidatesWindowController* cwc = cand_windows[window_id];
 
Index: AquaSKK/ChangeLog
diff -u AquaSKK/ChangeLog:1.33.2.8 AquaSKK/ChangeLog:1.33.2.9
--- AquaSKK/ChangeLog:1.33.2.8	Sat Feb  3 17:52:48 2007
+++ AquaSKK/ChangeLog	Thu Aug 16 19:58:18 2007
@@ -1,3 +1,36 @@
+2007-06-15  Tomotaka SUWA  <t.suw****@mac*****>
+
+	* AquaSKK.pbproj/project.pbxproj: Panther でビルドできるように修
+	正(OkuriganaEntry を除去)。
+
+2007-06-14  Tomotaka SUWA  <t.suw****@mac*****>
+
+	* *ConversionMode.*: 単語登録モードを安全に削除するように修正。
+
+	* KanjiConversionMode.*:
+	(1) 補完結果を現在の文字種別と合わせるように修正
+	(2) 単語登録時に見出し語が「ひらかな」に正規化されない不具合を修正
+	(3) 単語登録前の入力モードが復元されない不具合を修正
+
+2007-06-12  Tomotaka SUWA  <t.suw****@mac*****>
+
+	* ServerMessageReceiver.* (registerToggleEntry): トグル変換の結果を
+	ユーザー辞書に登録する。変換候補は空。
+
+	* KanjiConversionMode.* (registerToggleEntry): 新規追加関数。トグ
+	ル変換の結果を学習する。
+
+	* DictionarySet.cpp (RegisterOkuriNasi): entry.empty() チェックをし
+	ないように修正。トグル変換を学習する場合、entry は空のため。
+
+	* Dictionary.h: SKKEntry で空の変換候補に対応。
+
+	* BIMClientServer.h: kSKKRegisterToggleEntry を追加、コード整形。
+
+2007-06-09  Tomotaka SUWA  <t.suw****@mac*****>
+
+	* AquaSKK 3.4 リリース。
+
 2007-02-03  Tomotaka SUWA  <t.suw****@mac*****>
 
 	* tests/TestAquaSKK.scpt: 新規追加。AppleScript による自動テストス
Index: AquaSKK/Dictionary.h
diff -u AquaSKK/Dictionary.h:1.4.2.6 AquaSKK/Dictionary.h:1.4.2.7
--- AquaSKK/Dictionary.h:1.4.2.6	Sat Feb  3 17:52:48 2007
+++ AquaSKK/Dictionary.h	Thu Aug 16 19:58:18 2007
@@ -1,10 +1,10 @@
 /* -*- C++ -*-
-  $Id: Dictionary.h,v 1.4.2.6 2007/02/03 08:52:48 t-suwa Exp $
+  $Id: Dictionary.h,v 1.4.2.7 2007/08/16 10:58:18 t-suwa Exp $
 
   MacOS X implementation of the SKK input method.
 
   Copyright (C) 2002 phonohawk
-  Copyright (C) 2005-2006 Tomotaka SUWA <t.suw****@mac*****>
+  Copyright (C) 2005-2007 Tomotaka SUWA <t.suw****@mac*****>
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -354,6 +354,9 @@
     }
 
     void addCandidate(const SKKCandidate& theCandidate) {
+	// 候補が空なら何もしない
+	if(theCandidate.IsEmpty()) return;
+
 	// 註釈を含む完全なエントリを探す
 	SKKCandidateIterator i = getCandidateIterator(theCandidate);
 
@@ -367,6 +370,9 @@
     }
 
     void updateCandidate(const SKKCandidate& theCandidate) {
+	// 候補が空なら何もしない
+	if(theCandidate.IsEmpty()) return;
+
 	SKKCandidate target;
 
 	// 註釈を含む完全なエントリを探す
Index: AquaSKK/DictionarySet.cpp
diff -u AquaSKK/DictionarySet.cpp:1.5.2.7 AquaSKK/DictionarySet.cpp:1.5.2.8
--- AquaSKK/DictionarySet.cpp:1.5.2.7	Sat Feb  3 17:52:48 2007
+++ AquaSKK/DictionarySet.cpp	Thu Aug 16 19:58:18 2007
@@ -1,10 +1,10 @@
 /*
-  $Id: DictionarySet.cpp,v 1.5.2.7 2007/02/03 08:52:48 t-suwa Exp $
+  $Id: DictionarySet.cpp,v 1.5.2.8 2007/08/16 10:58:18 t-suwa Exp $
 
   MacOS X implementation of the SKK input method.
 
   Copyright (C) 2002-2004 phonohawk
-  Copyright (C) 2005-2006 Tomotaka SUWA <t.suw****@mac*****>
+  Copyright (C) 2005-2007 Tomotaka SUWA <t.suw****@mac*****>
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -273,7 +273,8 @@
 }
 
 void DictionarySet::RegisterOkuriNasi(const std::string& key, const std::string& entry) {
-    if(key.empty() || entry.empty()) {
+    // key だけチェックする(トグル変換の登録時は entry は空)
+    if(key.empty()) {
 	std::cerr << "AquaSKK: Invalid registration received" << std::endl;
     } else {
 	userdict_->registerOkuriNasi(key, entry);
Index: AquaSKK/KanjiConversionMode.cpp
diff -u AquaSKK/KanjiConversionMode.cpp:1.8.2.5 AquaSKK/KanjiConversionMode.cpp:1.8.2.6
--- AquaSKK/KanjiConversionMode.cpp:1.8.2.5	Sat Feb  3 17:52:48 2007
+++ AquaSKK/KanjiConversionMode.cpp	Thu Aug 16 19:58:18 2007
@@ -1,5 +1,5 @@
 /*
-  $Id: KanjiConversionMode.cpp,v 1.8.2.5 2007/02/03 08:52:48 t-suwa Exp $
+  $Id: KanjiConversionMode.cpp,v 1.8.2.6 2007/08/16 10:58:18 t-suwa Exp $
 
   MacOS X implementation of the SKK input method.
 
@@ -41,33 +41,34 @@
 #endif
 
 /*
-  ‚©‚È“ü—̓‚[ƒh‚ő啶Žš‚̃Aƒ‹ƒtƒ@ƒxƒbƒg‚ð“ü—Í‚·‚é‚ƁA
-  Š¿Žš“ü—̓‚[ƒh‚ɐ؂è‘Ö‚í‚èA‚»‚ÌŽž‚Ì•¶Žš‚ªhandleInput‚É“n‚³‚ê‚éB
+  かな入力モードで大文字のアルファベットを入力すると、
+  漢字入力モードに切り替わり、その時の文字がhandleInputに渡される。
   
-  handleInput‚Í‚Ü‚¸¤‚ðæ“ª‚É“ü‚ê‚Ä‚©‚çA¬•¶Žš‚É‚µ‚ÄHiraganaInputMode‚É“n‚·B
-  ƒXƒy[ƒX‚ª—ˆ‚½‚ç•ÏŠ·B‘—‚艼–¼‚ª“ü—Í‚³‚ê‚Ä‚à•ÏŠ·B
+  handleInputはまず▽を先頭に入れてから、小文字にしてHiraganaInputModeに渡す。
+  スペースが来たら変換。送り仮名が入力されても変換。
   
-  Oku   ¨ ¤‚¨‚­
-  OkuR  ¨ ¤‚¨‚­*r
-  OkuRi ¨ ¤‚¨‚­*‚è ¨ ¥‘—‚è
+  Oku   → ▽おく
+  OkuR  → ▽おく*r
+  OkuRi → ▽おく*り → ▼送り
   
-  Š¿Žš“ü—̓‚[ƒh‚ÌŽž‚́A“ü—Í‚³‚ꂽ•¶Žš‚Í‚»‚Ì‚Ü‚ÜKanjiConversionMode‚É“n‚³‚ê‚éB
+  漢字入力モードの時は、入力された文字はそのままKanjiConversionModeに渡される。
 */
 
 KanjiConversionMode::KanjiConversionMode(ParentInputMode& src)
     :ChildInputMode(src),
-     word_register_mode(NULL),
+     word_register_mode(0),
+     old_word_register_mode(0),
      status(STATUS_NULL),
      show_cands_window_after_Nth_cand(5),
      completion_mode(false),
-     henkanModeStatus(false) {
-    
+     henkanModeStatus(false),
+     priorInputMode_(Hirakana) {
+    // empty
 }
 
 KanjiConversionMode::~KanjiConversionMode() {
-    if(word_register_mode) {
-	delete word_register_mode;
-    }
+    delete word_register_mode;
+    delete old_word_register_mode;
 }
 
 bool KanjiConversionMode::handleInput(SKKChar skkchar) {
@@ -80,12 +81,12 @@
 bool KanjiConversionMode::handleInputChar(SKKChar skkchar) {
     if(word_register_mode) {
 	word_register_mode->handleInput(skkchar);
-	return false; // WordRegisterMode::handleInput()‚ª‰½‚ð•Ô‚»‚¤‚Æ‚àŠm’è‚Í‚µ‚È‚¢B
+	return false; // WordRegisterMode::handleInput()が何を返そうとも確定はしない。
     }
 
     if(SKKConfig::AbbrevNextKey() == skkchar) {
 	if(status == STATUS_WHITE_ROOT && completion_mode) {
-	    // ŽŸ‚ÌŒó•â‚ցBÅŒã‚܂ōs‚Á‚½‚çÅ‰‚É–ß‚éB
+	    // 次の候補へ。最後まで行ったら最初に戻る。
 	    current_completion_index++;
 	    if(current_completion_index >= completions.size()) {
 		current_completion_index = 0;
@@ -98,7 +99,7 @@
 
     if(SKKConfig::AbbrevPrevKey() == skkchar) {
 	if(status == STATUS_WHITE_ROOT && completion_mode) {
-	    // ‘O‚ÌŒó•â‚ցBÅ‰‚܂ōs‚Á‚½‚çÅŒã‚É–ß‚éB
+	    // 前の候補へ。最初まで行ったら最後に戻る。
 	    if(current_completion_index == 0) {
 		current_completion_index = completions.size() - 1;
 	    } else {
@@ -110,20 +111,20 @@
 	}
     }
 
-    // tab,ƒsƒŠƒIƒh,ƒJƒ“ƒ}ˆÈŠO‚Ì‚¢‚©‚Ȃ镶Žš‚ª“ü—Í‚³‚ê‚Ä‚à•âŠ®ƒ‚[ƒh‚𔲂¯‚éB
+    // tab,ピリオド,カンマ以外のいかなる文字が入力されても補完モードを抜ける。
     completion_mode = false;
 
     if(SKKConfig::ToggleKanaKey() == skkchar) {
 	if(status == STATUS_WHITE_ROOT || status == STATUS_WHITE_OKURI) {
-	    // currenInputMode‚ðterminate‚µ‚āAroot‚ÉgetStringToFix()‚Ì–ß‚è’l‚ð’ljÁ‚·‚éB
+	    // currenInputModeをterminateして、rootにgetStringToFix()の戻り値を追加する。
 	    parent->getCurrentInputMode().terminate();
 	    CppCFString to_fix(parent->getCurrentInputMode().getStringToFix());
 	    if (status == STATUS_WHITE_ROOT) {
 		root += to_fix;
 	    }
 
-	    // root‚ð‘SŠp•Ð‰¼–¼‚É•ÏŠ·‚µ‚Ä‚©‚çŠm’肵‚ďI—¹B
-	    // ‚½‚¾‚µ‘SŠp•Ð‰¼–¼ƒ‚[ƒh‚¾‚Á‚½‚畽‰¼–¼‚Ö•ÏŠ·‚·‚éB
+	    // rootを全角片仮名に変換してから確定して終了。
+	    // ただし全角片仮名モードだったら平仮名へ変換する。
 	    CppCFString cand;
 	    if(parent->isZenKataInputMode()) {
 		cand = HiraganaInputMode::convert(root);
@@ -131,8 +132,8 @@
 		cand = ZenKataInputMode::convert(root);
 	    }
 
-	    // ŒÂlŽ«‘‚É“o˜^‚·‚é
-	    sendWordToServerToRegister(root, cand);
+	    // トグル変換の結果を登録する
+	    registerToggleEntry(root);
 
 	    parent->fix(cand);
 	    parent->setEnabledKanjiMode(false);
@@ -141,9 +142,9 @@
 	    return false;
 	}
 	else if(status == STATUS_BLACK || status == STATUS_BLACK_WITH_WINDOW) {
-	    // Œ»Ý‚ÌŒó•â‚ðŠm’èB
-	    // 1) ‘SŠp•Ð‰¼–¼ƒ‚[ƒh‚Ȃ畽‰¼–¼ƒ‚[ƒh‚Ö
-	    // 2) ‚»‚êˆÈŠO‚È‚ç‘SŠp•Ð‰¼–¼ƒ‚[ƒh‚Ö
+	    // 現在の候補を確定。
+	    // 1) 全角片仮名モードなら平仮名モードへ
+	    // 2) それ以外なら全角片仮名モードへ
 
 	    parent->setEnabledKanjiMode(false);
 	    if(parent->isZenKataInputMode()) {
@@ -157,7 +158,7 @@
 
     if(SKKConfig::PrevKouhoKey() == skkchar) {
 	if(status == STATUS_BLACK) {
-	    // ˆê‚‘O‚ÌŒó•â‚ցBÅ‰‚ÌŒó•â‚¾‚Á‚½‚灤ƒ‚[ƒh‚Ö–ß‚éB
+	    // 一つ前の候補へ。最初の候補だったら▽モードへ戻る。
 	    if(current_candidate_index > 0) {
 		current_candidate_index--;
 	    } else {
@@ -169,17 +170,17 @@
 	    return false;
 	}
 	else if(status == STATUS_BLACK_WITH_WINDOW) {
-	    // delete‚ª‰Ÿ‚³‚ꂽ‚à‚Ì‚ÆŒ©˜ô‚·
+	    // deleteが押されたものと見做す
 	    handleBackSpace();
 	    return false;
 	}
-	// ‚»‚êˆÈŠO‚È‚ç‘f’Ê‚è
+	// それ以外なら素通り
     }
 
     if(SKKConfig::PurgeFromJisyoKey() == skkchar) {
 	if(status == STATUS_BLACK) {
-	    // íœƒvƒƒ“ƒvƒg‚ðo‚·B‚±‚Ì•ÏŠ·‚ªŽÀ‚̓†[ƒU[Ž«‘‚ɍڂÁ‚Ä‚¢‚È‚©‚Á‚½‚Æ‚µ‚Ä‚à
-	    // –Ê“|‚È‚Ì‚Å‚»‚ÌŽ–‚ð‚í‚´‚í‚´Šm”F‚µ‚È‚¢B—v–]‚Å‚à‚ ‚ê‚Εʂ¾‚ªB
+	    // 削除プロンプトを出す。この変換が実はユーザー辞書に載っていなかったとしても
+	    // 面倒なのでその事をわざわざ確認しない。要望でもあれば別だが。
 	    status = STATUS_PROMPT;
 	    prompt_type = PROMPT_DELETE_FROM_USER_DIC;
 	    prompt_input.clear();
@@ -199,28 +200,31 @@
 
     if(SKKConfig::ToggleKatakanaKey() == skkchar) {
 	if(status == STATUS_WHITE_ROOT || status == STATUS_WHITE_OKURI) {
-	    // currenInputMode‚ðterminate‚µ‚āAroot‚ÉgetStringToFix()‚Ì–ß‚è’l‚ð’ljÁ‚·‚éB
+	    // currenInputModeをterminateして、rootにgetStringToFix()の戻り値を追加する。
 	    parent->getCurrentInputMode().terminate();
 	    CppCFString to_fix(parent->getCurrentInputMode().getStringToFix());
 	    if (status == STATUS_WHITE_ROOT) {
 		root += to_fix;
 	    }
-	    // root‚𔼊p•Ð‰¼–¼‚É•ÏŠ·‚µ‚Ä‚©‚çŠm’肵‚ďI—¹B
-	    // ‚½‚¾‚µ”¼Šp•Ð‰¼–¼ƒ‚[ƒh‚¾‚Á‚½‚畽‰¼–¼‚É•ÏŠ·‚·‚éB
+	    // rootを半角片仮名に変換してから確定して終了。
+	    // ただし半角片仮名モードだったら平仮名に変換する。
 	    if(parent->isHanKataInputMode()) {
 		parent->fix(HiraganaInputMode::convert(root));
 	    } else {
 		parent->fix(HanKataInputMode::convert(root));
 	    }
 
+	    // トグル変換の結果を登録する
+	    registerToggleEntry(root);
+
 	    parent->setEnabledKanjiMode(false);
 	    initialize();
 	    return false;
 	}
 	else if(status == STATUS_BLACK || status == STATUS_BLACK_WITH_WINDOW) {
-	    // Œ»Ý‚ÌŒó•â‚ðŠm’肵‚Ä‚©‚çA
-	    // 1) ”¼Šp•Ð‰¼–¼ƒ‚[ƒh‚Ȃ畽‰¼–¼ƒ‚[ƒh‚Ö
-	    // 2) ‚»‚êˆÈŠO‚Ȃ甼Šp•Ð‰¼–¼‰¼–¼ƒ‚[ƒh‚Ö
+	    // 現在の候補を確定してから、
+	    // 1) 半角片仮名モードなら平仮名モードへ
+	    // 2) それ以外なら半角片仮名仮名モードへ
 	    
 	    parent->setEnabledKanjiMode(false);
 	    if(parent->isHanKataInputMode()) {
@@ -233,12 +237,12 @@
     }
 
     if(SKKConfig::KakuteiKey() == skkchar) {
-	return true; // Šm’è‚Ì‚Ý
+	return true; // 確定のみ
     }
 
     if(SKKConfig::LatinModeKey() == skkchar || SKKConfig::Jisx0208LatinModeKey() == skkchar) {
 	if(status == STATUS_WHITE_ROOT || status == STATUS_WHITE_OKURI || status == STATUS_BLACK) {
-	    // ‚»‚ꂼ‚ê‚ðŠm’肵‚Ä”¼Šp/‘SŠp‰p”Žšƒ‚[ƒh‚ցB
+	    // それぞれを確定して半角/全角英数字モードへ。
 	    if(SKKConfig::LatinModeKey() == skkchar) {
 		parent->goHanAscInputMode();
 	    } else {
@@ -246,15 +250,15 @@
 	    }
 	    return true;
 	}
-	// Œó•â‘I‘ð‰æ–Ê‚È‚ç‘f’Ê‚èB
+	// 候補選択画面なら素通り。
     }
 
     if(SKKConfig::AbbrevModeKey() == skkchar) {
-	// Œ»Ý‚ÌŒó•â‚ðŠm’肵‚½ŒãA‰Šú‰»‚µ‚ďI—¹‚·‚邪A
-	// “¯Žž‚ɍ¡‰ñ‚Ì•\Ž¦/fix‚ª”½‰f‚³‚ê‚È‚¢‚ƍ¢‚é‚Ì‚Å
-	// Š¿Žš•ÏŠ·ƒ‚[ƒh‚ðI—¹‚³‚¹‚Ä‚©‚çparent‚ÌhandleInput‚É“n‚·B
-	// KanjiConversionMode‚ÍSTATUS_NULL‚ÌŽž‚É‚Í
-	// í‚ÉkIgnoreThis‚ð•Ô‚·B
+	// 現在の候補を確定した後、初期化して終了するが、
+	// 同時に今回の表示/fixが反映されないと困るので
+	// 漢字変換モードを終了させてからparentのhandleInputに渡す。
+	// KanjiConversionModeはSTATUS_NULLの時には
+	// 常にkIgnoreThisを返す。
 
 	parent->fix(getStringToFix());
 	return parent->handleInput(skkchar);
@@ -262,14 +266,14 @@
 
     if(SKKConfig::NextKouhoKey() == skkchar) {
 	if(status == STATUS_WHITE_ROOT || status == STATUS_WHITE_OKURI) {
-	    // currenInputMode‚ðterminate‚µ‚āAroot‚à‚µ‚­‚Íokuri‚ÉgetStringToFix()‚Ì–ß‚è’l‚ð’ljÁ‚·‚éB
+	    // currenInputModeをterminateして、rootもしくはokuriにgetStringToFix()の戻り値を追加する。
 	    parent->getCurrentInputMode().terminate();
 	    if(status == STATUS_WHITE_ROOT) {
 		root += parent->getCurrentInputMode().getStringToFix();
 		root_to_display.clear().append(root).append(parent->getCurrentInputMode().getStringToDisplay());
 
 		if(root.length() == 0) {
-		    // I—¹
+		    // 終了
 		    parent->setEnabledKanjiMode(false);
 		    parent->display(CppCFString());
 		    initialize();
@@ -285,33 +289,33 @@
 	    }
 
 	    if(candidates.size() > 0) {
-		// Œó•â‚ª‘¶Ý‚µ‚½B¥ƒ‚[ƒh‚ցB
+		// 候補が存在した。▼モードへ。
 		status = STATUS_BLACK;
-		current_candidate_index = 0; // Å‰‚ÌŒó•âB
+		current_candidate_index = 0; // 最初の候補。
 	    } else {
-		// ˆê‚‚àŒó•â‚ª–³‚¢B’PŒê“o˜^ŠJŽnB
+		// 一つも候補が無い。単語登録開始。
 		startRegisteringWord();
 	    }
 	}
 	else if(status == STATUS_BLACK) {
-	    // ŽŸ‚ÌŒó•â‚Ö
+	    // 次の候補へ
 	    current_candidate_index++;
 
-	    if(current_candidate_index >= candidates.size()) { // I‚í‚è‚܂ōs‚Á‚½‚ç’PŒê“o˜^ŠJŽnB
+	    if(current_candidate_index >= candidates.size()) { // 終わりまで行ったら単語登録開始。
 		startRegisteringWord();
 	    }
 	    else if(current_candidate_index >= show_cands_window_after_Nth_cand - 1) {
-		// ‚±‚êˆÈ~‚̃[ƒe[ƒVƒ‡ƒ“‚ÅŒó•â‘I‘ðƒEƒCƒ“ƒhƒE‚ð•\Ž¦‚·‚éB
+		// これ以降のローテーションで候補選択ウインドウを表示する。
 		status = STATUS_BLACK_WITH_WINDOW;
 		openCandidatesWindow();
 	    }
 	}
 	else if(status == STATUS_BLACK_WITH_WINDOW) {
 	    if(candidates_window_current_frame < candidates_window_num_of_frames - 1) {
-		// ÅŒã‚̃tƒŒ[ƒ€‚Å‚È‚¯‚ê‚΁AŽŸ‚̃tƒŒ[ƒ€‚֍s‚­B
+		// 最後のフレームでなければ、次のフレームへ行く。
 		goToNextCandidatesFrame();
 	    } else {
-		// ÅŒã‚̃tƒŒ[ƒ€‚¾‚Á‚½‚çA’PŒê“o˜^‚ðŠJŽnB
+		// 最後のフレームだったら、単語登録を開始。
 		closeCandidatesWindow();
 		startRegisteringWord();
 	    }
@@ -319,17 +323,17 @@
 	return false;
     }
 
-    // •ÏŠ·ƒ|ƒCƒ“ƒgƒL[‚ª‚¨‚³‚ꂽŽž‚Ì“®ì
+    // 変換ポイントキーがおされた時の動作
     if(SKKConfig::SetHenkanPointKey() == skkchar) {
 	if(status == STATUS_NULL || (status == STATUS_WHITE_ROOT && root.length() == 0)) {
-	    status = STATUS_WHITE_ROOT; // ¤ƒ‚[ƒh‚ցB
+	    status = STATUS_WHITE_ROOT; // ▽モードへ。
 
-	    // ‰æ–Ê•\Ž¦—p
+	    // 画面表示用
 	    root_to_display.clear().append(root).append(parent->getCurrentInputMode().getStringToDisplay());
 	    return false;
 	}
 
-	// Šm’肵‚ÄŒp‘±
+	// 確定して継続
 	if(status == STATUS_WHITE_ROOT || status == STATUS_BLACK || status == STATUS_BLACK_WITH_WINDOW) {
 	    parent->fix(getStringToFix());
 	    parent->setEnabledKanjiMode(true);
@@ -337,13 +341,13 @@
 	}
     }
 
-    // ƒvƒƒ“ƒvƒg‚ɒljÁ
+    // プロンプトに追加
     if(status == STATUS_PROMPT) {
 	prompt_input += skkchar;
 	return false;
     }
 
-    // ‘I‘ð‚³‚ê‚½Œó•â‚ÅŠm’è‚·‚é
+    // 選択された候補で確定する
     if(status == STATUS_BLACK_WITH_WINDOW) {
 	CppCFString labels = CppCFString("asdfjkl").substring(0, candidates_window_cands_per_frame);
 	int cand_index = labels.indexOf(std::tolower(skkchar));
@@ -351,7 +355,7 @@
 	if(cand_index != -1) {
 	    unsigned new_index = current_candidate_index + cand_index;
 	    if(new_index < candidates.size()) {
-		// ‚±‚̃Cƒ“ƒfƒBƒbƒNƒX‚ª‹–‚³‚ê‚é‚È‚çŠm’èB
+		// このインディックスが許されるなら確定。
 		current_candidate_index = new_index;
 		return true;
 	    }
@@ -361,109 +365,109 @@
 
     if('A' <= skkchar && skkchar <= 'Z') {
 	if(status == STATUS_NULL || status == STATUS_WHITE_ROOT && root.length() == 0) {
-	    status = STATUS_WHITE_ROOT; // ¤ƒ‚[ƒh‚ցB
+	    status = STATUS_WHITE_ROOT; // ▽モードへ。
 
-	    // ¬•¶Žš‚É‚µ‚ĉ¼–¼“ü—Í‚ðŽÀsB
+	    // 小文字にして仮名入力を実行。
 	    parent->getCurrentInputMode().handleInput(skkchar + 0x20);
 
-	    // ‰¼–¼“ü—̓‚[ƒh‚Ìfixƒoƒbƒtƒ@‚ðroot‚֒ljÁB
+	    // 仮名入力モードのfixバッファをrootへ追加。
 	    root += parent->getCurrentInputMode().getStringToFix();
 
-	    // ‰æ–Ê•\Ž¦—p
+	    // 画面表示用
 	    root_to_display.clear().append(root).append(parent->getCurrentInputMode().getStringToDisplay());
 
-	    // okuri‚͏Á‚µ‚Ä‚¨‚­B‚±‚̏ó‘Ô‚ÅŠm’肳‚ꂽŽž‚ׂ̈ɁB
+	    // okuriは消しておく。この状態で確定された時の為に。
 	    okuri.clear();
 	}
 	else if(status == STATUS_WHITE_ROOT) {
-	    // terminate‚·‚é‘O‚ɍ¡‰ñ‚Ì“ü—Í‚ð‰Ÿ‚µž‚ށB
-	    // ‚±‚ê‚ð‚â‚ç‚È‚¢‚ÆKesSite‚ªu‚¯‚µ‚āv‚É‚È‚Á‚Ä‚µ‚Ü‚¤B
-	    // ’A‚µA‚±‚Ì“ü—͂̏¬•¶Žš‚ªAˆê•¶Žš‚¾‚¯‚ŏo—͂𐶐¬‚·‚éê‡‚É‚Í
-	    // (•W€“I‚ɂ͕ꉹ‚¨‚æ‚Ñn)A‚±‚Ì‘€ì‚ð‚µ‚È‚¢B
+	    // terminateする前に今回の入力を押し込む。
+	    // これをやらないとKesSiteが「けして」になってしまう。
+	    // 但し、この入力の小文字が、一文字だけで出力を生成する場合には
+	    // (標準的には母音およびn)、この操作をしない。
 	    CppCFString tmp_queue(skkchar + 0x20);
 	    CppCFString result =
 		KanaTreeController::defaultTreeController().trace(KanaTreeController::OUTPUT_HIRAGANA, tmp_queue);
 	    if(result.length() == 0 && tmp_queue != "n") {
-		parent->getCurrentInputMode().handleInput(skkchar + 0x20); // ¬•¶Žš
+		parent->getCurrentInputMode().handleInput(skkchar + 0x20); // 小文字
 	    }
 
-	    // currentInputMode‚ðterminate‚µ‚āAroot‚ÉgetStringToFix()‚Ì–ß‚è’l‚ð’ljÁ‚·‚éB
+	    // currentInputModeをterminateして、rootにgetStringToFix()の戻り値を追加する。
 	    parent->getCurrentInputMode().terminate();
 	    root += parent->getCurrentInputMode().getStringToFix();
 	    root_to_display.clear().append(root).append(parent->getCurrentInputMode().getStringToDisplay());
 
-	    status = STATUS_WHITE_OKURI; // ¤‘—‚艼–¼ƒ‚[ƒh‚ցB
+	    status = STATUS_WHITE_OKURI; // ▽送り仮名モードへ。
 
-	    okuri_head = skkchar + 0x20; // ¬•¶Žš
+	    okuri_head = skkchar + 0x20; // 小文字
 
-	    // ¬•¶Žš‚É‚µ‚ĉ¼–¼“ü—Í‚ðŽÀsB
+	    // 小文字にして仮名入力を実行。
 	    bool fix = parent->getCurrentInputMode().handleInput(okuri_head);
 
-	    // ‰¼–¼“ü—̓‚[ƒh‚Ìfixƒoƒbƒtƒ@‚ðokuri‚ÖƒRƒs[B
+	    // 仮名入力モードのfixバッファをokuriへコピー。
 	    okuri += parent->getCurrentInputMode().getStringToFix();
 
-	    // ‰æ–Ê•\Ž¦—p
+	    // 画面表示用
 	    okuri_to_display.clear().append(okuri).append(parent->getCurrentInputMode().getStringToDisplay());
 
-	    // ƒLƒ…[‚ª‹ó‚Å‚È‚¯‚ê‚΂܂¾•ÏŠ·‚µ‚Ä‚µ‚Ü‚í‚È‚¢B
+	    // キューが空でなければまだ変換してしまわない。
 	    if(fix && parent->getCurrentInputMode().isQueueEmpty()) {
-		// •ÏŠ·‚·‚éB
-		return handleInput(' '); // Ä“Ë“üBˆÓ–¡“I‚ɂ͍ċA‚Å‚Í‚È‚­continueB
+		// 変換する。
+		return handleInput(' '); // 再突入。意味的には再帰ではなくcontinue。
 	    }
 	}
 	else if(status == STATUS_WHITE_OKURI) {
-	    // ¬•¶Žš‚É‚µ‚ĉ¼–¼“ü—Í‚ðŽÀsB
+	    // 小文字にして仮名入力を実行。
 	    bool fix = parent->getCurrentInputMode().handleInput(skkchar + 0x20);
 
-	    // ‰¼–¼“ü—̓‚[ƒh‚Ìfixƒoƒbƒtƒ@‚ðokuri‚ÖƒRƒs[B
+	    // 仮名入力モードのfixバッファをokuriへコピー。
 	    okuri += parent->getCurrentInputMode().getStringToFix();
 
-	    // ‰æ–Ê•\Ž¦—p
+	    // 画面表示用
 	    okuri_to_display.clear().append(okuri).append(parent->getCurrentInputMode().getStringToDisplay());
 
-	    // ƒLƒ…[‚ª‹ó‚Å‚È‚¯‚ê‚΂܂¾•ÏŠ·‚µ‚Ä‚µ‚Ü‚í‚È‚¢B
+	    // キューが空でなければまだ変換してしまわない。
 	    if(fix && parent->getCurrentInputMode().isQueueEmpty()) {
-		// •ÏŠ·‚·‚éB
-		return handleInput(' '); // Ä“Ë“üBˆÓ–¡“I‚ɂ͍ċA‚Å‚Í‚È‚­continueB
+		// 変換する。
+		return handleInput(' '); // 再突入。意味的には再帰ではなくcontinue。
 	    }
 	}
 	else if(status == STATUS_BLACK) {
-	    // Œ»Ý‚ÌŒó•â‚ðŠm’肵‚ÄŒp‘±
+	    // 現在の候補を確定して継続
 	    parent->fix(getStringToFix());
 	    parent->setEnabledKanjiMode(true);
 	    return handleInput(skkchar);
 	}
     } else {
 	if(status == STATUS_WHITE_ROOT) {
-	    // ‰¼–¼“ü—Í‚ðŽÀsB
+	    // 仮名入力を実行。
 	    parent->getCurrentInputMode().handleInput(skkchar);
 
-	    // root‚ɒljÁB
+	    // rootに追加。
 	    root += parent->getCurrentInputMode().getStringToFix();
 
-	    // ‰æ–Ê•\Ž¦—p
+	    // 画面表示用
 	    root_to_display.clear().append(root).append(parent->getCurrentInputMode().getStringToDisplay());
 	}
 	else if(status == STATUS_WHITE_OKURI) {
-	    // currentInputMode::handleInput()‚ðs‚¢Atrue•Ô‚µ‚½‚ç‚»‚ê‚𑗂艼–¼‚Æ‚µ‚Ä•ÏŠ·B
-	    // ‚»‚¤‚Å‚È‚¯‚ê‚΁AcurrentInputMode::handleInput()‚É“n‚·‚¾‚¯B
+	    // currentInputMode::handleInput()を行い、true返したらそれを送り仮名として変換。
+	    // そうでなければ、currentInputMode::handleInput()に渡すだけ。
 	    bool fix = parent->getCurrentInputMode().handleInput(skkchar);
 	    const CppCFString& kanainput_result = parent->getCurrentInputMode().getStringToFix();
 
-	    // okuri‚ɒljÁB
+	    // okuriに追加。
 	    okuri += kanainput_result;
 
-	    // ‰æ–Ê•\Ž¦—p
+	    // 画面表示用
 	    okuri_to_display.clear().append(okuri).append(parent->getCurrentInputMode().getStringToDisplay());
 
-	    // ƒLƒ…[‚ª‹ó‚Å‚È‚¯‚ê‚΂܂¾•ÏŠ·‚µ‚È‚¢B
+	    // キューが空でなければまだ変換しない。
 	    if(fix && parent->getCurrentInputMode().isQueueEmpty()) {
-		// •ÏŠ·‚·‚éB
-		return handleInput(' '); // Ä“Ë“üBˆÓ–¡“I‚ɂ͍ċA‚Å‚Í‚È‚­continueB
+		// 変換する。
+		return handleInput(' '); // 再突入。意味的には再帰ではなくcontinue。
 	    }
 	}
 	else if(status == STATUS_BLACK) {
-	    // Œ»Ý‚ÌŒó•â‚ðŠm’肵‚ÄŒp‘±
+	    // 現在の候補を確定して継続
 	    parent->fix(getStringToFix());
 	    return parent->handleInput(skkchar);
 	}
@@ -474,15 +478,25 @@
 
 void KanjiConversionMode::startRegisteringWord() {
     CppCFString register_title;
-    if (okuri.length() > 0) {
+
+    if(okuri.length() > 0) {
 	register_title.append(root).append('*').append(okuri);
-    }
-    else {
+    } else {
 	register_title = root;
     }
-    register_title = HiraganaInputMode::convert(register_title); // •Ð‰¼–¼‚Í•½‰¼–¼‚É•ÏŠ·
-	
-    word_register_mode = new WordRegisterMode(*this,register_title);
+
+    // 現在の入力モードを保存しておく
+    if(parent->isHiraganaInputMode()) {
+	priorInputMode_ = Hirakana;
+    }
+    if(parent->isZenKataInputMode()) {
+	priorInputMode_ = Katakana;
+    }
+    if(parent->isHanKataInputMode()) {
+	priorInputMode_ = Jisx0201Kana;
+    }
+
+    word_register_mode = new WordRegisterMode(*this, HiraganaInputMode::convert(register_title));
     word_register_mode->redisplay();
     word_register_mode->updatePencilMenuIcon();
 }
@@ -490,7 +504,7 @@
 bool KanjiConversionMode::handleBackSpace() {
     if (word_register_mode) {
 	word_register_mode->handleBackSpace();
-	return true; // WordRegisterMode::handleBackSpace()‚ª‰½‚ð•Ô‚»‚¤‚Æ‚à–{•¶‚͏Á‚³‚È‚¢B
+	return true; // WordRegisterMode::handleBackSpace()が何を返そうとも本文は消さない。
     }
     
     if (status == STATUS_NULL) {
@@ -498,10 +512,10 @@
     }
     
     if (status == STATUS_WHITE_ROOT) {
-	// hiraganaInputMode->handleBackSpace()‚ªtrue‚ð•Ô‚µ‚½‚çroot_to_display‚ðXV‚·‚éB
-	// false‚ð•Ô‚µ‚½‚ç
-	//		root‚ª‹ó‚Ȃ珉Šú‰»‚µ‚ďI—¹B
-	//		‹ó‚Å‚È‚¯‚ê‚Îroot‚̍Ōã‚Ì•¶Žš‚ðÁ‚·B
+	// hiraganaInputMode->handleBackSpace()がtrueを返したらroot_to_displayを更新する。
+	// falseを返したら
+	//		rootが空なら初期化して終了。
+	//		空でなければrootの最後の文字を消す。
 	if (parent->getCurrentInputMode().handleBackSpace()) {
 	    root_to_display.clear().append(root).append(parent->getCurrentInputMode().getStringToDisplay());
 	}
@@ -512,20 +526,20 @@
 		initialize();
 	    }
 	    else {
-		completion_mode = false; // •âŠ®ƒ‚[ƒh‚¾‚Á‚½ê‡‚͕⊮ƒ‚[ƒh‚𔲂¯‚éB
+		completion_mode = false; // 補完モードだった場合は補完モードを抜ける。
 		root.eraseLast(1);
 		root_to_display = root;
 	    }
 	}
     }
     else if (status == STATUS_WHITE_OKURI) {
-	// hiraganaInputMode->handleBackSpace()‚ª
-	// true‚ð•Ô‚µ‚½‚ç
-	//      okuri_to_display‚ðXV‚·‚éB
-	//      ‚»‚ÌŽžAokuri‚ªˆê•¶Žš‚µ‚©–³‚¯‚ê‚ÎSTATUS_WHITE_ROOT‚Ö–ß‚·B
-	// false‚ð•Ô‚µ‚½‚ç
-	//		okuri‚ªˆê•¶Žš‚µ‚©–³‚¯‚ê‚ÎSTATUS_WHITE_ROOT‚Ö–ß‚·B
-	//		“ñ•¶ŽšˆÈã‚ ‚Á‚½‚çokuri‚̍Ōã‚Ì•¶Žš‚ðÁ‚·B
+	// hiraganaInputMode->handleBackSpace()が
+	// trueを返したら
+	//      okuri_to_displayを更新する。
+	//      その時、okuriが一文字しか無ければSTATUS_WHITE_ROOTへ戻す。
+	// falseを返したら
+	//		okuriが一文字しか無ければSTATUS_WHITE_ROOTへ戻す。
+	//		二文字以上あったらokuriの最後の文字を消す。
 	if (parent->getCurrentInputMode().handleBackSpace()) {
 	    okuri_to_display.clear().append(okuri).append(parent->getCurrentInputMode().getStringToDisplay());
 	    if (okuri.length() <= 1) {
@@ -545,20 +559,20 @@
 	}
     }
     else if (status == STATUS_BLACK) {
-	// Œ»Ý‚ÌŒó•â‚ðŠm’肵‚ĈꕶŽšíœ
+	// 現在の候補を確定して一文字削除
 	CppCFString str(getStringToFix());
 	str.eraseLast(1);
 	parent->fix(str);
 	parent->display(CppCFString());
     }
     else if (status == STATUS_BLACK_WITH_WINDOW) {
-	// Å‰‚̃tƒŒ[ƒ€‚Ȃ灥ƒ‚[ƒh‚Ö–ß‚éB
-	// ‚»‚¤‚Å‚È‚¯‚ê‚ΑO‚̃tƒŒ[ƒ€‚ցB
+	// 最初のフレームなら▼モードへ戻る。
+	// そうでなければ前のフレームへ。
 	if (candidates_window_current_frame == 0) {
-	    // ƒEƒCƒ“ƒhƒE‚ðŠJ‚­‘O‚É–ß‚·
+	    // ウインドウを開く前に戻す
 	    current_candidate_index = show_cands_window_after_Nth_cand - 2;
 	    
-	    // ƒEƒCƒ“ƒhƒE‚ð•Â‚¶‚éB
+	    // ウインドウを閉じる。
 	    closeCandidatesWindow();
 	    
 	    status = STATUS_BLACK;
@@ -568,7 +582,7 @@
 	}
     }
     else if (status == STATUS_PROMPT) {
-	// prompt_input‚ª‹ó‚Å‚È‚¯‚ê‚΍Ōã‚Ì•¶Žš‚ðÁ‚·B
+	// prompt_inputが空でなければ最後の文字を消す。
 	if (prompt_input.length() > 0) {
 	    prompt_input.eraseLast(1);
 	}
@@ -581,23 +595,23 @@
 	word_register_mode->handleReturn();
 	
 	if (word_register_mode) {
-	    // handleReturn‚©‚çwordRegistrationFinished‚ªŒÄ‚΂ꂽ‚çword_register_mode‚Í”jŠü‚³‚ê‚邽‚߁B
+	    // handleReturnからwordRegistrationFinishedが呼ばれたらword_register_modeは破棄されるため。
 	    word_register_mode->redisplay();
 	}
 	
-	return true; // í‚Étrue‚ð•Ô‚·B
+	return true; // 常にtrueを返す。
     }
     
     if (status == STATUS_PROMPT) {
 	switch (prompt_type) {
 	case PROMPT_DELETE_FROM_USER_DIC: {
-	    // prompt_input‚ªyes‚È‚çíœ‚µ‚ÄSTATUS_WHITE_ROOT‚É–ß‚éB
-	    // ‚»‚êˆÈŠO‚È‚çSTATUS_BLACK‚É–ß‚éB
+	    // prompt_inputがyesなら削除してSTATUS_WHITE_ROOTに戻る。
+	    // それ以外ならSTATUS_BLACKに戻る。
 	    if (prompt_input == "yes") {
-		// íœ
+		// 削除
 		makeServerRemoveWord();
 		
-		// STATUS_WHITE_ROOT‚Ö
+		// STATUS_WHITE_ROOTへ
 		if (okuri.length() > 0) {
 		    root += okuri;
 		    root_to_display = root;
@@ -620,9 +634,9 @@
     }
     
     if (ClientConfiguration::theInstance().isSkkEggLikeNewline()) {
-	// skk-egglike-newlineƒ‚[ƒh‚È‚çAŽ©—Í‚ÅŠm’肳‚¹‚Ä‚©‚珉Šú‰»‚µ‚Ätrue‚ð•Ô‚·B
+	// skk-egglike-newlineモードなら、自力で確定させてから初期化してtrueを返す。
 	
-	// „§‚³‚ê‚È‚¢‚ªA‹­§“I‚ÉŠm’肳‚¹‚éB
+	// 推奨されないが、強制的に確定させる。
 	parent->fix(getStringToFix());
 	return true;
     }
@@ -633,19 +647,19 @@
 
 bool KanjiConversionMode::handleArrow(SKKChar skkchar) {
     if (word_register_mode) {
-	return word_register_mode->handleArrow(skkchar); // ˆÏ÷
+	return word_register_mode->handleArrow(skkchar); // 委譲
     }
     
-    // •½‰¼–¼ƒCƒ“ƒvƒbƒgƒ‚[ƒh‚ÌhandleArrow‚ðŒÄ‚сAgetStringToFix()‚àŒÄ‚Ô‚ªAŒÄ‚Ô‚¾‚¯B
+    // 平仮名インプットモードのhandleArrowを呼び、getStringToFix()も呼ぶが、呼ぶだけ。
     parent->getCurrentInputMode().handleArrow(skkchar);
     parent->getCurrentInputMode().getStringToFix();
     
     if (status == STATUS_BLACK || status == STATUS_BLACK_WITH_WINDOW) {
-	// Œ»Ý‚ÌŒó•â‚ðŠm’è
+	// 現在の候補を確定
 	parent->fix(getStringToFix());
     }
     
-    // Š¿Žš•ÏŠ·ƒ‚[ƒh‚ðI—¹‚·‚éB
+    // 漢字変換モードを終了する。
     parent->setEnabledKanjiMode(false);
     initialize();
     return false;
@@ -656,18 +670,18 @@
 	return word_register_mode->handleCg();
     }
     
-    // •½‰¼–¼ƒCƒ“ƒvƒbƒgƒ‚[ƒh‚ÌhandleCg‚ðŒÄ‚сAgetStringToFix()‚àŒÄ‚Ô‚ªAŒÄ‚Ô‚¾‚¯B
+    // 平仮名インプットモードのhandleCgを呼び、getStringToFix()も呼ぶが、呼ぶだけ。
     parent->getCurrentInputMode().handleCg();
     parent->getCurrentInputMode().getStringToFix();
     
     if (status == STATUS_WHITE_ROOT || status == STATUS_WHITE_OKURI) {
-	// Š¿Žš•ÏŠ·ƒ‚[ƒhI—¹
+	// 漢字変換モード終了
 	parent->setEnabledKanjiMode(false);
 	initialize();
     }
     else if (status == STATUS_BLACK || status == STATUS_BLACK_WITH_WINDOW) {
-	// root‚Éokuri‚ð‚­‚Á‚‚¯‚ÄSTATUS_WHITE_ROOT‚Ö
-	// ƒEƒCƒ“ƒhƒE‚ªŠJ‚©‚ê‚Ä‚¢‚½‚ç•Â‚¶‚éB
+	// rootにokuriをくっつけてSTATUS_WHITE_ROOTへ
+	// ウインドウが開かれていたら閉じる。
 	if (status == STATUS_BLACK_WITH_WINDOW) {
 	    closeCandidatesWindow();
 	}
@@ -699,7 +713,7 @@
     
     if (status == STATUS_WHITE_ROOT) {
 	if (completion_mode) {
-	    // ŽŸ‚ÌŒó•â‚ցBÅŒã‚܂ōs‚Á‚½‚çÅ‰‚É–ß‚éB
+	    // 次の候補へ。最後まで行ったら最初に戻る。
 	    current_completion_index++;
 	    if (current_completion_index >= completions.size()) {
 		current_completion_index = 0;
@@ -708,15 +722,15 @@
 	    root_to_display = root;
 	}
 	else {
-	    // currentInputMode‚ðterminate‚µ‚āAroot‚ÉgetStringToFix()‚Ì–ß‚è’l‚ð’ljÁ‚·‚éB
+	    // currentInputModeをterminateして、rootにgetStringToFix()の戻り値を追加する。
 	    parent->getCurrentInputMode().terminate();
 	    root += parent->getCurrentInputMode().getStringToFix();
 	    root_to_display.clear().append(root).append(parent->getCurrentInputMode().getStringToDisplay());
 	    
-	    // ŽI‚É–â‚¢‡‚킹‚éB
+	    // 鯖に問い合わせる。
 	    askServerTheCompletions();
 	    
-	    // •âŠ®‚ÌŒó•â‚ª‚ ‚ê‚Ε⊮ŠJŽnB–³‚¯‚ê‚Ή½‚à‚¹‚¸‚É–ß‚éB
+	    // 補完の候補があれば補完開始。無ければ何もせずに戻る。
 	    if (completions.size() > 0) {
 		completion_mode = true;
 		root = completions[0];
@@ -734,67 +748,89 @@
     
     if (word_register_mode) {
 	word_register_mode->terminate();
-	delete word_register_mode;
-	word_register_mode = NULL;
+	resetRegistrationMode();
     }
 
-    // currenInputMode‚ðterminate‚µ‚āAroot‚ÉgetStringToFix()‚Ì–ß‚è’l‚ð’ljÁ‚·‚éB
+    // currenInputModeをterminateして、rootにgetStringToFix()の戻り値を追加する。
     parent->getCurrentInputMode().terminate();
     CppCFString to_fix(parent->getCurrentInputMode().getStringToFix());
     if (status == STATUS_WHITE_ROOT) {
 	root += to_fix;
     }
     
-    parent->fix(getStringToFix()); // Šm’è‚·‚é
+    parent->fix(getStringToFix()); // 確定する
     parent->setEnabledKanjiMode(false);
     initialize();
 }
 
+// 直前の単語登録モードを削除し、現在の単語登録モードを退避する
+void KanjiConversionMode::resetRegistrationMode() {
+    delete old_word_register_mode;
+    old_word_register_mode = word_register_mode;
+    word_register_mode = 0;
+}
+
+// 単語登録前の入力モードを復元する
+void KanjiConversionMode::restoreInputMode() {
+    switch(priorInputMode_) {
+    case Hirakana:
+	parent->goHiraganaInputMode();
+	break;
+    case Katakana:
+	parent->goZenKataInputMode();
+	break;
+    case Jisx0201Kana:
+	parent->goHanKataInputMode();
+	break;
+    }
+
+    parent->updatePencilMenuIcon();
+}
+
 void KanjiConversionMode::wordRegistrationFinished() {
     if(word_register_mode) {
 	CppCFString content = word_register_mode->getContent();
 	if(content.length() > 0) {
-	    // ŽI‚É‘—MB
+	    // 鯖に送信。
 	    if(okuri.length() > 0) {
 		if(SKKConfig::UseKanaToOkuri()) {
-#ifdef DEBUG
-		    cerr << "(A)OKURI-HEAD: " << okuri[0] << " - " << SKKConfig::ConvertKanaToOkuri(okuri[0]) << endl;
-#endif
-		    sendWordToServerToRegister(root + SKKConfig::ConvertKanaToOkuri(okuri[0]), okuri, content);
+		    sendWordToServerToRegister(
+			HiraganaInputMode::convert(root) + SKKConfig::ConvertKanaToOkuri(okuri[0]),
+			HiraganaInputMode::convert(okuri), content);
 		} else {
-		    sendWordToServerToRegister(root + okuri_head, okuri, content);
+		    sendWordToServerToRegister(
+			HiraganaInputMode::convert(root) + okuri_head,
+			HiraganaInputMode::convert(okuri), content);
 		}
 	    } else {
-		sendWordToServerToRegister(root, content);
+		sendWordToServerToRegister(HiraganaInputMode::convert(root), content);
 	    }
 
-	    // Šm’èB
-	    parent->fix(content + okuri); // ‘—‚艼–¼‚ð•t‚¯‚é
+	    // 確定。
+	    parent->fix(content + okuri); // 送り仮名を付ける
 
-	    // I—¹B
+	    // 終了。
 	    parent->setEnabledKanjiMode(false);
 	    initialize();
 	} else {
-	    if(okuri.length() > 0) { // ‘—‚艼–¼‚ª‚ ‚ê‚Î
+	    if(okuri.length() > 0) { // 送り仮名があれば
 		status = STATUS_WHITE_OKURI;
 	    } else {
 		status = STATUS_WHITE_ROOT;
 	    }
 	}
 
-	delete word_register_mode;
-	word_register_mode = NULL;
-	parent->updatePencilMenuIcon();
+	resetRegistrationMode();
+	restoreInputMode();
     }
 }
 
 void KanjiConversionMode::wordRegistrationCanceled() {
-    delete word_register_mode;
-    word_register_mode = NULL;
-    parent->updatePencilMenuIcon();
-    
+    resetRegistrationMode();
+    restoreInputMode();
+
     if (status == STATUS_WHITE_ROOT || status == STATUS_WHITE_OKURI) {
-	// root‚Éokuri‚ð‚­‚Á‚‚¯‚ÄSTATUS_WHITE_ROOT‚Ö
+	// rootにokuriをくっつけてSTATUS_WHITE_ROOTへ
 	root += okuri;
 	okuri.clear();
 	
@@ -804,36 +840,36 @@
 	status = STATUS_WHITE_ROOT;
     }
     else if (status == STATUS_BLACK) {
-	current_candidate_index = candidates.size() - 1; // ÅŒã‚ÌŒó•â‚ցB
+	current_candidate_index = candidates.size() - 1; // 最後の候補へ。
     }
     else if (status == STATUS_BLACK_WITH_WINDOW) {
-	// ƒEƒCƒ“ƒhƒE‚ðŠJ‚¢‚čŌã‚̃tƒŒ[ƒ€‚ðo‚·
-	current_candidate_index = show_cands_window_after_Nth_cand - 1; // goToNextCandidatesFrame()‚Å‚¸‚ê‚éB
+	// ウインドウを開いて最後のフレームを出す
+	current_candidate_index = show_cands_window_after_Nth_cand - 1; // goToNextCandidatesFrame()でずれる。
 	openCandidatesWindow(OpenReverse);
     }
 }
 
 CppCFString KanjiConversionMode::getStringToDisplay() {
     if (word_register_mode) {
-	// –³Ž‹‚³‚¹‚éB‚³‚à‚È‚¢‚Ɛ܊pWordRegisterMode‚ªÝ’肵‚½•¶Žš‚ð’ׂµ‚Ä‚µ‚Ü‚¤B
+	// 無視させる。さもないと折角WordRegisterModeが設定した文字を潰してしまう。
 	return CppCFString().append(kIgnoreThis);
     }
     
     if (status == STATUS_WHITE_ROOT) {
-	// ¤root
+	// â–½root
 	return CppCFString().append(0x25bd).append(root_to_display);
     }
     else if (status == STATUS_WHITE_OKURI) {
-	// ¤root*okuri
+	// â–½root*okuri
 	return CppCFString().append(0x25bd).append(root_to_display).append('*').append(okuri_to_display);
     }
     else if (status == STATUS_BLACK || status == STATUS_BLACK_WITH_WINDOW) {
 	CppCFString str = convertNumeric(numconv_, candidates[current_candidate_index]);
-	// ¥Œ»Ý‚ÌŒó•â
+	// ▼現在の候補
 	return CppCFString().append(0x25bc).append(str);
     }
     else if (status == STATUS_PROMPT) {
-	// [ƒvƒƒ“ƒvƒg][“ü—Í]
+	// [プロンプト][入力]
 	return CppCFString('[').append(prompt).append("][").append(prompt_input).append(kCaret).append(']');
     }
     else {
@@ -852,16 +888,16 @@
     else if (status == STATUS_BLACK) {
 	result = convertNumeric(numconv_, candidates[current_candidate_index]);
 
-	// ŽI‚É‘—M
+	// 鯖に送信
 	sendCurrentCandidateToServerToRegister();
     }
     else if (status == STATUS_BLACK_WITH_WINDOW) {
 	result = convertNumeric(numconv_, candidates[current_candidate_index]);
 
-	// ŽI‚É‘—M
+	// 鯖に送信
 	sendCurrentCandidateToServerToRegister();
 
-	// ƒEƒCƒ“ƒhƒE‚ð•Â‚¶‚éB
+	// ウインドウを閉じる。
 	closeCandidatesWindow();
     }
     else /* if (status == STATUS_NULL) */ {
@@ -869,8 +905,8 @@
 	result = CppCFString().append(kIgnoreThis);
     }
 	
-    // ‚±‚ꂪŒÄ‚΂ꂽ‚Æ‚¢‚¤‚±‚Æ‚Ífix‚³‚ê‚é‚Æ‚¢‚¤‚±‚Æ‚È‚Ì‚ÅŠ¿Žšƒ‚[ƒhI—¹B
-    // ‰Šú‰»‚·‚éB
+    // これが呼ばれたということはfixされるということなので漢字モード終了。
+    // 初期化する。
     parent->setEnabledKanjiMode(false);
     initialize();
     
@@ -891,22 +927,19 @@
 }
 
 void KanjiConversionMode::sendCurrentCandidateToServerToRegister() {
-    // ŽI‚É‘—MB
-    // •Ð‰¼–¼‚Í•½‰¼–¼‚É•ÏŠ·‚·‚éB
+    // 鯖に送信。
+    // 片仮名は平仮名に変換する。
     if(okuri.length() > 0) {
 	if(SKKConfig::UseKanaToOkuri()) {
-#ifdef DEBUG
-	    cerr << "(B)OKURI-HEAD: " << okuri[0] << " - " << SKKConfig::ConvertKanaToOkuri(okuri[0]) << endl;
-#endif
 	    sendWordToServerToRegister(
 		HiraganaInputMode::convert(root) + SKKConfig::ConvertKanaToOkuri(okuri[0]), 
 		HiraganaInputMode::convert(okuri),
-		candidates[current_candidate_index].clone().eraseLast(okuri.length())); // ‘—‚艼–¼‚ðÁ‚·B
+		candidates[current_candidate_index].clone().eraseLast(okuri.length())); // 送り仮名を消す。
 	} else {
 	    sendWordToServerToRegister(
 		HiraganaInputMode::convert(root) + okuri_head,
 		HiraganaInputMode::convert(okuri),
-		candidates[current_candidate_index].clone().eraseLast(okuri.length())); // ‘—‚艼–¼‚ðÁ‚·B
+		candidates[current_candidate_index].clone().eraseLast(okuri.length())); // 送り仮名を消す。
 	}
     } else {
 	sendWordToServerToRegister(HiraganaInputMode::convert(root), candidates[current_candidate_index]);
@@ -914,41 +947,41 @@
 }
 
 void KanjiConversionMode::askServerTheCandidates(bool hasOkuri) {
-    // ‘—‚艼–¼‚ª‚ ‚ê‚ΐ擪‚É+A–³‚¯‚ê‚Î-‚ð•t‚¯‚éB
+    // 送り仮名があれば先頭に+、無ければ-を付ける。
     CppCFString query;
     if(hasOkuri) {
 	query.append('+').append(root);
 	if(SKKConfig::UseKanaToOkuri()) {
 	    query.append(SKKConfig::ConvertKanaToOkuri(okuri[0])).append(SKK_MSG_DELIMITER).append(okuri);
 	} else {
-	    // ‚¨‚­‚è@¨@+‚¨‚­r ‚è
+	    // おくり → +おくr り
 	    query.append(okuri_head).append(SKK_MSG_DELIMITER).append(okuri);
 	}
     } else {
-	// ‚©‚ȁ@¨@-‚©‚È
+	// かな → -かな
 	query = CppCFString().append('-').append(root);
     }
 
-    // ‘SŠp‰¼–¼‚Æ”¼Šp‰¼–¼‚𕽉¼–¼‚É•ÏŠ·
+    // 全角仮名と半角仮名を平仮名に変換
     query = HiraganaInputMode::convert(query);
 
     D_PRINTF("query: %s\n",query.toCString(kCFStringEncodingEUC_JP));
 
-    // ŽI‚ɐq‚Ë‚é
+    // 鯖に尋ねる
     CppCFData cfdata_query;
     cfdata_query.own(query.toCFData());
 
     current_candidate_index = 0;
     ::askServerTheCandidates(cfdata_query, candidates);
 
-    // ‘—‚艼–¼‚ð•t—^‚·‚é
+    // 送り仮名を付与する
     if(hasOkuri) {
 	for(unsigned i = 0; i < candidates.size(); ++ i) {
 	    candidates[i] += okuri;
 	}
     }
 
-    // ”’l•ÏŠ·‚ª—LŒø‚©H
+    // 数値変換が有効か?
     if(!hasOkuri && ClientConfiguration::theInstance().useNumericConversion() &&
        numconv_.Setup(root.toStdString(kCFStringEncodingUTF8))) {
 	CppCFString normalized(numconv_.NormalizedKey().c_str(), kCFStringEncodingUTF8);
@@ -963,7 +996,7 @@
     }
 }
 
-// ”ñƒƒ“ƒo
+// 非メンバ
 void askServerTheCandidates(const CppCFData& query, std::vector<CppCFString>& candidates) {
     CppCFString reply(ServerConnectionFactory::theInstance().newConnection().
 		      send(kSKKMessageSearch, query, kAquaSKKServerRunLoopMode).getData());
@@ -978,8 +1011,8 @@
 void KanjiConversionMode::makeServerRemoveWord() {
     CppCFString query;
     if(okuri.length() > 0) {
-	// ‚¨‚­‚è ‘—‚è@¨@+‚¨‚­r ‚è ‘—
-	// “ǂ݂ɂ‚¢‚Ä‚Í‘SŠp‰¼–¼‚Æ”¼Šp‰¼–¼‚𕽉¼–¼‚É•ÏŠ·
+	// おくり 送り → +おくr り 送
+	// 読みについては全角仮名と半角仮名を平仮名に変換
 	query.append('+');
 	if (SKKConfig::UseKanaToOkuri()) {
 #ifdef DEBUG
@@ -990,35 +1023,53 @@
 	    query.append(HiraganaInputMode::convert(root)).append(okuri_head);
 	}
 	query.append(SKK_MSG_DELIMITER).append(
-	    candidates[current_candidate_index].clone().eraseLast(okuri.length())); // ‘—‚艼–¼‚ðÁ‚·B
+	    candidates[current_candidate_index].clone().eraseLast(okuri.length())); // 送り仮名を消す。
     } else {
-	// ‚©‚È ‰¼–¼@¨@-‚©‚È ‰¼–¼
-	// “ǂ݂ɂ‚¢‚Ä‚Í‘SŠp‰¼–¼‚Æ”¼Šp‰¼–¼‚𕽉¼–¼‚É•ÏŠ·
+	// かな 仮名 → -かな 仮名
+	// 読みについては全角仮名と半角仮名を平仮名に変換
 	query.append('-').append(HiraganaInputMode::convert(root)).append(SKK_MSG_DELIMITER);
 	query.append(candidates[current_candidate_index]);
     }
 
-    // ŽI‚É“n‚·
+    // 鯖に渡す
     CppCFData cfdata_query;
     cfdata_query.own(query.toCFData());
     ::makeServerRemoveWord(cfdata_query);
 }
 
-// ”ñƒƒ“ƒo
+// 非メンバ
 void makeServerRemoveWord(const CppCFData& query) {
     ServerConnectionFactory::theInstance().newConnection().send(kSKKRemoveThisFromUserDic, query);
 }
 
 void KanjiConversionMode::askServerTheCompletions() {
-    // ‘SŠp‰¼–¼‚Æ”¼Šp‰¼–¼‚𕽉¼–¼‚É•ÏŠ·
+    // 全角仮名と半角仮名を平仮名に変換
     CppCFString query = HiraganaInputMode::convert(root);
 
-    // ŽI‚ɐq‚Ë‚é
+    // 鯖に尋ねる
     CppCFData cfdata_query;
     cfdata_query.own(query.toCFData());
 
     current_completion_index = 0;
     ::askServerTheCompletions(cfdata_query, completions);
+
+    // 変換用ファンクタ
+    struct convert {
+	static void ToZenKana(CppCFString& str) {
+	    str = ZenKataInputMode::convert(str);
+	}
+	static void ToHanKana(CppCFString& str) {
+	    str = HanKataInputMode::convert(str);
+	}
+    };
+
+    // カタカナ、半角カナの場合は見出し語の文字種を変換する
+    if(parent->isZenKataInputMode()) {
+	std::for_each(completions.begin(), completions.end(), &convert::ToZenKana);
+    }
+    if(parent->isHanKataInputMode()) {
+	std::for_each(completions.begin(), completions.end(), &convert::ToHanKana);
+    }
 }
 
 void askServerTheCompletions(const CppCFData& query, std::vector<CppCFString>& completions) {
@@ -1028,7 +1079,7 @@
     completions = reply.split(SKK_MSG_DELIMITER);
 }
 
-// ”ñƒƒ“ƒo
+// 非メンバ
 void sendWordToServerToRegister(const CppCFString& index,const CppCFString& okuri,const CppCFString& kanji) {
     CppCFData query;
 
@@ -1060,6 +1111,15 @@
     ServerConnectionFactory::theInstance().newConnection().send(kSKKRegisterThisToUserDic, query);
 }
 
+// トグル変換の結果を登録する
+void registerToggleEntry(const CppCFString& entry) {
+    CppCFData query;
+
+    query.own(HiraganaInputMode::convert(entry).toCFData());
+
+    ServerConnectionFactory::theInstance().newConnection().send(kSKKRegisterToggleEntry, query);
+}
+
 void KanjiConversionMode::openCandidatesWindow(OpenDirection mode) {
     std::vector<CppCFString> cands_without_okuri;
     unsigned okuri_length = okuri.length();
@@ -1083,7 +1143,7 @@
 			   current_candidate_index, candidates.size(), mode);
 }
 
-// ”ñƒƒ“ƒo
+// 非メンバ
 void openCandidatesWindow(const CppCFString& str_candidates,
 			  unsigned& window_id,
 			  unsigned& cands_per_frame,
@@ -1092,7 +1152,7 @@
 			  unsigned& current_index,
 			  size_t num_of_candidates,
 			  SInt16 open_direction) {
-    // ƒCƒ“ƒ‰ƒCƒ““ü—Í‚ðs‚Á‚Ä‚¢‚éˆÊ’u‚ðŽæ“¾B
+    // インライン入力を行っている位置を取得。
     struct OffsetToPosParams offset_to_pos_params;
     offset_to_pos_params.fRefCon = 0;
     offset_to_pos_params.fTextOffset = 0;
@@ -1103,7 +1163,7 @@
     SInt16 qd_x = offset_to_pos_params.fReplyPoint.h;
     SInt16 qd_y = offset_to_pos_params.fReplyPoint.v;
 
-    // ƒT[ƒo[‚É‘—‚è•t‚¯‚éCFData‚ðì¬B
+    // サーバーに送り付けるCFDataを作成。
     CppCFData cands_to_be_attached;
     cands_to_be_attached.own(str_candidates.toCFData());
     CppCFData attachment;
@@ -1112,14 +1172,14 @@
     attachment.append(CFSwapInt16HostToBig(open_direction));
     attachment.append(cands_to_be_attached);
 
-    // ‘—ŽóM
+    // 送受信
     CppCFData reply(ServerConnectionFactory::theInstance().newConnection().
 		    send(kSKKCreateCandidatesWindow, attachment, kAquaSKKServerRunLoopMode));
 
-    // •Ô‚Á‚Ä‚«‚½ƒf[ƒ^‚ð•ª‰ð‚µ‚Ä•Û‘¶B
-    // +0  Œó•â‘I‘ð‰æ–ÊID             •„†–³‚µ2ƒoƒCƒg®”
-    // +2  1ƒtƒŒ[ƒ€‚É•\Ž¦‚·‚éŒó•â‚̐”  •„†–³‚µ2ƒoƒCƒg®”
-    // +4  ƒtƒŒ[ƒ€”                 •„†–³‚µ2ƒoƒCƒg®”
+    // 返ってきたデータを分解して保存。
+    // +0  候補選択画面ID             符号無し2バイト整数
+    // +2  1フレームに表示する候補の数  符号無し2バイト整数
+    // +4  フレーム数                 符号無し2バイト整数
     //CppCFData reply(reply_data);
     window_id = CFSwapInt16BigToHost(reply.getUInt16(0));
     cands_per_frame = CFSwapInt16BigToHost(reply.getUInt16(2));
@@ -1133,7 +1193,7 @@
     }
 }
 
-// ”ñƒƒ“ƒo
+// 非メンバ
 CppCFData newCFDataRefWithWindowID(unsigned window_id) {
     CppCFData result;
     result.append(static_cast<UInt16>(CFSwapInt16HostToBig(window_id)));
@@ -1142,45 +1202,35 @@
 }
 
 void KanjiConversionMode::goToNextCandidatesFrame() {
-    // ƒEƒCƒ“ƒhƒEID(UInt16)‚ðŠÜ‚ÞCFData‚ðì¬‚µAŽI‚Ö‘—‚éB
+    // ウインドウID(UInt16)を含むCFDataを作成し、鯖へ送る。
     CppCFData reply(ServerConnectionFactory::theInstance().newConnection().
 		    send(kSKKCandidatesWindowNext, newCFDataRefWithWindowID(candidates_window_id),
 			 kAquaSKKServerRunLoopMode));
 
-    // Œ»Ý‚̃tƒŒ[ƒ€”ԍ†‚ðƒCƒ“ƒNƒŠƒƒ“ƒg
+    // 現在のフレーム番号をインクリメント
     ++ candidates_window_current_frame;
 
-    // Œ»Ý‚ÌŒó•â”ԍ†‚ðƒtƒŒ[ƒ€“–‚½‚è‚ÌŒó•â”•ª‘‚â‚·B
+    // 現在の候補番号をフレーム当たりの候補数分増やす。
     current_candidate_index += candidates_window_cands_per_frame;
     candidates_window_cands_per_frame = CFSwapInt16BigToHost(reply.getUInt16(0));
 }
 
 void KanjiConversionMode::goToPrevCandidatesFrame() {
-    // ƒEƒCƒ“ƒhƒEID(UInt16)‚ðŠÜ‚ÞCFData‚ðì¬‚µAŽI‚Ö‘—‚éB
+    // ウインドウID(UInt16)を含むCFDataを作成し、鯖へ送る。
     CppCFData reply(ServerConnectionFactory::theInstance().newConnection().
 		    send(kSKKCandidatesWindowPrev, newCFDataRefWithWindowID(candidates_window_id),
 			 kAquaSKKServerRunLoopMode));
 
-    // Œ»Ý‚̃tƒŒ[ƒ€”ԍ†‚ðƒfƒNƒŠƒƒ“ƒg
+    // 現在のフレーム番号をデクリメント
     -- candidates_window_current_frame;
 
-    // Œ»Ý‚ÌŒó•â”ԍ†‚ðƒtƒŒ[ƒ€“–‚½‚è‚ÌŒó•â”•ªŒ¸‚ç‚·B
+    // 現在の候補番号をフレーム当たりの候補数分減らす。
     candidates_window_cands_per_frame = CFSwapInt16BigToHost(reply.getUInt16(0));
     current_candidate_index -= candidates_window_cands_per_frame;
 }
 
-void KanjiConversionMode::suspendCandidatesWindow() {
-    ServerConnectionFactory::theInstance().newConnection().
-	send(kSKKSuspendCandidatesWindow, newCFDataRefWithWindowID(candidates_window_id));
-}
-
-void KanjiConversionMode::resumeCandidatesWindow() {
-    ServerConnectionFactory::theInstance().newConnection().
-	send(kSKKResumeCandidatesWindow, newCFDataRefWithWindowID(candidates_window_id));
-}
-
 void KanjiConversionMode::closeCandidatesWindow() {
-    // ƒEƒCƒ“ƒhƒEID(UInt16)‚ðŠÜ‚ÞCFData‚ðì¬‚µAŽI‚Ö‘—‚éB
+    // ウインドウID(UInt16)を含むCFDataを作成し、鯖へ送る。
     ServerConnectionFactory::theInstance().newConnection().
 	send(kSKKCloseCandidatesWindow, newCFDataRefWithWindowID(candidates_window_id));
 }
@@ -1192,7 +1242,7 @@
 
     check.insert(CppCFString(numconv.OriginalKey().c_str(), kCFStringEncodingUTF8));
 
-    // €”õ
+    // 準備
     for(std::vector<CppCFString>::iterator iter = master.begin(); iter != master.end(); ++ iter) {
 	if(check.find(*iter) != check.end()) continue;
 
@@ -1200,7 +1250,7 @@
 	result.push_back(*iter);
     }
 
-    // ƒ}[ƒW
+    // マージ
     for(std::vector<CppCFString>::iterator iter = cands.begin(); iter != cands.end(); ++ iter) {
 	CppCFString target(convertNumeric(numconv, *iter));
 	if(check.find(target) != check.end()) continue;
Index: AquaSKK/KanjiConversionMode.h
diff -u AquaSKK/KanjiConversionMode.h:1.6.2.4 AquaSKK/KanjiConversionMode.h:1.6.2.5
--- AquaSKK/KanjiConversionMode.h:1.6.2.4	Sat Feb  3 17:52:48 2007
+++ AquaSKK/KanjiConversionMode.h	Thu Aug 16 19:58:18 2007
@@ -1,10 +1,10 @@
 /*
-  $Id: KanjiConversionMode.h,v 1.6.2.4 2007/02/03 08:52:48 t-suwa Exp $
+  $Id: KanjiConversionMode.h,v 1.6.2.5 2007/08/16 10:58:18 t-suwa Exp $
 
   MacOS X implementation of the SKK input method.
 
   Copyright (C) 2002 phonohawk
-  Copyright (C) 2006 Tomotaka SUWA <t.suw****@mac*****>
+  Copyright (C) 2006-2007 Tomotaka SUWA <t.suw****@mac*****>
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -37,43 +37,47 @@
 class KanjiConversionMode: public ChildInputMode, public RegistrationStarter {
     bool handleInputChar(SKKChar skkchar);
     NumericConverter numconv_;
+    int priorInputMode_;
+
+    enum { Hirakana, Katakana, Jisx0201Kana };
 
 protected:
-    static const int STATUS_NULL = 0; // Š¿Žš•ÏŠ·ƒ‚[ƒh‚É‚È‚Á‚Ä‚¢‚È‚¢ó‘ԁBæ“ª‚Ɂ¤‚à¥‚à–³‚¢B
-    static const int STATUS_WHITE_ROOT = 1; // ¤ƒ‚[ƒh‚ŁA‘—‚艼–¼‚ð“ü‚ê‚é‘O
-    static const int STATUS_WHITE_OKURI = 2; // ¤ƒ‚[ƒh‚ŁA‘—‚艼–¼‚ð“ü‚ꂽŒã
-    static const int STATUS_BLACK = 3; // ¥ƒ‚[ƒh
-    static const int STATUS_BLACK_WITH_WINDOW = 4; // ¥ƒ‚[ƒh‚ŁAŒó•â‘I‘ðƒEƒCƒ“ƒhƒE‚ªŠJ‚¢‚Ä‚¢‚éB
-    static const int STATUS_PROMPT = 5; // ƒvƒƒ“ƒvƒg‚ðo‚µ‚Ä‚¢‚éB
+    static const int STATUS_NULL = 0; // 漢字変換モードになっていない状態。先頭に▽も▼も無い。
+    static const int STATUS_WHITE_ROOT = 1; // ▽モードで、送り仮名を入れる前
+    static const int STATUS_WHITE_OKURI = 2; // ▽モードで、送り仮名を入れた後
+    static const int STATUS_BLACK = 3; // ▼モード
+    static const int STATUS_BLACK_WITH_WINDOW = 4; // ▼モードで、候補選択ウインドウが開いている。
+    static const int STATUS_PROMPT = 5; // プロンプトを出している。
 
-    WordRegisterMode* word_register_mode; // NULL‚Å‚È‚¢Žž‚Í’PŒê“o˜^ƒ‚[ƒh‚ª‹N“®’†B
+    WordRegisterMode* word_register_mode; // NULLでない時は単語登録モードが起動中。
+    WordRegisterMode* old_word_register_mode; // 直前まで有効だった単語登録モード
 
     int status;
-    CppCFString root; // ‘—‚艼–¼‚Ì–³‚¢•”•ªB—áFu‘—‚èv‚È‚çu‚¨‚­v
-    CppCFString okuri; // ‘—‚艼–¼‚Ì•”•ªB—áFu‘—‚èv‚È‚çu‚èv
-    UniChar okuri_head; // ‘—‚艼–¼‚Ì“ª‚̃Aƒ‹ƒtƒ@ƒxƒbƒgB—áFu‘—‚èv‚È‚çurv
-    CppCFString root_to_display,okuri_to_display; // ‰æ–Ê•\Ž¦—pB“ü—Í“r’†‚̃Aƒ‹ƒtƒ@ƒxƒbƒg‚È‚Ç‚à“ü‚éB
-
-    static const int PROMPT_DELETE_FROM_USER_DIC = 1; // ƒ†[ƒU[Ž«‘‚©‚ç’PŒê‚ðíœ
-    int prompt_type; // ƒvƒƒ“ƒvƒg‚ÌŽí—ށB
-    CppCFString prompt; // ƒvƒƒ“ƒvƒg
-    CppCFString prompt_input; // ƒvƒƒ“ƒvƒg‚Ƀ†[ƒU[‚ª“ü—Í‚µ‚½•¶Žš—ñ
-
-    std::vector<CppCFString> candidates; // ‘S‚Ä‚ÌŒó•â
-    unsigned current_candidate_index; // Œ»Ý‚ÌŒó•â”ԍ†
-
-    unsigned show_cands_window_after_Nth_cand; // ‰½ŒÂ–ڈȍ~‚ÌŒó•â‚ðŒó•â‘I‘ðƒEƒCƒ“ƒhƒE‚É•\Ž¦‚·‚é‚©B
-
-    unsigned candidates_window_id; // status‚ªSTATUS_BLACK_WITH_WINDOW‚Ì‚Æ‚«AŒó•â‘I‘ðƒEƒCƒ“ƒhƒE‚ÌIDB
-    unsigned candidates_window_current_frame; // Œó•â‘I‘ðƒEƒCƒ“ƒhƒE‚ÌŒ»Ý‚̃tƒŒ[ƒ€
-    unsigned candidates_window_cands_per_frame; // Œó•â‘I‘ðƒEƒCƒ“ƒhƒE‚Ì1ƒtƒŒ[ƒ€“–‚½‚è‚ÌŒó•â”
-    unsigned candidates_window_num_of_frames; // Œó•â‘I‘ðƒEƒCƒ“ƒhƒE‚̃tƒŒ[ƒ€”
-
-    bool completion_mode; // Œ©o‚µŒê•âŠ®ƒ‚[ƒhB‚±‚̃‚[ƒh‚ł̓sƒŠƒIƒh‚ƃJƒ“ƒ}‚ª•âŠ®‚Ì‘€ì‚ÉŽg‚í‚ê‚éB
-    std::vector<CppCFString> completions; // •âŠ®‚ÌŒó•â
-    unsigned current_completion_index; // Œ»Ý‚̕⊮‚ÌŒó•â”ԍ†
+    CppCFString root; // 送り仮名の無い部分。例:「送り」なら「おく」
+    CppCFString okuri; // 送り仮名の部分。例:「送り」なら「り」
+    UniChar okuri_head; // 送り仮名の頭のアルファベット。例:「送り」なら「r」
+    CppCFString root_to_display,okuri_to_display; // 画面表示用。入力途中のアルファベットなども入る。
+
+    static const int PROMPT_DELETE_FROM_USER_DIC = 1; // ユーザー辞書から単語を削除
+    int prompt_type; // プロンプトの種類。
+    CppCFString prompt; // プロンプト
+    CppCFString prompt_input; // プロンプトにユーザーが入力した文字列
+
+    std::vector<CppCFString> candidates; // 全ての候補
+    unsigned current_candidate_index; // 現在の候補番号
+
+    unsigned show_cands_window_after_Nth_cand; // 何個目以降の候補を候補選択ウインドウに表示するか。
+
+    unsigned candidates_window_id; // statusがSTATUS_BLACK_WITH_WINDOWのとき、候補選択ウインドウのID。
+    unsigned candidates_window_current_frame; // 候補選択ウインドウの現在のフレーム
+    unsigned candidates_window_cands_per_frame; // 候補選択ウインドウの1フレーム当たりの候補数
+    unsigned candidates_window_num_of_frames; // 候補選択ウインドウのフレーム数
+
+    bool completion_mode; // 見出し語補完モード。このモードではピリオドとカンマが補完の操作に使われる。
+    std::vector<CppCFString> completions; // 補完の候補
+    unsigned current_completion_index; // 現在の補完の候補番号
 
-    bool henkanModeStatus;	//Œ»Ý•ÏŠ·ó‘Ô‚É‚È‚Á‚Ä‚¢‚é‚©B
+    bool henkanModeStatus;	//現在変換状態になっているか。
 
     virtual void startRegisteringWord();
     virtual void askServerTheCandidates(bool hasOkuri);
@@ -83,10 +87,10 @@
     virtual void openCandidatesWindow(OpenDirection mode = OpenNormal);
     virtual void goToPrevCandidatesFrame();
     virtual void goToNextCandidatesFrame();
-    virtual void suspendCandidatesWindow();
-    virtual void resumeCandidatesWindow();
     virtual void closeCandidatesWindow();
     virtual void initialize();
+    virtual void resetRegistrationMode();
+    virtual void restoreInputMode();
 
 public:
     KanjiConversionMode(class ParentInputMode& parent);
@@ -103,14 +107,15 @@
     virtual CppCFString getStringToDisplay();
     virtual CppCFString getStringToFix();
 
-    virtual void wordRegistrationFinished(); // WordRegisterModeê—pB
-    virtual void wordRegistrationCanceled(); // WordRegisterModeê—pB
+    virtual void wordRegistrationFinished(); // WordRegisterMode専用。
+    virtual void wordRegistrationCanceled(); // WordRegisterMode専用。
 };
 
 void askServerTheCandidates(const CppCFData& query, std::vector<CppCFString>& candidates);
 void addCandidate(const CppCFString& candidate, std::vector<CppCFString>& candidates);
 void sendWordToServerToRegister(const CppCFString& index,const CppCFString& okuri,const CppCFString& kanji);
 void sendWordToServerToRegister(const CppCFString& index,const CppCFString& kanji);
+void registerToggleEntry(const CppCFString& entry);
 void askServerTheCompletions(const CppCFData& query, std::vector<CppCFString>& completions);
 void makeServerRemoveWord(const CppCFData& query);
 void openCandidatesWindow(const CppCFString& str_candidates,
Index: AquaSKK/ServerMessageReceiver.h
diff -u AquaSKK/ServerMessageReceiver.h:1.5.2.1 AquaSKK/ServerMessageReceiver.h:1.5.2.2
--- AquaSKK/ServerMessageReceiver.h:1.5.2.1	Sat Feb  3 16:53:29 2007
+++ AquaSKK/ServerMessageReceiver.h	Thu Aug 16 19:58:18 2007
@@ -1,10 +1,10 @@
 /*
-  $Id: ServerMessageReceiver.h,v 1.5.2.1 2007/02/03 07:53:29 t-suwa Exp $
+  $Id: ServerMessageReceiver.h,v 1.5.2.2 2007/08/16 10:58:18 t-suwa Exp $
 
   MacOS X implementation of the SKK input method.
 
   Copyright (C) 2002 phonohawk
-  Copyright (C) 2005 Tomotaka SUWA <t.suw****@mac*****>
+  Copyright (C) 2005-2007 Tomotaka SUWA <t.suw****@mac*****>
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -21,7 +21,8 @@
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
-#pragma once
+#ifndef INC__ServerMessageReceiver__
+#define INC__ServerMessageReceiver__
 
 #include <Carbon/Carbon.h>
 #include <exception>
@@ -30,7 +31,7 @@
 class CppCFData;
 
 /*
-  ƒNƒ‰ƒCƒAƒ“ƒg‚©‚ç‚̃ƒbƒZ[ƒW‚ðŽó‚¯Žæ‚éƒNƒ‰ƒX‚Å‚·B
+  クライアントからのメッセージを受け取るクラスです。
 */
 
 class ServerMessageReceiver: public CppMessagePortServer {
@@ -42,10 +43,9 @@
     CppCFData createCandidatesWindow(const CppCFData& attachment);
     CppCFData candidatesWindowNext(const CppCFData& attachment);
     CppCFData candidatesWindowPrev(const CppCFData& attachment);
-    void suspendCandidatesWindow(const CppCFData& attachment);
-    void resumeCandidatesWindow(const CppCFData& attachment);
     void closeCandidatesWindow(const CppCFData& attachment);
     void registerThisToUserDic(const CppCFData& attachment);
+    void registerToggleEntry(const CppCFData& attachment);
     void removeThisFromUserDic(const CppCFData& attachment);
     void showAboutBox();
     void showPreferencesBox();
@@ -55,3 +55,5 @@
 public:
     static void start(const CFStringRef loopMode);
 };
+
+#endif
Index: AquaSKK/ServerMessageReceiver.mm
diff -u AquaSKK/ServerMessageReceiver.mm:1.7.2.4 AquaSKK/ServerMessageReceiver.mm:1.7.2.5
--- AquaSKK/ServerMessageReceiver.mm:1.7.2.4	Sat Feb  3 17:52:48 2007
+++ AquaSKK/ServerMessageReceiver.mm	Thu Aug 16 19:58:18 2007
@@ -1,10 +1,10 @@
 /* -*- objc -*-
-  $Id: ServerMessageReceiver.mm,v 1.7.2.4 2007/02/03 08:52:48 t-suwa Exp $
+  $Id: ServerMessageReceiver.mm,v 1.7.2.5 2007/08/16 10:58:18 t-suwa Exp $
 
   MacOS X implementation of the SKK input method.
 
   Copyright (C) 2002 phonohawk
-  Copyright (C) 2005-2006 Tomotaka SUWA <t.suw****@mac*****>
+  Copyright (C) 2005-2007 Tomotaka SUWA <t.suw****@mac*****>
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -51,13 +51,13 @@
 CppCFData ServerMessageReceiver::messageReceived(SInt32 msgid, const CppCFData& packet) {
     CppCFData reply;
 
-    // ƒwƒbƒ_‚ðŽæ‚èo‚·BƒNƒ‰ƒCƒAƒ“ƒg‚ÌPSN‚ª“ü‚Á‚Ä‚¢‚éB
+    // ヘッダを取り出す。クライアントのPSNが入っている。
     BasicMessageHeader header;
     if(packet.getLength() > 0) {
 	packet.copyData(0, sizeof(BasicMessageHeader), &header);
     }
 
-    // PSN ‚ð Host Endian ‚É–ß‚·
+    // PSN を Host Endian に戻す
 #define Big2Host32(arg)	arg = CFSwapInt32BigToHost(arg)
     Big2Host32(header.fProcessSerialNumber.highLongOfPSN);
     Big2Host32(header.fProcessSerialNumber.lowLongOfPSN);
@@ -68,10 +68,10 @@
     }
 
     switch(msgid) {
-    case kBasicMessageActivated: // ƒNƒ‰ƒCƒAƒ“ƒg‚ªƒAƒNƒeƒBƒu‚É‚È‚Á‚½
+    case kBasicMessageActivated: // クライアントがアクティブになった
 	ClientConnectionFactory::theInstance().setDefaultTarget(header.fProcessSerialNumber);
 	break;
-    case kBasicMessageDeactivated: { // ƒNƒ‰ƒCƒAƒ“ƒg‚ªƒAƒNƒeƒBƒu‚Å‚È‚­‚È‚Á‚½
+    case kBasicMessageDeactivated: { // クライアントがアクティブでなくなった
 	ProcessSerialNumber psn;
 	psn.highLongOfPSN = 0;
 	psn.lowLongOfPSN = kNoProcess;
@@ -79,7 +79,7 @@
 	ClientConnectionFactory::theInstance().setDefaultTarget(psn);
 	break;
     }
-    case kBasicMessageHidePalettes: // ƒpƒŒƒbƒg‚ð‰B‚·‚悤TSM‚©‚çŽwŽ¦‚ª“ü‚Á‚½
+    case kBasicMessageHidePalettes: // パレットを隠すようTSMから指示が入った
 	break;
     case kSKKMessageSearch:
 	reply = searchWord(body);
@@ -99,6 +99,9 @@
     case kSKKRegisterThisToUserDic:
 	registerThisToUserDic(body);
 	break;
+    case kSKKRegisterToggleEntry:
+	registerToggleEntry(body);
+	break;
     case kSKKRemoveThisFromUserDic:
 	removeThisFromUserDic(body);
 	break;
@@ -141,7 +144,7 @@
     std::string query = data.toStdString(kCFStringEncodingUTF8).substr(1);
     std::string result;
 
-    // ‘—‚è‚ ‚èH
+    // 送りあり?
     if(data[0] == '+') {
 	int pos = query.find_first_of(SKK_MSG_DELIMITER);
 
@@ -159,7 +162,7 @@
 }
 
 CppCFData ServerMessageReceiver::createCandidatesWindow(const CppCFData& attachment) {
-    // ’ljÁƒf[ƒ^‚Æ‚µ‚ÄQuickDrawÀ•W‚ÆUniChar‚Ì”z—ñ‚ðŽæ‚éB
+    // 追加データとしてQuickDraw座標とUniCharの配列を取る。
     SInt16 qd_x = CFSwapInt16BigToHost(attachment.getSInt16(0));
     SInt16 qd_y = CFSwapInt16BigToHost(attachment.getSInt16(2));
     int showLast = CFSwapInt16BigToHost(attachment.getSInt16(4));
@@ -208,14 +211,6 @@
     return reply;
 }
 
-void ServerMessageReceiver::suspendCandidatesWindow(const CppCFData& attachment) {
-    CandidatesManager::sharedManager().suspendWindow(CFSwapInt16BigToHost(attachment.getUInt16(0)));
-}
-
-void ServerMessageReceiver::resumeCandidatesWindow(const CppCFData& attachment) {
-    CandidatesManager::sharedManager().resumeWindow(CFSwapInt16BigToHost(attachment.getUInt16(0)));
-}
-
 void ServerMessageReceiver::closeCandidatesWindow(const CppCFData& attachment) {
     CandidatesManager::sharedManager().closeWindow(CFSwapInt16BigToHost(attachment.getUInt16(0)));
 }
@@ -225,7 +220,7 @@
 
     std::string query = data.toStdString(kCFStringEncodingUTF8).substr(1);
 
-    // ‘—‚è‚ ‚èH
+    // 送りあり?
     if(data[0] == '+') {
 	int pos1 = query.find_first_of(SKK_MSG_DELIMITER);
 	int pos2 = query.find_first_of(SKK_MSG_DELIMITER, pos1 + 1);
@@ -245,6 +240,15 @@
     }
 }
 
+void ServerMessageReceiver::registerToggleEntry(const CppCFData& attachment) {
+    CppCFString data(attachment.getData());
+
+    std::string key = data.toStdString(kCFStringEncodingUTF8);
+
+    // 見出し語だけ登録する
+    DictionarySet::theInstance().RegisterOkuriNasi(key, "");
+}
+
 void ServerMessageReceiver::removeThisFromUserDic(const CppCFData& attachment) {
     CppCFString data(attachment.getData());
 
@@ -255,7 +259,7 @@
     std::string key = query.substr(0, pos);
     std::string kanji = query.substr(pos + 1);
 
-    // ‘—‚è‚ ‚èH
+    // 送りあり?
     if(data[0] == '+') {
 	DictionarySet::theInstance().RemoveOkuriAri(key, kanji);
     } else {


aquaskk-changes メーリングリストの案内