[aquaskk-changes 342] CVS update: AquaSKK/src/component

Tomotaka SUWA t-suw****@users*****
2007年 8月 19日 (日) 19:00:32 JST


Index: AquaSKK/src/component/BIM.cpp
diff -u /dev/null AquaSKK/src/component/BIM.cpp:1.1.2.1
--- /dev/null	Sun Aug 19 19:00:32 2007
+++ AquaSKK/src/component/BIM.cpp	Sun Aug 19 19:00:32 2007
@@ -0,0 +1,40 @@
+/*
+  $Id: BIM.cpp,v 1.1.2.1 2007/08/19 10:00:32 t-suwa Exp $
+
+  MacOS X implementation of the SKK input method.
+
+  Copyright (C) 2002-2004 phonohawk
+  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
+  the Free Software Foundation; either version 2 of the License, or
+  any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <Carbon/Carbon.h>
+
+#include "SKKComponent.h"
+
+// 鉛筆メニューのアイコンを設定する。
+void BIMSetPencilMenuIcon(int menu_icon_index) {
+    CFStringRef inputModes[] = {
+	kTextServiceInputModeJapanese,
+	kTextServiceInputModeJapaneseKatakana,
+	kTextServiceInputModeJapaneseHalfWidthKana,
+	kTextServiceInputModeJapaneseFullWidthRoman,
+	kTextServiceInputModeRoman,
+	0
+    };
+
+    SKKComponent::theInstance().NotifyInputMode(inputModes[menu_icon_index]);
+}
Index: AquaSKK/src/component/BIMInputEvents.cpp
diff -u /dev/null AquaSKK/src/component/BIMInputEvents.cpp:1.1.2.1
--- /dev/null	Sun Aug 19 19:00:32 2007
+++ AquaSKK/src/component/BIMInputEvents.cpp	Sun Aug 19 19:00:32 2007
@@ -0,0 +1,36 @@
+/*
+  $Id: BIMInputEvents.cpp,v 1.1.2.1 2007/08/19 10:00:32 t-suwa Exp $
+
+  MacOS X implementation of the SKK input method.
+
+  Copyright (C) 2002 phonohawk
+  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
+  the Free Software Foundation; either version 2 of the License, or
+  any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <Carbon/Carbon.h>
+#include "BIMClientServer.h"
+#include "BIMInputEvents.h"
+#include "SKKComponent.h"
+#include "SKKSession.h"
+
+// インプットエリアの各種情報を得る。
+void BIMHandleOffsetToPos(struct OffsetToPosParams* params) {
+    Point pt = SKKComponent::theInstance().Session().GetInputPosition();
+
+    params->fReplyPoint.h = pt.h;
+    params->fReplyPoint.v = pt.v;
+}
Index: AquaSKK/src/component/BIMInputEvents.h
diff -u /dev/null AquaSKK/src/component/BIMInputEvents.h:1.1.2.1
--- /dev/null	Sun Aug 19 19:00:32 2007
+++ AquaSKK/src/component/BIMInputEvents.h	Sun Aug 19 19:00:32 2007
@@ -0,0 +1,29 @@
+/*
+  $Id: BIMInputEvents.h,v 1.1.2.1 2007/08/19 10:00:32 t-suwa Exp $
+
+  MacOS X implementation of the SKK input method.
+
+  Copyright (C) 2002 phonohawk
+  Copyright (C) 2005-2006 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
+  the Free Software Foundation; either version 2 of the License, or
+  any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef INC__BIMInputEvents__
+#define INC__BIMInputEvents__
+
+void BIMHandleOffsetToPos(struct OffsetToPosParams *offsetToPosParams);
+
+#endif
Index: AquaSKK/src/component/IMSessionInputMode.cpp
diff -u /dev/null AquaSKK/src/component/IMSessionInputMode.cpp:1.1.2.1
--- /dev/null	Sun Aug 19 19:00:32 2007
+++ AquaSKK/src/component/IMSessionInputMode.cpp	Sun Aug 19 19:00:32 2007
@@ -0,0 +1,62 @@
+/*
+  $Id: IMSessionInputMode.cpp,v 1.1.2.1 2007/08/19 10:00:32 t-suwa Exp $
+
+  MacOS X implementation of the SKK input method.
+
+  Copyright (C) 2002-2004 phonohawk
+  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
+  the Free Software Foundation; either version 2 of the License, or
+  any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "SKKComponent.h"
+#include "SKKSession.h"
+#include "IMSessionInputMode.h"
+
+void IMSessionInputMode::terminate() {
+    ParentInputMode::terminate();
+
+    SKKComponent::theInstance().Session().Terminate();
+}
+
+void IMSessionInputMode::fix(const CppCFString& str) {
+    int caretpos = str.indexOf(kCaret);
+
+    if(caretpos != -1 && (unsigned)caretpos < str.length() - 1) {
+	CppCFString tmp;
+
+	tmp.append(str.substring(0, caretpos));
+	tmp.append(str.substring(caretpos + 1));
+
+	SKKComponent::theInstance().Session().FixString(tmp.getString());
+    } else {
+	SKKComponent::theInstance().Session().FixString(str.getString());
+    }
+}
+
+void IMSessionInputMode::display(const CppCFString& str) {
+    int caretpos = str.indexOf(kCaret);
+
+    if(caretpos != -1 && (unsigned)caretpos < str.length() - 1) {
+	CppCFString tmp;
+
+	tmp.append(str.substring(0, caretpos));
+	tmp.append(str.substring(caretpos + 1));
+
+	SKKComponent::theInstance().Session().DisplayString(tmp.getString(), 0, caretpos);
+    } else {
+	SKKComponent::theInstance().Session().DisplayString(str.getString(), 0, str.length());
+    }
+}
Index: AquaSKK/src/component/IMSessionInputMode.h
diff -u /dev/null AquaSKK/src/component/IMSessionInputMode.h:1.1.2.1
--- /dev/null	Sun Aug 19 19:00:32 2007
+++ AquaSKK/src/component/IMSessionInputMode.h	Sun Aug 19 19:00:32 2007
@@ -0,0 +1,38 @@
+/*
+  $Id: IMSessionInputMode.h,v 1.1.2.1 2007/08/19 10:00:32 t-suwa Exp $
+
+  MacOS X implementation of the SKK input method.
+
+  Copyright (C) 2002 phonohawk
+  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
+  the Free Software Foundation; either version 2 of the License, or
+  any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef INC__IMSessionInputMode__
+#define INC__IMSessionInputMode__
+
+#include "ParentInputMode.h"
+
+class CppCFString;
+
+class IMSessionInputMode: public ParentInputMode {
+public:
+    virtual void terminate();
+    virtual void fix(const CppCFString& str);
+    virtual void display(const CppCFString& str);
+};
+
+#endif
Index: AquaSKK/src/component/SKK.h
diff -u /dev/null AquaSKK/src/component/SKK.h:1.1.2.1
--- /dev/null	Sun Aug 19 19:00:32 2007
+++ AquaSKK/src/component/SKK.h	Sun Aug 19 19:00:32 2007
@@ -0,0 +1,36 @@
+/* -*- C++ -*-
+  $Id: SKK.h,v 1.1.2.1 2007/08/19 10:00:32 t-suwa Exp $
+
+  MacOS X implementation of the SKK input method.
+
+  Copyright (C) 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
+  the Free Software Foundation; either version 2 of the License, or
+  any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef INC__SKK__
+#define INC__SKK__
+
+namespace SKK {
+    enum InputMode {
+	Hirakana,
+	Katakana,
+	Jisx0201Kana,
+	Jisx0208Latin,
+	Ascii
+    };
+}
+
+#endif
Index: AquaSKK/src/component/SKK.r
diff -u /dev/null AquaSKK/src/component/SKK.r:1.1.2.1
--- /dev/null	Sun Aug 19 19:00:32 2007
+++ AquaSKK/src/component/SKK.r	Sun Aug 19 19:00:32 2007
@@ -0,0 +1,148 @@
+/*
+  $Id: SKK.r,v 1.1.2.1 2007/08/19 10:00:32 t-suwa Exp $
+
+  MacOS X implementation of the SKK input method.
+
+  Copyright (C) 2002 phonohawk
+  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
+  the Free Software Foundation; either version 2 of the License, or
+  any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#define thng_RezTemplateVersion 1
+
+#include <Carbon/Carbon.r>
+
+#ifdef ppc_YES
+  #define TARGET_REZ_MAC_PPC		1
+#endif
+ 
+#ifdef i386_YES
+  #define TARGET_REZ_MAC_X86		1
+#endif
+ 
+#if !defined(TARGET_REZ_MAC_X86)
+  #define TARGET_REZ_MAC_X86		0
+#endif
+ 
+#if !(TARGET_REZ_MAC_PPC || TARGET_REZ_MAC_X86)
+  #if TARGET_CPU_X86
+    #undef TARGET_REZ_MAC_X86
+    #define TARGET_REZ_MAC_X86		1
+  #elif TARGET_CPU_PPC
+    #undef TARGET_REZ_MAC_PPC
+    #define TARGET_REZ_MAC_PPC		1
+  #endif
+#endif
+ 
+#if TARGET_REZ_MAC_PPC && TARGET_REZ_MAC_X86
+  #define TARGET_REZ_UNIVERSAL_COMPONENTS
+  #define Target_PlatformType		platformPowerPCNativeEntryPoint
+  #define Target_SecondPlatformType	platformIA32NativeEntryPoint
+#elif TARGET_REZ_MAC_X86
+  #define Target_PlatformType		platformIA32NativeEntryPoint
+#else
+  #define Target_PlatformType		platformPowerPCNativeEntryPoint
+#endif
+
+#define	kAquaSKKBaseResouceID	16384
+#define kAquaSKKComponentFlags	0x8000 + smJapanese * 0x100 + langJapanese
+
+// "jp.sourceforge.AquaSKKInputMethod" ‚Ì pascal •¶Žš—ñ
+data 'cbnm' (0) {
+    $"216a 702e 736f 7572 6365 666f 7267 652e"
+    $"4171 7561 534b 4b49 6e70 7574 4d65 7468"
+    $"6f64"
+};
+
+resource 'thng' (kAquaSKKBaseResouceID) {
+    'tsvc',			// type
+    'inpm',			// subtype
+    'askk',			// manufacturer
+    0,				// component flags
+    0,				// component flags mask
+    0,				// code type
+    0,				// code ID
+    'STR ',			// name type
+    kAquaSKKBaseResouceID,	// name ID
+    'STR ',			// info type
+    kAquaSKKBaseResouceID + 1,	// info ID
+    'kcs8',			// icon type
+    kAquaSKKBaseResouceID,	// icon ID
+    0x00010000,			// version
+    componentHasMultiplePlatforms, // registration flags
+    0,				// resource ID of icon family
+    {				// component platform information
+	kAquaSKKComponentFlags,
+	'dlle',
+	kAquaSKKBaseResouceID,
+	Target_PlatformType,
+#ifdef TARGET_REZ_UNIVERSAL_COMPONENTS
+	kAquaSKKComponentFlags,
+	'dlle',
+	kAquaSKKBaseResouceID,
+	Target_SecondPlatformType
+#endif
+    };
+};
+
+resource 'dlle' (kAquaSKKBaseResouceID) {
+    "SKKEntryPoint"
+};
+
+resource 'STR ' (kAquaSKKBaseResouceID) {
+    "AquaSKK"
+};
+
+resource 'STR ' (kAquaSKKBaseResouceID + 1) {
+    "AquaSKK Input Method for Mac OS X"
+};
+
+data 'kcs#' (kAquaSKKBaseResouceID) {
+	$"FEFE FE82 7C44 7C44 3828 3828 1010 0000"
+	$"FEFE 82FE 447C 447C 2838 2838 1010 0000"
+	$"FEFE FEFE 7C7C 7C7C 3838 3838 1010 0000"
+	$"FEFE FEFE 7C7C 7C7C 3838 3838 1010 0000"
+};
+
+data 'kcs4' (kAquaSKKBaseResouceID) {
+	$"EEEE EEE0 DDDD DDD0 EDDE EFE0 D00C CCD0"
+	$"0EEE FE00 0DCC CD00 0EEE FE00 0DCC CD00"
+	$"00EF E000 00DC D000 00EF E000 00DC D000"
+	$"000E 0000 000D 0000 0000 0000 0000 0000"
+	$"DDDD DDD0 EEEE EEE0 D00C CCD0 EDDE EFE0"
+	$"0DCC CD00 0EEE FE00 0DCC CD00 0EEE FE00"
+	$"00DC D000 00EF E000 00DC D000 00EF E000"
+	$"000D 0000 000E 0000 0000 0000 0000 0000"
+};
+
+data 'kcs8' (kAquaSKKBaseResouceID) {
+	$"FBFB FBFB FBFB FB00 F9F9 F9F9 F9F9 F900"
+	$"FAF9 FAFB FCFD FA00 F800 F5F6 2BF7 F800"
+	$"00FB FBFC FDFB 0000 00F9 F62B F7F9 0000"
+	$"00FA FBFC FDFA 0000 00F8 F62B F7F8 0000"
+	$"0000 FBFD FB00 0000 0000 F9F7 F900 0000"
+	$"0000 FAFD FA00 0000 0000 F8F7 F800 0000"
+	$"0000 00FB 0000 0000 0000 00F9 0000 0000"
+	$"0000 0000 0000 0000 0000 0000 0000 0000"
+	$"F9F9 F9F9 F9F9 F900 FBFB FBFB FBFB FB00"
+	$"F800 F5F6 2BF7 F800 FAF9 FAFB FCFD FA00"
+	$"00F9 F62B F7F9 0000 00FB FBFC FDFB 0000"
+	$"00F8 F62B F7F8 0000 00FA FBFC FDFA 0000"
+	$"0000 F9F7 F900 0000 0000 FBFD FB00 0000"
+	$"0000 F8F7 F800 0000 0000 FAFD FA00 0000"
+	$"0000 00F9 0000 0000 0000 00FB 0000 0000"
+	$"0000 0000 0000 0000 0000 0000 0000 0000"
+};
Index: AquaSKK/src/component/SKKComponent.cpp
diff -u /dev/null AquaSKK/src/component/SKKComponent.cpp:1.1.2.1
--- /dev/null	Sun Aug 19 19:00:32 2007
+++ AquaSKK/src/component/SKKComponent.cpp	Sun Aug 19 19:00:32 2007
@@ -0,0 +1,347 @@
+/* -*- C++ -*-
+   $Id: SKKComponent.cpp,v 1.1.2.1 2007/08/19 10:00:32 t-suwa Exp $
+
+   MacOS X implementation of the SKK input method.
+
+   Copyright (C) 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
+   the Free Software Foundation; either version 2 of the License, or
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <algorithm>
+
+#include "CppCFData.h"
+
+#include "BIMClientServer.h"
+#include "ClientConfiguration.h"
+#include "ClientMessageReceiver.h"
+#include "ServerConnectionFactory.h"
+#include "SKKConfig.h"
+
+#include "SKKComponent.h"
+#include "SKKSession.h"
+
+enum {
+    kAboutCommand = 'abou',
+    kPreferencesCommand = 'pref',
+    kProjectWebCommand = 'sfjp',
+    kTipsCommand = 'tips',
+    kUseBrandNewEngine = 'bnew',
+    kUseLegacyEngine = 'lgcy'
+};
+
+static CFStringRef project_web_url = CFSTR("http://aquaskk.sourceforge.jp/");
+static CFStringRef tips_url = CFSTR("http://aquaskk.sourceforge.jp/inside_aquaskk/");
+
+// ======================================================================
+// ユーティリティ
+// ======================================================================
+static void InitializeKeyboardLayout() {
+    KeyboardLayoutIdentifier id = ClientConfiguration::theInstance().kbdLayoutId();
+    KeyboardLayoutRef kbd;
+
+    KLGetKeyboardLayoutWithIdentifier(id, &kbd);
+    KLSetCurrentKeyboardLayout(kbd);
+}
+
+static void OpenURL(const CFStringRef str) {
+    CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, str, 0);
+
+    LSOpenCFURLRef(url, 0);
+
+    CFRelease(url);
+}
+
+// ======================================================================
+// 削除ファンクタ
+// ======================================================================
+struct DeleteSession {
+    void operator()(const std::pair<ComponentInstance, SKKSession*>& obj) const {
+	delete obj.second;
+    }
+};
+
+SKKComponent& SKKComponent::theInstance() {
+    static SKKComponent obj;
+    return obj;
+}
+
+SKKComponent::SKKComponent() : active_(0), menu_(0) {
+    // Nib ファイルからメニューをロードする
+    CFBundleRef	bundle = CFBundleGetBundleWithIdentifier(CFSTR(kIMBundleIdentifier));
+    if(bundle) {
+	IBNibRef nib;
+
+	OSStatus err = CreateNibReferenceWithCFBundle(bundle, CFSTR("Menu"), &nib);
+	if(err == noErr) {
+	    err = CreateMenuFromNib(nib, CFSTR("AquaSKK"), &menu_);
+	    DisposeNibReference(nib);
+	    CFRetain(menu_);
+	}
+
+	// 鉛筆メニューのイベントハンドラをインストールする。
+	EventTypeSpec spec = { kEventClassCommand, kEventProcessCommand };
+	InstallEventHandler(GetMenuEventTarget(menu_), &SKKComponent::menuEventHandler, 1, &spec, 0, 0);
+    }
+
+    //  メッセージ受信機構を初期化
+    ClientMessageReceiver::start(kAquaSKKClientRunLoopMode);
+
+    //  AquaSKKServer の起動
+    ServerConnectionFactory::theInstance().prepareServer();
+}
+
+SKKComponent::~SKKComponent() {
+    std::for_each(sessions_.begin(), sessions_.end(), DeleteSession());
+
+    if(menu_) CFRelease(menu_);
+}
+
+SKKSession& SKKComponent::Session() {
+    return *active_;
+}
+
+// ======================================================================
+// Carbon コンポーネントインタフェース
+// ======================================================================
+ComponentResult SKKComponent::ComponentOpen(const ComponentInstance instance) {
+    // 設定をリロード
+    ClientConfiguration::theInstance().reloadConfiguration();
+
+    sessions_[instance] = new SKKSession(instance);
+
+    InitializeKeyboardLayout();
+
+    return noErr;
+}
+
+ComponentResult SKKComponent::ComponentClose(const ComponentInstance instance) {
+    delete sessions_[instance];
+    sessions_.erase(instance);
+
+    return noErr;
+}
+
+ComponentResult SKKComponent::ComponentCanDo(SInt16 selector) const {
+    switch(selector) {
+    case kComponentOpenSelect:
+    case kComponentCloseSelect:
+    case kComponentCanDoSelect:
+    case kComponentVersionSelect:
+    case kCMGetScriptLangSupport:
+    case kCMInitiateTextService:
+    case kCMTerminateTextService:
+    case kCMActivateTextService:
+    case kCMDeactivateTextService:
+    case kCMTextServiceEvent:
+    case kCMGetTextServiceMenu:
+    case kCMFixTextService:
+    case kCMHidePaletteWindows:
+    case kCMCopyTextServiceInputModeList:
+    case kCMSetTextServiceProperty:
+	return true;
+    }
+
+    return false;
+}
+
+ComponentResult SKKComponent::ComponentVersion() const {
+    return 0x00010000;
+}
+
+// ======================================================================
+// TSM コンポーネントインタフェース
+// ======================================================================
+ComponentResult SKKComponent::GetScriptLangSupport(ScriptLanguageSupportHandle* script) const {
+    if(!*script) {
+        *script = (ScriptLanguageSupportHandle)NewHandle(sizeof(SInt16));
+        if(!*script) return memFullErr;
+    } else {
+	SetHandleSize((Handle)*script, sizeof(SInt16));
+    }
+
+    OSStatus result = MemError();
+    if(result == noErr) {
+	(**script)->fScriptLanguageCount = 0;
+    }
+
+    ScriptLanguageRecord slr = { kTextEncodingUnicodeDefault, langJapanese };
+    result = PtrAndHand(&slr, (Handle)*script, sizeof(ScriptLanguageRecord));
+
+    if(result == noErr) {
+	(**script)->fScriptLanguageCount ++;
+    } else {
+	DisposeHandle((Handle)*script );
+	*script = 0;
+    }
+
+    return result;
+}
+
+ComponentResult SKKComponent::InitiateTextService(const ComponentInstance) {
+    return noErr;
+}
+
+ComponentResult SKKComponent::TerminateTextService(const ComponentInstance) {
+    return noErr;
+}
+
+ComponentResult SKKComponent::ActivateTextService(const ComponentInstance instance) {
+    active_ = sessions_[instance];
+
+    // 設定をリロード
+    ClientConfiguration::theInstance().reloadConfiguration();
+
+    // アクティブになった事をサーバーに伝える
+    ServerConnectionFactory::theInstance().newConnection().send(kBasicMessageActivated);
+
+    // キーボードレイアウトを初期化する
+    InitializeKeyboardLayout();
+
+    return noErr;
+}
+
+ComponentResult SKKComponent::DeactivateTextService(const ComponentInstance) {
+    return noErr;
+}
+
+ComponentResult SKKComponent::TextServiceEvent(const EventRef event) {
+    // キー入力処理
+    return active_->HandleInput(event);
+}
+
+ComponentResult SKKComponent::GetTextServiceMenu(MenuRef* menu) const {
+    *menu = menu_;
+
+    return noErr;
+}
+
+ComponentResult SKKComponent::FixTextService() {
+    active_->FixString(CFSTR(""));
+
+    return noErr;
+}
+
+ComponentResult SKKComponent::HidePaletteWindows() {
+    ServerConnectionFactory::theInstance().newConnection().send(kBasicMessageHidePalettes);
+
+    return noErr;
+}
+
+ComponentResult SKKComponent::CopyTextServiceInputModeList(CFDictionaryRef* modes) {
+    CFBundleRef bundle = CFBundleGetBundleWithIdentifier(CFSTR(kIMBundleIdentifier));
+    if(!bundle) {
+	return noErr;
+    }
+
+    CFDictionaryRef dict = CFBundleGetInfoDictionary(bundle);
+    if(!dict) {
+	return noErr;
+    }
+
+    CFRetain(dict);
+    CFDictionaryRef tmp = (CFDictionaryRef)CFDictionaryGetValue(dict, kComponentBundleInputModeDictKey);
+    if(tmp) {
+	*modes = CFDictionaryCreateCopy(kCFAllocatorDefault, tmp);
+    }
+    CFRelease(dict);
+
+    return noErr;
+}
+
+ComponentResult SKKComponent::SetTextServiceProperty(TextServicePropertyTag tag, TextServicePropertyValue value) {
+    if(tag != kTextServiceInputModePropertyTag) {
+	return tsmComponentPropertyUnsupportedErr;
+    }
+
+    static const struct {
+	SKK::InputMode skk;
+	CFStringRef tsm;
+    } modes[] = {
+	{ SKK::Hirakana, kTextServiceInputModeJapanese },
+	{ SKK::Katakana, kTextServiceInputModeJapaneseKatakana },
+	{ SKK::Jisx0201Kana, kTextServiceInputModeJapaneseHalfWidthKana },
+	{ SKK::Jisx0208Latin, kTextServiceInputModeJapaneseFullWidthRoman },
+	{ SKK::Ascii, kTextServiceInputModeRoman },
+	{ SKK::Hirakana, 0 }
+    };
+
+    CFStringRef str = (CFStringRef)value;
+    for(int i = 0; modes[i].tsm != 0; ++ i) {
+	if(CFStringCompare(str, modes[i].tsm, 0) == 0) {
+	    active_->SelectInputMode(modes[i].skk);
+	    break;
+	}
+    }
+
+    return noErr;
+}
+
+// ======================================================================
+// ユーティリティ
+// ======================================================================
+void SKKComponent::NotifyInputMode(const CFStringRef mode) const {
+    ComponentDescription cd;
+
+    cd.componentType = kTextService;
+    cd.componentSubType = kKeyboardInputMethodClass;
+    cd.componentManufacturer = 'askk';
+    cd.componentFlags = 0;
+    cd.componentFlagsMask = 0;
+
+    // 鉛筆メニューの入力モードアイコンを変更する
+    TSMSelectInputMode(FindNextComponent(0, &cd), mode);
+}
+
+// ======================================================================
+// メニューイベントハンドラ
+// ======================================================================
+OSStatus SKKComponent::menuEventHandler(EventHandlerCallRef, EventRef event, void*) {
+    HICommand cmd;
+
+    OSStatus result = GetEventParameter(event, kEventParamDirectObject, typeHICommand, 0, sizeof(cmd), 0, &cmd);
+    if(result == noErr) {
+	switch(cmd.commandID) {
+	case kAboutCommand:
+	    ServerConnectionFactory::theInstance().newConnection().send(kSKKShowAboutBox);
+	    break;
+
+	case kPreferencesCommand:
+	    ServerConnectionFactory::theInstance().newConnection().send(kSKKShowPreferencesBox);
+	    break;
+
+	case kProjectWebCommand:
+	    OpenURL(project_web_url);
+	    break;
+
+	case kTipsCommand:
+	    OpenURL(tips_url);
+	    break;
+
+	default:
+	    std::cerr << "unknown menu event[" << cmd.commandID << "], "
+		      << "index[" << cmd.menu.menuItemIndex << "]" << std::endl;
+	    result = eventNotHandledErr;
+	    break;
+        }
+    } else {
+	result = eventNotHandledErr;
+    }
+
+    return result;
+}
Index: AquaSKK/src/component/SKKComponent.h
diff -u /dev/null AquaSKK/src/component/SKKComponent.h:1.1.2.1
--- /dev/null	Sun Aug 19 19:00:32 2007
+++ AquaSKK/src/component/SKKComponent.h	Sun Aug 19 19:00:32 2007
@@ -0,0 +1,71 @@
+/* -*- C++ -*-
+   $Id: SKKComponent.h,v 1.1.2.1 2007/08/19 10:00:32 t-suwa Exp $
+
+   MacOS X implementation of the SKK input method.
+
+   Copyright (C) 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
+   the Free Software Foundation; either version 2 of the License, or
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef INC__SKKComponent__
+#define INC__SKKComponent__
+
+#include <Carbon/Carbon.h>
+#include <map>
+#include "SKK.h"
+
+class SKKSession;
+
+// TSM コンポーネント
+class SKKComponent {
+    std::map<ComponentInstance, SKKSession*> sessions_;
+    SKKSession* active_;
+    MenuRef menu_;
+
+    SKKComponent();
+    static OSStatus menuEventHandler(EventHandlerCallRef chain, EventRef event, void* data);
+
+public:
+    static SKKComponent& theInstance();
+    ~SKKComponent();
+
+    // アクティブなセッション
+    SKKSession& Session();
+
+    // Carbon コンポーネントインタフェース
+    ComponentResult ComponentOpen(const ComponentInstance instance);
+    ComponentResult ComponentClose(const ComponentInstance instance);
+    ComponentResult ComponentCanDo(SInt16 selector) const;
+    ComponentResult ComponentVersion() const;
+
+    // TSM コンポーネントインタフェース
+    ComponentResult GetScriptLangSupport(ScriptLanguageSupportHandle* script) const;
+    ComponentResult InitiateTextService(const ComponentInstance instance);
+    ComponentResult TerminateTextService(const ComponentInstance instance);
+    ComponentResult ActivateTextService(const ComponentInstance instance);
+    ComponentResult DeactivateTextService(const ComponentInstance instance);
+    ComponentResult TextServiceEvent(const EventRef event);
+    ComponentResult GetTextServiceMenu(MenuRef* menu) const;
+    ComponentResult FixTextService();
+    ComponentResult HidePaletteWindows();
+    ComponentResult CopyTextServiceInputModeList(CFDictionaryRef* modes);
+    ComponentResult SetTextServiceProperty(TextServicePropertyTag tag, TextServicePropertyValue value);
+
+    // ユーティリティ
+    void NotifyInputMode(const CFStringRef mode) const;
+};
+
+#endif
Index: AquaSKK/src/component/SKKEntryPoint.cpp
diff -u /dev/null AquaSKK/src/component/SKKEntryPoint.cpp:1.1.2.1
--- /dev/null	Sun Aug 19 19:00:32 2007
+++ AquaSKK/src/component/SKKEntryPoint.cpp	Sun Aug 19 19:00:32 2007
@@ -0,0 +1,215 @@
+/*
+  $Id: SKKEntryPoint.cpp,v 1.1.2.1 2007/08/19 10:00:32 t-suwa Exp $
+
+  MacOS X implementation of the SKK input method.
+
+  Copyright (C) 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
+  the Free Software Foundation; either version 2 of the License, or
+  any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <Carbon/Carbon.h>
+#include "SKKComponent.h"
+
+// ======================================================================
+// コンポーネント関数起動ヘルパ
+// ======================================================================
+class Invoke {
+    ComponentFunctionUPP function_;
+
+public:
+    Invoke(ProcPtr proc, ProcInfoType info) {
+	function_ = NewComponentFunctionUPP(proc, info);
+    }
+
+    ~Invoke() {
+	DisposeComponentFunctionUPP(function_);
+    }
+
+    ComponentResult operator()(ComponentParameters* params) {
+	return CallComponentFunction(params, function_);
+    }
+};
+
+// ======================================================================
+// コンポーネント関数群
+// ======================================================================
+pascal ComponentResult ComponentOpen_(ComponentInstance instance) {
+    return SKKComponent::theInstance().ComponentOpen(instance);
+}
+
+pascal ComponentResult ComponentClose_(ComponentInstance instance) {
+    return SKKComponent::theInstance().ComponentClose(instance);
+}
+
+pascal ComponentResult ComponentCanDo_(SInt16 selector) {
+    return SKKComponent::theInstance().ComponentCanDo(selector);
+}
+
+pascal ComponentResult ComponentVersion_() {
+    return SKKComponent::theInstance().ComponentVersion();
+}
+
+pascal ComponentResult GetScriptLangSupport_(ScriptLanguageSupportHandle* ptr) {
+    return SKKComponent::theInstance().GetScriptLangSupport(ptr);
+}
+
+pascal ComponentResult InitiateTextService_(const ComponentInstance instance) {
+    return SKKComponent::theInstance().InitiateTextService(instance);
+}
+
+pascal ComponentResult TerminateTextService_(const ComponentInstance instance) {
+    return SKKComponent::theInstance().TerminateTextService(instance);
+}
+
+pascal ComponentResult ActivateTextService_(const ComponentInstance instance) {
+    return SKKComponent::theInstance().ActivateTextService(instance);
+}
+
+pascal ComponentResult DeactivateTextService_(const ComponentInstance instance) {
+    return SKKComponent::theInstance().DeactivateTextService(instance);
+}
+
+pascal ComponentResult TextServiceEvent_(const EventRef event) {
+    return SKKComponent::theInstance().TextServiceEvent(event);
+}
+
+pascal ComponentResult GetTextServiceMenu_(MenuRef* menu_ptr) {
+    return SKKComponent::theInstance().GetTextServiceMenu(menu_ptr);
+}
+
+pascal ComponentResult FixTextService_() {
+    return SKKComponent::theInstance().FixTextService();
+}
+
+pascal ComponentResult HidePaletteWindows_() {
+    return SKKComponent::theInstance().HidePaletteWindows();
+}
+
+pascal ComponentResult CopyTextServiceInputModeList_(CFDictionaryRef* mode) {
+    return SKKComponent::theInstance().CopyTextServiceInputModeList(mode);
+}
+
+pascal ComponentResult SetTextServiceProperty_(TextServicePropertyTag tag, TextServicePropertyValue value) {
+    return SKKComponent::theInstance().SetTextServiceProperty(tag, value);
+}
+
+// ======================================================================
+// コンポーネント関数情報群、または黒魔術 ;-)
+// ======================================================================
+enum {
+    uppComponentOpen = kPascalStackBased
+    | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult)))
+    | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(ComponentInstance))),
+
+    uppComponentClose = kPascalStackBased
+    | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult)))
+    | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(ComponentInstance))),
+
+    uppComponentCanDo = kPascalStackBased
+    | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult)))
+    | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(SInt16))),
+
+    uppComponentVersion = kPascalStackBased
+    | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult))),
+
+    uppGetScriptLangSupport = kPascalStackBased
+    | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult)))
+    | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(ScriptLanguageSupportHandle*))),
+
+    uppInitiateTextService = kPascalStackBased
+    | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult)))
+    | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(ComponentInstance))),
+
+    uppTerminateTextService = kPascalStackBased
+    | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult)))
+    | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(ComponentInstance))),
+
+    uppActivateTextService = kPascalStackBased
+    | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult)))
+    | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(ComponentInstance))),
+
+    uppDeactivateTextService = kPascalStackBased
+    | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult)))
+    | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(ComponentInstance))),
+
+    uppTextServiceEvent = kPascalStackBased
+    | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult)))
+    | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(EventRef))),
+
+    uppGetTextServiceMenu = kPascalStackBased
+    | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult)))
+    | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(MenuRef*))),
+
+    uppFixTextService = kPascalStackBased
+    | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult))),
+
+    uppHidePaletteWindows = kPascalStackBased
+    | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult))),
+
+    uppCopyTextServiceInputModeList = kPascalStackBased
+    | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult)))
+    | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(CFDictionaryRef*))),
+
+    uppSetTextServiceProperty = kPascalStackBased
+    | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult)))
+    | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(TextServicePropertyTag)))
+    | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(TextServicePropertyValue)))
+};
+
+// ======================================================================
+// コールバック用構造体
+// ======================================================================
+struct callback {
+    int selector;
+    ProcPtr addr;
+    ProcInfoType info;
+};
+
+// ======================================================================
+// コールバックテーブル
+// ======================================================================
+static callback table[] = {
+    { kComponentOpenSelect,		(ProcPtr)ComponentOpen_,		uppComponentOpen },
+    { kComponentCloseSelect,		(ProcPtr)ComponentClose_,		uppComponentClose },
+    { kComponentCanDoSelect,		(ProcPtr)ComponentCanDo_,		uppComponentCanDo },
+    { kComponentVersionSelect,		(ProcPtr)ComponentVersion_,		uppComponentVersion },
+    { kCMGetScriptLangSupport,		(ProcPtr)GetScriptLangSupport_,		uppGetScriptLangSupport },
+    { kCMInitiateTextService,		(ProcPtr)InitiateTextService_,		uppInitiateTextService },
+    { kCMTerminateTextService,		(ProcPtr)TerminateTextService_,		uppTerminateTextService },
+    { kCMActivateTextService,		(ProcPtr)ActivateTextService_,		uppActivateTextService },
+    { kCMDeactivateTextService,		(ProcPtr)DeactivateTextService_,	uppDeactivateTextService },
+    { kCMTextServiceEvent,		(ProcPtr)TextServiceEvent_,		uppTextServiceEvent },
+    { kCMGetTextServiceMenu,		(ProcPtr)GetTextServiceMenu_,		uppGetTextServiceMenu },
+    { kCMFixTextService,		(ProcPtr)FixTextService_,		uppFixTextService },
+    { kCMHidePaletteWindows,		(ProcPtr)HidePaletteWindows_,		uppHidePaletteWindows },
+    { kCMCopyTextServiceInputModeList,	(ProcPtr)CopyTextServiceInputModeList_,	uppCopyTextServiceInputModeList },
+    { kCMSetTextServiceProperty,	(ProcPtr)SetTextServiceProperty_,	uppSetTextServiceProperty },
+    { 0, 				0, 					0 }
+};
+
+// ======================================================================
+// エントリポイント
+// ======================================================================
+extern "C"
+pascal ComponentResult SKKEntryPoint(ComponentParameters* params, Handle) {
+    for(callback* func = table; func->addr != 0; ++ func) {
+	if(params->what == func->selector) {
+	    return Invoke(func->addr, func->info)(params);
+	}
+    }
+
+    return badComponentSelector;
+}
Index: AquaSKK/src/component/SKKSession.cpp
diff -u /dev/null AquaSKK/src/component/SKKSession.cpp:1.1.2.1
--- /dev/null	Sun Aug 19 19:00:32 2007
+++ AquaSKK/src/component/SKKSession.cpp	Sun Aug 19 19:00:32 2007
@@ -0,0 +1,420 @@
+/* -*- C++ -*-
+   $Id: SKKSession.cpp,v 1.1.2.1 2007/08/19 10:00:32 t-suwa Exp $
+
+   MacOS X implementation of the SKK input method.
+
+   Copyright (C) 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
+   the Free Software Foundation; either version 2 of the License, or
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "ClientConfiguration.h"
+
+#include "BIM.h"
+#include "SKKComponent.h"
+#include "SKKSession.h"
+#include "SKKConfig.h"
+
+SKKSession::SKKSession(const ComponentInstance instance) : instance_(instance) {
+}
+
+// イベント
+bool SKKSession::HandleInput(const EventRef event) {
+    // レガシーエンジン
+    SKKEvent legacy_event(event);
+
+    // 処理すべきイベントではない?
+    if(!legacy_event) {
+	return false;
+    }
+
+    // 処理すべきキーではない?
+    if(legacy_event.Modifier() & cmdKey) {
+	return false;
+    }
+
+    // 処理すべきキーではない?
+    if((legacy_event.Modifier() & controlKey) && !SKKConfig::IsMappedKey(legacy_event)) {
+	return false;
+    }
+
+    bool handled = legacyInput(legacy_event);
+
+    //バッファの値が0なら強制的にフローティングウィンドウを閉じる
+    if(bufsize_.curr == 0) {
+        hideFloatingWindow();
+    }
+
+    return handled;
+}
+
+// 入力モード変更
+void SKKSession::SelectInputMode(SKK::InputMode mode) {
+    // 入力モードを変更する
+    switch(mode) {
+    case SKK::Hirakana:
+	if(!legacy_.isHiraganaInputMode()) {
+	    legacy_.goHiraganaInputMode();
+	}
+	break;
+
+    case SKK::Katakana:
+	if(!legacy_.isZenKataInputMode()) {
+	    legacy_.goZenKataInputMode();
+	}
+	break;
+
+    case SKK::Jisx0201Kana:
+	if(!legacy_.isHanKataInputMode()) {
+	    legacy_.goHanKataInputMode();
+	}
+	break;
+
+    case SKK::Jisx0208Latin:
+	if(!legacy_.isZenAscInputMode()) {
+	    legacy_.goZenAscInputMode();
+	}
+	break;
+
+    case SKK::Ascii:
+	if(!legacy_.isHanAscInputMode()) {
+	    legacy_.goHanAscInputMode();
+	}
+	break;
+    }
+}
+
+Point SKKSession::GetInputPosition(long offset) const {
+    EventRef event = 0;
+
+    // イベントを作成する
+    OSStatus status = CreateEvent(0, kEventClassTextInput, kEventTextInputOffsetToPos, 0,
+				  kEventAttributeUserEvent, &event);
+
+    // コンポーネントインスタンス
+    if(status == noErr) {
+        status = SetEventParameter(event, kEventParamTextInputSendComponentInstance, typeComponentInstance,
+				   sizeof(ComponentInstance), &instance_);
+    }
+
+    // リファレンスカウンタ
+    if(status == noErr) {
+	long refcon = 1;
+        status = SetEventParameter(event, kEventParamTextInputSendRefCon, typeLongInteger,
+				   sizeof(long), &refcon);
+    }
+
+    // テキスト位置
+    if(status == noErr) {
+        status = SetEventParameter(event, kEventParamTextInputSendTextOffset, typeLongInteger,
+				   sizeof(long), &offset);
+    }
+
+    // 送信
+    if(status == noErr) {
+        status = SendTextInputEvent(event);
+    }
+
+    // 位置の QD グローバル座標を取得
+    Point pt;
+    if(status == noErr) {
+        status = GetEventParameter(event, kEventParamTextInputReplyPoint, typeQDPoint, 0,
+				   sizeof(Point), 0, &pt);
+    }
+
+    if(event) {
+        ReleaseEvent(event);
+    }
+
+    // 座標の調整
+    CGRect mainscreen = CGDisplayBounds(CGMainDisplayID());
+    pt.v = mainscreen.size.height - pt.v;
+
+    return pt;
+}
+
+void SKKSession::DisplayString(const CFStringRef str, int fixlen, int caretpos) {
+    updateActiveInputArea(str, sizeof(UniChar) * fixlen, sizeof(UniChar) * caretpos);
+}
+
+void SKKSession::FixString(const CFStringRef str) {
+    long fixlen = CFStringGetLength(str);
+
+    updateActiveInputArea(str, sizeof(UniChar) * fixlen, sizeof(UniChar) * fixlen);
+
+    bufsize_.curr = bufsize_.prev = 0;
+}
+
+void SKKSession::Terminate() {
+    bufsize_.curr = bufsize_.prev = 0;
+}
+
+IMSessionInputMode& SKKSession::LegacyEngine() {
+    return legacy_;
+}
+
+// ======================================================================
+// private method
+// ======================================================================
+
+void SKKSession::updateActiveInputArea(const CFStringRef str, int UniChar_fixlen, int UniChar_caretpos) {
+    EventRef event = 0;
+
+    bufsize_.curr = CFStringGetLength(str);
+
+    // イベントを作成
+    OSErr error = CreateEvent(0, kEventClassTextInput, kEventTextInputUpdateActiveInputArea, 0,
+			      kEventAttributeUserEvent, &event);
+
+    // コンポーネントインスタンス
+    if(error == noErr) {
+        error = SetEventParameter(event, kEventParamTextInputSendComponentInstance, typeComponentInstance,
+				  sizeof(ComponentInstance), &instance_);
+    }
+
+
+    // リファンレンスカウンタ
+    if(error == noErr) {
+	long refcon = 1;
+        error = SetEventParameter(event, kEventParamTextInputSendRefCon, typeLongInteger,
+				  sizeof(long), &refcon);
+    }
+
+    // 二つ目のパラメタは言語情報
+    if(error == noErr) {
+	ScriptLanguageRecord scriptLanguageRecord;
+        scriptLanguageRecord.fScript = smJapanese;
+        scriptLanguageRecord.fLanguage = langJapanese;
+
+        error = SetEventParameter(event, kEventParamTextInputSendSLRec, typeIntlWritingCode,
+				  sizeof(ScriptLanguageRecord), &scriptLanguageRecord);
+    }
+
+    // 確定する文字数の設定
+    if(error == noErr) {
+        error = SetEventParameter(event, kEventParamTextInputSendFixLen, typeLongInteger,
+				  sizeof(long), &UniChar_fixlen);
+    }
+
+
+    // 更新する内容(UCS-32の配列)
+    if(error == noErr) {
+	UniChar* buf = new UniChar[bufsize_.curr];
+
+	CFStringGetCharacters(str, CFRangeMake(0, bufsize_.curr), buf);
+
+	error = SetEventParameter(event, kEventParamTextInputSendText, typeUnicodeText,
+				  sizeof(UniChar) * bufsize_.curr, buf);
+
+	delete[] buf;
+    }
+
+    // テキストが変更されていなければ空の更新領域を渡す。さもなくば全ての領域を更新させる。
+    if(error == noErr) {
+	TextRangeArray* update = (TextRangeArrayPtr)NewPtrClear(sizeof(short) + sizeof(TextRange) * 2);
+
+	update->fNumOfRanges = 2;
+
+	// 前回のバッファ
+	update->fRange[0].fStart = 0;
+	update->fRange[0].fEnd = bufsize_.prev;
+	update->fRange[0].fHiliteStyle = 0;
+
+	// 今回のバッファ
+	update->fRange[1].fStart = 0;
+	update->fRange[1].fEnd = sizeof(UniChar) * bufsize_.curr - UniChar_fixlen;
+	update->fRange[1].fHiliteStyle = 0;
+
+	// バッファサイズをバックアップ
+	bufsize_.prev = update->fRange[1].fEnd;
+
+	if(error == noErr) {
+	    error = SetEventParameter(event, kEventParamTextInputSendUpdateRng, typeTextRangeArray,
+				      sizeof(short) + sizeof(TextRange) * 2, update);
+	}
+
+	DisposePtr((Ptr)update);
+    }
+
+    // ハイライトの範囲とキャレットの位置
+    if(error == noErr) {
+	TextRangeArray* highlight = 0;
+
+	if(UniChar_fixlen == 0) {
+	    highlight = (TextRangeArrayPtr)NewPtrClear(sizeof(short) + sizeof(TextRange) * 2);
+
+	    highlight->fNumOfRanges = 2;
+
+	    highlight->fRange[0].fStart = 0;
+	    highlight->fRange[0].fEnd = sizeof(UniChar) * bufsize_.curr - UniChar_fixlen;
+	    highlight->fRange[1].fStart = UniChar_caretpos;
+	    highlight->fRange[1].fEnd = UniChar_caretpos;
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
+	    highlight->fRange[0].fHiliteStyle = kTSMHiliteRawText;
+	    highlight->fRange[1].fHiliteStyle = kTSMHiliteCaretPosition;
+#else
+	    highlight->fRange[0].fHiliteStyle = kRawText;
+	    highlight->fRange[1].fHiliteStyle = kCaretPosition;
+#endif
+
+	    error = SetEventParameter(event, kEventParamTextInputSendHiliteRng, typeTextRangeArray,
+				      sizeof(short) + sizeof(TextRange) * 2, highlight);
+	} else {
+	    highlight = (TextRangeArrayPtr)NewPtrClear(sizeof(short) + sizeof(TextRange) * 1);
+
+	    highlight->fNumOfRanges = 1;
+
+	    highlight->fRange[0].fStart = UniChar_caretpos;
+	    highlight->fRange[0].fEnd = UniChar_caretpos;
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
+	    highlight->fRange[0].fHiliteStyle = kTSMHiliteCaretPosition;
+#else
+	    highlight->fRange[0].fHiliteStyle = kCaretPosition;
+#endif
+
+	    error = SetEventParameter(event, kEventParamTextInputSendHiliteRng, typeTextRangeArray,
+				      sizeof(short) + sizeof(TextRange) * 1, highlight);
+	}
+
+	DisposePtr((Ptr)highlight);
+    }
+
+    // 全体の幅
+    if(error == noErr) {
+	TextRange range;
+
+	range.fStart = 0;
+	range.fEnd = sizeof(UniChar) * bufsize_.curr - UniChar_fixlen;
+
+        error = SetEventParameter(event, kEventParamTextInputSendPinRng, typeTextRange,
+				  sizeof(TextRange), &range);
+    }
+
+    // 送信
+    if(error == noErr) {
+        error = SendTextInputEvent(event);
+	ReleaseEvent(event);
+    }
+}
+
+// 文字の入力に対しての処理。
+bool SKKSession::legacyInput(const SKKEvent& event) {
+    switch(event.KeyCode()) {
+    case 0x41:			// .
+    case 0x43:			// *
+    case 0x45:			// +
+    case 0x4b:			// /
+    case 0x4e:			// -
+    case 0x51:			// =
+    case 0x52:			// 0
+    case 0x53:			// 1
+    case 0x54:			// 2
+    case 0x55:			// 3
+    case 0x56:			// 4
+    case 0x57:			// 5
+    case 0x58:			// 6
+    case 0x59:			// 7
+    case 0x5b:			// 8
+    case 0x5c:			// 9
+    case 0x5f:			// ,
+	if(ClientConfiguration::theInstance().isNumericKeypad_HalfWidth()) {
+	    return legacy_.handleNumKey(event.CharCode());
+	} else {
+	    return legacy_.handleInput(event);
+	}
+	break;
+
+    case 0x66:			// 英数
+	if(SKKConfig::UseEisuuToSetHenkanPoint()) {
+	    return legacy_.handleInput(SKKConfig::SetHenkanPointKey());
+	} else {
+	    return true;
+	}
+	break;
+
+    case 0x68:			// かな
+	if(SKKConfig::UseKanaToSetHenkanPoint()) {
+	    return legacy_.handleInput(SKKConfig::SetHenkanPointKey());
+	} else {
+	    return legacy_.handleInput(SKKConfig::KanaModeKey());
+	}
+    }
+
+    switch(event.CharCode()) {
+    case kNullCharCode:
+	return true;
+
+    case kBackspaceCharCode:
+	return legacy_.handleBackSpace();
+
+    case kTabCharCode:
+	return legacy_.handleTab();
+
+    case kEnterCharCode:
+    case kReturnCharCode:
+	return legacy_.handleReturn();
+
+    case kLeftArrowCharCode:
+    case kRightArrowCharCode:
+    case kUpArrowCharCode:
+    case kDownArrowCharCode:
+	return legacy_.handleArrow(event);
+
+    default:
+	if(event == SKKConfig::CancelKey()) {
+	    return legacy_.handleCg();
+	}
+	if(event == SKKConfig::PasteKey()) {
+	    return legacy_.handleCy();
+	}
+	if((0x20 <= event && event <= 0x7e) || SKKConfig::IsMappedKey(event)) {
+	    return legacy_.handleInput(event);
+	}
+    }
+    
+    return false;
+}
+
+void SKKSession::hideFloatingWindow() const {
+    EventRef event = 0;
+
+    // kEventClassTextInput/kEventTextInputShowHideBottomWindowのCarbonイベントを作成
+    OSErr error = CreateEvent(0, kEventClassTextInput, kEventTextInputShowHideBottomWindow, 0,
+			kEventAttributeUserEvent, &event);
+
+    if(error == noErr) {
+        error = SetEventParameter(event, kEventParamTextInputSendComponentInstance, typeComponentInstance,
+				  sizeof(ComponentInstance), &instance_);
+    }
+
+    if(error == noErr) {
+	ScriptLanguageRecord slr = { smJapanese, langJapanese };
+        error = SetEventParameter(event, kEventParamTextInputSendSLRec, typeIntlWritingCode,
+				  sizeof(ScriptLanguageRecord), &slr);
+    }
+
+    if(error == noErr) {
+	Boolean showBottomWindow = false;
+        error = SetEventParameter(event, kEventParamTextInputSendShowHide, typeBoolean,
+				  sizeof(Boolean), &showBottomWindow);
+    }
+
+    if(error == noErr) {
+        error = SendTextInputEvent(event);
+	ReleaseEvent(event);
+    }
+}
Index: AquaSKK/src/component/SKKSession.h
diff -u /dev/null AquaSKK/src/component/SKKSession.h:1.1.2.1
--- /dev/null	Sun Aug 19 19:00:32 2007
+++ AquaSKK/src/component/SKKSession.h	Sun Aug 19 19:00:32 2007
@@ -0,0 +1,68 @@
+/* -*- C++ -*-
+   $Id: SKKSession.h,v 1.1.2.1 2007/08/19 10:00:32 t-suwa Exp $
+
+   MacOS X implementation of the SKK input method.
+
+   Copyright (C) 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
+   the Free Software Foundation; either version 2 of the License, or
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef INC__SKKSession__
+#define INC__SKKSession__
+
+#include <Carbon/Carbon.h>
+
+#include "SKK.h"
+#include "SKKEvent.h"
+#include "IMSessionInputMode.h"
+
+class SKKSession {
+    ComponentInstance instance_;
+    IMSessionInputMode legacy_;
+
+    struct buffer_size {
+	long prev;
+	long curr;
+	buffer_size() : prev(0), curr(0) {}
+    };
+
+    buffer_size bufsize_;
+
+    void updateActiveInputArea(const CFStringRef str, int fixlen, int caretpos);
+    bool legacyInput(const SKKEvent& event);
+    void hideFloatingWindow() const;
+
+public:
+    SKKSession(const ComponentInstance instance);
+
+    // イベントハンドリング
+    bool HandleInput(const EventRef event);
+
+    // 入力モード変更
+    void SelectInputMode(SKK::InputMode mode);
+
+    // 入力位置座標取得
+    Point GetInputPosition(long offset = 0) const;
+
+    // 表示更新
+    void DisplayString(const CFStringRef str, int fixlen, int caretpos = -1);
+    void FixString(const CFStringRef str);
+    void Terminate();
+
+    IMSessionInputMode& LegacyEngine();
+};
+
+#endif
Index: AquaSKK/src/component/WordRegisterMode.cpp
diff -u /dev/null AquaSKK/src/component/WordRegisterMode.cpp:1.1.2.1
--- /dev/null	Sun Aug 19 19:00:32 2007
+++ AquaSKK/src/component/WordRegisterMode.cpp	Sun Aug 19 19:00:32 2007
@@ -0,0 +1,236 @@
+/*
+  $Id: WordRegisterMode.cpp,v 1.1.2.1 2007/08/19 10:00:32 t-suwa Exp $
+
+  MacOS X implementation of the SKK input method.
+
+  Copyright (C) 2002 phonohawk
+  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
+  the Free Software Foundation; either version 2 of the License, or
+  any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "BIM.h"
+#include "CppCFData.h"
+#include "ParentInputMode.h"
+#include "IMSessionInputMode.h"
+#include "WordRegisterMode.h"
+
+#include "SKKComponent.h"
+#include "SKKSession.h"
+
+WordRegisterMode::WordRegisterMode(ChildInputMode& src, const CppCFString& word)
+    : ParentInputMode(), owner(&src), caret(0) {
+    // [“o˜^:word]
+    title.append('[').append(0x767b).append(0x9332).append(':').append(word).append(']');
+
+    imsession_input_mode = &SKKComponent::theInstance().Session().LegacyEngine();
+}
+
+bool WordRegisterMode::handleBackSpace() {
+    if(getReallyCurrentInputMode().handleBackSpace()) {
+	// really current input mode‚ªtrue‚ð•Ô‚µ‚½‚牽‚à‚¹‚¸‚Étrue‚ð•Ô‚·B
+	redisplay();
+	return true;
+    }
+
+    ChildInputMode& input_mode = getReallyCurrentInputMode();
+
+    if(!input_mode.handleBackSpace()) {
+	// ƒLƒƒƒŒƒbƒg‚̈ʒu‚æ‚è‘O‚É•¶Žš‚ª‚ ‚ê‚ΈꕶŽšíœB–³‚¯‚ê‚Ζ³Ž‹B
+	if(caret > 0) {
+	    buffer.eraseCharAt(caret-1);
+	    caret--;
+	}
+    }
+    //redisplay();
+    display(CppCFString());
+    return true; // ‚Ç‚¿‚ç‚É‚Å‚à–{•¶‚͏Á‚³‚¹‚È‚¢B
+}
+
+bool WordRegisterMode::handleReturn() {
+    ChildInputMode& input_mode = getReallyCurrentInputMode();
+	
+    if(!input_mode.handleReturn()) {
+	fix(input_mode.getStringToFix());
+
+	if(buffer.length() > 0) {
+	    (dynamic_cast<RegistrationStarter*>(owner))->wordRegistrationFinished(); // ’PŒê“o˜^I—¹B
+	} else {
+	    (dynamic_cast<RegistrationStarter*>(owner))->wordRegistrationCanceled(); // ’PŒê“o˜^’†’fB
+	}
+    }
+    return true;
+}
+
+bool WordRegisterMode::handleArrow(SKKChar skkchar) {
+    if(getReallyCurrentInputMode().handleArrow(skkchar)) {
+	return true;
+    }
+
+    switch(skkchar) {
+    case kLeftArrowCharCode:	// ¶
+	if(caret > 0) {
+	    -- caret;
+	}
+	break;
+    case kRightArrowCharCode:	// ‰E
+	if(caret < buffer.length()) {
+	    ++ caret;
+	}
+	break;
+    case kUpArrowCharCode:	// æ“ª
+	caret = 0;
+	break;
+    case kDownArrowCharCode:	// ––”ö
+	caret = buffer.length();
+	break;
+    }
+
+    display(CppCFString());
+
+    return true;
+}
+
+bool WordRegisterMode::handleCg() {
+    if(getReallyCurrentInputMode().handleCg()) {
+	// really current input mode‚ªtrue‚ð•Ô‚µ‚½‚牽‚à‚¹‚¸‚Étrue‚ð•Ô‚·B
+	redisplay();
+	return true;
+    }
+
+    getReallyCurrentInputMode().terminate();
+
+    // buffer‚ð‹ó‚É‚·‚éB
+    buffer.clear();
+    caret = 0;
+    (dynamic_cast<RegistrationStarter*>(owner))->wordRegistrationCanceled(); // ’PŒê“o˜^’†’fB
+    return true;
+}
+
+bool WordRegisterMode::handleCy() {
+    if(getReallyCurrentInputMode().handleCy()) {
+	// really current input mode‚ªtrue‚ð•Ô‚µ‚½‚牽‚à‚¹‚¸‚Étrue‚ð•Ô‚·B
+	return true;
+    }
+	
+    PasteboardRef pasteboard;
+
+    PasteboardCreate(kPasteboardClipboard, &pasteboard);
+    PasteboardSynchronize(pasteboard);
+
+    ItemCount items;
+    PasteboardGetItemCount(pasteboard, &items);
+    for(UInt32 pos = 0; pos < items; ++ pos) {
+	PasteboardItemID id;
+	// index ‚Í 1 based
+	if(PasteboardGetItemIdentifier(pasteboard, pos + 1, &id) < 0) continue;
+
+	CFDataRef data;
+	CppCFString str;
+	if(PasteboardCopyItemFlavorData(pasteboard, id, CFSTR("public.utf8-plain-text"), &data) == 0) {
+	    CFStringRef tmp = CFStringCreateWithBytes(NULL, CFDataGetBytePtr(data), CFDataGetLength(data),
+						      kCFStringEncodingUTF8, false);
+	    str = CppCFString(tmp);
+	    CFRelease(tmp);
+	} else {
+	    if(PasteboardCopyItemFlavorData(pasteboard, id, CFSTR("com.apple.traditional-mac-plain-text"), &data) < 0) {
+		continue;
+	    }
+	    CFStringRef tmp = CFStringCreateWithBytes(NULL, CFDataGetBytePtr(data), CFDataGetLength(data),
+						      CFStringGetSystemEncoding(), false);
+	    str = CppCFString(tmp);
+	    CFRelease(tmp);
+	}
+	CFRelease(data);
+
+	buffer.insert(caret, str);
+	caret += str.length();
+	display(CppCFString());
+
+	break;
+    }
+    CFRelease(pasteboard);
+
+    return true;
+}
+
+bool WordRegisterMode::handleTab() {
+    ParentInputMode::handleTab();
+    return true; // í‚ɐH‚¤B
+}
+
+bool WordRegisterMode::handleInput(SKKChar skkchar) {
+    ChildInputMode* input_mode;
+    if(is_kanji_mode) {
+	input_mode = &kanji_conversion_mode;
+    } else if(is_ascii_conv_mode) {
+	input_mode = &ascii_conversion_mode;
+    } else {
+	if(skkchar >= 'A' && skkchar <= 'Z' && skkchar != 'L' &&	//XXX
+	   !isHanAscInputMode() && !isZenAscInputMode()) {
+	    is_kanji_mode = true;
+	    input_mode = &kanji_conversion_mode;
+	} else {
+	    input_mode = current_input_mode;
+	}
+    }
+
+    bool do_fix = input_mode->handleInput(skkchar);
+    if(do_fix) {
+	fixUnlessIgnore(input_mode->getStringToFix());
+    }
+    displayUnlessIgnore(input_mode->getStringToDisplay());
+	
+    return true;
+}
+
+CppCFString WordRegisterMode::getContent() const {
+    return buffer;
+}
+
+void WordRegisterMode::redisplay() {
+    ChildInputMode& input_mode = getReallyCurrentInputMode();
+	
+    CppCFString str_to_display = input_mode.getStringToDisplay();
+    if(str_to_display.length() == 0 ||
+	(str_to_display.length() > 0 && str_to_display[0] != kIgnoreThis)) // kIgnoreThis‚È‚çXV‚µ‚È‚¢B
+    {
+	display(str_to_display);
+    }
+}
+
+void WordRegisterMode::fix(const CppCFString& str_to_fix) {
+    if(str_to_fix.length() > 0 && str_to_fix[0] == kIgnoreThis) return;
+
+    // ƒoƒbƒtƒ@‚̃LƒƒƒŒƒbƒg‚̈ʒu‚É‘}“ü‚·‚éB
+    buffer.insert(caret,str_to_fix);
+
+    // ƒLƒƒƒŒƒbƒg‚ð‘}“ü‚µ‚½•¶Žš”•ªA‰E‚Ɉړ®‚·‚éB
+    caret += str_to_fix.length();
+
+    imsession_input_mode->display(CppCFString(title).append('[')
+				  .append(buffer.substring(0, caret)).append(kCaret)
+				  .append(buffer.substring(caret)).append(']'));
+}
+
+void WordRegisterMode::display(const CppCFString& str_to_display) {
+    if(str_to_display.length() > 0 && str_to_display[0] == kIgnoreThis) return;
+		
+    // •\Ž¦—áF
+    // [‚¯*‚·][Á]
+    imsession_input_mode->display(CppCFString(title).append('[')
+				  .append(buffer.substring(0, caret)).append(str_to_display).append(kCaret)
+				  .append(buffer.substring(caret)).append(']'));
+}
Index: AquaSKK/src/component/WordRegisterMode.h
diff -u /dev/null AquaSKK/src/component/WordRegisterMode.h:1.1.2.1
--- /dev/null	Sun Aug 19 19:00:32 2007
+++ AquaSKK/src/component/WordRegisterMode.h	Sun Aug 19 19:00:32 2007
@@ -0,0 +1,61 @@
+/*
+  $Id: WordRegisterMode.h,v 1.1.2.1 2007/08/19 10:00:32 t-suwa Exp $
+
+  MacOS X implementation of the SKK input method.
+
+  Copyright (C) 2002 phonohawk
+  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
+  the Free Software Foundation; either version 2 of the License, or
+  any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef INC__WordRegisterMode__
+#define INC__WordRegisterMode__
+
+#include "ParentInputMode.h"
+
+class IMSessionInputMode;
+class ChildInputMode;
+class CppCFString;
+
+class WordRegisterMode: public ParentInputMode {
+protected:
+    class ChildInputMode* owner;
+    CppCFString title;
+    CppCFString buffer;
+    unsigned caret;
+
+    IMSessionInputMode* imsession_input_mode;
+
+public:
+    // title‚Ì—áFu‚É‚°*‚évAu‚Í‚°v“™
+    // owner‚ÍRegistrationStarter‚àŒp³‚µ‚Ä‚¢‚È‚¯‚ê‚΂Ȃç‚È‚¢B
+    WordRegisterMode(class ChildInputMode& owner, const CppCFString& word);
+    virtual ~WordRegisterMode() {}
+
+    virtual bool handleReturn();
+    virtual bool handleBackSpace();
+    virtual bool handleArrow(SKKChar skkchar);
+    virtual bool handleCg();
+    virtual bool handleCy();
+    virtual bool handleTab();
+    virtual bool handleInput(SKKChar skkchar);
+    virtual void fix(const CppCFString& str_to_fix);
+    virtual void display(const CppCFString& str_to_display);
+    virtual void redisplay();
+    virtual CppCFString getContent() const;
+};
+
+#endif	// INC__WordRegisterMode__


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