Palm用インラインPOBox

現在のところ、 公開している部分(マニュアル/掲示板)と 内部使用の部分(ソース)が 分離している。

■ TODO

公開している 要望掲示板および 要望番付をもとにしている。

■ 更新履歴

更新履歴

■ 辞書について

辞書の構造

“{コンテクスト\001}検索パタン{\002単語}\n” というエントリの集合を辞書とする。
例文辞書の場合はコンテクストを指定する。
POBox 検索パタンと単語が一致する場合(英語の場合など)は検索パタンは省略できる。

PDBのレコード番号で辞書を区別している。

1.1.4以降は このような構造 になっている。

辞書のバックアップ

PDBのバックアップビットをプレファレンスで設定可能としている。 バックアップビットを立てるとHotSyncでバックアップされる。

1.4.4以降で PBinlearnDBという学習専用辞書を用意した。 ( 記事)

データベース形式について

メモリ内のデータベースとPDB, PRCはほとんど同じ形をしている。 PRCを作るにははbuild-prcが使えるが PDBを作るにはword2pdbのように自力で作る。
PDB, PRC内のバックアップビットが立っているとHotSyncで自動的に バックアップされる。

■ 関連文書

DB関連マニュアル (PDF)

プログラム

#pragma pack(2)

#define SEARCHAGAIN	// 候補選択後、次候補を表示するかどうか
#define SHOWPATINWIN	// 入力パタンをもとFieldでなく候補枠に表示する

#if SDK_VERSION >= 35
#include 
#ifdef USEVFS
#include 
#endif
#else
#include 
#include "NewTypes.h"
#endif

#include 
#include 
#include 
#include 

#include "DropModule.h" // Drag&Dropモジュール対応のため

#include "pbinline.h"
#include "search.h"
#include "ctype.h" // ToUpper(), etc.
#include "dict.h"
#include "id.h"
#include "dispmode.h"

// #include "sony.h"
#include "SonyChars.h"

#ifdef WNN_PALM_OS
#include "libwnn.h"
#endif

Err PBInline(FieldPtr fld, EventPtr e);
Err PBEnable(PointType *start, PointType *end);
void GsiEnableHack(Boolean enable);
void GsiSetShiftStateHack(UInt16 lockstate, UInt16 tempshift);

static void OpenPBInline(Global *g);
static void ClosePBInline(Global *g);
static Boolean AppHandleEvent(Global *g,EventPtr e);
static void EraseCand(Global *g);
static Boolean AddCand(Global *g,unsigned char *cstr,int study);
static void SelCand(Global *g, int n);
static void SearchCand(Global *g, int kind);
static void InsertPat(Global *g);
static void InsertPatAndFix(Global *g);
static void InsertPatAndSearch(Global *g);
static void RegisterPhrase(Global *g, DmOpenRef dic, int n);
static int NextDictRecord(Global *g, int resid, int c);

//void OpenRomaTable(Global *g);
//void CloseRomaTable(Global *g);
//unsigned char *Roma2Kana(Global *g,unsigned char *s, int len);
int CurrentEnvironment();

static Boolean ASCIIStr(unsigned char *s);
static Boolean AlphaStr(unsigned char *s);

デバッグ用のソースとかは小さなフォントにしておこう。
static int HexChar(int n)
{
	return (n < 10 ? '0'+n : 'A'+(n-10));
}

void
DumpHex(int val, int x, int y)
{
	unsigned char buf[10];
	buf[0] = HexChar((val >> 12) & 0xf);
	buf[1] = HexChar((val >> 8) & 0xf);
	buf[2] = HexChar((val >> 4) & 0xf);
	buf[3] = HexChar(val & 0xf);
	WinDrawChars(buf,4,x,y);
}

VoidPtr GetObjPtr(Int id)
{
	VoidPtr p = NULL;
	FormPtr frm;
	UInt16 idx;
	if((frm = FrmGetActiveForm())){
		idx = FrmGetObjectIndex(frm, id);
		ErrFatalDisplayIf(idx==NULL,"GetObjPtr fail");
		p = FrmGetObjectPtr(frm, idx);
		ErrFatalDisplayIf(p==NULL,"Null Ptr");
	}
	return p;
}

Boolean BackupBit(DmOpenRef dic)
{
	LocalID id;
	UInt16 cardno;
	UInt16 attr;

	DmOpenDatabaseInfo(dic,&id,NULL,NULL,&cardno,NULL);
	DmDatabaseInfo(cardno,id,NULL,&attr,NULL,NULL,NULL,NULL,NULL,NULL,NULL,	NULL,NULL);
	return (attr & dmHdrAttrBackup ? true : false);
}

void SetBackupBit(DmOpenRef dic,int backup)
{
	LocalID id;
	UInt16 cardno;
	UInt16 attr;

	DmOpenDatabaseInfo(dic,&id,NULL,NULL,&cardno,NULL);
	DmDatabaseInfo(cardno,id,NULL,&attr,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
	attr = (backup ? (attr | dmHdrAttrBackup) : (attr & ~dmHdrAttrBackup));
	DmSetDatabaseInfo(cardno,id,NULL,&attr,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
}

Boolean Lock(void) // HackのLockをこころみ、成功すればtrueを返す
{
	Err err;
	UInt32 locked;
	err = FtrGet(CREATORID,FEATURE_LOCK,&locked);
	if(err) locked = 0;
	if(locked == 0){
		FtrSet(CREATORID,FEATURE_LOCK,1); // Lock
		return true;
	}
	return false;
}

void Unlock(void)
{
	FtrSet(CREATORID,FEATURE_LOCK,0); // UnLock
}

static void GetFeaturePref(int option, UInt32 *featurep, int defaultval)
//
//	Featureとしてセーブされたオプションを取得する。
//	設定されていない場合はデフォルト値を設定する。
//
{
	Err err;
        err = FtrGet(CREATORID,option,featurep);
	if(err){
		*featurep = (UInt32)defaultval;
		FtrSet(CREATORID,option,*featurep);
	}
}

#ifdef USEVFS
FileRef CheckVFSDict()
//
//	CLIEのメモリースティックのような外部ファイルシステムが
//	存在するか調べ、存在する場合はFileRefを返す
//
{
	Err err;
	UInt32 vfsMgrVersion;
	UInt32 volIterator;
	UInt16 volRefNum;
	FileRef fileRef;

	// VFS Managerが存在するかチェック
	err = FtrGet(sysFileCVFSMgr, vfsFtrIDVersion, &vfsMgrVersion);
	if(err) return NULL; // 外部メモリが存在しない

	// マウントされているボリュームを取得する。複数マウントされて
	// いる場合は最後のものを返す。
	volIterator = expIteratorStart;
	for(;;){
		err = VFSVolumeEnumerate(&volRefNum,&volIterator);
		if(err) return NULL;
		if(volIterator == expIteratorStop) break;
	}

	// POBox辞書をオープン
	err = VFSFileOpen(volRefNum,"/PALM/Programs/POBox/PBInlineDB.pdb",
		vfsModeRead,&fileRef);
	if(err) return NULL; // POBox辞書が存在しない

	return fileRef;
}
#endif

メインルーチン

Err PBInline(FieldPtr fld, EventPtr e)
//
//	sysTrapFldHandleEvent() の置き換え(Hack)関数
//
{
	EventType event;
	Global *g;
	UInt32 ftrvalue;
	UInt32 enable;
	UInt32 shift;
	UInt32 selection; // 選択領域 - 前に選択した領域が現在の選択領域と同じならばPOBox継続と思う
	FormPtr frm;
	FldHandleEventTrapFunc *trapfunc;
	UInt16 c;
	Err err;
	Boolean poboxinprogress;
	int i;
//	POBoxPref pref;
	UInt16 prefsize;

	UInt16 wb,we;
	UInt dbmode;

	MemHandle h;
	UChar *s;

	// 2000/11/11 04:47:17
	UInt alarmamp,sysamp,defamp;       // デフォルトの音量
	UInt pbalarmamp,pbsysamp,pbdefamp; // 音を消すためのもの

	if(e->eType == nilEvent) return 1; // 2001/7/23 Stowaway Keyboard対応?

	SndGetDefaultVolume(&alarmamp,&sysamp,&defamp);
	pbalarmamp = pbsysamp = pbdefamp = 0;

	// オリジナルのトラップを取得
	FtrGet(CREATORID,1000,&ftrvalue);
	trapfunc = (FldHandleEventTrapFunc*)ftrvalue;

	// POBoxを使用するモードかどうか調べる
	GetFeaturePref(FEATURE_ENABLE,&enable,false);

	// Command+Space, キーボード呼出文字などの場合トグルする
	if(e->eType == keyDownEvent && 
	   (e->data.keyDown.chr == 0xf2   || // Alt-X for Palm Portable Keyboard
	    e->data.keyDown.chr == 0x13ac || // Alt-X for Happy Hacking Keyboard
	    e->data.keyDown.chr == 0x00d7 || // Alt-X for GoType!
	    e->data.keyDown.chr == TOGGLECHR
		)){	
		// Palm Portable KBはCommand-なんとかとかControl-なんとかを出力しないので
		// 上記のような変なコードを割り当てている。
		if(!enable){
			// POBoxが動いていないときのシフトインジケータの状態を得て保存
			shift = (UInt32)GsiEnabled();
			FtrSet(CREATORID,FEATURE_SHIFT,shift);
		}
		enable = !enable;
		DisplayPOBoxMode((int)enable);
		FtrSet(CREATORID,FEATURE_ENABLE,enable);
		if(!enable){
			GsiEnable(shift ? true : false);
		}
		return 0;
	}

	// 上ドラッグ-下ドラッグ, 下ドラッグ-上ドラッグでon/offするように (2000/11/07 12:29:39)
	if(e->eType == keyDownEvent){
		if(e->data.keyDown.chr == nextFieldChr){
			enable = true;
			DisplayPOBoxMode(enable);
			FtrSet(CREATORID,FEATURE_ENABLE,enable);
			return 0;
		}
		else if(e->data.keyDown.chr == prevFieldChr){
			enable = false;
			DisplayPOBoxMode(enable);
			FtrSet(CREATORID,FEATURE_ENABLE,enable);
			FtrGet(CREATORID,FEATURE_SHIFT,&shift);
			GsiEnable(shift ? true : false);
			return 0;
		}
	}

	if(! enable){
		GsiEnable(true);
		return (*trapfunc)(fld,e);
	}
	GsiEnable(false);

	DisplayPOBoxMode(true); // 2001/7/23 StowawayキーボードのドライバがnilEventを吐くのに

	// キーダウンイベントのときだけPOBox起動
	if(e->eType != keyDownEvent){
		UInt32 selection = 0xffffffff;
		// POBox入力継続中止
		FtrSet(CREATORID,FEATURE_SELECTION,selection);
		// もともとのシステムコール呼出し
		return (*trapfunc)(fld,e);
	}
	//
	// Keyboard, Keyboard hackなどでもうまく動くようにする工夫。
	// POBox終了時の選択領域がPOBox開始時の選択領域と一致した場合は	
	// POBoxがまだ実行中だということで、空白文字や後退文字でも
	// POBox的処理を行なう。そうでない場合はアルファベットが入力
	// されたときだけPOBox枠を表示して変換を開始する。
	//
	poboxinprogress = false;
	FldGetSelection(fld,&wb,&we);
	err = FtrGet(CREATORID,FEATURE_SELECTION,&selection);
	if(!err){
		if(wb != we &&
		  (wb == (UInt16)((selection & 0xffff0000) >> 16)) &&
		  (we == (UInt16)(selection & 0xffff))){ // 前の選択と同じ
			poboxinprogress = true;
		}
	}
	if(! poboxinprogress){
		c = e->data.keyDown.chr;
		if(c < 0x20 || c >= 0x100 || (c == 0x20 && wb == we)){
			return (*trapfunc)(fld,e);
		}
	}

	if(! Lock()){ // 二重よびだし禁止
		return (*trapfunc)(fld,e);
	}

	DisplayPOBoxMode(true);

	if((frm = FrmGetActiveForm()) == NULL) return 0;
	if(FrmGetFocus(frm) == -1) return 0;

#ifdef WNN_PALM_OS
	if(wnn_palm_init()) return 0;
	if(wnn_dic_enable()){
		wnn_palm_term();
		return 0;
	}
#endif

	// グローバルデータ領域確保
	g = (Global*)MemPtrNew(sizeof(Global));
	ErrFatalDisplayIf(g==NULL,"Can't alloc global data");

	//
	// 「大域変数」をFeatureに格納しておく
	//
	FtrSet(CREATORID,FEATURE_GLOBAL,(UInt32)g);

	g->origform = frm;
	g->field = fld;	

	//
	// 空白文字を入力すると遅延変換
	//
	if(e->data.keyDown.chr != 0x20){
		g->useselection =  poboxinprogress;
		EvtAddEventToQueue(e); // Fieldに入力されたイベント(キー入力とか)がPOBox枠で処理されるようにする。
	}
	else {
		g->useselection = true;
	}

	/////////////////////////////////////////////////////////////////
	//                       辞書関連初期化                        //
	/////////////////////////////////////////////////////////////////

	//
	// (もしあれば)学習辞書データベースオープン 2000/11/11 21:49:39
	//
	g->ldic = DmOpenDatabaseByTypeCreator(LDICTYPE,CREATORID,dmModeReadWrite);

	// 辞書データベースオープン
	//
	// 学習辞書があるときは拡張辞書は読み出し専用にする。
	// (TRG Proのフラッシュに焼けるようになることを期待) 2001/1/15
	//
	// g->dicはNULLかもしれないので注意。(1.4.x以前ではg->dicは常にnon-NULL)
	//
	dbmode = (g->ldic ? dmModeReadOnly : dmModeReadWrite);
	g->dic = DmOpenDatabaseByTypeCreator(DICTYPE,CREATORID,dbmode);

#ifdef USEVFS
	// (もしあれば)外部メモリ辞書オープン 2001/5/20
	//
	g->vdic = CheckVFSDict();
#endif

	// 学習辞書と固定辞書(もしあれば)の存在チェック
	if(g->ldic){
#ifdef USEVFS
		ErrFatalDisplayIf(g->dic == NULL && g->vdic == NULL,
			"Learning dict with no static dictionary");
#else
		ErrFatalDisplayIf(g->dic == NULL,
			"Learning dict with no static dictionary");
#endif
	}
	else {
		ErrFatalDisplayIf(g->dic == NULL, "No learning dictionary");
	}

	//
	//	拡張辞書の数と先頭文字を調査
	//
#ifdef USEVFS
	if(g->vdic){
		//
		// VFS(メモリースティックなど)内部に固定辞書DBがある場合
		//
		Int32 pos;
		UInt8 c;
		UInt32 *offset,dummy;
		Boolean extraindexexists;
		UInt16 nrecords;

		// レコード数を取得
		VFSFileDBInfo(g->vdic,NULL,
			NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
			&nrecords);

		// 拡張辞書のインデクスが存在するか調べる
		err = VFSFileDBGetRecord(g->vdic,nrecords-1,&h,(UInt8*)NULL,(UInt32*)NULL);
		ErrFatalDisplayIf(err,"Can't get VFS handle");
		ErrFatalDisplayIf(h==NULL,"Can't open extra dictionary index");
		s = MemHandleLock(h);
		extraindexexists = (*s == '\0');
		if(extraindexexists){
			StrCopy(g->extra,s+1);
			g->nextra = StrLen(g->extra);
		}
		MemHandleUnlock(h);
		MemHandleFree(h);

		if(!extraindexexists){
			// VFSFileDBGetRecord()が遅いのでPDBファイルの内容を自力で読む。
			// PDBファイルヘッダは78バイトで、その後にポインタ等が
			// レコードの数だけ並んでいる。
			pos = 78 + (8 * 0xa00);
			VFSFileSeek(g->vdic,fsOriginBeginning,pos);
			g->nextra = nrecords - 0xa00;
			if(g->nextra > MAXEXTRA) g->nextra = MAXEXTRA;
			offset = MemPtrNew(sizeof(UInt32) * (nrecords - 0xa00));
			for(i=0;i< g->nextra; i++){
				VFSFileRead(g->vdic,4,&offset[i],NULL);
				VFSFileRead(g->vdic,4,&dummy,NULL);
			}
			for(i=0;i< g->nextra; i++){
				VFSFileSeek(g->vdic,fsOriginBeginning,offset[i]);
				VFSFileRead(g->vdic,1,&c,NULL);
				g->extra[i] = c;
			}
			MemPtrFree(offset);
		}
	/*
		// メモリ内データベースと同様のやり方を適用した場合。
		// 拡張辞書エントリをひとつずつ調べると非常に遅い!
		// VFSFileDBGetRecord()がいちいちメモリに展開するからと思われる
		for(i=0;i< g->nextra;i++){
			err = VFSFileDBGetRecord(g->vdic,0xa00+i,&h,(UInt8*)NULL,(UInt32*)NULL);
			ErrFatalDisplayIf(err,"Can't get VFS handle");
			ErrFatalDisplayIf(h==NULL,"Can't open extra dictionary area");
			s0 = MemHandleLock(h);
			g->extra[i] = *s0;
			MemHandleUnlock(h);
			MemHandleFree(h);
		}
	*/
	}
	else
#endif
	if(g->dic){
		g->nextra = DmNumRecords(g->dic) - 0xa00;
		if(g->nextra > MAXEXTRA) g->nextra = MAXEXTRA;
		for(i=0;i< g->nextra;i++){
			h = DmQueryRecord(g->dic,0xa00+i);
			ErrFatalDisplayIf(h==NULL,"Can't open extra dictionary area");
			s = MemHandleLock(h);
			g->extra[i] = *s;
			MemHandleUnlock(h);
		}
	}
	else { // NOTREACHED
		ErrFatalDisplayIf(true,"No dict");
	}

	// Formを呼びだせるようにするために共通データベースをオープン
	g->db = DmOpenDatabaseByTypeCreator(APPTYPE,CREATORID,
					    dmModeReadWrite);
	ErrFatalDisplayIf(g->db==NULL,"Can't open PBInline DB");

	//
	//	プレファレンス
	//
	prefsize = sizeof(POBoxPref);
	if(PrefGetAppPreferences(CREATORID,0,&(g->pref),&prefsize,true) == noPreferenceFound){
		g->pref.savedict = false;
		g->pref.dispbottom = false;
		g->pref.spacefortankanji = false;
		g->pref.righthanded = true;
		PrefSetAppPreferences(CREATORID,0,1,&(g->pref),sizeof(POBoxPref),true);
	}

	g->prevwascommandkey = false;
	g->prevwordlen = 0;
	g->exact = 0;

	g->searchlevel[0] = 0;

//	OpenRomaTable(g);
	g->rktable = InitRomaTable();

	OpenPBInline(g); // PBInline画面初期化

	SearchCand(g,NEWCAND); // 何故かこれが無いと動かない??
#ifdef XXXX
	g->patlen = 0;
	g->pat[g->patlen++] = (char)e->data.keyDown.chr;
	InsertPatAndSearch(g);
#endif



//GrfSetState(true,false,false);
	g->finish = false;

	/////////////////////////////////////////////////////////////////
	//                  PBInlineのイベント処理ループ               //
	/////////////////////////////////////////////////////////////////

	do {
		UInt16 error;

		// 2000/11/11 04:50:02
		// フォーム外をタップするとエラー音がするので
		// 一時的に音量をゼロにする
		SndSetDefaultVolume(&pbalarmamp,&pbsysamp,&pbdefamp);

		EvtGetEvent(&event, evtWaitForever);

		SndSetDefaultVolume(&alarmamp,&sysamp,&defamp);
//if(event.eType == nilEvent) continue;
		if(event.eType == penDownEvent &&
		  (event.screenY < 0 || 
		  (event.screenY > 20 && g->pbform->window.windowBounds.topLeft.y + event.screenY < 160))){
			MenuBarType *menu;
			menu = MenuGetActiveMenu();
			if(! (menu && menu->attr.visible)){ // メニューが出ているとき以外は枠外をタップされると終了する
				EventType evt;
				evt.eType = keyDownEvent;
				// \n, \r などによりPOBox枠の終了を指示する。
				// \r のときは選択領域を変化させない。(次回に継続)
				evt.data.keyDown.chr = '\n'; // 窓終了文字
				evt.data.keyDown.chr = '\r'; // 窓終了文字
				evt.data.keyDown.modifiers = 0;
				EvtAddEventToQueue(&evt);
				EvtAddEventToQueue(&event); // 本来のイベントを使う。(荒井氏による指摘)
			}
			continue;
		}
		if (AppHandleEvent(g,&event)) continue;
		if (SysHandleEvent(&event)) continue;
		if (MenuHandleEvent(NULL, &event, &error)) continue;
		FrmDispatchEvent(&event);
	}
	//
	// Applicationボタンを押した場合はすぐに別アプリに移るように
	// してみていたが、TODOなどではappStopEventの処理が足りないせいか
	// FatalErrorになってしまうので、POBox枠が出ているときは
	// 終了できないことにする。
	//
#ifndef FINISH_IF_APPBUTTON_IS_PRESSED
	while (! g->finish);
#else
	while (! g->finish && event.eType != appStopEvent);
	if(event.eType == appStopEvent){
		EvtAddEventToQueue(&event);
	}
#endif

//	CloseRomaTable(g);

	if(g->dic) DmCloseDatabase(g->dic);
	if(g->ldic) DmCloseDatabase(g->ldic);
#ifdef USEVFS
	if(g->vdic) VFSFileClose(g->vdic);
#endif
	DmCloseDatabase(g->db); /////

	Unlock();
	MemPtrFree(g->rktable);
	MemPtrFree(g);

//	DisplayPOBoxMode(true);
	FtrGet(CREATORID,FEATURE_ENABLE,&enable);
	if(enable){
		DisplayPOBoxMode(true);
	}
	else {
		DisplayPOBoxMode(false);
		FtrGet(CREATORID,FEATURE_SHIFT,&shift);
		GsiEnable(shift ? true : false);
	}

	//
	// 次回のPBInline()呼出しがこの呼出しに引き続くものかどうか
	// 判断できるようにするため、現在の領域選択状況をFeatureに記憶しておく。
	// この値が変化すればPOBox処理は継続でないと判断する。
	//
	FldGetSelection(fld,&wb,&we);
	selection = ((((UInt32)wb) << 16) & 0xffff0000) + ((UInt32)(we) & 0xffff);
	FtrSet(CREATORID,FEATURE_SELECTION,selection);

#ifdef WNN_PALM_OS
	wnn_dic_disable();
	wnn_palm_term();
#endif

	return 1;
}
/*
PBInline画面開始/終了
*/ static Boolean MainFormEvent(EventPtr e) // ダミー { return false; } static Boolean PrefFormEvent(EventPtr e) { Boolean handled = false; ControlPtr cp; UInt16 c; Global *g; Err err; err = FtrGet(CREATORID,FEATURE_GLOBAL,(UInt32*)(&g)); ErrFatalDisplayIf(err,"Can't get global value"); switch(e->eType){ case ctlSelectEvent: handled = true; c = e->data.ctlSelect.controlID; cp = e->data.ctlSelect.pControl; ErrNonFatalDisplayIf(cp==NULL,"Invalid CtrPtr"); switch(c){ case ID_CHECKBOX_BACKUP: g->tmppref.savedict = (CtlGetValue(cp) ? true : false); break; case ID_BUTTON_NEARCURSOR: g->tmppref.dispbottom = (CtlGetValue(cp) ? false : true); break; case ID_BUTTON_BOTTOM: g->tmppref.dispbottom = (CtlGetValue(cp) ? true : false); break; case ID_BUTTON_USESPACE: g->tmppref.spacefortankanji = (CtlGetValue(cp) ? true : false); break; case ID_BUTTON_USERETURN: g->tmppref.spacefortankanji = (CtlGetValue(cp) ? false : true); break; case ID_BUTTON_RIGHTHANDED: g->tmppref.righthanded = (CtlGetValue(cp) ? true : false); break; case ID_BUTTON_LEFTHANDED: g->tmppref.righthanded = (CtlGetValue(cp) ? false : true); break; default: handled = false; break; } default: break; } return handled; } static void OpenPBInline(Global *g) { short x,y,ny; UInt16 wb,we; int cb,ce; // begin/end of context UChar *fieldtext; UInt16 bytes; unsigned char c; Boolean capslock,numlock,autoshifted; UInt16 tmpshift; GrfGetState(&capslock,&numlock,&tmpshift,&autoshifted); DisplayPOBoxMode(true); g->pbform = FrmInitForm(ID_MAINFORM); ErrFatalDisplayIf(g->pbform==NULL,"Can't init Form"); // FrmSetEventHandler(g->pbform, MainFormEvent); // FrmSetActiveForm(g->pbform); g->patlen = 0; g->pat[g->patlen] = '\0'; // 現在のコンテクストを取得 fieldtext = FldGetTextPtr(g->field); if(fieldtext){ FldGetSelection(g->field,&wb,&we); if(wb==we) wb = we = FldGetInsPtPosition(g->field); if(g->useselection){ int i; g->patlen = we - wb; for(i=0;i<=g->patlen;i++){ g->searchlevel[i] = 0; } } else { g->patlen = 0; if(wb != we){ // 2000/11/11 04:43:00 // カット対象が無いときFldCutを呼ぶと // エラー音がするようなので FldCut(g->field); } g->useselection = true; } StrNCopy(g->pat,fieldtext+wb,g->patlen); g->pat[g->patlen] = '\0'; cb = ce = (int)wb; while(cb > 0 && fieldtext[cb-1]!='\n') cb--; while(ce > 0 && fieldtext[ce-1]==' ') ce--; while(ce-cb > 8){ cb += (fieldtext[cb] & 0x80 ? 2 : 1); } g->clen = ce - cb; StrNCopy(g->context,fieldtext+cb,g->clen); g->context[g->clen] = '\0'; for(;;){ c = fieldtext[cb]; bytes = ((c & 0x80) ? 2 : 1); if(cb + bytes >= ce) break; cb += bytes; } g->alphaend = ((c & 0x80) == 0 && IsAlpha(c) && cb < ce) ? true : false; if(g->prevwordlen == 0){ StrNCopy(g->prevword,g->context,g->clen); g->prevwordlen = g->clen; } } else { // Fieldが完全に空だとFldGetTextPtr()はNULLを返す g->clen = 0; } g->context[g->clen] = '\0'; // EraseCand(g); if(g->pref.dispbottom){ g->pbform->window.windowBounds.topLeft.y = 144; } else { InsPtGetLocation(&x,&y); ny = y + 13; if(ny + 14 >= 160) ny = y - 14; g->pbform->window.windowBounds.topLeft.y = ny; } FrmSetEventHandler(g->pbform, MainFormEvent); FrmSetActiveForm(g->pbform); EraseCand(g); FrmDrawForm(g->pbform); } static void ClosePBInline(Global *g) { Boolean capslock,numlock,autoshifted; UInt16 tmpshift; GrfGetState(&capslock,&numlock,&tmpshift,&autoshifted); FrmReturnToForm(NULL); // アプリケーション画面に復帰 // このときにGraffitiのシフト状態が初期化されてしまうようなので // 前のフォームでのの状態を回復するようにする。 GrfSetState(capslock,numlock,tmpshift); DisplayPOBoxMode(true); } static void regword(Global *g) { unsigned char buf[200]; MemHandle h; unsigned char *p; UInt16 length; FormPtr frm; int x,y; UInt16 id; DmOpenRef d; d = (g->ldic ? g->ldic : g->dic); h = ClipboardGetItem(clipboardText,&length); if(h == NULL || length > 30){ FrmAlert(ID_ALERT_REGWORD); return; } p = MemHandleLock(h); ErrFatalDisplayIf(p == NULL,"Null clipboard text"); frm = FrmInitForm(ID_REGWORDFORM); ErrFatalDisplayIf(frm==NULL,"Null frm"); FrmSetActiveForm(frm); FrmDrawForm(frm); x = 12; y = 33; WinDrawChars("\x81\x75",2,x,y); x += 10; WinDrawChars(p,length,x,y); x += FntCharsWidth(buf,length); WinDrawChars("\x81\x76",2,x,y); x += 10; WinDrawChars("\x81\x75",2,x,y); x += 10; WinDrawChars(g->pat,g->patlen,x,y); x += FntCharsWidth(g->pat,g->patlen); WinDrawChars("\x81\x76",2,x,y); id = FrmDoDialog(frm); if(id == ID_BUTTON_REGW_OK){ int ind; g->pat[g->patlen] = '\0'; StrToLower(buf,g->pat); // 2000/11/12 13:45:44 //StrNCopy(buf,g->pat,g->patlen); StrCopy(buf+g->patlen,"\002"); StrNCopy(buf+g->patlen+1,p,length); buf[g->patlen+1+length] = '\0'; ind = buf[0]; if(IsUpper(ind)) ind = ToLower(ind); AddDicEntry(d,ind,buf,true); FrmReturnToForm(NULL); // 最初のフォームに戻る ClosePBInline(g); OpenPBInline(g); SearchCand(g,NEWCAND); } else { FrmReturnToForm(NULL); // 最初のフォームに戻る } MemHandleUnlock(h); } static void delent(Global *g, unsigned char *ent) { register unsigned char *s,*p,*entry; MemHandle h; int ind; unsigned char *s0; DmOpenRef d,ds; d = (g->ldic ? g->ldic : g->dic); ds = d; ind = ent[0]; if(IsUpper(ind)) ind = ToLower(ind); while(ind){ h = DmQueryRecord(ds,ind); ErrFatalDisplayIf(h == NULL,"Null handle..."); s0 = MemHandleLock(h); ErrFatalDisplayIf(s0 == NULL,"Null dict entry"); s=s0; while(*s){ // if(StrCompare(s,buf)==0) break; p = ent; entry = s; for(;*s;s++,p++){ if(*s != *p) break; } if(*s == '\0' && *p == '\0'){ s = entry; break; } for(;*s;s++); s++; } MemHandleUnlock(h); if(*s){ DeleteDicEntry(d,ind,s-s0); } ind = NextDictRecord(g,ind,(int)ent[0]); ds = g->dic; } for(ind=0x900;ind<=0x9ff;ind++){ // 環境辞書 h = DmQueryRecord(d,ind); if(h && (s0 = MemHandleLock(h))){ s=s0; while(*s){ // if(StrCompare(s,buf)==0) break; p = ent; entry = s; for(;*s;s++,p++){ if(*s != *p) break; } if(*s == '\0' && *p == '\0'){ s = entry; break; } for(;*s;s++); s++; } MemHandleUnlock(h); if(*s){ DeleteDicEntry(d,ind,s-s0); } } } } static void delword(Global *g) // 2000/11/08 04:03:24 { // register unsigned char *s,*p,*entry; unsigned char buf[200]; unsigned char *pat,*word; int plen,wlen; FormPtr frm; int x,y; UInt16 id; int ind; if(g->ncands <= 0) return; ind = 0; if(g->candindex > 0) ind = g->candindex-1; pat = g->candspell[ind]; word = g->candstr[ind]; if(pat == NULL || *pat == '\0' || word == NULL || *word == '\0') return; plen = StrLen(pat); wlen = StrLen(word); frm = FrmInitForm(ID_DELWORDFORM); ErrFatalDisplayIf(frm==NULL,"Null frm"); FrmSetActiveForm(frm); FrmDrawForm(frm); x = 12; y = 33; WinDrawChars("\x81\x75",2,x,y); x += 10; WinDrawChars(pat,plen,x,y); x += FntCharsWidth(pat,plen); WinDrawChars("\x81\x76",2,x,y); x += 10; WinDrawChars("\x81\x75",2,x,y); x += 10; WinDrawChars(word,wlen,x,y); x += FntCharsWidth(word,wlen); WinDrawChars("\x81\x76",2,x,y); id = FrmDoDialog(frm); if(id == ID_BUTTON_DELW_OK){ StrCopy(buf,pat); StrCat(buf,"\002"); StrCat(buf,word); delent(g,buf); if(StrCompare(pat,word) == 0){ // ASCIIエントリの場合 StrCopy(buf,pat); delent(g,buf); } FrmReturnToForm(NULL); // 最初のフォームに戻る ClosePBInline(g); OpenPBInline(g); SearchCand(g,NEWCAND); } else { FrmReturnToForm(NULL); // 最初のフォームに戻る } } static void setpref(Global *g) { UInt16 id; ControlPtr cp; g->prefform = FrmInitForm(ID_PREFFORM); ErrFatalDisplayIf(g->prefform==0,"No prefform"); FrmSetActiveForm(g->prefform); FrmSetEventHandler(g->prefform,PrefFormEvent); g->tmppref = g->pref; g->tmppref.savedict = (g->dic ? BackupBit(g->dic) : false); cp = GetObjPtr(ID_CHECKBOX_BACKUP); CtlSetValue(cp,g->tmppref.savedict ? 1 : 0); cp = GetObjPtr(ID_BUTTON_BOTTOM); CtlSetValue(cp,g->tmppref.dispbottom ? 1 : 0); cp = GetObjPtr(ID_BUTTON_NEARCURSOR); CtlSetValue(cp,g->tmppref.dispbottom ? 0 : 1); cp = GetObjPtr(ID_BUTTON_USESPACE); CtlSetValue(cp,g->tmppref.spacefortankanji ? 1 : 0); cp = GetObjPtr(ID_BUTTON_USERETURN); CtlSetValue(cp,g->tmppref.spacefortankanji ? 0 : 1); cp = GetObjPtr(ID_BUTTON_RIGHTHANDED); CtlSetValue(cp,g->tmppref.righthanded ? 1 : 0); cp = GetObjPtr(ID_BUTTON_LEFTHANDED); CtlSetValue(cp,g->tmppref.righthanded ? 0 : 1); FrmDrawForm(g->prefform); id = FrmDoDialog(g->prefform); FrmReturnToForm(NULL); if(id == ID_BUTTON_PREF_OK){ g->pref = g->tmppref; PrefSetAppPreferences(CREATORID,0,1,&(g->pref),sizeof(POBoxPref),true); if(g->dic) SetBackupBit(g->dic,g->tmppref.savedict); } } /*
PBInlineのイベント処理

*/ static Boolean AppHandleEvent(Global *g,EventPtr e) { Boolean handled = true; UInt16 c; UInt16 w1,w2; unsigned char cc; ControlPtr cp; UInt16 idx; UInt32 enable; switch(e->eType){ // case nilEvent: // // 2001/6/2 // // nilEventが来たとき何故か再描画しないと表示されない。要調査。 // SearchCand(g,NEWCAND); // break; case nilEvent: break; case ctlSelectEvent: c = e->data.ctlSelect.controlID; switch(c){ case ID_BUTTON1: case ID_BUTTON2: case ID_BUTTON3: case ID_BUTTON4: case ID_BUTTON5: case ID_BUTTON6: case ID_BUTTON7: case ID_BUTTON8: case ID_BUTTON9: case ID_BUTTON10: SelCand(g,c-ID_BUTTON); break; case ID_BUTTON_PREVCANDS: SearchCand(g,PREVCAND); // 前候補表示 break; case ID_BUTTON_NEXTCANDS: SearchCand(g,NEXTCAND); // 次候補表示 break; default: handled = false; break; } break; case keyDownEvent: c = e->data.keyDown.chr; if(g->prevwascommandkey){ // 直前にコマンドキーを押していた場合 g->prevwascommandkey = false; switch(c){ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': SelCand(g,c-'1'); return handled = true; case '0': ClosePBInline(g); FldGetSelection(g->field,&w1,&w2); if(w1 != w2){ FldCut(g->field); } g->patlen = 0; g->pat[g->patlen] = '\0'; g->finish = true; return handled = true; case 'r': // pref setpref(g); return handled = true; case 'w': // register changed 2000/11/08 03:34:32 regword(g); return handled = true; case 'd': // delete delword(g); return handled = true; default: break; } } // if(e->data.keyDown.modifiers & commandKeyMask || c == commandChr){ ! ハードキーを押すとcommandKeyMaskが立つ if(c == commandChr){ g->prevwascommandkey = true; } if(c == 0x0c){ SearchCand(g,NEWCAND); } else if(c >= 0x21 && c <= 0x7e){ if(g->candindex > 0){ SelCand(g,g->candindex-1); } else if(g->exact == 1){ // 直前にスペースやリターンなどで単漢字指定されていればひらがなに確定してしまう ClosePBInline(g); FldGetSelection(g->field,&w1,&w2); if(w1 != w2){ FldCut(g->field); } // g->kana = Roma2Kana(g,g->pat,g->patlen); // if(g->kana){ // FldInsert(g->field,g->kana,StrLen(g->kana)); // } g->pat[g->patlen] = '\0'; Roma2Kana(g->pat,g->kana,g->rktable); FldInsert(g->field,g->kana,StrLen(g->kana)); OpenPBInline(g); } if(g->patlen < MAXWORDLEN-1){ g->pat[g->patlen++] = (unsigned char)c; g->pat[g->patlen] = '\0'; // !!!!! g->searchlevel[g->patlen] = g->searchlevel[g->patlen-1]; } g->exact = 0; InsertPatAndSearch(g); } else { switch(c){ case '\0': SearchCand(g,NEWCAND); break; case vchrJogBack: // Backボタンでキャンセル 2001/7/23 ClosePBInline(g); g->finish = true; break; case vchrJogRelease: case '\n': // 確定 or 単漢字 if(g->candindex == 0 && (g->pref.spacefortankanji || g->exact == 1 || g->patlen == 0)){ // 確定 ClosePBInline(g); #ifdef ASCIIKAKUTEI w2 = FldGetInsPtPosition(g->field); FldSetSelection(g->field,w2,w2); #else FldGetSelection(g->field,&w1,&w2); if(w1 != w2){ FldCut(g->field); } // if(AlphaStr(g->pat) && (g->kana = Roma2Kana(g,g->pat,g->patlen))){ if(AlphaStr(g->pat)){ g->pat[g->patlen] = '\0'; Roma2Kana(g->pat,g->kana,g->rktable); FldInsert(g->field,g->kana,StrLen(g->kana)); } else FldInsert(g->field,g->pat,g->patlen); #endif g->finish = true; } else if(g->candindex == 0 && g->exact != 1){ // 単漢字 g->exact = 1; SearchCand(g,NEWCAND); } else { // カーソルで選択されている候補 SelCand(g,g->candindex-1); } break; case TOGGLECHR: enable = false; FtrSet(CREATORID,FEATURE_ENABLE,enable); // fall through case '\r': // 確定 !!!!!! ClosePBInline(g); #ifdef SHOWPATINWIN InsertPat(g); #endif g->finish = true; break; case 0x08: case 0x7f: // BS/DEL if(g->candindex == 0 && g->pageindex == 0){ g->exact = 0; if(g->patlen == 0){ ClosePBInline(g); g->finish = true; } else if(g->patlen == 1){ ClosePBInline(g); FldGetSelection(g->field,&w1,&w2); if(w1 != w2){ FldCut(g->field); } //FldCut(g->field); g->patlen = 0; g->pat[g->patlen] = '\0'; #ifdef SEARCHAGAIN OpenPBInline(g); SearchCand(g,NEWCAND); if(g->ncands == 0){ // 例文から次候補をみつけられない ClosePBInline(g); g->finish = true; } #else g->finish = true; #endif } else { g->patlen--; g->pat[g->patlen] = '\0'; // InsertPatAndSearch(g); SearchCand(g,NOCAND); } break; } // それ以外は左矢印と同じ動作 case vchrJogUp: case leftArrowChr: if(c == vchrJogUp && g->candindex == 0){ // ASCII確定 2000/11/12 13:03:14 ClosePBInline(g); InsertPatAndFix(g); g->finish = true; break; } if(g->candindex > 0){ // BSの処理と似ている。共通にする? idx = FrmGetObjectIndex(g->pbform,ID_BUTTON+g->candindex-1); cp = FrmGetObjectPtr(g->pbform,idx); CtlSetValue(cp,0); g->candindex--; } if(g->candindex > 0){ idx = FrmGetObjectIndex(g->pbform,ID_BUTTON+g->candindex-1); cp = FrmGetObjectPtr(g->pbform,idx); CtlSetValue(cp,1); } else if(g->pageindex > 0){ SearchCand(g,PREVCAND); if(g->ncands > 0){ g->candindex = g->ncands; idx = FrmGetObjectIndex(g->pbform,ID_BUTTON+g->candindex-1); cp = FrmGetObjectPtr(g->pbform,idx); CtlSetValue(cp,1); } } break; case spaceChr: if(g->pref.spacefortankanji && !g->exact){ g->exact = 1; SearchCand(g,NEWCAND); break; } // 空白文字で単漢字でない場合は右矢印と同じ動作をさせる case vchrJogDown: case rightArrowChr: if(g->candindex < g->ncands){ if(g->candindex > 0){ idx = FrmGetObjectIndex(g->pbform,ID_BUTTON+g->candindex-1); cp = FrmGetObjectPtr(g->pbform,idx); CtlSetValue(cp,0); } g->candindex++; idx = FrmGetObjectIndex(g->pbform,ID_BUTTON+g->candindex-1); cp = FrmGetObjectPtr(g->pbform,idx); CtlSetValue(cp,1); } else { SearchCand(g,NEXTCAND); if(g->ncands > 0){ g->candindex = 1; idx = FrmGetObjectIndex(g->pbform,ID_BUTTON+g->candindex-1); cp = FrmGetObjectPtr(g->pbform,idx); CtlSetValue(cp,1); } } break; case vchrJogPageDown: // ジョグ左回し case nextFieldChr: // 上ドラッグ-下ドラッグ case downArrowChr: // 下向き矢印キー case pageDownChr: // 下スクロールボタン SearchCand(g,NEXTCAND); break; case vchrJogPageUp: // ジョグ右回し case prevFieldChr: // 下ドラッグ-上ドラッグ case upArrowChr: // 上向き矢印キー case pageUpChr: // 上スクロールボタン if(g->pageindex > 0){ SearchCand(g,PREVCAND); // 前候補表示 } else { // ASCII確定 ClosePBInline(g); InsertPatAndFix(g); g->finish = true; if(g->patlen == 0 && c == prevFieldChr){ // 2000/11/07 13:34:47 UInt32 enable; enable = false; DisplayPOBoxMode(enable); FtrSet(CREATORID,FEATURE_ENABLE,enable); } } break; case hard1Chr: if(! g->pref.righthanded){ g->exact = 1; SearchCand(g,NEWCAND); break; } SelCand(g,0); break; case hard2Chr: case hard3Chr: SelCand(g,g->pref.righthanded ? c-hard1Chr : c-hard2Chr); break; case hard4Chr: if(g->pref.righthanded){ g->exact = 1; SearchCand(g,NEWCAND); break; } SelCand(g,2); break; #ifdef MENUCHR case menuChr: g->prefform = FrmInitForm(ID_PREFFORM); ErrFatalDisplayIf(g->prefform==0,"No prefform"); FrmSetActiveForm(g->prefform); FrmSetEventHandler(g->prefform,PrefFormEvent); cp = GetObjPtr(ID_CHECKBOX_BACKUP); CtlSetValue(cp,g->dic ? (BackupBit(g->dic) ? 1 : 0) : 0); FrmDrawForm(g->prefform); id = FrmDoDialog(g->prefform); FrmReturnToForm(NULL); break; #endif default: if(c >= 0x20 && c < 0x7f){ ClosePBInline(g); w2 = FldGetInsPtPosition(g->field); FldSetSelection(g->field,w2,w2); cc = (unsigned char)c; FldInsert(g->field,&cc,1); g->exact = 0; g->finish = true; } else { handled = false; } } } break; case menuEvent: switch(e->data.menu.itemID){ case ID_MENU_ABOUT: FrmAlert(ID_ALERT_ABOUTPOBOX); break; case ID_MENU_MAINHELP: FrmHelp(ID_MAINHELP); break; case ID_MENU_MOJIHELP: FrmHelp(ID_MOJIHELP); break; case ID_MENU_TANHELP: FrmHelp(ID_TANHELP); break; case ID_MENU_KANAHELP: FrmHelp(ID_KANAHELP); break; case ID_MENU_DICHELP: FrmHelp(ID_DICHELP); break; case ID_MENU_KIGOUHELP: FrmHelp(ID_KIGOUHELP); break; case ID_MENU_ABBREVHELP: FrmHelp(ID_ABBREVHELP); break; case ID_MENU_REGWORDHELP: FrmHelp(ID_REGWORDHELP); break; case ID_MENU_DELWORDHELP: FrmHelp(ID_DELWORDHELP); break; case ID_MENU_TIPSHELP: FrmHelp(ID_TIPSHELP); break; case ID_MENU_PREFERENCES: setpref(g); break; case ID_MENU_REGWORD: regword(g); break; case ID_MENU_DELWORD: delword(g); break; default: break; } break; default: handled = false; break; } return handled; } //////////////////////////////////////////////////////////// // 候補単語表示 //////////////////////////////////////////////////////////// static void EraseCand(Global *g) // 候補クリヤ { int i; UInt16 idx; g->ncands = 0; g->candpos = 0; for(i=0;ipbform,ID_BUTTON+i); CtlHideControl(FrmGetObjectPtr(g->pbform,idx)); g->candstr[i][0] = '\0'; } } static Boolean AddCand(Global *g,unsigned char *cstr,int study) // // cstrを候補リストに加えて表示。余裕がなければfalseを返す。 // 呼ばれる度に候補ボタンとして表示するので、候補はみつかる毎に // 五月雨式に表示されることになる。 // { int i, width; ControlPtr cp; UInt16 idx; unsigned char *word,*pat; unsigned char buf[200]; int len; if(g->ncands >= MAXCANDS) return false; // 読み→word, パタン→pat StrCopy(buf,cstr); word = pat = buf; for(;*word;word++){ if(*word == '\002'){ *word = '\0'; word++; break; } } if(! *word) word = cstr; // // Drag&Dropモジュール呼び出し // len = StrLen(word); if(len >= 6 && word[len-1] == '}'){ // モジュールはCreatorIDを中括弧でくくって指定する。 // e.g. "ds#{PBTS}" (ユーザ定義辞書の場合) // 不定長の場合は、何でもマッチするテキストとして空白文字を使って // "1...#{CTAB}" // のように定義する。モジュールが複数機能をサポートしている場合は // "1...#{CTAB2}" // のようにする。 // また、"@word" などとプレフィクスをつけたときにモジュールを // 呼び出せるようにする場合は // "@...#@{CTAB2}" // のように共通プレフィクスを指定すると、 // プレフィクスを除いた文字列がモジュールにわたされる。 // unsigned char *s,*p; int start; s = g->pat; p = word; for(start=0;s[start]==p[start];start++); // プレフィクススキップ if(p[start]=='{' && len-start >= 6){ Err err; unsigned short cardNo; unsigned long result; LocalID dbID; DmSearchStateType searchState; tDropLaunchCmdParamRec param; unsigned long creatorID; // creatorID = ((p[1] << 24) | (p[2] << 16) | (p[3] << 8) | p[4]); intになってしまうのか? 動かない。 creatorID = word[start+1]; creatorID <<= 8; creatorID |= word[start+2]; creatorID <<= 8; creatorID |= word[start+3]; creatorID <<= 8; creatorID |= word[start+4]; // アプリケーションの検索 err = DmGetNextDatabaseByTypeCreator (true, &searchState, sysFileTApplication, creatorID, true, &cardNo, &dbID); if(err) return true; param.selector = ((word[start+5] >= '0' && word[start+5] <= '9') ? word[start+5]-'0' : 0); // モジュールの何番目の機能か g->pat[g->patlen] = '\0'; param.srcTextLength = g->patlen - start; param.srcText = g->pat + start; param.resultTextLength = 0; param.resultText = NULL; param.resultBehavior = 0; err = SysAppLaunch (cardNo, dbID, 0, dDropLaunchCmd, (Ptr)¶m, &result); ErrFatalDisplayIf(err, "Error sending lookup action to app"); if(! param.resultText) return true; buf[param.resultTextLength] = '\0'; StrCopy(buf,param.resultText); study = CAND_NOSTUDY; MemPtrFree(param.resultText); // 受け取った文字列はFreeするというD&Dの仕様 word = buf; } } // 既にその侯補が侯補リストにあれば何もしない for(i=0;incands;i++) if(StrCompare(word,g->candstr[i]) == 0) return true; // 新しい候補文字列をボタンに登録/表示 width = FntCharsWidth(word,StrLen(word)) + 4; if(width < 8) width = 8; // if(g->candpos + 2 + width >= 156) return false; if(g->candpos + 2 + width >= 140) return false; StrCopy(g->candstr[g->ncands],word); StrCopy(g->candspell[g->ncands],pat); g->candtype[g->ncands] = study; idx = FrmGetObjectIndex(g->pbform,ID_BUTTON+g->ncands); cp = FrmGetObjectPtr(g->pbform,idx); cp->bounds.topLeft.x = g->candpos + (g->pref.righthanded ? 2 : 15); cp->bounds.extent.x = width; cp->text = g->candstr[g->ncands]; CtlSetValue(cp,0); CtlShowControl(cp); g->candpos += width+3; g->ncands++; return true; } static int NextDictRecord(Global *g, int resid, int c) { //DumpHex(resid,40,20); //DumpHex(c,60,20); if(resid == c){ resid = 0xa00; } else { resid++; } for(;resid < 0xa00 + g->nextra;resid++){ if(g->extra[resid - 0xa00] == c) return resid; } return 0; } static void Hira2Kata(unsigned char *h, unsigned char *buf) { unsigned char *k = buf; int c1,c2,j1,j2; while(*h){ if(*h < 0x80){ *k++ = *h++; } else { c1 = *h++; c2 = *h++; if(c1 >= 0xe0) c1 -= 0x40; if(c2 >= 0x80) c2--; j1 = (c1-0x81) * 2 + (c2>=0x9e ? 1 : 0) + 0x21; j2 = (c2 >= 0x9e ? c2-0x9e : c2-0x40) + 0x21; if(j1 == 0x24) j1++; j2 = (j1 & 1 ? j2-0x21+0x40 : j2-0x21+0x9e); j1 = (j1 - 0x21) / 2 + 0x81; c1 = (j1 >= 0xa0 ? j1 + 0x40 : j1); c2 = (j2 >= 0x7f ? j2 + 1 : j2); *k++ = c1; *k++ = c2; } } *k = '\0'; } static Boolean PenIsDownOrQueueIsNotEmpty(void) { // ペン動作中は検索などを行なわないようにしていたが // ThumbTypeで問題があるので消してしまった。 // Int16 x,y; // Boolean down; // EvtGetPen(&x,&y,&down); // if(down) return true; return !EvtKeyQueueEmpty(); } static int consonant(int c) { // char *consonants = "bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ"; char *consonants = "bcdfghjklmpqrstvwxyz"; char *s; for(s=consonants;*s;s++){ if(*s == c) return 1; } return 0; } //static int //XStrLen(unsigned char *s) // \002か\000までの文字列長を計算 //{ // int i=0; // for(;*s != '\002' && *s != '\0';s++,i++); // return i; //} // // SearchCand()の方針について // // パタン形式や、候補がみつかるかどうかによって検索手法はいろいろ // 変わってくる。ショートカットやD&Dモジュールを呼び出す場合も有る。 // // 新しいパタンに対する最初の呼出し(kind=NEWCAND)のときに検索モードを決定し、 // 次候補などを検索する場合(kind=NEXTCAND/PREVCAND)は前の検索結果以降から // 検索を再開する。 // // 以下のような検索モードがある。 // // 単語の前方マッチのみ exact=0, // ひらがな/カタカナ + 完全マッチ exact=1, // ショートカット文字列 + 前方マッチ exact=0, shortcut=1 // Drag&Drop呼出文字列 + 前方マッチ exact=0, dd=1 // // 後の三者では単語検索以外にも候補を表示する必要があるので、 // kind=NEWCANDにおける検索時に候補単語列をあらかじめ検索しておく。 // // 曖昧検索に失敗した場合、何度も曖昧検索を実行するのは時間がかかるので、 // searchlevel[パタン長]という配列に検索レベルを入れておき、パタンが // 追加された場合は前の検索レベル以降を試す。検索レベルは // // 1: 通常検索(前方マッチ) // 2: 送り仮名検索 // 3: 曖昧検索 // // である。検索レベルも新規検索時(kind=NEWCAND)のときに決定する。 // 候補画面選択時(kind=PREVCAND/NEXTCAND)には変更しない。 // // 初期状態 ←→ 1文字目入力 ←→ 2文字目入力 ←→ // 次候補↓↑前候補 ↓↑ // 2画面目 2画面目 // 次候補↓↑前候補 ↓↑ // /* メモリースティック辞書などの扱い 1.4以前 内蔵PBinlineDB PBinlearnDB ● ◯ PBinlearnDBだけ学習 ◯ × PBinlineDBで学習 × ◯ NG? × × NG (学習できない) 1.5以降 内蔵PBinlineDB PBinlearnDB 外部PBinlineDB ★ (●) ◯ ● PBinlearnDBだけ学習 内蔵PBinlineDBを無視 ★ ● ◯ × PBinlearnDBだけ学習 ★ ◯ × (◯) 内蔵PBinlineDBで学習 ★ ◯ × × 内蔵PBinlineDBで学習 ★ × ◯ ● PBinlearnDBだけ学習 × ◯ × NG? × × ◯ NG (学習できない) × × × NG 方針: ・PBinlearnDBが有る場合は学習辞書に使う 外部PBinlineDBが有る場合はこれを固定辞書に使う (type3) 内部PBinlineDBが有る場合はこれを固定辞書に使う (type2) 両方無い場合はエラー ・PBinlearnDBが無い場合は 内部PBinlineDBですべて学習する。(type1) これが無い場合はエラー */ static void SearchCand(Global *g, int kind) // // 動的曖昧検索を実行して候補単語リストを表示 // { #define SIMPLE //#define USEFUNC #ifndef SIMPLE #ifndef USEFUNC register UInt32 match_i0; register UInt32 match_e; register UInt32 *match_p; register UChar match_c; #endif #endif register UChar *p,*s,*s0; UChar pat[100]; unsigned char patchar; UInt16 resid; UInt16 offset; MemHandle h; Boolean found = false; ////// // ULong size; int mismatch; // 曖昧度 int i; Boolean havespace = true; ControlPtr cp; int patwidth; unsigned char buf[100]; unsigned char k[100]; int objindex; RectangleType bounds; DmOpenRef d,ds; Err err; d = (g->ldic ? g->ldic : g->dic); patchar = (IsUpper(*(g->pat)) ? ToLower(*(g->pat)) : *(g->pat)); switch(kind){ case NEWCAND: g->pageindex = 0; for(i=0;ipageoffset[i] = 0; g->ppageoffset[i] = 0; g->lpageoffset[i] = 0; g->pageresid[i] = patchar; g->opageoffset[i] = 0; g->opageresid[i] = patchar; } g->searchlevel[0] = 0; g->searchlevel[1] = 0; break; case NEXTCAND: if(g->pageindex >= MAXCANDPAGES-1) return; g->pageindex++; break; case PREVCAND: if(g->pageindex <= 0) return; g->pageindex--; break; default: } g->candindex = 0; if(PenIsDownOrQueueIsNotEmpty()) return; // // 前候補/次候補の矢印ボタン表示 (右利き/左利きで場所を変える) // objindex = FrmGetObjectIndex(g->pbform,ID_BUTTON_PREVCANDS); cp = FrmGetObjectPtr(g->pbform,objindex); CtlSetLabel(cp,g->pageindex == 0 ? "\003" : "\001"); bounds.topLeft.x = (g->pref.righthanded ? 143 : 0); bounds.topLeft.y = 0; bounds.extent.x = 12; bounds.extent.y = 8; FrmSetObjectBounds(g->pbform,objindex,&bounds); CtlShowControl(cp); objindex = FrmGetObjectIndex(g->pbform,ID_BUTTON_NEXTCANDS); cp = FrmGetObjectPtr(g->pbform,objindex); // CtlSetLabel(cp,"\002"); bounds.topLeft.x = (g->pref.righthanded ? 143 : 0); bounds.topLeft.y = 7; bounds.extent.x = 12; bounds.extent.y = 8; FrmSetObjectBounds(g->pbform,objindex,&bounds); CtlShowControl(cp); EraseCand(g); #ifdef SHOWPATINWIN // // 入力した読みをFieldにコピーするかわりにPOBox枠で表示する場合。 // インライン的ではなくなるが速度がかなり向上する。 // if(g->pageindex == 0 && g->patlen > 0){ int offset = (g->pref.righthanded ? 3 : 16); WinDrawChars(" ",20,offset,1); patwidth = FntCharsWidth(g->pat,g->patlen); WinDrawChars(g->pat,g->patlen,offset,1); WinDrawChars(" ",4,offset+patwidth,1); g->candpos = patwidth + 4; } else { int offset = (g->pref.righthanded ? 3 : 16); WinDrawChars(" ",20,offset,1); } #endif if(kind == NOCAND) return; //////////////////////////////////////////////////////////////////////////////// // // 特殊な候補の作成 // if(g->pageindex == 0){ g->ndc[0] = 0; g->nc = 0; // if(g->patlen > 0 && g->exact){ if(1){ // // 単漢字変換指定の場合はひらがな/カタカナと無変換文字列も候補にする。 // StrNCopy(pat,g->pat,g->patlen); pat[g->patlen] = '\0'; // g->kana = Roma2Kana(g,g->pat,g->patlen); // if(g->kana == NULL) g->kana = ""; // ローマ字にできないときは出さない... if(Roma2Kana(g->pat,g->kana,g->rktable)){ // if(! ASCIIStr(g->kana)){ StrNCopy(buf,g->pat,g->patlen); StrCopy(buf+g->patlen,"\002"); StrCopy(buf+g->patlen+1,g->kana); g->extracandsstudy[g->nc] = CAND_STUDY; StrCopy(g->extracands[g->nc++],buf); Hira2Kata(buf,k); g->extracandsstudy[g->nc] = CAND_STUDY; StrCopy(g->extracands[g->nc++],k); } StrNCopy(pat,g->pat,g->patlen); pat[g->patlen] = '\0'; g->extracandsstudy[g->nc] = CAND_STUDY; StrCopy(g->extracands[g->nc++],pat); } } // // 特殊候補を表示 // g->ndc[g->pageindex + 1] = g->ndc[g->pageindex]; if(g->patlen > 0 && g->exact){ if(g->ndc[g->pageindex] < g->nc){ int n = g->ndc[g->pageindex]; for(;havespace && n < g->nc ;n++){ havespace = AddCand(g,g->extracands[n],g->extracandsstudy[n]); if(havespace) g->ndc[g->pageindex+1]++; } } } //////////////////////////////////////////////////////////////////////////////// // // ここから以降が通常の辞書検索 // // // 環境辞書を検索 // if(PenIsDownOrQueueIsNotEmpty()) return; if(havespace && g->patlen > 0 && g->pageindex == 0){ // ちょっとずるい resid = 0x900 + CurrentEnvironment(); h = DmQueryRecord(d,resid); if(h && (s0 = MemHandleLock(h))){ StrNCopy(pat,g->pat,g->patlen); if(! g->exact) StrCopy(pat+g->patlen," "); MakePat(g,pat,0); s = s0; while(*s){ if(Match0(g,s)){ havespace = AddCand(g,s,CAND_STUDY); if(!havespace) break; } for(;*s;s++); s++; } MemHandleUnlock(h); } } if(PenIsDownOrQueueIsNotEmpty()) return; // // 例文学習辞書を検索 // if(g->ldic){ if(g->pageindex+1 < MAXCANDPAGES) g->lpageoffset[g->pageindex+1] = 0; if(! g->exact && havespace){ for(i=0;i< g->clen && havespace;i++){ int clen; unsigned char lastc = g->context[g->clen-1]; clen = g->clen - i; StrNCopy(pat,g->context+i,clen); StrCopy(pat+clen,"\001"); resid = clen * 0x100 + lastc; h = DmQueryRecord(g->ldic,resid); if(h && (s0 = MemHandleLock(h))){ s = s0 + g->lpageoffset[g->pageindex]; while(*s){ if(StrNCompare(pat,s,clen+1)==0){ if(StrNCompare(s+clen+1,g->pat,g->patlen)==0 || g->patlen == 0){ havespace = AddCand(g,s+clen+1,CAND_STUDY); if(!havespace) break; } } for(;*s;s++); s++; } if(g->pageindex+1 < MAXCANDPAGES) g->lpageoffset[g->pageindex+1] = s - s0; MemHandleUnlock(h); } } } if(PenIsDownOrQueueIsNotEmpty()) return; } if(PenIsDownOrQueueIsNotEmpty()) return; // // 例文固定?辞書を検索 // if(g->pageindex+1 < MAXCANDPAGES) g->ppageoffset[g->pageindex+1] = 0; if(! g->exact && havespace){ for(i=0;i< g->clen && havespace;i++){ int clen; unsigned char lastc = g->context[g->clen-1]; clen = g->clen - i; StrNCopy(pat,g->context+i,clen); StrCopy(pat+clen,"\001"); resid = clen * 0x100 + lastc; #ifdef USEVFS if(g->vdic){ err = VFSFileDBGetRecord(g->vdic,resid,&h,(UInt8*)NULL,(UInt32*)NULL); ErrFatalDisplayIf(err,"Can't get VFS handle"); } else #endif { h = DmQueryRecord(g->dic,resid); } // h = DmQueryRecord(g->dic,resid); if(h && (s0 = MemHandleLock(h))){ s = s0 + g->ppageoffset[g->pageindex]; while(*s){ if(StrNCompare(pat,s,clen+1)==0){ if(StrNCompare(s+clen+1,g->pat,g->patlen)==0 || g->patlen == 0){ havespace = AddCand(g,s+clen+1,CAND_STUDY); if(!havespace) break; } } for(;*s;s++); s++; } if(g->pageindex+1 < MAXCANDPAGES) g->ppageoffset[g->pageindex+1] = s - s0; MemHandleUnlock(h); #ifdef USEVFS if(g->vdic){ MemHandleFree(h); } #endif } } } if(PenIsDownOrQueueIsNotEmpty()) return; // // 単語辞書を検索 // if(havespace && g->patlen > 0){ StrNCopy(pat,g->pat,g->patlen); pat[g->patlen] = '\0'; #ifndef SIMPLE if(! g->exact) StrCat(pat," "); #else for(s=pat;*s;s++){ if(IsUpper(*s)) *s = ToLower(*s); } #endif // // 単語辞書からの検索 // found = false; // // 基本単語辞書/拡張単語辞書の完全マッチを試す // if(g->searchlevel[g->patlen] == 0){ MakePat(g,pat,mismatch=0); #ifndef SIMPLE #ifndef USEFUNC match_p = g->shiftpat; #endif #endif resid = g->pageresid[g->pageindex]; offset = g->pageoffset[g->pageindex]; ds = (resid < 0x100 && g->ldic ? g->ldic : g->dic); // 2000/11/12 18:01:24 // ds = d; while(havespace && resid){ #ifdef USEVFS if(ds == g->ldic || ! g->vdic){ h = DmQueryRecord(ds,resid); } else { err = VFSFileDBGetRecord(g->vdic,resid,&h,(UInt8*)NULL,(UInt32*)NULL); ErrFatalDisplayIf(err,"Can't get VFS handle"); } #else h = DmQueryRecord(ds,resid); #endif if(h && (s0 = MemHandleLock(h))){ s = s0 + offset; while(*s){ // DBの最後はヌルになってると仮定 unsigned char *sw; //if(PenIsDownOrQueueIsNotEmpty()) break; sw = s; #ifdef SIMPLE for(p = pat;*p && (*p == *s || *s == ' '); p++,s++); if(!*p && (!g->exact || g->exact && (*s == '\002' || !*s))){ #else #ifdef USEFUNC if(Match0(g,s)){ #else match_i0 = INITPAT; match_e = g->epsilon; for(;(match_c = *s) && match_c != '\002';s++){ match_i0 = (match_i0 & match_e) | ((match_i0 & match_p[match_c]) >> 1); } if(match_i0 & g->acceptpat){ #endif #endif found = true; havespace = AddCand(g,sw,CAND_STUDY); if(!havespace){ s = sw; break; } } for(;*s;s++); s++; } MemHandleUnlock(h); #ifdef USEVFS if(ds != g->ldic && g->vdic ){ MemHandleFree(h); } #endif if(g->pageindex+1 < MAXCANDPAGES){ g->pageresid[g->pageindex+1] = resid; g->pageoffset[g->pageindex+1] = s - s0; } } if(!havespace) break; // // 次の単語辞書をさがす // resid = NextDictRecord(g,resid,(int)patchar); ds = g->dic; offset = 0; } } if(!found && g->pageindex == 0){ for(i=g->patlen;isearchlevel[i] = 1; // g->searchlevel[g->patlen] = 1;///////// // g->searchlevel[g->patlen+1] = 1;///////// } #ifdef WNN_PALM_OS if(havespace && g->pageindex == 0){ Char buf[200],convbuf[200],*s,*d; UInt16 len; len = StrLen(g->pat); StrCopy(buf,g->pat); buf[len] = '\002'; Roma2Kana(g->pat,g->kana,g->rktable); if(jl_ren_conv(g->kana,convbuf,200,0x01) >= 0){ for(s=convbuf,d=buf+len+1;*s;){ if(*s != 0x01){ *d++ = *s++; } else { s++; } } *d = '\0'; havespace = AddCand(g,buf,CAND_STUDY); } jl_flush(); } #endif // // 送りがなのマッチを調べる。 // "tab 食" という辞書エントリがあるとき"taberu"が入力されると // "食べる"を候補とする... パタンの最後が子音の場合。 // if(havespace && !consonant(g->pat[g->patlen-1])){ // if(g->searchlevel[g->patlen] == 1 && havespace){///////// // if(g->searchlevel[g->patlen] == 1 && !found && havespace){///////// // if(g->searchlevel[g->patlen] == 0 && havespace && Roma2Kana(g->pat,g->kana,g->rktable)){ // かなに変換可能なときだけ resid = g->opageresid[g->pageindex]; //////// offset = g->opageoffset[g->pageindex]; ds = (resid < 0x100 && g->ldic ? g->ldic : g->dic); // 2000/11/12 18:01:24 // ds = d; while(havespace && resid){ #ifdef USEVFS if(ds == g->ldic || ! g->vdic){ h = DmQueryRecord(ds,resid); } else { err = VFSFileDBGetRecord(g->vdic,resid,&h,(UInt8*)NULL,(UInt32*)NULL); ErrFatalDisplayIf(err,"Can't get VFS handle"); } #else h = DmQueryRecord(ds,resid); #endif //h = DmQueryRecord(ds,resid); if(h && (s0 = MemHandleLock(h))){ s = s0 + offset; while(*s){ // int len; if(PenIsDownOrQueueIsNotEmpty()) break; // if(PMatch(g,s) && ((len = XStrLen(s)-1) >= 1) && consonant(s[len])){ // for(p = pat;*p == *s && (*s != '\002') && *s; p++,s++); for(p = pat;*p == *s; p++,s++); if(*s == '\002' && consonant(*(s-1)) && (p-pat > 1) && (*(s+1) & 0x80)){ // 日本語のときだけ){ StrNCopy(buf,g->pat,g->patlen); StrCopy(buf+g->patlen,s); Roma2Kana(g->pat+(p-pat-1),g->kana,g->rktable); StrCat(buf,g->kana); found = true; havespace = AddCand(g,buf,CAND_STUDY); if(! havespace) break; } for(;*s;s++); s++; } MemHandleUnlock(h); #ifdef USEVFS if(ds != g->ldic && g->vdic ){ MemHandleFree(h); } #endif if(g->pageindex+1 < MAXCANDPAGES){ g->opageresid[g->pageindex+1] = resid; g->opageoffset[g->pageindex+1] = s - s0; } } if(!havespace) break; // // 次の単語辞書をさがす // resid = NextDictRecord(g,resid,(int)patchar); ds = g->dic; offset = 0; } } // if(!found && g->pageindex == 0) g->searchlevel[g->patlen] = 2; if(!found && g->pageindex == 0) g->searchlevel[g->patlen] = 1; // // それでもみつからなかった場合、基本単語中をかなりの曖昧度で試す // 'dsg' => 'd s g ', etc. // // 曖昧検索はPOBoxの特徴のひとつなのだが、時間がかかって操作性が // 悪くなることがある。 // // if(g->searchlevel[g->patlen] == 2 && !found && havespace && g->patlen < 6 // 長いパタンだと曖昧検索をやめる if(g->searchlevel[g->patlen] == 1 && !found && havespace && g->patlen < 6 // 長いパタンだと曖昧検索をやめる ){ resid = patchar; h = DmQueryRecord(d,resid); if(h && (s0 = MemHandleLock(h))){ for(p=pat,s=g->pat;s < g->pat+g->patlen;s++){ *p++ = *s; *p++ = ' '; } *p = '\0'; for(mismatch=0;mismatch<2 && havespace && !found;mismatch++){ // 動的曖昧検索実行 if(PenIsDownOrQueueIsNotEmpty()) break; MakePat(g,pat,mismatch); s = s0 + g->pageoffset[g->pageindex]; while(*s){ if(PenIsDownOrQueueIsNotEmpty()) break; if(Match(g,s)){ found = true; havespace = AddCand(g,s,CAND_STUDY); if(! havespace) break; } for(;*s;s++); s++; } } MemHandleUnlock(h); if(g->pageindex+1 < MAXCANDPAGES){ g->pageresid[g->pageindex+1] = patchar; g->pageoffset[g->pageindex+1] = s - s0; } } } if(!found && g->pageindex == 0) g->searchlevel[g->patlen] = 3; } // // どうしても何も予測できない場合は助詞を表示する。 // 文の先頭などでは表示しない。 // if(g->ncands < 3 && g->patlen == 0 && !g->alphaend && g->clen > 0){ if(havespace) havespace = AddCand(g,"no\002\202\314",CAND_STUDY); // の if(havespace) havespace = AddCand(g,"wo\002\202\360",CAND_STUDY); // を if(havespace) havespace = AddCand(g,"ga\002\202\252",CAND_STUDY); // が if(havespace) havespace = AddCand(g,"ha\002\202\315",CAND_STUDY); // は if(havespace) havespace = AddCand(g,"ni\002\202\311",CAND_STUDY); // に if(havespace) havespace = AddCand(g,"to\002\202\306",CAND_STUDY); // と if(havespace) havespace = AddCand(g,"to\002\202\305",CAND_STUDY); // で if(havespace) havespace = AddCand(g,"to\002\202\310",CAND_STUDY); // な } // // カタカナ候補などを表示 // if(g->patlen > 0){ if(g->ndc[g->pageindex] < g->nc){ int n = g->ndc[g->pageindex]; for(;havespace && n < g->nc ;n++){ havespace = AddCand(g,g->extracands[n],g->extracandsstudy[n]); if(havespace) g->ndc[g->pageindex+1]++; } } } } static Boolean ASCIIStr(unsigned char *s) { if(s == NULL) return false; for(;*s;s++){ if(*s >= 0x80) return false; } return true; } static Boolean AlphaStr(unsigned char *s) { if(s == NULL) return false; for(;*s;s++){ if(*s >= 'a' && *s <= 'z') continue; if(*s >= 'A' && *s <= 'Z') continue; if(*s == '\'') continue; if(*s == '-') continue; return false; } return true; } static void SelCand(Global *g, int n) // Select nth candidate and insert/end { unsigned char *s; int slen; int offset; unsigned char buf[200]; int ind; DmOpenRef d; d = (g->ldic ? g->ldic : g->dic); ClosePBInline(g); if(n < g->ncands){ s = g->candstr[n]; slen = StrLen(s); if(ASCIIStr(s) && g->alphaend) FldInsert(g->field," ",1); FldInsert(g->field,s,slen); StrCopy(buf,g->candspell[n]); if(StrCompare(g->candspell[n],g->candstr[n])){ StrCopy(buf+StrLen(g->candspell[n]),"\002"); StrCopy(buf+StrLen(g->candspell[n])+1,g->candstr[n]); } ind = buf[0]; if(IsUpper(ind)) ind = ToLower(ind); if(g->candtype[n] == CAND_STUDY){ AddDicEntry(d,ind,buf,true); AddDicEntry(d,CurrentEnvironment()+0x900,buf,true); RegisterPhrase(g,d,n); } offset = 0; while(slen-offset > 8){ offset += (s[offset] & 0x80 ? 2 : 1); } StrNCopy(g->prevword,s+offset,slen-offset); g->prevwordlen = slen-offset; } g->exact = 0; g->patlen = 0; g->pat[g->patlen] = '\0'; #ifdef SEARCHAGAIN OpenPBInline(g); SearchCand(g,NEWCAND); if(g->ncands == 0){ // 例文から次候補をみつけられない ClosePBInline(g); g->finish = true; } #else g->finish = true; #endif } static void RegisterPhrase(Global *g, DmOpenRef dic, int n) // // n番目の候補を例文登録 // { UInt16 resid; UChar buf[200]; if(dic == NULL) return; if(g->prevwordlen == 0 || g->prevwordlen > 8) return; resid = g->prevwordlen * 0x100 + g->prevword[g->prevwordlen-1]; StrNCopy(buf,g->prevword,g->prevwordlen); StrCopy(buf+g->prevwordlen,"\001"); StrCat(buf,g->candspell[n]); StrCat(buf,"\002"); StrCat(buf,g->candstr[n]); AddDicEntry(dic,resid,buf,true); } static void InsertPat(Global *g) { UInt16 w1,w2; FldGetSelection(g->field,&w1,&w2); if(w1 == w2) w1=w2= FldGetInsPtPosition(g->field); FldInsert(g->field,g->pat,g->patlen); w2 = FldGetInsPtPosition(g->field); FldSetSelection(g->field,w1,w2); } static void InsertPatAndFix(Global *g) { UInt16 w1,w2; InsertPat(g); FldGetSelection(g->field,&w1,&w2); FldSetSelection(g->field,w2,w2); } static void InsertPatAndSearch(Global *g) { if(PenIsDownOrQueueIsNotEmpty()) return; #ifdef SHOWPATINWIN // FrmEraseForm(g->pbform); // FrmDrawForm(g->pbform); #else // ClosePBInline(g); //FrmEraseForm(g->pbform); FrmSetActiveForm(g->origform); InsertPat(g); // FldGetSelection(g->field,&w1,&w2); // if(w1 == w2) w1=w2= FldGetInsPtPosition(g->field); // FldInsert(g->field,g->pat,g->patlen); // w2 = FldGetInsPtPosition(g->field); // FldSetSelection(g->fie ld,w1,w2); FrmSetActiveForm(g->pbform); FrmDrawForm(g->pbform); // OpenPBInline(g); #endif SearchCand(g,NEWCAND); /* // SearchCand()に取り込む if(g->ncands == 0){ // 荒井氏による指摘.. 候補が無いとカタカナ候補を出す g->exact = 2; SearchCand(g,NEWCAND); } */ /* if(g->ncands == 0){ ClosePBInline(g); w2 = FldGetInsPtPosition(g->field); FldSetSelection(g->field,w2,w2); g->finish = true; } */ } // // アプリの開いているデータベース名から // 現在の環境のハッシュ値を得る // int CurrentEnvironment() { DmOpenRef db; LocalID id; UInt cardno; unsigned char name[40]; int i; unsigned int hash = 0; db = DmNextOpenDatabase(NULL); while(db){ DmOpenDatabaseInfo(db,&id, NULL,NULL,&cardno,NULL); DmDatabaseInfo(cardno,id, name,NULL,NULL, NULL,NULL,NULL, NULL,NULL,NULL, NULL,NULL); for(i=0;i<32 && name[i];i++){ hash += name[i]; } db = DmNextOpenDatabase(db); } return hash & 0xff; } #ifdef APP static Boolean MainAppFormEvent(EventPtr e) { Boolean handled = false; // UInt16 c; // ControlPtr cp; switch(e->eType){ case ctlSelectEvent: // c = e->data.ctlSelect.controlID; // cp = e->data.ctlSelect.pControl; // if(CtlGetValue(cp)){ // } // else { // } // handled = true; break; default: break; } return handled; } static Boolean ApplicationHandleEvent(EventPtr e) { Boolean handled = false; FormPtr frm; UInt16 c; ControlPtr cp; POBoxPref pref; UInt16 prefsize; // Err err; UInt32 use,olduse; UInt32 trap; DmOpenRef dic; //printf("AppHandleEvent(%d)\n",(int)(e->eType)); switch(e->eType){ case ctlSelectEvent: c = e->data.ctlSelect.controlID; cp = e->data.ctlSelect.pControl; PrefGetAppPreferences(CREATORID,0,&pref,&prefsize,true); switch(c){ case ID_CHECKBOX_USEPOBOX: // // アプリケーション設定画面で「POBoxを使う」設定にすることにより // HackMasterによる設定と同じことを行なう。 // GetFeaturePref(FEATURE_USEPOBOX,&olduse,false); use = (CtlGetValue(cp) ? true : false); if(! olduse && use){ // 現在のトラップアドレスを保存してPOBox関数を登録する trap = (UInt32)SysGetTrapAddress(sysTrapFldHandleEvent); FtrSet(CREATORID,1000,trap); SysSetTrapAddress(sysTrapFldHandleEvent,PBInline); trap = (UInt32)SysGetTrapAddress(sysTrapEvtProcessSoftKeyStroke); FtrSet(CREATORID,1001,trap); SysSetTrapAddress(sysTrapEvtProcessSoftKeyStroke,PBEnable); trap = (UInt32)SysGetTrapAddress(sysTrapGsiEnable); FtrSet(CREATORID,1002,trap); SysSetTrapAddress(sysTrapGsiEnable,GsiEnableHack); trap = (UInt32)SysGetTrapAddress(sysTrapGsiSetShiftState); FtrSet(CREATORID,1003,trap); SysSetTrapAddress(sysTrapGsiSetShiftState,GsiSetShiftStateHack); } else if(olduse && ! use){ // トラップアドレスをもとにもどす FtrGet(CREATORID,1000,&trap); SysSetTrapAddress(sysTrapFldHandleEvent,(FldHandleEventTrapFunc*)trap); FtrGet(CREATORID,1001,&trap); SysSetTrapAddress(sysTrapEvtProcessSoftKeyStroke,(EvtProcessSoftKeyStrokeTrapFunc*)trap); FtrGet(CREATORID,1002,&trap); SysSetTrapAddress(sysTrapGsiEnable,(GsiEnableTrapFunc*)trap); FtrGet(CREATORID,1003,&trap); SysSetTrapAddress(sysTrapGsiSetShiftState,(GsiSetShiftStateTrapFunc*)trap); } FtrSet(CREATORID,FEATURE_USEPOBOX,use); handled = true; break; case ID_CHECKBOX_BACKUP: pref.savedict = (CtlGetValue(cp) ? true : false); dic = DmOpenDatabaseByTypeCreator(DICTYPE,CREATORID,dmModeReadWrite); if(dic){ // 本体に辞書があるときだけバックアップ SetBackupBit(dic,pref.savedict); DmCloseDatabase(dic); } break; case ID_BUTTON_NEARCURSOR: pref.dispbottom = (CtlGetValue(cp) ? false : true); break; case ID_BUTTON_BOTTOM: pref.dispbottom = (CtlGetValue(cp) ? true : false); break; case ID_BUTTON_USESPACE: pref.spacefortankanji = (CtlGetValue(cp) ? true : false); break; case ID_BUTTON_USERETURN: pref.spacefortankanji = (CtlGetValue(cp) ? false : true); break; case ID_BUTTON_RIGHTHANDED: pref.righthanded = (CtlGetValue(cp) ? true : false); break; case ID_BUTTON_LEFTHANDED: pref.righthanded = (CtlGetValue(cp) ? false : true); break; default: break; } PrefSetAppPreferences(CREATORID,0,1,&pref,sizeof(pref),true); break; case frmLoadEvent: frm = FrmInitForm(e->data.frmLoad.formID); ErrFatalDisplayIf(frm==NULL,"Null FormPtr"); FrmSetActiveForm(frm); FrmSetEventHandler(frm, MainAppFormEvent); handled = true; break; case frmOpenEvent: GetFeaturePref(FEATURE_USEPOBOX,&use,false); cp = GetObjPtr(ID_CHECKBOX_USEPOBOX); CtlSetValue(cp,use ? 1 : 0); PrefGetAppPreferences(CREATORID,0,&pref,&prefsize,true); cp = GetObjPtr(ID_CHECKBOX_BACKUP); CtlSetValue(cp,pref.savedict ? 1 : 0); cp = GetObjPtr(ID_BUTTON_BOTTOM); CtlSetValue(cp,pref.dispbottom ? 1 : 0); cp = GetObjPtr(ID_BUTTON_NEARCURSOR); CtlSetValue(cp,pref.dispbottom ? 0 : 1); cp = GetObjPtr(ID_BUTTON_USESPACE); CtlSetValue(cp,pref.spacefortankanji ? 1 : 0); cp = GetObjPtr(ID_BUTTON_USERETURN); CtlSetValue(cp,pref.spacefortankanji ? 0 : 1); cp = GetObjPtr(ID_BUTTON_RIGHTHANDED); CtlSetValue(cp,pref.righthanded ? 1 : 0); cp = GetObjPtr(ID_BUTTON_LEFTHANDED); CtlSetValue(cp,pref.righthanded ? 0 : 1); FrmDrawForm(FrmGetActiveForm()); handled = true; break; default: break; } return handled; } void InitApplication() { POBoxPref pref; DmOpenRef dic; UInt16 prefsize; FrmGotoForm(ID_APPFORM); dic = DmOpenDatabaseByTypeCreator(DICTYPE,CREATORID,dmModeReadWrite); // ErrFatalDisplayIf(dic==NULL,"Can't open PBInline DB"); if(dic){ pref.savedict = BackupBit(dic); DmCloseDatabase(dic); } else pref.savedict = false; if(PrefGetAppPreferences(CREATORID,0,&pref,&prefsize,true) == noPreferenceFound){ pref.dispbottom = false; pref.spacefortankanji = false; pref.righthanded = true; PrefSetAppPreferences(CREATORID,0,1,&pref,sizeof(pref),true); } } void StopApplication() { } UInt32 PilotMain(UInt16 cmd, Ptr cmdPBP, UInt16 launchFlags) { EventType event; UInt16 error; if (cmd == sysAppLaunchCmdNormalLaunch) { InitApplication(); do { EvtGetEvent(&event, evtWaitForever); if (SysHandleEvent(&event)) continue; if (MenuHandleEvent(NULL, &event, &error)) continue; if (ApplicationHandleEvent(&event)) continue; FrmDispatchEvent(&event); } while (event.eType != appStopEvent); StopApplication(); } return 0; } #endif