#define	STRICT
#include	<windows.h>
#include	<windowsx.h>
#include	<commctrl.h>
#include	<tchar.h>
#include	"aygshell.h"
#include	"sip.h"
#include	"kctrl.h"
#include	"controls.h"
#include	"resource.h"
#include	"pobox.h"
#include	"jpconv.h"

enum ShiftMode {
	KEY_NORMAL = 0, KEY_CAPSHIFT, KEY_SHIFT, KEY_CAPS
} ;

extern "C" {
	DWORD	g_dwAppVersion = 10 ;
	TCHAR	MessageBuf[ 512 ] ;
	TCHAR	g_szDictBase[ MAX_PATH ] = TEXT("\\Dic") ;
	DWORD	g_dwSoftKey = 1 ;			/* 0:NONE, 1:HIRA, 2:ROMA, 3:1LINE */
	BOOL	g_fSaveDic = FALSE ;		/* 辞書保存フラグ */
	BOOL	g_fPredict = TRUE ;			/* 予測表示フラグ */
	DWORD	g_dwSelColor = 0x00FFFFFF ;

	DWORD	g_dwWidth = 240 ;
	DWORD	g_dwConfirmH = 20 ;
	DWORD	g_dwKeyH = 80 ;
	DWORD	g_dwHeight = 20+CANDHEIGHT+80+6 ;

	BOOL	check_next_key() ;

	extern	DWORD	g_dwFontH ;
} ;

RomaText	g_Roma ;
InputMode	inputmode = JAPANESE ;
LPCSTR		g_szPrevSel = 0 ;

#define		isalpha(c)	(((c)>='a'&&(c)<='z')||((c)>='A'&&(c)<='Z'))

int
strwidth( LPCSTR str )
{
	return strlen( str ) * GetFontHW() ;
}

BOOL
havealpha( LPCSTR s )
{
	for ( ; *s ; s ++ ) {
		if ( isalpha( *s ) ) {
			return 1 ;
		}
	}
	return 0 ;
}

BOOL
check_next_key()
{
	return FALSE ;
}

class POBoxCtrl {
protected:
	HWND		m_hwnd ;
	HWND		m_hwndParent ;	/* コントロールの親ウィンドウ */
	WORD		m_idCtrl ;		/* コントロールの識別番号 */
	IIMCallback	*m_pCallback ;
	HWND		m_hwndCurrent ;
	HWND		m_hwndText ;
	HWND		m_hwndCand ;
	HWND		m_hwndRoma ;
	HWND		m_hwndHira ;
	HWND		m_hwndNormal ;
	HWND		m_hwndShift ;
	CHAR		m_sFixed[ 256 ] ;
	DWORD		m_dwMuhenkan ;
	enum ShiftMode	m_smShifted ;

public:
	POBoxCtrl() : m_hwnd(0), m_hwndParent(0), m_idCtrl(0), m_pCallback(NULL),
				  m_hwndCurrent(0), m_dwMuhenkan(ROMA_NORMAL), m_smShifted(KEY_NORMAL) {
		m_sFixed[0] = 0 ;
	}
	~POBoxCtrl() {}

	void	WMCreate( HWND hWnd, LPCREATESTRUCT lpcs ) ;
	void	CreateCtrl( HINSTANCE hInst, HWND hWnd, DWORD w, DWORD h ) ;
	void	ChangeKeyMode( DWORD w, DWORD h ) ;
	void	WMDestroy() ;
	void	Show( BOOL fShow ) ;

	void	SetCallback( IIMCallback *pCb ) { m_pCallback = pCb ; }
	void	SendVirtualKey( BYTE bVK, DWORD dwFlags ) const ;
	void	SendCharEvents( UINT uVK, UINT uKeyFlags, UINT uChars, UINT *puShift, UINT *puChars ) const ;
	void	SendString( LPTSTR ptszString, DWORD dwSize ) const ;
	void	SendText( LPCSTR szText ) const ;
	BOOL	ConfirmInput() ;
	BOOL	ConfirmFixed() ;

	LRESULT	WMCommand( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam ) ;
	void	SetCurrent( HWND hWnd ) ;
	BOOL	IsCurrent( HWND hWnd ) const ;
	BOOL	CommandKey( Key* key ) ;
	void	JpnKey( Key* key1 ) ;
	void	NormalKey( Key* key ) ;
	void	CandKey( Key* key1 ) ;
	void	KeyEnter() ;
	void	KeyESC() ;
	void	KeyBS() ;
	void	KeyUp() ;
	void	KeyDown() ;
	void	KeySpace( BOOL fForceSpace ) ;
	BOOL	AddDict() ;
	void	AltConv() ;
	DWORD	GetSelect() const ;
	void	ToMuhenkan() ;
	void	NextCand() ;
	void	PrevCand() ;
	void	ChangeMuhenkan( WORD id ) ;
	BOOL	GetFromClipboard( LPTSTR unicode, DWORD dstsize ) ;
	void	SetConfirm( LPCSTR szFixed, LPCSTR szInput ) const ;

	friend	LRESULT CALLBACK	POBoxCtrlWndProc( HWND hWnd,  UINT msg, WPARAM wParam, LPARAM lParam ) ;
} ;
typedef	POBoxCtrl	*PPOBoxCtrl ;

void
POBoxCtrl::WMCreate( HWND hWnd, LPCREATESTRUCT lpcs )
{
	RECT		rect ;
	DWORD		y = 0 ;

	m_hwnd = hWnd ;
	m_hwndParent = lpcs->hwndParent ;
	m_idCtrl = (WORD) lpcs->hMenu ;
	g_dwConfirmH = g_dwFontH + 2 ;

	CreateCtrl( lpcs->hInstance, m_hwnd, g_dwWidth, g_dwHeight ) ;

	GetWindowRect( m_hwndParent, &rect ) ;
	y = rect.top - g_dwConfirmH ;
	m_hwndText = ::CreateWindow( CTRL_CONFIRM,
						TEXT(""),
						WS_POPUP|WS_BORDER,
						0, y, g_dwWidth - 17, g_dwConfirmH,
						m_hwndParent,
						(HMENU) IDC_TEXT,
						lpcs->hInstance, 0 ) ;
	SendMessage( m_hwndText, CONFIRM_SETCOLSEL, 0, (LPARAM) g_dwSelColor ) ;
//	y += g_dwConfirmH + 2 ;
}

void
POBoxCtrl::CreateCtrl( HINSTANCE hInst, HWND hWnd, DWORD w, DWORD h )
{
	DWORD		y = 0 ;

	y = 0 ;
	m_hwndCand = ::CreateWindow( CTRL_SOFTKEY,
						TEXT(""),
						WS_CHILD|WS_VISIBLE,
						CANDLEFT, y, CANDWIDTH, CANDHEIGHT,
						hWnd,
						(HMENU) IDC_CANDKEY,
						hInst, 0 ) ;
	SendMessage( m_hwndCand, SOFTKEY_SETLIST, 0, (LPARAM) candkey ) ;
	SendMessage( m_hwndCand, SOFTKEY_SETCOLSEL, 0, (LPARAM) g_dwSelColor ) ;
	SendMessage( m_hwndCand, SOFTKEY_SETPARENT, (WPARAM) m_hwnd, 0 ) ;

	m_hwndRoma = ::CreateWindow( CTRL_SOFTKEY,
						TEXT(""),
						WS_CHILD|WS_VISIBLE,
						0, y, w, g_dwKeyH,
						hWnd,
						(HMENU) IDC_ROMAKEY,
						hInst, 0 ) ;
	SendMessage( m_hwndRoma, SOFTKEY_SETLIST, 0, (LPARAM) g_KeyRoma ) ;
	SendMessage( m_hwndRoma, SOFTKEY_SETBITMAP, 0,
				 (LPARAM) LoadBitmap( hInst, MAKEINTRESOURCE(IDB_ROMAKEY) ) ) ;
	SendMessage( m_hwndRoma, SOFTKEY_SETCOLSEL, 0, (LPARAM) g_dwSelColor ) ;
	ShowWindow( m_hwndRoma, SW_HIDE ) ;

	m_hwndHira = ::CreateWindow( CTRL_SOFTKEY,
						TEXT(""),
						WS_CHILD|WS_VISIBLE,
						0, y, w, g_dwKeyH,
						hWnd,
						(HMENU) IDC_HIRAKEY,
						hInst, 0 ) ;
	SendMessage( m_hwndHira, SOFTKEY_SETLIST, 0, (LPARAM) g_KeyHira ) ;
	SendMessage( m_hwndHira, SOFTKEY_SETBITMAP, 0,
				 (LPARAM) LoadBitmap( hInst, MAKEINTRESOURCE(IDB_HIRAKEY) ) ) ;
	SendMessage( m_hwndHira, SOFTKEY_SETCOLSEL, 0, (LPARAM) g_dwSelColor ) ;
	ShowWindow( m_hwndHira, SW_HIDE ) ;

	m_hwndNormal = ::CreateWindow( CTRL_SOFTKEY,
						TEXT(""),
						WS_CHILD|WS_VISIBLE,
						0, y, w, g_dwKeyH,
						hWnd,
						(HMENU) IDC_NORMALKEY,
						hInst, 0 ) ;
	SendMessage( m_hwndNormal, SOFTKEY_SETLIST, 0, (LPARAM) g_KeyNormal ) ;
	SendMessage( m_hwndNormal, SOFTKEY_SETBITMAP, 0,
				 (LPARAM) LoadBitmap( hInst, MAKEINTRESOURCE(IDB_NORMALKEY) ) ) ;
	SendMessage( m_hwndNormal, SOFTKEY_SETCOLSEL, 0, (LPARAM) g_dwSelColor ) ;
	ShowWindow( m_hwndNormal, SW_HIDE ) ;

	m_hwndShift = ::CreateWindow( CTRL_SOFTKEY,
						TEXT(""),
						WS_CHILD|WS_VISIBLE,
						0, y, w, g_dwKeyH,
						hWnd,
						(HMENU) IDC_SHIFTKEY,
						hInst, 0 ) ;
	SendMessage( m_hwndShift, SOFTKEY_SETLIST, 0, (LPARAM) g_KeyShift ) ;
	SendMessage( m_hwndShift, SOFTKEY_SETBITMAP, 0,
				 (LPARAM) LoadBitmap( hInst, MAKEINTRESOURCE(IDB_SHIFTKEY) ) ) ;
	SendMessage( m_hwndShift, SOFTKEY_SETCOLSEL, 0, (LPARAM) g_dwSelColor ) ;
	ShowWindow( m_hwndShift, SW_HIDE ) ;

	y += g_dwKeyH + 2 ;

	ChangeKeyMode( w, h ) ;
}

void
POBoxCtrl::ChangeKeyMode( DWORD w, DWORD h )
{
	inputmode = JAPANESE ;
	if ( m_hwndCurrent ) {
		ShowWindow( m_hwndCurrent, SW_HIDE ) ;
	}
	switch ( g_dwSoftKey ) {
	case 1:
		/* かなキーボード */
		m_hwndCurrent = m_hwndHira ;
		ShowWindow( m_hwndCurrent, SW_SHOW ) ;
		break ;
	case 2:
		/* ローマ字キーボード */
		m_hwndCurrent = m_hwndRoma ;
		ShowWindow( m_hwndCurrent, SW_SHOW ) ;
		break ;
	}
//ComPOBox用に候補一覧を短くしたため
//	g_CandPos.width = w, g_CandPos.height = CANDHEIGHT ;
}

void
POBoxCtrl::WMDestroy()
{
	DestroyWindow( m_hwndText ) ;
	DestroyWindow( m_hwndCand ) ;
//	DestroyWindow( m_hwndCtrl ) ;
}

void
POBoxCtrl::Show( BOOL fShow )
{
	ShowWindow( m_hwnd,     fShow ? SW_SHOW   : SW_HIDE ) ;
	if ( fShow ) {
		ShowWindow( m_hwndCand, !(m_hwndCurrent == m_hwndNormal || m_hwndCurrent == m_hwndShift) ? SW_SHOWNA : SW_HIDE ) ;
		SetConfirm( 0, 0 ) ;
	} else {
		ShowWindow( m_hwndText, SW_HIDE ) ;
		ShowWindow( m_hwndCand, SW_HIDE ) ;
	}
}

void
POBoxCtrl::SendVirtualKey( BYTE bVK, DWORD dwFlags ) const
{
	if ( m_pCallback ) {
		m_pCallback->SendVirtualKey( bVK, dwFlags ) ;
	}
}

void
POBoxCtrl::SendCharEvents( UINT uVK, UINT uKeyFlags, UINT uChars, UINT *puShift, UINT *puChars ) const
{
	if ( m_pCallback ) {
		m_pCallback->SendCharEvents( uVK, uKeyFlags, uChars, puShift, puChars ) ;
	}
}

void
POBoxCtrl::SendString( LPTSTR ptszString, DWORD dwSize ) const
{
	if ( m_pCallback ) {
		m_pCallback->SendString( ptszString, dwSize ) ;
	}
}

#define KeyStateDownFlag            0x0080

void
POBoxCtrl::SendText( LPCSTR sjis ) const
{
	UINT	uShift, uChar ;
	TCHAR	c, unicode[ 256 ] ;
	BOOL	bVisibleText ;

	bVisibleText = IsWindowVisible( m_hwndText ) ;
	if ( bVisibleText ) {
		ShowWindow( m_hwndText, SW_HIDE ) ;
	}
	sjis2unicode( (LPBYTE) sjis, unicode, sizeof unicode ) ;
	c = *unicode ;
	switch ( c ) {
	case TEXT('\n'):
	case TEXT('\r'):
		uShift = KeyStateDownFlag ;
		uChar  = '\r' ;
		SendCharEvents( VK_RETURN, KeyStateDownFlag, 1, &uShift, &uChar ) ;
		break ;
	case 0x08:
		SendVirtualKey( VK_BACK, KEYEVENTF_SILENT ) ;
		break ;
	case 0x1B:
		uShift = KeyStateDownFlag ;
		uChar  = '\033' ;
		SendCharEvents( VK_ESCAPE, KeyStateDownFlag, 1, &uShift, &uChar ) ;
		break ;
	case 0:
		break ;
	default:
		SendString( unicode, _tcslen( unicode ) ) ;
		break ;
	}
	if ( bVisibleText ) {
		ShowWindow( m_hwndText, SW_SHOWNA ) ;
	}
}

/*
 * 入力中の未確定文字列を確定する
 */
BOOL
POBoxCtrl::ConfirmInput()
{
	if ( !strlen( hstr ) ) {
		return FALSE ;
	}
	g_Roma.getmuhenkan( m_dwMuhenkan, &m_sFixed[ strlen( m_sFixed ) ] ) ;
	m_dwMuhenkan = ROMA_NORMAL ;
	g_Roma.clear() ;
	g_Roma.getkana( hstr ) ;
	makecand( NEWCAND, FALSE ) ;
	SetConfirm( m_sFixed, 0 ) ;
	return TRUE ;
}

/*
 * 入力中の確定文字列を送信する
 */
BOOL
POBoxCtrl::ConfirmFixed()
{
	if ( !strlen( m_sFixed ) ) {
		return FALSE ;
	}
	SendText( m_sFixed ) ;
	strcpy( m_sFixed, "" ) ;
	SetConfirm( m_sFixed, 0 ) ;
	return TRUE ;
}

LRESULT
POBoxCtrl::WMCommand( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
	WORD	notifyCode = HIWORD(wParam), cmd = LOWORD(wParam) ;

	switch ( cmd ) {
	case IDC_ROMAKEY:
	case IDC_HIRAKEY:
		JpnKey( (Key*) lParam ) ;
		break ;
	case IDC_NORMALKEY:
		NormalKey( (Key*) lParam ) ;
		break ;
	case IDC_SHIFTKEY:
		NormalKey( (Key*) lParam ) ;
		break ;
	case IDC_CANDKEY:
		CandKey( (Key*) lParam ) ;
		break ;
//	case IDM_ENTER:
//		KeyEnter() ;
//		break ;
//	case IDM_ESCAPE:
//		KeyESC() ;
//		break ;
//	case IDM_UP:
//		KeyUp() ;
//		break ;
//	case IDM_DOWN:
//		KeyDown() ;
//		break ;
	}
	return 0 ;
}

void
POBoxCtrl::SetCurrent( HWND hWnd )
{
	if ( !hWnd || hWnd == m_hwndCurrent ) {
		return ;
	}
	ShowWindow( hWnd, SW_SHOW ) ;
	if ( m_hwndCurrent ) {
		ShowWindow( m_hwndCurrent, SW_HIDE ) ;
	}
	m_hwndCurrent = hWnd ;
	ShowWindow( m_hwndCand, !(m_hwndCurrent == m_hwndNormal || m_hwndCurrent == m_hwndShift) ? SW_SHOWNA : SW_HIDE ) ;
	SetConfirm( 0, 0 ) ;
}

BOOL
POBoxCtrl::IsCurrent( HWND hWnd ) const
{
	return m_hwndCurrent == hWnd ;
}

BOOL
POBoxCtrl::CommandKey( Key* key )
{
	if ( !strcmp( key->str, ENTERSTR ) ) {
		/* 改行 */
		KeyEnter() ;
	} else if ( !strcmp( key->str, MODSTR ) ) {
		/* 登録 */
		AddDict() ;
	} else if ( !strcmp( key->str, DELSTR ) ) {
		/* 削除 */
		KeyBS() ;
	} else if ( !strcmp( key->str, CANSTR ) ) {
		/* 取消 */
		KeyESC() ;
	} else if ( !strcmp( key->str, ALTSTR ) ) {
		/* 異体字 */
		AltConv() ;
	} else if ( !strcmp( key->str, PREVSTR ) ) {
		/* 前候補 */
		PrevCand() ;
	} else if ( !strcmp( key->str, NEXTSTR ) ) {
		/* 次候補 */
		NextCand() ;
	} else {
		return FALSE ;
	}
	SetConfirm( 0, hstr ) ;
	InvalidateRect( m_hwndCand, NULL, TRUE ) ;
	return TRUE ;
}

void
POBoxCtrl::JpnKey( Key* key1 )
{
	if ( CommandKey( key1 ) ) {
		return ;
	}
	if ( !strcmp( key1->str, UPSTR ) ) {
		if ( strlen( hstr ) || strlen( m_sFixed ) ) {
			PrevCand() ;
		} else {
			SendVirtualKey( VK_UP, KEYEVENTF_SILENT ) ;
		}
	} else if ( !strcmp( key1->str, DOWNSTR ) ) {
		if ( strlen( hstr ) || strlen( m_sFixed ) ) {
			NextCand() ;
		} else {
			SendVirtualKey( VK_DOWN, KEYEVENTF_SILENT ) ;
		}
	} else if ( !strcmp( key1->str, LEFTSTR ) ) {
		if ( strlen( hstr ) || strlen( m_sFixed ) ) {
			KeyUp() ;
		} else {
			SendVirtualKey( VK_LEFT, KEYEVENTF_SILENT ) ;
		}
	} else if ( !strcmp( key1->str, RIGHTSTR ) ) {
		if ( strlen( hstr ) || strlen( m_sFixed ) ) {
			KeyDown() ;
		} else {
			SendVirtualKey( VK_RIGHT, KEYEVENTF_SILENT ) ;
		}
	} else if ( !strcmp( key1->str, HANSTR ) ) {
		ChangeMuhenkan( IDM_HAN ) ;
		return ;
	} else if ( !strcmp( key1->str, ZENSTR ) ) {
		ChangeMuhenkan( IDM_ROMA ) ;
		return ;
	} else if ( !strcmp( key1->str, KATASTR ) ) {
		ChangeMuhenkan( IDM_ZENKATA ) ;
		return ;
	} else if ( !strcmp( key1->str, ENGSTR ) ) {
		inputmode = ENGLISH ;
		m_smShifted = KEY_NORMAL ;
		SetCurrent( m_hwndNormal ) ;
		SetConfirm( 0, hstr ) ;
		InvalidateRect( m_hwndCand, NULL, TRUE ) ;
		return ;
	} else if ( inputmode == JAPANESE ) {
		if ( !strcmp( key1->yomi, " " ) ) {
			KeySpace( TRUE ) ;
		} else {
			m_dwMuhenkan = ROMA_NORMAL ;
			if ( g_dwSoftKey == 1 ) {
				g_Roma.addstr( key1->yomi ) ;
			} else {
				g_Roma.addromachar( (CHAR) *key1->yomi ) ;
			}
			g_Roma.getkana( hstr ) ;
			makecand( NEWCAND, FALSE ) ;
			SendMessage( m_hwndCand, SOFTKEY_SETCUR, 0, 0 ) ;
		}
	} else {
		ConfirmInput() ;
		strcat( m_sFixed, key1->yomi ) ;
		ConfirmFixed() ;
	}
	SetConfirm( 0, hstr ) ;
	InvalidateRect( m_hwndCand, NULL, TRUE ) ;
}

void
POBoxCtrl::NormalKey( Key* key )
{
	if ( CommandKey( key ) ) {
		return ;
	}
	if ( !strcmp( key->str, UPSTR ) ) {
		SendVirtualKey( VK_UP, KEYEVENTF_SILENT ) ;
	} else if ( !strcmp( key->str, DOWNSTR ) ) {
		SendVirtualKey( VK_DOWN, KEYEVENTF_SILENT ) ;
	} else if ( !strcmp( key->str, LEFTSTR ) ) {
		SendVirtualKey( VK_LEFT, KEYEVENTF_SILENT ) ;
	} else if ( !strcmp( key->str, RIGHTSTR ) ) {
		SendVirtualKey( VK_RIGHT, KEYEVENTF_SILENT ) ;
	} else if ( !strcmp( key->str, TABSTR ) ) {
		SendVirtualKey( VK_TAB, KEYEVENTF_SILENT ) ;
	} else if ( !strcmp( key->str, JPNSTR ) ) {
		inputmode = JAPANESE ;
		m_smShifted = KEY_NORMAL ;
		SetCurrent( g_dwSoftKey == 1 ? m_hwndHira : m_hwndRoma ) ;
		SetConfirm( 0, hstr ) ;
		InvalidateRect( m_hwndCand, NULL, TRUE ) ;
		return ;
	} else if ( !strcmp( key->str, SFTSTR ) ) {
		switch ( m_smShifted ) {
		case KEY_NORMAL:	m_smShifted = KEY_SHIFT ;		break ;
		case KEY_CAPSHIFT:	m_smShifted = KEY_CAPS ;		break ;
		case KEY_SHIFT:		m_smShifted = KEY_NORMAL ;		break ;
		case KEY_CAPS:		m_smShifted = KEY_CAPSHIFT ;	break ;
		}
		SetCurrent( m_smShifted == KEY_SHIFT || m_smShifted == KEY_CAPS ? m_hwndShift : m_hwndNormal ) ;
		return ;
	} else if ( !strcmp( key->str, CAPSTR ) ) {
		switch ( m_smShifted ) {
		case KEY_NORMAL:	m_smShifted = KEY_CAPS ;		break ;
		case KEY_CAPSHIFT:	m_smShifted = KEY_SHIFT ;		break ;
		case KEY_SHIFT:		m_smShifted = KEY_CAPSHIFT ;	break ;
		case KEY_CAPS:		m_smShifted = KEY_NORMAL ;		break ;
		}
		SetCurrent( m_smShifted == KEY_SHIFT || m_smShifted == KEY_CAPS ? m_hwndShift : m_hwndNormal ) ;
		return ;
	} else {
		JpnKey( key ) ;
		switch ( m_smShifted ) {
		case KEY_SHIFT:
			m_smShifted = KEY_NORMAL ;
			SetCurrent( m_hwndNormal ) ;
			break ;
		case KEY_CAPSHIFT:
			m_smShifted = KEY_CAPS ;
			SetCurrent( m_hwndShift ) ;
			break ;
		}
	}
}

void
POBoxCtrl::CandKey( Key* key1 )
{
	strcat( outstr, key1->str ) ;
	if ( inputmode == ENGLISH ) {
		strcat( m_sFixed, " " ) ;
	}
	havealpha( key1->str ) ;
	g_Roma.clear() ;
	g_Roma.getkana( hstr ) ;
	g_szPrevSel = addphrase( g_szPrevSel, key1->str, key1->yomi, FALSE ) ;
	strcat( m_sFixed, key1->str ) ;
	makecand( NEWCAND, FALSE ) ;
	SetConfirm( m_sFixed, hstr ) ;
	SendMessage( m_hwndCand, SOFTKEY_SETCUR, 0, 0 ) ;
	InvalidateRect( m_hwndCand, NULL, TRUE ) ;
}

/*
 * 改行
 */
void
POBoxCtrl::KeyEnter()
{
	if ( g_dwNumCand && GetSelect() ) {
		Key*	key = (Key*) SendMessage( m_hwndCand, SOFTKEY_GETCURCAND, 0, 0 ) ;
		if ( key ) {
			CandKey( key ) ;
			return ;
		}
		SendMessage( m_hwndCand, SOFTKEY_SETCUR, 0, 0 ) ;
	}
	if ( ConfirmInput() ) {
	} else if ( ConfirmFixed() ) {
	} else {
		SendText( "\n" ) ;
	}
	SetConfirm( 0, hstr ) ;
	InvalidateRect( m_hwndCand, NULL, TRUE ) ;
}

/*
 * 取消
 */
void
POBoxCtrl::KeyESC()
{
	if ( g_dwNumCand && GetSelect() ) {
		/* 取消(候補の取消) */
		SendMessage( m_hwndCand, SOFTKEY_SETCUR, 0, 0 ) ;
		return ;
	}
	if ( strlen( hstr ) ) {
		m_dwMuhenkan = ROMA_NORMAL ;
		g_Roma.clear() ;
		g_Roma.getkana( hstr ) ;
	} else if ( strlen( m_sFixed ) ) {
		strcpy( m_sFixed, "" ) ;
		SetConfirm( m_sFixed, 0 ) ;
	} else {
		/* 取消キーを送る */
		SendText( "\x1B" ) ;
		return ;
	}
	makecand( NEWCAND, FALSE ) ;
	SetConfirm( 0, hstr ) ;
	InvalidateRect( m_hwndCand, NULL, TRUE ) ;
}

/*
 * 削除
 */
void
POBoxCtrl::KeyBS()
{
	int		len ;
	TCHAR	unicode[ 256 ] ;

	if ( *hstr ) {
		if ( GetSelect() ) {
			SendMessage( m_hwndCand, SOFTKEY_SETCUR, 0, 0 ) ;
			return ;
		}
		/* 入力中の文字を削除する */
		m_dwMuhenkan = ROMA_NORMAL ;
		g_Roma.backspace() ;
		g_Roma.getkana( hstr ) ;
		makecand( NEWCAND, FALSE ) ;
	} else {
		sjis2unicode( (LPBYTE) m_sFixed, unicode, sizeof unicode ) ;
		len = _tcslen( unicode ) ;
		if ( len ) {
			/* 入力済の文字を削除する */
			unicode[ -- len ] = 0 ;
			unicode2sjis( unicode, (LPBYTE) m_sFixed, sizeof m_sFixed ) ;
			SetConfirm( m_sFixed, 0 ) ;
		} else {
			/* BSキーを送る */
			SendText( "\x08" ) ;
		}
	}
	SetConfirm( 0, hstr ) ;
	InvalidateRect( m_hwndCand, NULL, TRUE ) ;
}

/*
 * 上キー
 */
void
POBoxCtrl::KeyUp()
{
	DWORD	ret = GetSelect() ;

	if ( ret > 1 ) {
		SendMessage( m_hwndCand, SOFTKEY_SETCUR, 0, ret - 1 ) ;
	} else {
		if ( g_dwCandIndex ) {
			makecand( PREVCAND, FALSE ) ;
			SendMessage( m_hwndCand, SOFTKEY_SETCUR, 0, g_dwNumCand ) ;
		} else if ( ret ) {
			SendMessage( m_hwndCand, SOFTKEY_SETCUR, 0, 0 ) ;
		}
	}
}

/*
 * 下キー
 */
void
POBoxCtrl::KeyDown()
{
	int		ret = GetSelect() + 1 ;

	if ( check_abort() ) {
		makecand( NEWCAND, TRUE ) ;
	}
	if ( !g_dwNumCand ) {
		return ;
	} else if ( ret > g_dwNumCand ) {
		makecand( NEXTCAND, FALSE ) ;
		ret = 1 ;
	}
	SendMessage( m_hwndCand, SOFTKEY_SETCUR, 0, ret ) ;
}

/*
 * 候補選択
 */
void
POBoxCtrl::KeySpace( BOOL fForceSpace )
{
	int		len ;

	if ( !g_dwNumCand || fForceSpace ) {
		/* 空白文字列を追加する場合 */
		if ( strlen( hstr ) ) {
			g_Roma.getmuhenkan( m_dwMuhenkan, &m_sFixed[ strlen( m_sFixed ) ] ) ;
			m_dwMuhenkan = ROMA_NORMAL ;
			g_Roma.clear() ;
			g_Roma.getkana( hstr ) ;
		}
		len = strlen( m_sFixed ) ;
		if ( len && m_sFixed[ len - 1 ] == ' ' ) {
			strcpy( &m_sFixed[ len - 1 ], "　" ) ;
		} else {
			m_sFixed[ len ++ ] = ' ' ;
			m_sFixed[ len ] = 0 ;
		}
		makecand( NEWCAND, FALSE ) ;
		SetConfirm( m_sFixed, hstr ) ;
		SendMessage( m_hwndCand, SOFTKEY_SETCUR, 0, 0 ) ;
		InvalidateRect( m_hwndCand, NULL, TRUE ) ;
	} else {
		KeyDown() ;
	}
}

BOOL
POBoxCtrl::AddDict()
{
	TCHAR	unicode[ 128 ] ;

	if ( !*hstr || !*m_sFixed ) {
		/* 登録文字列がない場合はクリップボードを参照 */
		if ( !GetFromClipboard( unicode, sizeof unicode ) ) {
			MessageBeep( MB_ICONHAND ) ;
		} else {
			/* クリップボード内の文字列を入力済文字列に移す */
			unicode2sjis( unicode, (LPBYTE) m_sFixed, sizeof m_sFixed ) ;
			SetConfirm( m_sFixed, 0 ) ;
		}
		return FALSE ;
	}
	g_szPrevSel = addphrase( g_szPrevSel, m_sFixed, hstr, TRUE ) ;
	makecand( NEWCAND, FALSE ) ;
	/* 辞書登録の後は読みを消す */
	m_dwMuhenkan = ROMA_NORMAL ;
	g_Roma.clear() ;
	g_Roma.getkana( hstr ) ;
	SetConfirm( 0, hstr ) ;
	SendMessage( m_hwndCand, SOFTKEY_SETCUR, 0, 0 ) ;
	InvalidateRect( m_hwndCand, NULL, TRUE ) ;
	MessageBeep( MB_ICONINFORMATION ) ;
	return TRUE ;
}

void
POBoxCtrl::AltConv()
{
	if ( !*hstr ) {
		return ;
	}
	itaiconv( hstr, hstr ) ;
	g_Roma.setkana( hstr ) ;
	SetConfirm( 0, hstr ) ;
	InvalidateRect( m_hwndCand, NULL, TRUE ) ;
}

DWORD
POBoxCtrl::GetSelect() const
{
	return SendMessage( m_hwndCand, SOFTKEY_GETCUR, 0, 0 ) ;
}

void
POBoxCtrl::ToMuhenkan()
{
	SendMessage( m_hwndCand, SOFTKEY_SETCUR, 0, 0 ) ;
	g_Roma.clear() ;
	g_Roma.getkana( hstr ) ;
	strcpy( m_sFixed, "" ) ;
	SetConfirm( m_sFixed, 0 ) ;
	makecand( NEWCAND, FALSE ) ;
	SetConfirm( 0, hstr ) ;
//	Hide() ;
}

void
POBoxCtrl::NextCand()
{
	makecand( NEXTCAND, FALSE ) ;
	SendMessage( m_hwndCand, SOFTKEY_SETCUR, 0, 1 ) ;
}

void
POBoxCtrl::PrevCand()
{
	makecand( PREVCAND, FALSE ) ;
	SendMessage( m_hwndCand, SOFTKEY_SETCUR, 0, 1 ) ;
}

void
POBoxCtrl::ChangeMuhenkan( WORD id )
{
	CHAR	buf[ 128 ] ;
	DWORD	muhenkan = m_dwMuhenkan ;

	switch ( id ) {
	case IDM_ZENHIRA:
		if ( *hstr ) {
			muhenkan = ROMA_ZENHIRA ;
		}
		break ;
	case IDM_ZENKATA:
		if ( *hstr ) {
			muhenkan = ROMA_ZENKATA ;
		}
		break ;
	case IDM_HAN:
		if ( *hstr ) {
			if ( muhenkan == ROMA_ZENROMA || muhenkan == ROMA_HANROMA ) {
				muhenkan = ROMA_HANROMA ;
			} else {
				muhenkan = ROMA_HANKATA ;
			}
		}
		break ;
	case IDM_ROMA:
		if ( *hstr ) {
			muhenkan = ROMA_ZENROMA ;
		}
		break ;
	}
	if ( muhenkan != m_dwMuhenkan ) {
		m_dwMuhenkan = muhenkan ;
		g_Roma.getmuhenkan( m_dwMuhenkan, buf ) ;
		SetConfirm( 0, buf ) ;
	}
}

/*
 * クリップボードからUnicode文字列を取得する
 */
BOOL
POBoxCtrl::GetFromClipboard( LPTSTR unicode, DWORD dstsize )
{
	TCHAR	c ;
	DWORD	cbsize ;
	LPCTSTR	cbptr, src ;
	BOOL	ret = FALSE ;

	/* 格納先の領域サイズを文字数に変換する */
	dstsize /= sizeof (TCHAR) ;
	if ( dstsize -- <= 1 ) {
		return FALSE ;
	}
	/* クリップボードをオープンする */
	if ( !OpenClipboard( m_hwnd ) ) {
		return FALSE ;
	}
#ifdef	_WIN32_WCE
	HLOCAL	hGMem = GetClipboardData( CF_UNICODETEXT ) ;
	cbsize = LocalSize( hGMem ) ;
	cbptr = (LPCTSTR) hGMem ;
#else	/* _WIN32_WCE */
	HGLOBAL	hGMem = GetClipboardData( CF_UNICODETEXT ) ;
	cbsize = GlobalSize( hGMem ) ;
	cbptr = (LPCTSTR) GlobalLock( hGMem ) ;
#endif	/* _WIN32_WCE */
	if ( !cbsize ) {
		goto exit ;
	}
	/* コード変換開始 */
	setup_codeconv( unicode ) ;
	src = cbptr ;
	cbsize /= sizeof (TCHAR) ;
	do {
		c = *src++ ;
		jis_unicode_char( c ) ;
	} while ( -- cbsize && -- dstsize && c ) ;
	jis_unicode_char( 0 ) ;
	putchar_codeconv( 0 ) ;
	ret = TRUE ;

exit:
#ifndef	_WIN32_WCE
	GlobalUnlock( hGMem ) ;
#endif	/* _WIN32_WCE */
	CloseClipboard() ;
	return ret ;
}

void
POBoxCtrl::SetConfirm( LPCSTR szFixed, LPCSTR szInput ) const
{
	BOOL	bShow ;

	if ( szFixed ) {
		SendMessage( m_hwndText, CONFIRM_SETFIXED, 0, (LPARAM) szFixed ) ;
	}
	if ( szInput ) {
		SendMessage( m_hwndText, CONFIRM_SETINPUT, 0, (LPARAM) szInput ) ;
	}
	bShow = !(m_hwndCurrent == m_hwndNormal || m_hwndCurrent == m_hwndShift) ;
	bShow = bShow && !SendMessage( m_hwndText, CONFIRM_ISEMPTY, 0, 0 ) ;
	ShowWindow( m_hwndText, bShow ? SW_SHOWNA : SW_HIDE ) ;
}

BOOL
POBoxCtrlRegisterClass( HINSTANCE hInst )
{
	WNDCLASS	wc ;

	wc.style         = NULL ;
	wc.lpfnWndProc   = (WNDPROC) POBoxCtrlWndProc ;
	wc.cbClsExtra    = 0 ;
	wc.cbWndExtra    = 4 ;
	wc.hInstance     = hInst ;
	wc.hIcon         = NULL ;
	wc.hCursor       = NULL ;
	wc.hbrBackground = (HBRUSH) GetStockObject( WHITE_BRUSH ) ;
	wc.lpszMenuName  = 0 ;
	wc.lpszClassName = CTRL_POBoxCtrl ;
	return ::RegisterClass( &wc ) ;
}

LRESULT CALLBACK
POBoxCtrlWndProc( HWND hWnd,  UINT msg, WPARAM wParam, LPARAM lParam )
{
	PPOBoxCtrl	pWindow ;

	if ( msg == WM_CREATE ) {
		LPCREATESTRUCT	lpStruct = (LPCREATESTRUCT) lParam ;
		pWindow = new POBoxCtrl() ;
		SetWindowLong( hWnd, 0, (LONG) pWindow ) ;
		pWindow->WMCreate( hWnd, lpStruct ) ;
		return 0 ;
	}
	pWindow = (PPOBoxCtrl) GetWindowLong( hWnd, 0 ) ;
	if ( !pWindow ) {
		return DefWindowProc( hWnd, msg, wParam, lParam ) ;
	}
	switch ( msg ) {
	case WM_DESTROY:
		pWindow->WMDestroy() ;
		delete pWindow ;
		SetWindowLong( hWnd, 0, (LONG) 0 ) ;
		break ;
	case WM_COMMAND:
		pWindow->WMCommand( hWnd, msg, wParam, lParam ) ;
		break ;
	case POBOX_SETCALLBACK:
		pWindow->SetCallback( (IIMCallback*) lParam ) ;
		break ;
	case POBOX_SHOW:
		pWindow->Show( (BOOL) wParam ) ;
		break ;
	default:
		return DefWindowProc( hWnd, msg, wParam, lParam ) ;
	}
	return 0 ;
}
