/*
Copyright 1990-2003 Sun Microsystems, Inc. All Rights Reserved.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions: The above copyright notice and this
permission notice shall be included in all copies or substantial
portions of the Software.


THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE OPEN GROUP OR SUN MICROSYSTEMS, INC. BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE EVEN IF
ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.


Except as contained in this notice, the names of The Open Group and/or
Sun Microsystems, Inc. shall not be used in advertising or otherwise to
promote the sale, use or other dealings in this Software without prior
written authorization from The Open Group and/or Sun Microsystems,
Inc., as applicable.


X Window System is a trademark of The Open Group

OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF
logo, LBX, X Window System, and Xinerama are trademarks of the Open
Group. All other trademarks and registered trademarks mentioned herein
are the property of their respective owners. No right, title or
interest in or to any trademark, service mark, logo or trade name of
Sun Microsystems, Inc. or its licensors is granted.

*/

#include "PYIM.h"

extern  JWORD     *pwNewpySym[];
extern  JINT       nGlobalSpMode;     /* Defined in Cmso.c */

/* KeysymType.c */
JINT    IsWantedKeysym(JINT *pks);
JINT    IsQuitKeysym(JINT *pks);
JINT    IsQpSpSwitchKeysym(JINT *pks);
JINT    IsEditKeysym(JINT *pks);
JINT    IsPageKeysym(JINT *pks);
JINT    IsSelectKeysym(JINT *pks);

/* Jword.c */
VOID    GetAsciiFromJword(JWORD* pwJwordArray, CHAR* szAsciiArray, JINT nLen);
JINT    JwordValidLen(JWORD* pwJwordArray, JINT nMaxLen);
JINT    JwordStrStrReplace(JWORD* pwDst, JWORD* pwSrc1, JWORD* pwSrc2, JINT nLenSrc2);
JWORD*  StrToJword(CHAR* szStr);
VOID    JwordInfo(JWORD* pwJwordArray, JINT nMaxLen);
VOID    Jword2Uchar(JWORD* pwJword, UCHAR* szUch, JINT nMaxLen);
UCHAR*  RecovDyz2244(UCHAR *szDyz2244);
JWORD*  RecovDyzNWord2244(JWORD* pwDyz2244, JINT nMaxLen);

/* ParsePreedit.c */
VOID    DecompPeIntArray(JINT *pnOutPreedit, CHAR* szDspPreedit);
VOID    ParseRawInputStr(char* szPreedit, int* pnOutPreedit);

/* Cmso.c */
VOID    InitSge(SesGuiElement* pSgeStruct);

JINT    IMPinyinTrans(JINT* pKsThis, SesGuiElement* pSge);  
JINT    OnEditKeysym(JINT* pNextKeysym, SesGuiElement* pSge);
JINT    OnPageKeysym(JINT* pNextKeysym, SesGuiElement* pSge);
JINT    OnSelectKeysym(JINT* pNextKeysym, SesGuiElement* pSge);
JINT    PixWidBetween (JWORD* pwPrsStr, JINT nFrom, JINT nTo);
JINT    PixWidBetween_SP (JWORD* pwPrsStr, JINT nFrom, JINT nTo);
VOID    GetDspPEandCaretPos (SesGuiElement* pSge);
VOID    GetDspPEandCaretPos_PS (SesGuiElement* pSge);
JINT    RestoreHzToPy(SesGuiElement* pSge, JINT nResFlag);
JINT    YjCodeToYjStr(JINT nYjCode, CHAR* szYjStr);
JINT    IsIntArrayEqual (JINT *pnIntArray1, JINT *pnIntArray2, JINT nLen);
VOID    PraseMixRawPe(SesGuiElement* pSge);
JINT    QpCaretToPrsCaret(JWORD* pwPrsStr, JINT nQpCaret);

VOID    GetFirst9Yj(JINT* pnPrsYj, JINT* pnF9Yj, JINT* pnLen, JINT* pnMatchMode);
JINT    LookupCiku(JINT* pnOrgYj, JINT nLenYj, JINT nMatchMode, SysCandi* psc, UdcCandi* puc);

JINT    GetXrdCandi(SysCandi* psc, UdcCandi* puc, JINT nXrd, JWORD* pwOneCandi);
VOID    ScrollViewCandiPage(SysCandi* psc, UdcCandi* puc, SesGuiElement* pSge);
VOID    ListCandiInfo(SysCandi *psc, UdcCandi *puc);
JWORD   RecovDyzWord2244(JWORD wDyz2244);

JINT    TypeOfSpMixWord(JWORD *pwSpMix, JINT nPos, JINT nKeyLayMode);
JINT    OnSelectKeysym_SP(JINT* pNextKeysym, SesGuiElement* pSge);
JINT    RestoreHzToPy_SP(SesGuiElement* pSge, JINT nResFlag);
VOID    SpMix2QpMix(JWORD* pwSpMix, JWORD* pwMix, JINT nSpCaret, JINT *pnCaret, JINT nKeyLayMode);
JINT    OnEditKeysym_SP(JINT* pNextKeysym, SesGuiElement* pSge, JINT nKeyLayMode);

/* PyBasic.c */
JINT    TypeOfSpChar(CHAR *pszOrgSp, JINT nPos, JINT nKeyLayMode);
JINT    IsValidSpSuite(CHAR chSM, CHAR chYM, JINT nKeyLayMode);

VOID    GetIehFromSge(ImToXSun *pIeh, SesGuiElement* pSge);
VOID    ProcSymbIMKey(SesGuiElement* pSge, JINT nSymbType, JINT *pNextKeysym, ImToXSun *pIeh);
JINT    PrepareSymbolSge(SesGuiElement* pSge, JINT nSymbType);

VOID ProcAllKeysym(JINT* pKsThis, SesGuiElement* pSge)
{
	JINT    i;
	JINT    nKsLen;
	
	nKsLen = 0;
	/* for (i = 0; (i < SUN_NUM_KEYSYM) && (pKsThis[i] != 0x0L); i++) */
	for (i = 0; (i < 1) && (pKsThis[i] != 0x0L); i++)
		nKsLen ++;
	if (nKsLen >= 1) 
	{
		if ((pKsThis[0] == IMXK_Shift_L) || (pKsThis[0] == IMXK_Shift_R))
			bShiftIsPressed = (JSHORT)(1 - bShiftIsPressed);
		else if (pKsThis[0] == IMXK_Caps_Lock)
			bCapsIsPressed  = (JSHORT)(1 - bCapsIsPressed);
			
		else if ((pKsThis[0] == IMXK_Alt_L) ||
			 (pKsThis[0] == IMXK_Alt_L) )
			bAltIsPressed = (JSHORT)(1 - bAltIsPressed);
			
		/* The Following Key is used as Switcher of Ime Window */
		else if ((pKsThis[0] == IMXK_Control_L) || 
			 (pKsThis[0] == IMXK_Control_R) )
			bCtrlIsPressed = (JSHORT)(1 - bCtrlIsPressed);
			
		else if ((pKsThis[0] == IMXK_Meta_L) ||
			 (pKsThis[0] == IMXK_Meta_R) )
			bMetaIsPressed = (JSHORT)(1 - bMetaIsPressed);
			
		else if ((pKsThis[0] == IMSunXK_AltGraph) ||
			 (pKsThis[0] == IMXK_Mode_switch) )
			bAltGrIsPressed = (JSHORT)(1 - bAltGrIsPressed);
			
		else if ((pKsThis[0] == IMSunXK_Compose) ||
			 (pKsThis[0] == IMXK_Multi_key) )
			bCompIsPressed = (JSHORT)(1 - bCompIsPressed);
			
		/* 
		** If some other key is combined with the above switcher(s),
		** These switcher is turn Off and be send as a fully key
		** to application. (Committed)
		*/
		else if ((bCtrlIsPressed == 1 ) || (bMetaIsPressed == 1) ||
			 (bAltGrIsPressed == 1) || (bCompIsPressed == 1))
		{
		}
		
		/*
		** Alt is used to Switch IM (QuanPin, ShuangPin, WuBi...)
		** Other combination besides IM switcher is committed out.
		** To avoid conflict with Application, Alt + 1, 2, 3, 4 is preferred.
		*/
		else if (bAltIsPressed == 1)
		{
		}
			
		/*
		**  Normal single Key is transferred to IM_trans.
		*/
		else if ((bShiftIsPressed == 0) && (bCapsIsPressed == 0))
		{
			if ((pKsThis[0] >= IMXK_A) && (pKsThis[0] <= IMXK_Z))
				pKsThis[0] += (IMXK_a - IMXK_A);

			IMPinyinTrans(pKsThis, pSge);  
		}
		
		else if ((bShiftIsPressed == 1) && (bCapsIsPressed == 1))
		{
			/* Bounce Keyevent directly back application */
			if ((pKsThis[0] >= IMXK_A) && (pKsThis[0] <= IMXK_Z))
				pKsThis[0] += (IMXK_a - IMXK_A);
		}
		else if ((bShiftIsPressed == 0) && (bCapsIsPressed == 1))
		{
			if (nKsLen > 1)
				pKsThis[0] = pKsThis[1];
		}
		else if ((bShiftIsPressed == 1) && (bCapsIsPressed == 0))
		{
			if (nKsLen > 1)
				pKsThis[0] = pKsThis[1];
		}
	}
}


JINT IMPinyinTrans(JINT* pNextKeysym, SesGuiElement* pSge)
{
	JINT    i, nTmpRes, nTmp;
	JINT    nF9Yj[9], nYjLen, nMatchMode;
	/*  The following 3 lines were commented to Fix BugID 4165549
	static JINT  nPrevMatchMode = -1;
	static JINT  pnCurChoiceYjNew[9] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
	static JINT  pnCurChoiceYjOld[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
	*/

	nTmpRes = FALSE;
	if (IsEditKeysym(pNextKeysym) == TRUE)
	{
		if (nGlobalSpMode == KEYLAYMODE_NEWPY)
			nTmpRes     = OnEditKeysym(pNextKeysym, pSge);
		else if ((nGlobalSpMode >= 0) && (nGlobalSpMode <= 2))
			nTmpRes     = OnEditKeysym_SP(pNextKeysym, pSge, nGlobalSpMode);
		else
		{
			fprintf(stderr, "Error nGlobalSpMode Invalid.\n");
			return FALSE;
		}
		
		/*
		**  Get first nine Yinjie AND 
		**  Process ['a' 'e' 'm' 'n' 'o'] in (nF9Yj[0] ~ nF9Yj[8])
		*/
		GetFirst9Yj(pSge->nPrsPyYjCode, nF9Yj, &nYjLen, &nMatchMode);

		for(i = 0; i < nYjLen; i++)
		{
			if ((nF9Yj[i] & 0x000001FF) == 0)
				nF9Yj[i] += (450 - 0);
			else if ((nF9Yj[i] & 0x000001FF) == 80)
				nF9Yj[i] += (455 - 80);
			else if ((nF9Yj[i] & 0x000001FF) == 191)
				nF9Yj[i] += (462 - 191);
			else if ((nF9Yj[i] & 0x000001FF) == 211)
				nF9Yj[i] += (463 - 211);
			else if ((nF9Yj[i] & 0x000001FF) == 237)
				nF9Yj[i] += (464 - 237);

		}
		for(i = nYjLen; i < 9; i++)
			nF9Yj[i] = 0;

		/*
		**  NOTICE: pnCurChoiceYjOld[] & pnCurChoiceNew[] start from 0x0800 to avoid confliction
		**          with YinJie Code 0 (a).
		*/
		for(i = 0; i < 9; i++)
			pSge->pnCurChoiceYjNew[i] = 0x0800 + nF9Yj[i];

		/* Must compare nMatchMode also. ...!!! */
		if ((IsIntArrayEqual(pSge->pnCurChoiceYjNew, pSge->pnCurChoiceYjOld, 9) != TRUE) || 
			(pSge->nPrevMatchMode != nMatchMode))
		{
			for (i = 0; i < 9; i++)
				pSge->pnCurChoiceYjOld[i] = pSge->pnCurChoiceYjNew[i];
			pSge->nPrevMatchMode  = nMatchMode;
			
			LookupCiku(nF9Yj, nYjLen, nMatchMode, &(pSge->scSysCandi), &(pSge->ucUdcCandi));
			
			pSge->nViewCandiStart   = 0;
			pSge->nViewCandiEnd     = 0;
			pSge->nViewPage         = 0;
			ScrollViewCandiPage(&(pSge->scSysCandi), &(pSge->ucUdcCandi), pSge);

			if (pSge->nViewCandiStart == 0)
				pSge->nIconFlag &= (~F_PREVPAGE);
			else
				pSge->nIconFlag |= F_PREVPAGE;

			nTmp  = pSge->scSysCandi.nNumMhCandi   + pSge->scSysCandi.nNumDhCandi  +
			        pSge->scSysCandi.nNumShCandi   + pSge->scSysCandi.nNumGbkCandi + 
					pSge->ucUdcCandi.nNumSpecCandi + pSge->ucUdcCandi.nNumUdc28Candi;
			if (pSge->nViewCandiEnd < nTmp)
				pSge->nIconFlag |= F_NEXTPAGE;
			else
				pSge->nIconFlag &= (~F_NEXTPAGE);
		}
	}
	
	else if (IsPageKeysym(pNextKeysym) == TRUE)
		nTmpRes = OnPageKeysym(pNextKeysym, pSge);
		
	else if (IsSelectKeysym(pNextKeysym) == TRUE)
	{
		if (nGlobalSpMode == KEYLAYMODE_NEWPY)
			nTmpRes     = OnSelectKeysym(pNextKeysym, pSge);
		else if ((nGlobalSpMode >= 0) && (nGlobalSpMode <= 2))
			nTmpRes     = OnSelectKeysym_SP(pNextKeysym, pSge);
		else
		{
			fprintf(stderr, "Error nGlobalSpMode Invalid.\n");
			return FALSE;
		}
	}

	return nTmpRes;
}


JINT OnEditKeysym(JINT* pNextKeysym, SesGuiElement* pSge)
{
	JINT    nLen, nLenRaw, i, j, k, nTmp;

	JINT    nViewPixWid, nTmpWid;
	nViewPixWid = WIN_W - 61;	/* Here 59? 61? Is Accurate, with 9 indent in left!!! */
	
	nLen    = JwordValidLen (pSge->pwMixPeStr, 256);
	nLenRaw = JwordValidLen (pSge->pwRawPyStr, 256);

	nTmpWid = 0;

	if (pNextKeysym[0] == IMXK_Escape)
	{
		InitSge(pSge);
		goto LABEL0002;
	}

	else if( (pNextKeysym[0] == IMXK_quoteright) && 
	       ( (pSge->pwMixPeStr[pSge->nRawCaretPos] == IMVXK_QUOTER) || 
	       ( (pSge->nRawCaretPos > 0) && (pSge->pwMixPeStr[pSge->nRawCaretPos - 1] == IMVXK_QUOTER) )))
	{
#ifdef _DRAW_IM_WIN_H
		XBell (pDspIme, 100);
#endif
		goto LABEL0002;
	}

	else if (((pNextKeysym[0] >= IMXK_a) && (pNextKeysym[0] <= IMXK_z)) || (pNextKeysym[0] == IMXK_quoteright))
	{
		if ( (nLen >= 222) || (nLenRaw >= 222)  ||
		     ((nLen == 0) && 
		      ((pNextKeysym[0] == IMXK_i) || (pNextKeysym[0] == IMXK_u) || (pNextKeysym[0] == IMXK_v))) )
		{
#ifdef _DRAW_IM_WIN_H
			XBell (pDspIme, 100);
#endif
			goto LABEL0002;
		}
		
		for (i = (nLen - 1); i >= pSge->nRawCaretPos; i--)
			pSge->pwMixPeStr[i + 1] = pSge->pwMixPeStr[i];
			
		pSge->pwMixPeStr[pSge->nRawCaretPos] = (JWORD)pNextKeysym[0];
		pSge->pwMixPeStr[nLen + 1] = 0x0000;
		(pSge->nRawCaretPos)++;
		nLen += 1;
		
		goto LABEL0001;
	}

	else if (pNextKeysym[0] == IMXK_Delete)
	{
		if (pSge->nRawCaretPos == nLen)
		{
#ifdef _DRAW_IM_WIN_H
			XBell (pDspIme, 100);
#endif
			goto LABEL0002;
		}
		else
		{
			for (i = pSge->nRawCaretPos; i < nLen; i++)
				pSge->pwMixPeStr[i] = pSge->pwMixPeStr[i + 1];
			pSge->pwMixPeStr[nLen] = 0;
			for (k = nLen; k < UONE; k++)
				pSge->pwMixPeStr[k] = 0x0000;
			nLen -= 1;
			
			/* TWO [']['] connected! */
			j = pSge->nRawCaretPos;
			if ((j > 0) && (pSge->pwMixPeStr[j - 1] == pSge->pwMixPeStr[j]) && (pSge->pwMixPeStr[j] == '\''))
			{
				for (i = (pSge->nRawCaretPos) - 1; i < nLen; i++)
					pSge->pwMixPeStr[i] = pSge->pwMixPeStr[i + 1];
				pSge->pwMixPeStr[nLen] = 0;
				for (k = nLen; k < 256; k++)
					pSge->pwMixPeStr[k] = 0;
				nLen -= 1;
			}
			
			/* pSge->nRawCaretPos remain previous value */
			goto LABEL0001;
		}
	}

	else if (pNextKeysym[0] == IMXK_BackSpace)
	{
		if ((pSge->nRawCaretPos == 0) || (nLen == 0))
		{
#ifdef _DRAW_IM_WIN_H
			XBell (pDspIme, 100);
#endif
			goto LABEL0002;
		}
		else if (pSge->pwMixPeStr[(pSge->nRawCaretPos) - 1] >= 0x8140)   /* Chracter before Caret is Hanzi */
		{
			RestoreHzToPy(pSge, PYIM_RESTORE_LAST);
			nLen = JwordValidLen(pSge->pwMixPeStr, 256);
			
			j = 0;
			for (i = 0; i < nLen; i++)
				if (pSge->pwMixPeStr[i] >= 0x8140)
					j ++;
			pSge->nRawCaretPos = j;
			
			if (pSge->nRawCaretPos <= pSge->nViewPeStart)
				pSge->nViewPeStart = pSge->nRawCaretPos - _MIN(3, pSge->nRawCaretPos);

			goto LABEL0001;
		}
		else
		{
			for (i = (pSge->nRawCaretPos) - 1; i < (nLen - 1); i++)
				pSge->pwMixPeStr[i] = pSge->pwMixPeStr[i + 1];
			pSge->pwMixPeStr[nLen - 1] = 0;
			nLen -= 1;
			for (k = nLen; k < 256; k++)
				pSge->pwMixPeStr[k] = 0;
			(pSge->nRawCaretPos)--;

			/* TWO [']['] connected! */
			j = pSge->nRawCaretPos;
			if ((j > 0) && (pSge->pwMixPeStr[j - 1] == pSge->pwMixPeStr[j]) 
			    && (pSge->pwMixPeStr[j] == '\''))
			{
				for (i = (pSge->nRawCaretPos) - 1; i < nLen; i++)
					pSge->pwMixPeStr[i] = pSge->pwMixPeStr[i + 1];
				pSge->pwMixPeStr[nLen] = 0;
				for (k = nLen; k < 256; k++)
					pSge->pwMixPeStr[k] = 0;
				nLen -= 1;
			}

			if (pSge->nRawCaretPos <= pSge->nViewPeStart)
				pSge->nViewPeStart = pSge->nRawCaretPos - _MIN(3, pSge->nRawCaretPos);

			goto LABEL0001;
		}
	}

	else if (pNextKeysym[0] == IMXK_Left)
	{
		if ((pSge->nRawCaretPos == 0) || (nLen == 0))
		{
#ifdef _DRAW_IM_WIN_H
			XBell (pDspIme, 100);
#endif
			goto LABEL0002;
		}
		else if (pSge->pwMixPeStr[(pSge->nRawCaretPos) - 1] >= 0x8140)
		{
			RestoreHzToPy(pSge, PYIM_RESTORE_LAST);
			nLen = JwordValidLen(pSge->pwMixPeStr, 256);
				
			j = 0;
			for (i = 0; i < nLen; i++)
				if (pSge->pwMixPeStr[i] >= 0x8140)
					j ++;
			pSge->nRawCaretPos = j;
			
			if (pSge->nRawCaretPos <= pSge->nViewPeStart)
				pSge->nViewPeStart = pSge->nRawCaretPos - _MIN(3, pSge->nRawCaretPos);
					
			goto LABEL0001;
		}
		else 
		{
			(pSge->nRawCaretPos)--;
			if (pSge->nRawCaretPos <= pSge->nViewPeStart)
				pSge->nViewPeStart = pSge->nRawCaretPos - _MIN(3, pSge->nRawCaretPos);
					
			goto LABEL0001;
		}
	}

	else if (pNextKeysym[0] == IMXK_Right)
	{
		if (pSge->nRawCaretPos == nLen)
		{
#ifdef _DRAW_IM_WIN_H
			XBell (pDspIme, 100);
#endif
			goto LABEL0002;
		}
		else
		{
			(pSge->nRawCaretPos)++;
			goto LABEL0001;			
		}
	}

	else if (pNextKeysym[0] == IMXK_Home)
	{
		RestoreHzToPy(pSge, PYIM_RESTORE_ALL);
		nLen = JwordValidLen(pSge->pwMixPeStr, 256);

		pSge->nRawCaretPos  = 0;
		pSge->nViewCaretPos = 0;
		pSge->nViewPeStart  = 0;
		
		goto LABEL0001;
	}

	else if (pNextKeysym[0] == IMXK_End)
	{
		pSge->nRawCaretPos = nLen;
		goto LABEL0001;
	}
	
	/*
	** This judgement is added to process Selection Action or 
	** Backspace/Home/LeftArrow to existing Hanzi 
	*/
	else if (pNextKeysym[0] == IMXK_REDRAW_INTERNAL)
	{
		nTmp = JwordValidLen(pSge->pwSlctHz, 512);
		k = 0;
		for (i = 0; i < nTmp; i++)
			if (pSge->pwSlctHz[i] >= 0x8140)
				k++;
		
		pSge->nViewPeStart = _MAX(0, k - 8);

		goto LABEL0001;
	}
	
	else
		goto LABEL0002;

LABEL0001:
	{
		/* Prase pwMixPeStr and fill other related pSge field */
		PraseMixRawPe(pSge);
		
		nTmpWid = PixWidBetween (pSge->pwPrsMixStr, pSge->nViewPeStart, pSge->nRawCaretPos);
		if (nTmpWid > nViewPixWid)
		{
			for (i = pSge->nViewPeStart; nTmpWid > nViewPixWid; i++)
				nTmpWid = PixWidBetween (pSge->pwPrsMixStr, i, pSge->nRawCaretPos);
			
			pSge->nViewPeStart = i - 1;
			pSge->nViewPeEnd   = pSge->nRawCaretPos;
		}
		
		nTmpWid = 0;
		for (i = pSge->nViewPeStart; (i <= nLen) && (nTmpWid <= nViewPixWid); i++)
			nTmpWid = PixWidBetween (pSge->pwPrsMixStr, pSge->nViewPeStart, i);
		
		pSge->nViewPeEnd = i - 1;
		GetDspPEandCaretPos (pSge);
	}

LABEL0002:	
	return TRUE;
}


JINT OnPageKeysym(JINT* pNextKeysym, SesGuiElement* pSge)
{
	JINT    nTmp;
	JINT    nPageSh, nPageGbk, nCurPage, nTargetPage;
	
	/* Prev Page */
	if ((pNextKeysym[0] == IMXK_minus) || (pNextKeysym[0] == IMXK_bracketleft) 
		|| (pNextKeysym[0] == IMXK_comma) || (pNextKeysym[0] == IMXK_MOUSEPREV))
	{
		if (pSge->nViewCandiStart > 0)
		{
			pSge->nViewPage --;
			ScrollViewCandiPage(&(pSge->scSysCandi), &(pSge->ucUdcCandi), pSge);
			goto LABEL0003;
		}
		else
		{
#ifdef _DRAW_IM_WIN_H
			XBell (pDspIme, 100);
#endif
			goto LABEL0004;
		}
	}
	/* Next Page */
	else if ((pNextKeysym[0] == IMXK_equal) || (pNextKeysym[0] == IMXK_bracketright) 
		|| (pNextKeysym[0] == IMXK_period) || (pNextKeysym[0] == IMXK_MOUSENEXT))
	{
		nTmp  = pSge->scSysCandi.nNumMhCandi   + pSge->scSysCandi.nNumDhCandi  +
		        pSge->scSysCandi.nNumShCandi   + pSge->scSysCandi.nNumGbkCandi +
		        pSge->ucUdcCandi.nNumSpecCandi + pSge->ucUdcCandi.nNumUdc28Candi;

		if (pSge->nViewCandiEnd < nTmp)
		{
			pSge->nViewPage ++;
			ScrollViewCandiPage(&(pSge->scSysCandi), &(pSge->ucUdcCandi), pSge);
			goto LABEL0003;
		}
		else
		{
#ifdef _DRAW_IM_WIN_H
			XBell (pDspIme, 100);
#endif
			goto LABEL0004;
		}
	}
	else if (pNextKeysym[0] == IMXK_Return)
	{
		nTmp     = pSge->scSysCandi.nNumMhCandi   + pSge->scSysCandi.nNumDhCandi  +
		           pSge->scSysCandi.nNumShCandi   + pSge->scSysCandi.nNumGbkCandi +
		           pSge->ucUdcCandi.nNumSpecCandi + pSge->ucUdcCandi.nNumUdc28Candi;
		           
		nPageSh  = pSge->ucUdcCandi.nNumSpecCandi + pSge->ucUdcCandi.nNumUdc28Candi +
		           pSge->scSysCandi.nNumMhCandi   + pSge->scSysCandi.nNumDhCandi;
		           
		nPageGbk = nPageSh + pSge->scSysCandi.nNumShCandi;
		nCurPage = pSge->nViewCandiStart;
		
		if ((nCurPage < nPageSh) && (pSge->scSysCandi.nNumShCandi + pSge->scSysCandi.nNumGbkCandi > 0))
			nTargetPage = nPageSh;
		else if ((nCurPage >= nPageSh) && (nCurPage < nPageGbk) && (pSge->scSysCandi.nNumGbkCandi > 0))
			nTargetPage = nPageGbk;
		else                           /* (nCurPage >= nPageGbk) */
			nTargetPage = 0;
		
		pSge->nViewCandiStart   = 0;
		pSge->nViewCandiEnd     = 0;
		pSge->nViewPage         = 0;
		for ( ; ;  )
		{
			ScrollViewCandiPage(&(pSge->scSysCandi), &(pSge->ucUdcCandi), pSge);
			if ((pSge->nViewCandiEnd < nTmp) && (pSge->nViewCandiStart < nTargetPage))
				pSge->nViewPage ++;
			else
				break;
		}
		
		goto LABEL0003;
	}
	
	/* 以下LABEL0003代码可被组合到函数ScrollViewCandiPage中去. MXL 97.11.28 04:15 */
LABEL0003:
	{	
			if (pSge->nViewCandiStart == 0)
				pSge->nIconFlag &= (~F_PREVPAGE);
			else
				pSge->nIconFlag |= F_PREVPAGE;
			
			nTmp  = pSge->scSysCandi.nNumMhCandi   + pSge->scSysCandi.nNumDhCandi  +
			        pSge->scSysCandi.nNumShCandi   + pSge->scSysCandi.nNumGbkCandi +
			        pSge->ucUdcCandi.nNumSpecCandi + pSge->ucUdcCandi.nNumUdc28Candi;
			if (pSge->nViewCandiEnd < nTmp)
				pSge->nIconFlag |= F_NEXTPAGE;
			else
				pSge->nIconFlag &= (~F_NEXTPAGE);
	}

LABEL0004:
	return TRUE;
}

JINT OnSelectKeysym(JINT* pNextKeysym, SesGuiElement* pSge)
{
	JINT   i, j, nTmp, nTmpLen, nTmpRes, nRes;
	JINT   nCurCandiNum;
	JINT   nChoiceMark;    /* nChoiceMark start from 1 to nCurCandiNum */
	CHAR   szYjStr[80];    /* Yinjie String (including [']) corressponding to current Selection */
	JINT   nLenThisSel;
	JWORD  wThisSel[9];
	JINT   nXrd;
	JINT   nYj, nYjLen;
	
	nCurCandiNum = pSge->nViewCandiEnd - pSge->nViewCandiStart;
	
	if ((pNextKeysym[0] == IMXK_space) && (nCurCandiNum >= 1))
		pNextKeysym[0] = IMXK_1;
	else if ((pNextKeysym[0] == IMXK_space) && (nCurCandiNum == 0))
	{
#ifdef _DRAW_IM_WIN_H
		XBell (pDspIme, 100);
#endif
		return TRUE;
	}
	
	if ((pNextKeysym[0] > IMXK_0) && (pNextKeysym[0] <= (IMXK_0 + nCurCandiNum)))
	{
		for(i = 0; i < 9; i++)
			wThisSel[i] = 0x0000;
		nChoiceMark     = pNextKeysym[0] - IMXK_0;
		nXrd            = pSge->nViewCandiStart + nChoiceMark - 1;
		nLenThisSel     = GetXrdCandi(&(pSge->scSysCandi), &(pSge->ucUdcCandi), nXrd, wThisSel);

		for(i = 0; i < 80; i++)
			szYjStr[i]  = '\0';

		/* 考虑 XIAN 问题, 如果nXrd指示是在SingleHanzi, 则只取第一个音节串 */
		if (nXrd >= (pSge->ucUdcCandi.nNumSpecCandi + pSge->ucUdcCandi.nNumUdc28Candi + 
		             pSge->scSysCandi.nNumMhCandi   + pSge->scSysCandi.nNumDhCandi))
			nTmp = 1;
		else       /* 是双字或多字选择 */
			nTmp = nLenThisSel;
		
		/*
		**  BUG FIXED: nTmp May be 7, more example, "中华人民共和国",
		**             But OrgYj String is "zh h r m g". [0, 1, 2, 3, 4]
		**             nOrgYj[5] & nOrgYj[6] have been set to 0 in GetF9Yj,
		**             So, change the judgement condition
		**             FROM (j < nTmp) TO (j < nTmp) && (j < nLenYj) !!
		**                  ^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^
		**             MXL, 97-12-06.
		*/
		for(j = 0; (j < nTmp) && (j < pSge->scSysCandi.nLenYj); j++)
		{
			if ((pSge->scSysCandi.nOrgYj[j] & 0xFFFD0000) == 0xFFFD0000)    /* There is a ['] aheader */
				strcat(szYjStr, "'");

			/****  Aha,  ShuangPin's Parse Algorigthm has changed it!!!  - Scott Ma 
			if (pSge->scSysCandi.nOrgYj[j] >= 0x00010000)
				strcat(szYjStr, "'");
			*/

			nYj = pSge->scSysCandi.nOrgYj[j] & 0x01FF;
			if ((nYj >= 0) && (nYj < NUM_YINJIE))
				strcat(szYjStr, YINJIESTR_CSZ[nYj]);
			else if ((nYj >= 450) && (nYj <= 475))
				strcat(szYjStr, SHENGMUSTR[nYj - 450]);
		}

#ifdef _DEBUG
		printf("TO BE REPLACED: [%s], nLenYj is %d\n", szYjStr, pSge->scSysCandi.nLenYj);
#endif
		
		nRes = nTmpLen = JwordValidLen(pSge->pwSlctHz, 512);
		
		for(i = 0; i < nLenThisSel; i++)
			pSge->pwSlctHz[nTmpLen + i]        = wThisSel[i];
		pSge->pwSlctHz[nTmpLen + nLenThisSel]  = 0x0009;        /* Horizonal Tab Key */
		(pSge->nSlctSteps)++;

		/* Calc new pSge->nRawCaretPos */
		nTmp    = 0;
		nTmpLen = JwordValidLen(pSge->pwSlctHz, 512);
		for (i = 0; i < nTmpLen; i++)
			if (pSge->pwSlctHz[i] != 0x0009)
				nTmp++;
		pSge->nRawCaretPos = nTmp;

		nTmpRes  = JwordStrStrReplace(pSge->pwMixPeStr, StrToJword(szYjStr), (JWORD*)RecovDyz2244((UCHAR*)wThisSel), nLenThisSel);
		if (nTmpRes == FALSE)
			fprintf (stderr, "Failed in OnSelectKeysym(): JwordStrStrReplace\n");
		
		nTmpLen  = JwordValidLen(pSge->pwSlctRawPy, 512);
		nYjLen   = strlen(szYjStr);
		for (i = nTmpLen; i < (nTmpLen + nYjLen); i++)
			pSge->pwSlctRawPy[i] = (JWORD)szYjStr[i - nTmpLen];
		pSge->pwSlctRawPy[nTmpLen + nYjLen] = 0x0009;	/* Horizonal Tab Key */
		
		/* Recycle call to IMPinyinTrans() !!!! */
		pNextKeysym[0] = IMXK_REDRAW_INTERNAL;
		IMPinyinTrans(pNextKeysym, pSge);
	}
	else
	{
#ifdef _DRAW_IM_WIN_H
		XBell (pDspIme, 100);
#endif
		;
	}

	return TRUE;
}


JINT QpCaretToPrsCaret(JWORD* pwPrsStr, JINT nQpCaret)
{
	JINT    nPrsCaret;
	JINT    nTotLen, i, j;
	
	nTotLen = JwordValidLen(pwPrsStr, UTWO);
	assert((nQpCaret <= nTotLen) && (nQpCaret >= 0));
	
	nPrsCaret = 0;
	j = 0;
	for (i = 0; i <= nTotLen; i++)
	{
		if (pwPrsStr[i] != (JWORD)' ')
		{
			if (j == nQpCaret)
				nPrsCaret = i;
			j++;
		}
	}
	return nPrsCaret;
}


/*
**  Range of nFrom and nTo here IS: [0] ~ [JwordValidLen(pSge->pwMixPeStr, 256)], 
**  NOT [0] ~ [JwordValidLen(szRawPeStr, 256) - 1] !!!!
*/
JINT PixWidBetween (JWORD* pwPrsStr, JINT nFrom, JINT nTo)
{
	JINT    nTotLen, i, j, t1, t2, nt1;
	
	assert(nTo >= nFrom);
	nTotLen = JwordValidLen(pwPrsStr, UTWO);

	t1 = t2 = j = 0;
	for (i = 0; i <= nTotLen; i++)
	{
		if (pwPrsStr[i] != (JWORD)' ')
		{
			if (j == nFrom)
				t1 = i;
			if (j == nTo)
				t2 = i;
			j++;
		}
	}

	nt1 = 0;
	for (i = t1; i < t2; i++)
	{
		/* REVIEW:  pwPrsStr[nTotLen] is 0 !!! */
		if ((pwPrsStr[i] != 0) && (pwPrsStr[i] >= 0x8140))
			nt1 += HZPIXWID;
		else if ((pwPrsStr[i] != 0) && (pwPrsStr[i] < 0x0080))
			nt1 += wAlphaIconWid[pwPrsStr[i] - 0x20];
	}
	return nt1;
}


/*
**  Range of nFrom and nTo here IS: [0] ~ [JwordValidLen(pSge->pwMixPeStr, 256)], 
**  NOT [0] ~ [JwordValidLen(szRawPeStr, 256) - 1] !!!!
*/
JINT PixWidBetween_SP (JWORD* pwPrsStr, JINT nFrom, JINT nTo)
{
	JINT    nTotLen, i, j, nt1;
	
	assert(nTo >= nFrom);
	nTotLen = JwordValidLen(pwPrsStr, UTWO);

	nt1 = 0;
	for (i = nFrom; i < nTo; i++)
	{
		/* REVIEW:  pwPrsStr[nTotLen] is 0 !!! */
		if ((pwPrsStr[i] != 0) && (pwPrsStr[i] >= 0x8140))
			nt1 += HZPIXWID;
		else if ((pwPrsStr[i] != 0) && (pwPrsStr[i] < 0x0080))
			nt1 += wAlphaIconWid[pwPrsStr[i] - 0x20];
	}
	return nt1;
}




VOID GetDspPEandCaretPos_SP (SesGuiElement* pSge)
{
	JINT    nTotLen, i, j, t1, t2, t3;
	
	JINT    nFrom, nTo, nRawCaret, nPrsCaretPos;
	
	nFrom     = pSge->nViewPeStart;
	nTo       = pSge->nViewPeEnd;
	nRawCaret = pSge->nRawCaretPos;
	
/*
	==>[szOrgSp]>>vs#hw#rf#mn#gs#he#go#mz#tm#bu [29]
	==>[  szQp ]>>zhong#hua#ren#min#gong#he#guo#mei#tian#bu [41]
	pwPrsMixStr >>zhong# hua# ren# min# gong# he# guo# mei# tian# bu [50]
	nLenSp is 29 nSpRawCaretPos[29], nLenQp is 41 nRawCaretPos[41]
	[nViewPeStart][ 0]  [nViewPeEnd][50]  [nRawCaretPos][41]
*/

	nTotLen      = JwordValidLen(pSge->pwPrsMixStr, UTWO);
	nPrsCaretPos = QpCaretToPrsCaret(pSge->pwPrsMixStr, pSge->nRawCaretPos);
	
	t1 = t2 = t3 = j = 0;
	for (i = 0; i <= nTotLen; i++)
	{
		if (i == nFrom)
			t1 = i;
		if (i == nTo)
			t2 = i;
		if (i == nPrsCaretPos)
			t3 = i;
	}
	
	assert((t3 <= t2) && (t3 >= t1));

	pSge->nViewCaretPos = t3 - t1;

	for (i = t1; i < t2; i++)
		pSge->pwViewPe[i - t1] = pSge->pwPrsMixStr[i];
	pSge->pwViewPe[t2 - t1] = 0;
	
	if (t1 == 0)
		pSge->nIconFlag &= (~F_LEFTARROW);
	else
		pSge->nIconFlag |= F_LEFTARROW;
		
	if ( t2 >= (nTotLen - 1))
		pSge->nIconFlag &= (~F_RIGHTARROW);
	else
		pSge->nIconFlag |= F_RIGHTARROW;

}



VOID GetDspPEandCaretPos (SesGuiElement* pSge)
{
	JINT    nTotLen, i, j, t1, t2, t3;
	
	JINT    nFrom, nTo, nRawCaret;
	
	nFrom     = pSge->nViewPeStart;
	nTo       = pSge->nViewPeEnd;
	nRawCaret = pSge->nRawCaretPos;
	
	/***** Above is a PATCH  MXL For ShuangPin 98-02-23 ******/
	
	assert((nRawCaret <= nTo) && (nRawCaret >= nFrom));
	
	nTotLen   = JwordValidLen(pSge->pwPrsMixStr, UTWO);
	
	t1 = t2 = t3 = j = 0;
	for (i = 0; i <= nTotLen; i++)
	{
		if (pSge->pwPrsMixStr[i] != (JWORD)' ')
		{
			if (j == nFrom)
				t1 = i;
			if (j == nTo)
				t2 = i;
			if (j == nRawCaret)
				t3 = i;
			j++;
		}
	}
	
	pSge->nViewCaretPos = t3 - t1;

	for (i = t1; i < t2; i++)
		pSge->pwViewPe[i - t1] = pSge->pwPrsMixStr[i];
	pSge->pwViewPe[t2 - t1] = 0;

	if (t1 == 0)
		pSge->nIconFlag &= (~F_LEFTARROW);
	else
		pSge->nIconFlag |= F_LEFTARROW;
		
	if ( t2 >= (nTotLen - 1))
		pSge->nIconFlag &= (~F_RIGHTARROW);
	else
		pSge->nIconFlag |= F_RIGHTARROW;
}



/*
**  nResFlag: PYIM_RESTORE_ALL  PYIM_RESTORE_LAST
**  Conside only "HHHHHHHeeeeeee", Not include "HHHHHHeeeeHeeeeHHeee"
*/
JINT RestoreHzToPy(SesGuiElement* pSge, JINT nResFlag)
{
	JINT   nSelectHzLen, nSelectRawEngLen, nTotRawLen;
	JWORD  waHz[256], waEng[256];
	JINT   i, j, k, nTmp;
	JINT   nLenHz, nLenEng, nFirstAddr;
	
	nSelectHzLen     = JwordValidLen(pSge->pwSlctHz, 512);
	nSelectRawEngLen = JwordValidLen(pSge->pwSlctRawPy, 512);
	nTotRawLen       = JwordValidLen(pSge->pwMixPeStr, 256);
	
	for (i = 0; i < 256; i++)
	{
		waHz[i]  = 0x0000;
		waEng[i] = 0x0000;
	}

	if (nResFlag == PYIM_RESTORE_ALL)
	{
		i = j = 0;
		for (i = 0; i < nSelectHzLen; i++)
			if (pSge->pwSlctHz[i] >= 0x8140)
				waHz[j++] = pSge->pwSlctHz[i];
		nLenHz = j;

		i = j = 0;
		for (i = 0; i < nSelectRawEngLen; i++)
			if (pSge->pwSlctRawPy[i] >= 0x0020)
				waEng[j++] = pSge->pwSlctRawPy[i];
		nLenEng = j;

		for (i = 0; i < 512; i++)
		{
			pSge->pwSlctRawPy[i] = 0x0000;
			pSge->pwSlctHz[i]    = 0x0000;
		}
		pSge->nSlctSteps = 0;
	}

	else if (nResFlag == PYIM_RESTORE_LAST)
	{
		i = j = k = 0;
		for (i = 0; i < nSelectRawEngLen; i++)
		{
			if (pSge->pwSlctRawPy[i] == 0x0009)
				j++;
			
			if ((j == (pSge->nSlctSteps - 1)) && (pSge->pwSlctRawPy[i] != 0x0009))
			{
				waEng[k++] = pSge->pwSlctRawPy[i];
				pSge->pwSlctRawPy[i] = 0x0000;
			}
			if (j == pSge->nSlctSteps)
				pSge->pwSlctRawPy[i] = 0x0000;
		}
		nLenEng = k;
				
		i = j = k = 0;
		for (i = 0; i < nSelectHzLen; i++)
		{
			if (pSge->pwSlctHz[i] == 0x0009)
				j++;
			
			if ((j == (pSge->nSlctSteps - 1)) && (pSge->pwSlctHz[i] != 0x0009))
			{
				waHz[k++] = pSge->pwSlctHz[i];
				pSge->pwSlctHz[i] = 0x0000;
			}
			if (j == pSge->nSlctSteps)
				pSge->pwSlctHz[i] = 0x0000;
		}
		nLenHz = k;
		
		(pSge->nSlctSteps)--;

	}
	else
		return FALSE;

	if (nResFlag == PYIM_RESTORE_ALL)
		nFirstAddr = 0;
	else    /* nResFlag == PYIM_RESTORE_LAST */
	{
		nTmp = 0;
		for (i = 0; i < nTotRawLen; i++)
			if (pSge->pwMixPeStr[i] >= 0x8140)
				nTmp++;
		
		nFirstAddr = nTmp - nLenHz;
	}
	
	if (nLenHz >= nLenEng)
	{
		for (i = nFirstAddr; i < (nFirstAddr + nLenEng); i++)
			*(pSge->pwMixPeStr + i) = waEng[i - nFirstAddr];
			
		for (i = (nFirstAddr + nLenEng); i < (nTotRawLen - (nLenHz - nLenEng)); i++)
			*(pSge->pwMixPeStr + i) = *(pSge->pwMixPeStr + i + (nLenHz - nLenEng));
			
		for (i = (nTotRawLen - (nLenHz - nLenEng)); i < 256; i++)
			*(pSge->pwMixPeStr + i) = 0x0000;
	}
	else if (nLenHz < nLenEng)
	{
		for (i == (nTotRawLen + (nLenEng - nLenHz)); i < 256; i++)
			*(pSge->pwMixPeStr + i) = 0x0000;
			
		/* To be rewriten TO: i++ MXL: 1997-12-27 */
		for (i = nTotRawLen + (nLenEng - nLenHz) - 1; i >= (nFirstAddr + nLenEng); i--)
			*(pSge->pwMixPeStr + i) = *(pSge->pwMixPeStr + i - nLenEng + nLenHz);
			
		for (i = nFirstAddr; i < (nFirstAddr + nLenEng); i++)
			*(pSge->pwMixPeStr + i) = waEng[i - nFirstAddr];
	}
	
	/*******
	PraseMixRawPe(pSge);
	*******/
	return TRUE;
}

/*
**  nYjCode is bewteen 0~414, 450~475. Else, return FALSE.
*/
JINT YjCodeToYjStr(JINT nYjCode, CHAR* szYjStr)
{
	if ((nYjCode >= 0) && (nYjCode < NUM_YINJIE))
		strcpy(szYjStr, YINJIESTR_CSZ[nYjCode]);
	else if ((nYjCode >= 450) && (nYjCode <= 475))
		strcpy(szYjStr, SHENGMUSTR[nYjCode - 450]);
	else
		return FALSE;
	
	return TRUE;
}


JINT IsIntArrayEqual (JINT *pnInt1, JINT *pnInt2, JINT nLen)
{
	JINT   i, nFlag;
	
	nFlag = TRUE;
	for(i = 0; i < nLen; i++)
	{
		if(pnInt1[i] != pnInt2[i])
		{
			nFlag = FALSE;
			break;
		}
	}
	
	return nFlag;
}


VOID PraseMixRawPe(SesGuiElement* pSge)
{
	JINT    nMixRawLen, nHzPartLen, nEngLen, i;
	CHAR    szEngRawPeStr[256];
	CHAR    szTmpParsedPE[512];
	JINT    nSpaceFlag;
	
	nHzPartLen = 0;
	nMixRawLen = JwordValidLen(pSge->pwMixPeStr, UONE);
	
	for (i = 0; (i < nMixRawLen) && (pSge->pwMixPeStr[i] >= 0x8140); i++)
		nHzPartLen++;
	
	for (i = 0; i < 256; i++)
		szEngRawPeStr[i] = '\0';
	for (i = 0; i < 512; i++)
		szTmpParsedPE[i] = '\0';
		
	for (i = nHzPartLen; (i < nMixRawLen) && (pSge->pwMixPeStr[i] < 0x0080); i++)
		szEngRawPeStr[i - nHzPartLen] = (CHAR)pSge->pwMixPeStr[i];

	ParseRawInputStr (szEngRawPeStr, pSge->nPrsPyYjCode);
	DecompPeIntArray (pSge->nPrsPyYjCode, szTmpParsedPE);
	nEngLen = strlen(szTmpParsedPE);
	
	for (i = 0; i < nHzPartLen; i++)
		pSge->pwPrsMixStr[i] = pSge->pwMixPeStr[i];
		
	/*
	**  By Wendy's Suggestion, 
	**  为美化显示, 特意在汉字和英文之间加一空格
	*/
	nSpaceFlag = 0;
	if (nHzPartLen > 0)
	{
		pSge->pwPrsMixStr[nHzPartLen] = (JWORD)' ';
		pSge->pwPrsPyStr[0] = (JWORD)' ';
		i++;
		nSpaceFlag = 1;
	}
	
	for (i = 0; i < nEngLen; i++)
	{
		pSge->pwPrsMixStr[i + nHzPartLen + nSpaceFlag] = (JWORD)szTmpParsedPE[i];
		pSge->pwPrsPyStr[i + nSpaceFlag] = (JWORD)szTmpParsedPE[i];
	}

	for (i = nEngLen + nHzPartLen + nSpaceFlag; i < 512; i++)
		pSge->pwPrsMixStr[i] = 0x0000;
}


/*
**  Parse Current SysCandi, Set pSge->pwViewCandi, pSge->nViewCandiStart, pSge->nViewCandiEnd.
**  Notice:  pSge->nViewCandiEnd means the first candi in NEXT page.
**           nViewCandiStart and nViewCandiEnd are only used to specify whether to display
**              the NEXT and PREV candidates Flag << & >> and determine how a select key
**              corressponding to a Candidates Hanzi String.
**           Really important Page Flag is defined in parameter pSge->nViewPage.
**              Each time that when is a PageDown or PageUp key, judge from nViewCandiStart
**              and nViewCandiEnd to determine whether it is PageDownable or PageUpable.
**              If yes, (pSge->nViewPage)-- or (pSge->nViewPage)++ first, and then call
**              the function.
**           For the function, the minimum nViewPage is 0. Get the corressponding 
**              pSge->pwViewCandi of the certain nViewPage by calculate from the 
**              first candidate.
*/
VOID ScrollViewCandiPage(SysCandi* psc, UdcCandi* puc, SesGuiElement* pSge)
{
	JINT    i, j, k, m;

	JINT    nNumMark;              /* Digital Alpha. 1. 2. 3. 4.*** to mark Candi Number */ 
	JINT    nTotCandi;
	JINT    nMAXPIX, nTmpPix;
	JINT    nWantPage, nCurPage;
	JWORD   wNextCandi[9];
	JINT    nPixOfNext;            /* Width of wNextCandi[9] */
	JINT    nLenOfNext;            /* Hanzi Number in wNextCandi[9] after GetXrdCandi() */
	JINT    nPageSh, nPageGbk;

	nTotCandi = psc->nNumMhCandi  + psc->nNumDhCandi   + psc->nNumShCandi + 
	            psc->nNumGbkCandi + puc->nNumSpecCandi + puc->nNumUdc28Candi;  /* Candi Number */
	/* To Assure Max Candi Num is 7, so minus 20 !! */
	nMAXPIX   = WIN_W - 61 - 20;   /* Same as nViewPixWid in Preedit Area */
	nWantPage = pSge->nViewPage;   /* Page Number want to be displayed */

	/*
	**  在这里暂且不管词的频率, 按先后顺序显示. 单字最多7个. 
	**  象素点的数量与Preedit中的相同: 
	**  1.象素  2.XXXX  3.**
	**  必须保证: 任何一个Candidates的长度加上nNumMark的长度不会超过 nMAXPIX
	**
	**  [** TO IMPROVE: In SortSysCandi(), Rearrange XIAN candies to proper position **] 97.11.28.
	*/
	for (m = 0; m < UHLF; m++)
		pSge->pwViewCandi[m] = 0x0000;

	nCurPage  = 0;
	nTmpPix   = 0;
	nNumMark  = 1;
	j = k = m = 0;
	
	nPageSh   = puc->nNumSpecCandi + puc->nNumUdc28Candi + psc->nNumMhCandi + psc->nNumDhCandi;
	nPageGbk  = nPageSh + psc->nNumShCandi;
	
	pSge->nViewCandiStart = 0;
	/* No i++ in this FOR sentence */
	for (i = 0; i < nTotCandi;  )
	{
		if (nCurPage == nWantPage)
		{
			nLenOfNext   = GetXrdCandi(psc, puc, i, wNextCandi);
			/* Width of Hanzies PLUS [1.SS], S indicates SPACE ' '(0x20) */
			nPixOfNext   = (nLenOfNext * HZPIXWID) + wAlphaIconWid[nNumMark + '0' - 0x20]  + 
			                wAlphaIconWid['.' - 0x20] + (2 * wAlphaIconWid[' ' - 0x20]);

			/*
			**  If not beyond nMAXPIX, Write wNextCandi[] to pSge->nViewCandi 
			**  and set pSge->nViewCandiEnd to i+1
			*/
			if ( ((nTmpPix + nPixOfNext) >= nMAXPIX) || ((i == nPageSh || i == nPageGbk) && (nNumMark > 1) ))
				break;        /* BREAK of FOR_i sentence */
			else 
			{
				nTmpPix  += nPixOfNext;
				pSge->nViewCandiEnd = i + 1;

				pSge->pwViewCandi[m++]     = (JWORD)(nNumMark + '0');
				pSge->pwViewCandi[m++]     = (JWORD)'.';
				for (k = 0; k < nLenOfNext; )
				{
					pSge->pwViewCandi[m]   = RecovDyzWord2244(wNextCandi[k]);
					m++;
					k++;
				}
				pSge->pwViewCandi[m++]     = 0x20;    /* SPACE: Add two SPACE after each candi */
				pSge->pwViewCandi[m++]     = 0x20;    /* SPACE */

				nNumMark += 1;
				i++;
			}
		}

		else   /* (nCurPage < nWantPage) */
		{
			nLenOfNext   = GetXrdCandi(psc, puc, i, wNextCandi);
			/* Width of Hanzies PLUS [1.  ] */
			nPixOfNext   = (nLenOfNext * HZPIXWID) + wAlphaIconWid[nNumMark + '0' - 0x20]    + 
			                wAlphaIconWid['.' - 0x20] + (2 * wAlphaIconWid[' ' - 0x20]);

			/*
			**  Reset nTmpPix & nNumMark to 0 & 1, Increase nCurPage by 1.
			**  Don't increase i to let it recalulate again.
			*/
			if ( ((nTmpPix + nPixOfNext) >= nMAXPIX) || ((i == nPageSh || i == nPageGbk) && (nNumMark > 1) ))
			{
				nTmpPix   = 0;
				nNumMark  = 1;
				nCurPage += 1;

				pSge->nViewCandiStart = i;
			}
			/* If not beyond nMAXPIX */
			else
			{
				nTmpPix  += nPixOfNext;
				nNumMark += 1;
				i++;
			}
		}
	} /* End of FOR_i */

}


/*
**  Get the Xrd Candidates which store in structure psc. The content is to be
**  store to pwOneCandi.
**  Notice:  Range of nXrd is between [0 ~ (nTmp - 1)]. 
**           Spec -> Udc28 -> Mh -> Dh -> Sh -> Gbk
**  Return:  Valid Length of this candidate in JWORD.
*/
JINT GetXrdCandi(SysCandi* psc, UdcCandi* puc, JINT nXrd, JWORD* pwOneCandi)
{
	JINT    i, k, m, nTmp;
	JINT    nRet;
	JINT    nNumSpec, nNumUdc28, nNumMh, nNumDh, nNumSh, nNumGbk;
	
	nRet  = 0;
	nNumSpec  = puc->nNumSpecCandi;
	nNumUdc28 = puc->nNumUdc28Candi;
	nNumMh    = psc->nNumMhCandi;
	nNumDh    = psc->nNumDhCandi;
	nNumSh    = psc->nNumShCandi;
	nNumGbk   = psc->nNumGbkCandi;

	nTmp  = nNumSpec + nNumUdc28 + nNumMh + nNumDh + nNumSh + nNumGbk;	
	if ((nXrd < 0) || (nXrd > (nTmp - 1)))
		return nRet;
	
	/* SpecHz */
	if (nXrd < nNumSpec)                       /* [0 ~ (nNumSpecCandi - 1)] */
	{
		pwOneCandi[0] = puc->pwSpecCandi[nXrd];
		nRet = 1;
		return nRet;
	}
	/* Udc28 */
	else if ((nXrd >= nNumSpec) && (nXrd < (nNumSpec + nNumUdc28)))
	{
		m = nNumSpec;
		for (k = 0; k < puc->nSizUdc28Candi; k++)
		{
			if (m == nXrd)
			{
				k++;
				for(i = 0; puc->pwUdc28Candi[k] != 0x0000;  )
					pwOneCandi[i++] = puc->pwUdc28Candi[k++];
				nRet = i;
				break;           /* 退出k++的BREAK, NOT i++ */
			}
			else if (puc->pwUdc28Candi[k] == 0x0000)
				m++;
		}
	}
	/* Mh */
	else if ( (nXrd >= (nNumSpec + nNumUdc28)) && 
	        (nXrd < (nNumSpec + nNumUdc28 + nNumMh)) )
	{
		m = nNumSpec + nNumUdc28;
		for (k = 0; k < psc->nSizMhCandi; k++)
		{
			if (m == nXrd)
			{
				k++;
				for(i = 0; psc->pwMhCandi[k] != 0x0000;  )
					pwOneCandi[i++] = psc->pwMhCandi[k++];
				nRet = i;

				break;           /* 退出k++的BREAK, NOT i++ */
			}
			else if (psc->pwMhCandi[k] == 0x0000)
				m++;
		}
	}
	/* Dh */
	else if ( (nXrd >= (nNumSpec + nNumUdc28 + nNumMh)) && 
	        (nXrd < (nNumSpec + nNumUdc28 + nNumMh + nNumDh)) )
	{
		m = nNumSpec + nNumUdc28 + nNumMh;
		for (k = 0; k < psc->nSizDhCandi; k++)
		{
			if (m == nXrd)
			{
				k++;
				for (i = 0; psc->pwDhCandi[k] != 0x0000;  )
					pwOneCandi[i++] = psc->pwDhCandi[k++];
				nRet = i;
				break;           /* 退出k++的BREAK, NOT i++ */
			}
			else if (psc->pwDhCandi[k] == 0x0000)
				m++;
		}
		nRet  = 2;
	}
	/*
	**  Sh
	**  Special Consideration for Single Hanzi Area: Because there is 'Xian' Question
	**  Here!!!! nRet may be 2.
	*/
	else if ((nXrd >= (nNumSpec + nNumUdc28 + nNumMh + nNumDh)) && 
	        (nXrd < (nNumSpec + nNumUdc28 + nNumMh + nNumDh + nNumSh)) )
	{
		m = nNumSpec + nNumUdc28 + nNumMh + nNumDh;
		for (k = 0; k < psc->nSizShCandi; k++)
		{
			if (m == nXrd)
			{
				for (i = 0; psc->pwShCandi[k] != 0x0000;  )
					pwOneCandi[i++] = psc->pwShCandi[k++];
				nRet = i;
				break;           /* 退出k++的BREAK, NOT i++ */
			}
			else if (psc->pwShCandi[k] == 0x0000)
				m++;
		}
	}
	/*Gbk */
	else if ((nXrd >= (nNumSpec + nNumUdc28 + nNumMh + nNumDh + nNumSh)) && 
	        (nXrd < (nNumSpec + nNumUdc28 + nNumMh + nNumDh + nNumSh + nNumGbk)) )
	{
		m = nNumSpec + nNumUdc28 + nNumMh + nNumDh + nNumSh;
		for (k = 0; k < psc->nSizGbkCandi; k++)
		{
			if (m == nXrd)
			{
				for (i = 0; psc->pwGbkCandi[k] != 0x0000;  )
					pwOneCandi[i++] = psc->pwGbkCandi[k++];
				nRet = i;
				break;           /* 退出k++的BREAK, NOT i++ */
			}
			else if (psc->pwGbkCandi[k] == 0x0000)
				m++;
		}
	}
	else
	{
		fprintf(stderr, "nXrd is too Large!! in function GetXrdCandi().\n");
		nRet = 0;
	}
	
	return nRet;
}


/*
**  List All Those Information in Struct SysCandi.
**  This function is designed for DEBUG only. MXL 97.12.27
*/
VOID ListCandiInfo(SysCandi *psc, UdcCandi *puc)
{
	JINT    i, k, m;
	JWORD   wCandi[10];
	UCHAR   szCandi[20];
	
	for(i = 0; i < psc->nLenYj; i++)
	{
		if ((psc->nOrgYj[i] >= 450) && (psc->nOrgYj[i] <= 475) )
			printf("%s ", SHENGMUSTR[psc->nOrgYj[i] - 450]);
		else if ((psc->nOrgYj[i] >= 0) && (psc->nOrgYj[i] < 415) )
			printf("%s ", YINJIESTR_CSZ[psc->nOrgYj[i]]);
	}
	printf("\n\n");

	memset (wCandi,  '\0', 10 * sizeof(JWORD));
	memset (szCandi, '\0', 20);
	
	/* SpecCandi */
	printf("[SpecCandi]\n");
	i = m = 0;
	for (k = 0; k < puc->nNumSpecCandi; k++)
	{
		m = 1;
		Jword2Uchar(RecovDyzNWord2244(&(puc->pwSpecCandi[k]), m), szCandi, m);
		printf("%s\n", szCandi);

		memset (szCandi, '\0', 20);
	}
	printf("\n");

	/* Udc28Candi */
	printf("[Udc28Candi]\n");
	i = m = 0;
	for (k = 1; k < puc->nNumUdc28Candi; k++)
	{
		if (puc->pwUdc28Candi[k] == 0x0000)
		{
			Jword2Uchar(RecovDyzNWord2244(wCandi, m), szCandi, m);
			printf("%s\n", szCandi);

			i++;
			k++;
			m = 0;
			memset (wCandi, '\0', 10 * sizeof(JWORD));
			memset (szCandi, '\0', 20);
		}
		else
			wCandi[m++] = puc->pwUdc28Candi[k];
	}
	printf("\n");
	
	/* MhCandi */
	printf("[MhCandi]\n");
	i = m = 0;
	for(k = 1; i < psc->nNumMhCandi; k++)
	{
		if (psc->pwMhCandi[k] == 0x0000)
		{
			Jword2Uchar(RecovDyzNWord2244(wCandi, m), szCandi, m);
			printf("%s\n", szCandi);

			i++;
			k++;
			m = 0;
			memset (wCandi, '\0', 10 * sizeof(JWORD));
			memset (szCandi, '\0', 20);
		}
		else
			wCandi[m++] = psc->pwMhCandi[k];
	}
	printf("\n");
	
	/* DhCandi */
	printf("[DhCandi]\n");
	i = m = 0;
	for(k = 1; i < psc->nNumDhCandi; k++)
	{
		if (psc->pwDhCandi[k] == 0x0000)
		{
			Jword2Uchar(RecovDyzNWord2244(wCandi, m), szCandi, m);
			printf("%s\n", szCandi);

			i++;
			k++;
			m = 0;
			memset (wCandi, '\0', 10 * sizeof(JWORD));
			memset (szCandi, '\0', 20);
		}
		else
			wCandi[m++] = psc->pwDhCandi[k];
	}
	printf("\n");
	
	/* ShCandi */
	printf("[ShCandi]\n");
	i = m = 0;
	for(k = 0; i < psc->nNumShCandi; k++)
	{
		if (psc->pwShCandi[k] == 0x0000)
		{
			Jword2Uchar(RecovDyzNWord2244(wCandi, m), szCandi, m);
			printf("%s\n", szCandi);

			i++;
			m = 0;
			memset (wCandi, '\0', 10 * sizeof(JWORD));
			memset (szCandi, '\0', 20);
		}
		else
			wCandi[m++] = psc->pwShCandi[k];
	}
	printf("\n");

	/* GbkCandi */
	printf("[GbkCandi]\n");
	i = m = 0;
	for(k = 0; i < psc->nNumGbkCandi; k++)
	{
		if (psc->pwGbkCandi[k] == 0x0000)
		{
			Jword2Uchar(RecovDyzNWord2244(wCandi, m), szCandi, m);
			printf("%s\n", szCandi);

			i++;
			m = 0;
			memset (wCandi, '\0', 10 * sizeof(JWORD));
			memset (szCandi, '\0', 20);
		}
		else
			wCandi[m++] = psc->pwGbkCandi[k];
	}
	printf("\n\n");
}


/*
**                     X x I y Y 
**       X --> nTypeSpYj01   x --> nTypeSpYj1
**       Y --> nTypeSpYj02   y --> nTypeSpYj2
**       I --> Insert Position of nSpRawCaretPos
*/
JINT OnEditKeysym_SP(JINT* pNextKeysym, SesGuiElement* pSge, JINT nKeyLayMode)
{
	JINT    nLen, nLenRaw, nLenPrs, i, j, k, nTmp;
	JINT    nLenSp, nLenSpRaw;
	JINT    nTypeSpYj1, nTypeSpYj2, nTypeSpYj01, nTypeSpYj02, nTypeSpYj002, nTypeSpYj0002;

	JINT    nViewPixWid, nTmpWid;
	JINT    nPrsCaretPos;
	nViewPixWid = WIN_W - 61;	/* Here 59? 61? Is Accurate, with 9 indent in left!!! */
	
	nLenSp    = JwordValidLen (pSge->pwSpMixPeStr, 256);
	nLenSpRaw = JwordValidLen (pSge->pwSpRawPyStr, 40);

	nLen      = JwordValidLen (pSge->pwMixPeStr, 256);
	nLenRaw   = JwordValidLen (pSge->pwRawPyStr, 256);

	nTmpWid = 0;

	nTypeSpYj1 = nTypeSpYj2 = nTypeSpYj01 = nTypeSpYj02 = nTypeSpYj002 = nTypeSpYj0002 = -1;
	
	nTypeSpYj01   = TypeOfSpMixWord(pSge->pwSpMixPeStr, (pSge->nSpRawCaretPos - 2), nKeyLayMode);
	nTypeSpYj1    = TypeOfSpMixWord(pSge->pwSpMixPeStr, (pSge->nSpRawCaretPos - 1), nKeyLayMode);
	nTypeSpYj2    = TypeOfSpMixWord(pSge->pwSpMixPeStr, pSge->nSpRawCaretPos, nKeyLayMode);
	nTypeSpYj02   = TypeOfSpMixWord(pSge->pwSpMixPeStr, (pSge->nSpRawCaretPos + 1), nKeyLayMode);
	nTypeSpYj002  = TypeOfSpMixWord(pSge->pwSpMixPeStr, (pSge->nSpRawCaretPos + 2), nKeyLayMode);
	nTypeSpYj0002 = TypeOfSpMixWord(pSge->pwSpMixPeStr, (pSge->nSpRawCaretPos + 3), nKeyLayMode);
	
	if (pNextKeysym[0] == IMXK_Escape)
	{
		InitSge(pSge);
		goto LABEL0002SP;
	}

	/* QuoteRight is omitted in ShuangPin Model. MXL */
	else if (pNextKeysym[0] == IMXK_quoteright)
	{
#ifdef _DRAW_IM_WIN_H
		XBell (pDspIme, 100);
#endif
		goto LABEL0002SP;
	}

	else if ( ((pNextKeysym[0] >= IMXK_a) && (pNextKeysym[0] <= IMXK_z)) ||
	          ((pNextKeysym[0] >= IMXK_A) && (pNextKeysym[0] <= IMXK_Z)) )
	{
		if ((nLen >= 222) || (nLenRaw >= 222) || (nLenSp >= 30) || (nLenSpRaw >= 30))
		{
#ifdef _DRAW_IM_WIN_H
			XBell (pDspIme, 100);
#endif
			goto LABEL0002SP;
		}
		
		if (nTypeSpYj1 == SPYJ_YUNMU)
		{
			/* append [v] to [hw#rf#mn] to form [hw#rf#mn#v] ===> INVALID */
			/* Insert [v] to [hw#rf#mn] to form [hw#rf#v#mn] ===> NUMSIGN */
			/* Insert [v] to [hw#rf$mn] to form [hw#rf#v$mn] ===> DOLLAR  */
			/* Insert [v] to [hw#rf'mn] to form [hw#rf#v'mn] ===> QUOTE   */
			if ((nTypeSpYj2 == SPYJ_INVALID) || (nTypeSpYj2 == SPYJ_NUMSIGN) ||
				(nTypeSpYj2 == SPYJ_DOLLAR) || (nTypeSpYj2 == SPYJ_QUOTE))
			{
				/* Insert [#v] to Here!! */
				for (i = (nLenSp - 1); i >= pSge->nSpRawCaretPos; i--)
					pSge->pwSpMixPeStr[i + 2]    = pSge->pwSpMixPeStr[i];

				pSge->pwSpMixPeStr[pSge->nSpRawCaretPos]     = (JWORD)'#';
				pSge->pwSpMixPeStr[pSge->nSpRawCaretPos + 1] = (JWORD)pNextKeysym[0];
				pSge->pwSpMixPeStr[nLenSp + 2]               = 0x0000;
				(pSge->nSpRawCaretPos) += 2;
			}
			else
			{
				assert((nTypeSpYj2 != SPYJ_SHENGMU) && (nTypeSpYj2 != SPYJ_YUNMU));
			}
		}
		else if (nTypeSpYj1 == SPYJ_SHENGMU)
		{
			/* append [s] to [hw#rf#mn#v] to form [hw#rf#mn#vs] or [hw#rf#mn#v#s] ==> INVALID */
			/* Insert [s] to [hw#rf#v#mn] to form [hw#rf#vs#mn] or [hw#rf#v#s#mn] ==> NUMSIGN */
			/* Insert [s] to [hw#rf#v'mn] to form [hw#rf#vs'mn] or [hw#rf#v#s'#mn]==> QUOTE   */
			if ((nTypeSpYj2 == SPYJ_INVALID) || (nTypeSpYj2 == SPYJ_NUMSIGN) 
				|| (nTypeSpYj2 == SPYJ_QUOTE))
			{
				assert(pSge->nSpRawCaretPos >= 1);
				if (IsValidSpSuite((CHAR)pSge->pwSpMixPeStr[pSge->nSpRawCaretPos - 1], 
					(CHAR)pNextKeysym[0], nKeyLayMode) == TRUE)
				{
					/* Insert [s] */
					for (i = (nLenSp - 1); i >= pSge->nSpRawCaretPos; i--)
						pSge->pwSpMixPeStr[i + 1]    = pSge->pwSpMixPeStr[i];
					
					pSge->pwSpMixPeStr[pSge->nSpRawCaretPos]     = (JWORD)pNextKeysym[0];
					pSge->pwSpMixPeStr[nLenSp + 1]               = 0x0000;
					(pSge->nSpRawCaretPos) += 1;
				}
				else
				{
					/* Insert [#v] Here */
					for (i = (nLenSp - 1); i >= pSge->nSpRawCaretPos; i--)
						pSge->pwSpMixPeStr[i + 2]    = pSge->pwSpMixPeStr[i];

					pSge->pwSpMixPeStr[pSge->nSpRawCaretPos]     = (JWORD)'#';
					pSge->pwSpMixPeStr[pSge->nSpRawCaretPos + 1] = (JWORD)pNextKeysym[0];
					pSge->pwSpMixPeStr[nLenSp + 2]               = 0x0000;
					(pSge->nSpRawCaretPos) += 2;
				}
			}
			/* Insert [s] to [hw#rf#v$mn] to form [hw#rf#vs#mn] or [hw#rf#v$s#mn] */
			else if (nTypeSpYj2 == SPYJ_DOLLAR)
			{
				assert(pSge->nSpRawCaretPos >= 1);
				if (IsValidSpSuite((CHAR)pSge->pwSpMixPeStr[pSge->nSpRawCaretPos - 1], 
					(CHAR)pNextKeysym[0], nKeyLayMode) == TRUE)
				{
					/* replace [$] with [s#] and increase CaretPos by 1 */
					for (i = (nLenSp - 1); i >= pSge->nSpRawCaretPos; i--)
						pSge->pwSpMixPeStr[i + 1]    = pSge->pwSpMixPeStr[i];
					
					pSge->pwSpMixPeStr[pSge->nSpRawCaretPos]     = (JWORD)pNextKeysym[0];
					pSge->pwSpMixPeStr[pSge->nSpRawCaretPos + 1] = (JWORD)'#';
					pSge->pwSpMixPeStr[nLenSp + 1]               = 0x0000;
					(pSge->nSpRawCaretPos) += 1;
				}
				else
				{
					/* Insert [s#] after [$], NOT AFTER [v] */
					for (i = (nLenSp - 1); i >= (pSge->nSpRawCaretPos + 1); i--)
						pSge->pwSpMixPeStr[i + 2]    = pSge->pwSpMixPeStr[i];

					pSge->pwSpMixPeStr[pSge->nSpRawCaretPos + 1] = (JWORD)pNextKeysym[0];
					pSge->pwSpMixPeStr[pSge->nSpRawCaretPos + 2] = (JWORD)'#';
					pSge->pwSpMixPeStr[nLenSp + 2]               = 0x0000;
					(pSge->nSpRawCaretPos) += 2;
				}
			}
			/* Insert [s] to [hw#rf#vw#mn] to form [hw#rf#vs#mn] or [hw#rf#v#s#mn] */
			else if (nTypeSpYj2 == SPYJ_YUNMU)
			{
				assert(pSge->nSpRawCaretPos >= 1);
				if (IsValidSpSuite((CHAR)pSge->pwSpMixPeStr[pSge->nSpRawCaretPos - 1], 
					(CHAR)pNextKeysym[0], nKeyLayMode) == TRUE)
				{
					/* Replace [w] with [s], move Caret to the next position */
					pSge->pwSpMixPeStr[pSge->nSpRawCaretPos]     = (JWORD)pNextKeysym[0];
					(pSge->nSpRawCaretPos) += 1;
				}
				else
				{
					/* Replace [w] with [#s], add Caret by 2 */
					for (i = (nLenSp - 1); i >= pSge->nSpRawCaretPos; i--)
						pSge->pwSpMixPeStr[i + 1]    = pSge->pwSpMixPeStr[i];
					
					pSge->pwSpMixPeStr[pSge->nSpRawCaretPos]     = (JWORD)'#';
					pSge->pwSpMixPeStr[pSge->nSpRawCaretPos + 1] = (JWORD)pNextKeysym[0];
					pSge->pwSpMixPeStr[nLenSp + 1]               = 0x0000;
					(pSge->nSpRawCaretPos) += 2;
				}
			}
			else   /* nTypeSpYj2 == SPYJ_SHENGMU */
			{
				assert(nTypeSpYj2 != SPYJ_SHENGMU);
			}
		}
		/* From the header of SpStr part of this pwSpMixPeStr */
		else if (nTypeSpYj1 == SPYJ_INVALID)
		{
			if (nTypeSpYj2 == SPYJ_SHENGMU)    /* Insert [v] before [hw#rf#mn] to form [v#hw#rf#mn] */
			{
				/* Insert [v#], add CaretPos by 1 */
				for (i = (nLenSp - 1); i >= pSge->nSpRawCaretPos; i--)
					pSge->pwSpMixPeStr[i + 2]    = pSge->pwSpMixPeStr[i];
				
				pSge->pwSpMixPeStr[pSge->nSpRawCaretPos]     = (JWORD)pNextKeysym[0];
				pSge->pwSpMixPeStr[pSge->nSpRawCaretPos + 1] = (JWORD)'#';
				pSge->pwSpMixPeStr[nLenSp + 2]               = 0x0000;
				(pSge->nSpRawCaretPos) += 1;
			}
			else if (nTypeSpYj2 == SPYJ_QUOTE) /* Insert [v] before ['hw#rf#mn] to form [v'hw#rf#mn] */
			{
				/* Insert [v], add CaretPos by 1 */
				for (i = (nLenSp - 1); i >= pSge->nSpRawCaretPos; i--)
					pSge->pwSpMixPeStr[i + 1]    = pSge->pwSpMixPeStr[i];
					
				pSge->pwSpMixPeStr[pSge->nSpRawCaretPos]     = (JWORD)pNextKeysym[0];
				pSge->pwSpMixPeStr[nLenSp + 1]               = 0x0000;
				(pSge->nSpRawCaretPos) += 1;
			}
			else if (nTypeSpYj2 == SPYJ_INVALID)  /* Insert a single [v] to form [v] */
			{
				/* Only a single [v] in pwSpMixPeStr */
				assert((nLenSp == 0) && (pSge->nSpRawCaretPos == 0));

				pSge->pwSpMixPeStr[pSge->nSpRawCaretPos]     = (JWORD)pNextKeysym[0];
				pSge->pwSpMixPeStr[nLenSp + 1]               = 0x0000;
				(pSge->nSpRawCaretPos) += 1;
			}
			else
			{
				assert((nTypeSpYj2 != SPYJ_YUNMU) && (nTypeSpYj2 != SPYJ_NUMSIGN) && (nTypeSpYj2 != SPYJ_DOLLAR));
			}
		}
		else if (nTypeSpYj1 == SPYJ_QUOTE)
		{
			if (nTypeSpYj2 == SPYJ_INVALID)   /* Append [v] to [hw#rf'] to form [hw#rf'v] */
			{
				/* Because it means that Caret is at the end of pwSpMixPeStr */
				assert(nLenSp == pSge->nSpRawCaretPos);

				pSge->pwSpMixPeStr[pSge->nSpRawCaretPos]     = (JWORD)pNextKeysym[0];
				pSge->pwSpMixPeStr[nLenSp + 1]               = 0x0000;
				(pSge->nSpRawCaretPos) += 1;
			}
			else if (nTypeSpYj2 == SPYJ_SHENGMU)   /* Insert [s] to [hw#rf'v#mn] to form [hw#rf's#v#mn] */
			{
				/* Insert [s#], add CaretPos by 1 */
				for (i = (nLenSp - 1); i >= pSge->nSpRawCaretPos; i--)
					pSge->pwSpMixPeStr[i + 2]    = pSge->pwSpMixPeStr[i];
				
				pSge->pwSpMixPeStr[pSge->nSpRawCaretPos]     = (JWORD)pNextKeysym[0];
				pSge->pwSpMixPeStr[pSge->nSpRawCaretPos + 1] = (JWORD)'#';
				pSge->pwSpMixPeStr[nLenSp + 2]               = 0x0000;
				(pSge->nSpRawCaretPos) += 1;
			}
			else
			{
				/* nTypeSpYj2 should not be SPYJ_NUMSIGN   SPYJ_DOLLAR   SPYJ_YUNMU */
				assert(0);
			}
		}
		else if ((nTypeSpYj1 == SPYJ_NUMSIGN) || (nTypeSpYj1 == SPYJ_DOLLAR))
		{
			/* Error condition for this UI design. For _DEBUG Only */
			printf ("Error: Caret been Moved to the end of SPYJ_NUMSIGN or SPYJ_DOLLAR.\n");
		}
		
		/*********
		for (i = (nLenSp - 1); i >= pSge->nSpRawCaretPos; i--)
			pSge->pwSpMixPeStr[i + 1]    = pSge->pwSpMixPeStr[i];
		
		pSge->pwSpMixPeStr[pSge->nSpRawCaretPos] = (JWORD)pNextKeysym[0];
		pSge->pwSpMixPeStr[nLen + 1]             = 0x0000;
		(pSge->nSpRawCaretPos)++;
		********/

		/* Convert SpMix to QuanPinMix, include nSpRawCaretPos and nRawCaretPos */
		SpMix2QpMix(pSge->pwSpMixPeStr, pSge->pwMixPeStr, pSge->nSpRawCaretPos, &(pSge->nRawCaretPos), nKeyLayMode);
		nLenSp    = JwordValidLen (pSge->pwSpMixPeStr, 256);
		nLen      = JwordValidLen (pSge->pwMixPeStr, 256);
		
		goto LABEL0001SP;
	}

	else if (pNextKeysym[0] == IMXK_Delete)
	{
		if ((pSge->nRawCaretPos == nLen) || (pSge->nSpRawCaretPos == nLenSp))
		{
#ifdef _DRAW_IM_WIN_H
			XBell (pDspIme, 100);
#endif
			goto LABEL0002SP;
		}
		else
		{
			/*
			**  If to be deleted is a ShengMu, try to Delete a more YunMu also, and delete
			**  SPYJ_NUMSIGN or SPYJ_DOLLAR also.
			*/
			/*
			**  SPYJ_SHENGMU & SPYJ_YUNMU & SPYJ_QUOTE & SPYJ_NUMSIGN & SPYJ_DOLLAR & SPYJ_INVALID
			*/
			if (nTypeSpYj2 == SPYJ_INVALID)
			{
#ifdef _DRAW_IM_WIN_H
				XBell (pDspIme, 100);
#endif
				goto LABEL0002SP;
			}
			else if (nTypeSpYj2 == SPYJ_YUNMU)
			{
				/* Delete this YUNMU, No matter what content of nTypeSpYj02 */
				for (i = pSge->nSpRawCaretPos; i < (nLenSp - 1); i++)
					pSge->pwSpMixPeStr[i]      = pSge->pwSpMixPeStr[i + 1];
					
				pSge->pwSpMixPeStr[nLenSp - 1] = 0x0000;
			}
			else if (nTypeSpYj2 == SPYJ_SHENGMU)
			{
				if ((nTypeSpYj02 == SPYJ_QUOTE) || (nTypeSpYj02 == SPYJ_NUMSIGN)
					|| (nTypeSpYj02 == SPYJ_DOLLAR))
				{
					/* Delete this SHENGMU and QUOTE/NUMSIGN/DOLLAR */
					/* [vs#hw#^r#mn#gs]  ==> [vs#hw#^mn#gs]           */
					for (i = pSge->nSpRawCaretPos; i < (nLenSp - 2); i++)
						pSge->pwSpMixPeStr[i]      = pSge->pwSpMixPeStr[i + 2];
					
					pSge->pwSpMixPeStr[nLenSp - 2] = 0x0000;
					pSge->pwSpMixPeStr[nLenSp - 1] = 0x0000;
				}
				else if (nTypeSpYj02 == SPYJ_YUNMU)
				{
					if ((nTypeSpYj002 == SPYJ_QUOTE) || (nTypeSpYj002 == SPYJ_NUMSIGN) 
						|| (nTypeSpYj002 == SPYJ_DOLLAR))
					{
						/* Delete this SHENGMU and YUNMU and QUOTE/NUMSIGN/DOLLAR */
						/* [vs#hw#^rf#mn#gs]  ==> [vs#hw#^mn#gs] */
						/* [^vs#hw#rf#mn#gs]  ==> [^hw#rf#mn#gs] */
						for (i = pSge->nSpRawCaretPos; i < (nLenSp - 3); i++)
							pSge->pwSpMixPeStr[i]      = pSge->pwSpMixPeStr[i + 3];
					
						pSge->pwSpMixPeStr[nLenSp - 3] = 0x0000;
						pSge->pwSpMixPeStr[nLenSp - 2] = 0x0000;
						pSge->pwSpMixPeStr[nLenSp - 1] = 0x0000;
					}
					else if (nTypeSpYj002 == SPYJ_INVALID)
					{
						/* Delete this SHENGMU and YUNMU */
						/* [vs#hw#rf#mn#^gs]  ==> [vs#hw#rf#mn#^] */
						for (i = pSge->nSpRawCaretPos; i < (nLenSp - 2); i++)
							pSge->pwSpMixPeStr[i]      = pSge->pwSpMixPeStr[i + 2];
					
						pSge->pwSpMixPeStr[nLenSp - 2] = 0x0000;
						pSge->pwSpMixPeStr[nLenSp - 1] = 0x0000;
					}
					else
					{
						assert((nTypeSpYj002 != SPYJ_SHENGMU) && (nTypeSpYj002 != SPYJ_YUNMU));
					}
				}
				else if (nTypeSpYj02 == SPYJ_INVALID)
				{
					/* Delete Only this SHENGMU */
					/* [vs#hw#^f]        ==> [vs#hw#^]        INVALID  */
					/* [^f]              ==> [^]              INVALID  */
					for (i = pSge->nSpRawCaretPos; i < (nLenSp - 1); i++)
						pSge->pwSpMixPeStr[i]      = pSge->pwSpMixPeStr[i + 1];
					
					pSge->pwSpMixPeStr[nLenSp - 1] = 0x0000;
				}
				else
				{
					assert(nTypeSpYj02 != SPYJ_SHENGMU);
				}
			}
			else if (nTypeSpYj2 == SPYJ_QUOTE)
			{
				/*
				**  if nTypeSpYj02 == INVALID, Just delete it
				**  if nTypeSpYj02 == SHENGMU, replace it by [#]
				**  Else, assert failure.
				*/
				if (nTypeSpYj02 == SPYJ_INVALID)
				{
					for (i = pSge->nSpRawCaretPos; i < (nLenSp - 1); i++)
						pSge->pwSpMixPeStr[i]      = pSge->pwSpMixPeStr[i + 1];
					
					pSge->pwSpMixPeStr[nLenSp - 1] = 0x0000;
				}
				else if (nTypeSpYj02 == SPYJ_SHENGMU)
				{
					pSge->pwSpMixPeStr[pSge->nSpRawCaretPos] = (JWORD)'#';
				}
				else
				{
					assert(0);
				}
			}
			else if ((nTypeSpYj2 == SPYJ_NUMSIGN) || (nTypeSpYj2 == SPYJ_DOLLAR))
			{
				assert(nTypeSpYj02 == SPYJ_SHENGMU);
				
				/* Same as nTypeSpYj2 == SPYJ_SHENGMU, but delete this NUMSIGN/DOLLAR also */
				if ((nTypeSpYj002 == SPYJ_QUOTE) || (nTypeSpYj002 == SPYJ_NUMSIGN)
					|| (nTypeSpYj002 == SPYJ_DOLLAR) || (nTypeSpYj002 == SPYJ_INVALID))
				{
					/* Delete this SHENGMU and QUOTE/NUMSIGN/DOLLAR */
					/* [vs#hw^#r#mn#gs]  ==> [vs#hw^#mn#gs]           */
					/* [vs#hw^#f]        ==> [vs#hw^]        INVALID  */
					for (i = pSge->nSpRawCaretPos; i < (nLenSp - 2); i++)
						pSge->pwSpMixPeStr[i]      = pSge->pwSpMixPeStr[i + 2];
					
					pSge->pwSpMixPeStr[nLenSp - 2] = 0x0000;
					pSge->pwSpMixPeStr[nLenSp - 1] = 0x0000;
				}
				else if (nTypeSpYj002 == SPYJ_YUNMU)
				{
					/* [vs#hw^#rf#mn#gs]  ==> [vs#hw^#mn#gs] */
					/* [vs#hw#rf#mn^#gs]  ==> [vs#hw#rf#mn^] */
					if ((nTypeSpYj0002 == SPYJ_QUOTE) || (nTypeSpYj0002 == SPYJ_NUMSIGN) 
						|| (nTypeSpYj0002 == SPYJ_DOLLAR) || (nTypeSpYj0002 == SPYJ_INVALID))
					{
						/* Delete this SHENGMU and YUNMU and QUOTE/NUMSIGN/DOLLAR */
						for (i = pSge->nSpRawCaretPos; i < (nLenSp - 3); i++)
							pSge->pwSpMixPeStr[i]      = pSge->pwSpMixPeStr[i + 3];
						
						pSge->pwSpMixPeStr[nLenSp - 3] = 0x0000;
						pSge->pwSpMixPeStr[nLenSp - 2] = 0x0000;
						pSge->pwSpMixPeStr[nLenSp - 1] = 0x0000;
					}
					else
					{
						assert((nTypeSpYj0002 != SPYJ_SHENGMU) && (nTypeSpYj0002 != SPYJ_YUNMU));
					}
				}
				else
				{
					assert(nTypeSpYj002 != SPYJ_SHENGMU);
				}
			}

			/* pSge->nSpRawCaretPos remain previous value */
			
			/* Convert SpMix to QuanPinMix, include nSpRawCaretPos and nRawCaretPos */
			SpMix2QpMix(pSge->pwSpMixPeStr, pSge->pwMixPeStr, pSge->nSpRawCaretPos, &(pSge->nRawCaretPos), nKeyLayMode);
			nLenSp    = JwordValidLen (pSge->pwSpMixPeStr, UONE);
			nLen      = JwordValidLen (pSge->pwMixPeStr, UONE);

			goto LABEL0001SP;
		}
	}

	else if (pNextKeysym[0] == IMXK_BackSpace)
	{
		if ((pSge->nRawCaretPos == 0) || (nLen == 0) || (nLenSp == 0) || (pSge->nSpRawCaretPos == 0))
		{
#ifdef _DRAW_IM_WIN_H
			XBell (pDspIme, 100);
#endif
			goto LABEL0002SP;
		}
		else if (pSge->pwSpMixPeStr[(pSge->nSpRawCaretPos) - 1] >= 0x8140)   /* Character before Caret is Hanzi */
		{
			/* Simple be explained as [LEFT Arrow]  */
			pNextKeysym[0] = IMXK_Left;
			OnEditKeysym_SP(pNextKeysym, pSge, nKeyLayMode);
		}
		else
		{
			/* Simple be explained as [LEFT Arrow] and [Delete] */
			pNextKeysym[0] = IMXK_Left;
			OnEditKeysym_SP(pNextKeysym, pSge, nKeyLayMode);
			pNextKeysym[0] = IMXK_Delete;
			OnEditKeysym_SP(pNextKeysym, pSge, nKeyLayMode);
		}
	}

	else if (pNextKeysym[0] == IMXK_Left)
	{
		if ((pSge->nRawCaretPos == 0) || (nLen == 0) || (nLenSp == 0) || (pSge->nSpRawCaretPos == 0))
		{
#ifdef _DRAW_IM_WIN_H
			XBell (pDspIme, 100);
#endif
			goto LABEL0002SP;
		}
		else if (pSge->pwSpMixPeStr[(pSge->nSpRawCaretPos) - 1] >= 0x8140)   /* Chracter before Caret is Hanzi */
		{
			/* For ShuangPin Model, This function call SpMix2QpMix() also. */
			RestoreHzToPy_SP(pSge, PYIM_RESTORE_LAST);
			nLenSp = JwordValidLen(pSge->pwSpMixPeStr, UONE);

			j = 0;
			for (i = 0; i < nLen; i++)
				if (pSge->pwSpMixPeStr[i] >= 0x8140)
					j ++;
			pSge->nSpRawCaretPos = j;

			/*
			**  Convert SpMix to QuanPinMix, include nSpRawCaretPos and nRawCaretPos 
			*/
			SpMix2QpMix(pSge->pwSpMixPeStr, pSge->pwMixPeStr, pSge->nSpRawCaretPos, &(pSge->nRawCaretPos), nKeyLayMode);
			nLen      = JwordValidLen (pSge->pwMixPeStr, UONE);

			goto LABEL0001SP;
		}
		else
		{
			if (nTypeSpYj1 != SPYJ_INVALID)
			{
				if ((nTypeSpYj01 == SPYJ_NUMSIGN) || (nTypeSpYj02 == SPYJ_DOLLAR))
					pSge->nSpRawCaretPos -= 2;
				else
					pSge->nSpRawCaretPos -= 1;
			}
			else
			{
				assert(0);
			}
			
			SpMix2QpMix(pSge->pwSpMixPeStr, pSge->pwMixPeStr, pSge->nSpRawCaretPos, &(pSge->nRawCaretPos), nKeyLayMode);
			nLen      = JwordValidLen (pSge->pwMixPeStr, UONE);

			goto LABEL0001SP;
		}
	}

	else if (pNextKeysym[0] == IMXK_Right)
	{
		if ((pSge->nRawCaretPos == nLen) || (pSge->nSpRawCaretPos == nLenSp))
		{
#ifdef _DRAW_IM_WIN_H
			XBell (pDspIme, 100);
#endif
			goto LABEL0002SP;
		}
		else
		{
			if (nTypeSpYj2 != SPYJ_INVALID)
			{
				if ((nTypeSpYj2 == SPYJ_NUMSIGN) || (nTypeSpYj2 == SPYJ_DOLLAR))
					pSge->nSpRawCaretPos += 2;
				else
					pSge->nSpRawCaretPos += 1;
			}
			else
			{
				assert(0);
			}
			
			SpMix2QpMix(pSge->pwSpMixPeStr, pSge->pwMixPeStr, pSge->nSpRawCaretPos, &(pSge->nRawCaretPos), nKeyLayMode);
			nLen      = JwordValidLen (pSge->pwMixPeStr, UONE);

			goto LABEL0001SP;
		}
	}

	else if (pNextKeysym[0] == IMXK_Home)
	{
		RestoreHzToPy_SP(pSge, PYIM_RESTORE_ALL);
		nLenSp   = JwordValidLen(pSge->pwSpMixPeStr, UONE);
		pSge->nSpRawCaretPos = 0;
		
		/*
		**  Convert SpMix to QuanPinMix, include nSpRawCaretPos and nRawCaretPos 
		*/
		SpMix2QpMix(pSge->pwSpMixPeStr, pSge->pwMixPeStr, pSge->nSpRawCaretPos, &(pSge->nRawCaretPos), nKeyLayMode);
		nLen      = JwordValidLen (pSge->pwMixPeStr, UONE);
		
		pSge->nRawCaretPos  = 0;
		pSge->nViewCaretPos = 0;
		pSge->nViewPeStart  = 0;
		
		goto LABEL0001SP;
	}

	else if (pNextKeysym[0] == IMXK_End)
	{
		pSge->nSpRawCaretPos = nLenSp;
		pSge->nRawCaretPos   = nLen;
		goto LABEL0001SP;
	}
	
	/*
	** This judgement is added to process Selection Action or 
	** Backspace/Home/LeftArrow to existing Hanzi 
	*/
	else if (pNextKeysym[0] == IMXK_REDRAW_INTERNAL)
	{
		/*
		**  Convert SpMix to QuanPinMix, include nSpRawCaretPos and nRawCaretPos 
		*/
		SpMix2QpMix(pSge->pwSpMixPeStr, pSge->pwMixPeStr, pSge->nSpRawCaretPos, &(pSge->nRawCaretPos), nKeyLayMode);
		nLenSp    = JwordValidLen (pSge->pwSpMixPeStr, 256);
		nLen      = JwordValidLen (pSge->pwMixPeStr, 256);
		
		nTmp = JwordValidLen(pSge->pwSlctHz, 512);
		k = 0;
		for (i = 0; i < nTmp; i++)
			if (pSge->pwSlctHz[i] >= 0x8140)
				k++;
		
		pSge->nViewPeStart = _MAX(0, k - 8);

		goto LABEL0001SP;
	}
	
	else
		goto LABEL0002SP;

LABEL0001SP:
	{
		/* Prase pwMixPeStr and fill other related pSge field */
		PraseMixRawPe(pSge);
		
		nPrsCaretPos = QpCaretToPrsCaret(pSge->pwPrsMixStr, pSge->nRawCaretPos);
		if (nPrsCaretPos <= pSge->nViewPeStart)
			pSge->nViewPeStart = nPrsCaretPos - _MIN(3, nPrsCaretPos);

		nTmpWid = PixWidBetween_SP (pSge->pwPrsMixStr, pSge->nViewPeStart, nPrsCaretPos);
		
		if (nTmpWid > nViewPixWid)
		{
			for (i = pSge->nViewPeStart; nTmpWid > nViewPixWid; i++)
				nTmpWid = PixWidBetween_SP (pSge->pwPrsMixStr, i, nPrsCaretPos);
			
			pSge->nViewPeStart = i - 1;
			pSge->nViewPeEnd   = nPrsCaretPos;
		}
		
		nTmpWid = 0;
		nLenPrs = JwordValidLen(pSge->pwPrsMixStr, UTWO);
		for (i = pSge->nViewPeStart; (i <= nLenPrs) && (nTmpWid <= nViewPixWid); i++)
			nTmpWid = PixWidBetween_SP (pSge->pwPrsMixStr, pSge->nViewPeStart, i);
		
		pSge->nViewPeEnd = i - 1;
		
		GetDspPEandCaretPos_SP (pSge);
	}

LABEL0002SP:	
	return TRUE;
}


/*
** NOTICE:    pSge->pwRawPyStr WAS NOT USED Properly!!   MXL 
** In QianPinYin Model, pwRawPyStr must be filled each time.
** Replaced by a KeyStroke Count maybe more helpful!!
*/

/*
**  Convert pwSpMix to pwMix. pwSpMix is Hanzi and Sp Chars string. convert these Sp Chars to
**  Qp Chars (without SPACE), and recalulates Caret Pos.
*/
VOID SpMix2QpMix(JWORD* pwSpMix, JWORD* pwMix, JINT nSpCaret, JINT *pnCaret, JINT nKeyLayMode)
{
	CHAR    szOrgSp[40], szQp[256];
	JINT    i, nLen, nLenHz;
	JINT    nTmpCaret;
	
	nLen   = JwordValidLen (pwSpMix, 256);
	nLenHz = 0;
	
	for (i = 0; i < nLen; i++)
	{
		if (pwSpMix[i] <= 0x0080)
			break;               /* BREAK out FOR_i */
	}
	nLenHz = i;
	
	assert((nLen - nLenHz) < 40);
	assert(nSpCaret >= nLenHz);
	
	memset (szOrgSp, '\0', 40);
	memset (szQp,    '\0', 256);
	
	for (i = nLenHz; i < nLen; i++)
		szOrgSp[i - nLenHz] = (CHAR)(pwSpMix[i] & 0x00FF);
	
	Sp2QpStr_Better(szOrgSp, szQp, nKeyLayMode, nSpCaret - nLenHz, &nTmpCaret);
	
	for (i = 0; i < nLenHz; i++)
		pwMix[i] = pwSpMix[i];

	assert((nLenHz + strlen(szQp)) < 240);

	for (i = nLenHz; i < nLenHz + strlen(szQp); i++)
		pwMix[i] = (JWORD)szQp[i - nLenHz];
		
	pwMix[i] = 0x0000;
	*pnCaret = nTmpCaret + nLenHz;
}


JINT TypeOfSpMixWord(JWORD *pwSpMix, JINT nPos, JINT nKeyLayMode)
{
	CHAR    szOrgSp[40];
	JINT    i, nLenHz, nLen;
	JINT    nRes;

	nLen   = JwordValidLen (pwSpMix, 256);
	nLenHz = 0;
	
	for (i = 0; i < nLen; i++)
	{
		if (pwSpMix[i] <= 0x0080)
			break;               /* BREAK out FOR_i */
	}
	nLenHz = i;

	memset (szOrgSp, '\0', 40);
	
#ifdef _DEBUG
	if ((nLen - nLenHz) > 39)
		fprintf (stderr, "Error in TypeOfSpMixWord(): > 39!\n");
#endif

	for (i = nLenHz; i < nLen; i++)
		szOrgSp[i - nLenHz] = (CHAR)(pwSpMix[i] & 0x00FF);
		
	nRes = TypeOfSpChar(szOrgSp, (nPos - nLenHz), nKeyLayMode);
	return nRes;
}


/*
**  nResFlag: PYIM_RESTORE_ALL  PYIM_RESTORE_LAST
**  Conside only "HHHHHHHeeeeeee", Not include "HHHHHHeeeeHeeeeHHeee"
*/
JINT RestoreHzToPy_SP(SesGuiElement* pSge, JINT nResFlag)
{
	JINT    nSelectHzLen, nSpSelectRawEngLen, nSpTotRawLen;
	JINT    nLenHz, nLenSpEng, nFirstAddr;
	JWORD   waHz[256], waSpEng[256];
	
	JINT   i, j, k, nTmp;

	nSelectHzLen        = JwordValidLen(pSge->pwSlctHz, 512);
	nSpSelectRawEngLen  = JwordValidLen(pSge->pwSpSlctRawPy, 512);
	nSpTotRawLen        = JwordValidLen(pSge->pwSpMixPeStr, 256);
	
	for (i = 0; i < 256; i++)
	{
		waHz[i]     = 0x0000;
		waSpEng[i]  = 0x0000;
	}

	if (nResFlag == PYIM_RESTORE_ALL)
	{
		i = j = 0;
		for (i = 0; i < nSelectHzLen; i++)
			if (pSge->pwSlctHz[i] >= 0x8140)
				waHz[j++] = pSge->pwSlctHz[i];
		nLenHz = j;

		i = j = 0;
		for (i = 0; i < nSpSelectRawEngLen; i++)
			if (pSge->pwSpSlctRawPy[i] >= 0x0020)
				waSpEng[j++] = pSge->pwSpSlctRawPy[i];
		nLenSpEng = j;
		
		for (i = 0; i < 512; i++)
		{
			pSge->pwSlctHz[i]      = 0x0000;
			pSge->pwSpSlctRawPy[i] = 0x0000;
		}
		pSge->nSlctSteps = 0;
	}

	else if (nResFlag == PYIM_RESTORE_LAST)
	{
		i = j = k = 0;
		for (i = 0; i < nSpSelectRawEngLen; i++)
		{
			if (pSge->pwSpSlctRawPy[i] == 0x0009)
				j++;
			
			if ((j == (pSge->nSlctSteps - 1)) && (pSge->pwSpSlctRawPy[i] != 0x0009))
			{
				waSpEng[k++]           = pSge->pwSpSlctRawPy[i];
				pSge->pwSpSlctRawPy[i] = 0x0000;
			}
			if (j == pSge->nSlctSteps)
				pSge->pwSpSlctRawPy[i] = 0x0000;
		}
		nLenSpEng = k;
				
		i = j = k = 0;
		for (i = 0; i < nSelectHzLen; i++)
		{
			if (pSge->pwSlctHz[i] == 0x0009)
				j++;
			
			if ((j == (pSge->nSlctSteps - 1)) && (pSge->pwSlctHz[i] != 0x0009))
			{
				waHz[k++] = pSge->pwSlctHz[i];
				pSge->pwSlctHz[i] = 0x0000;
			}
			if (j == pSge->nSlctSteps)
				pSge->pwSlctHz[i] = 0x0000;
		}
		nLenHz = k;
		
		(pSge->nSlctSteps)--;

	}
	else
		return FALSE;

	if (nResFlag == PYIM_RESTORE_ALL)
		nFirstAddr = 0;
	else    /* nResFlag == PYIM_RESTORE_LAST */
	{
		nTmp = 0;
		for (i = 0; i < nSpTotRawLen; i++)
			if (pSge->pwSpMixPeStr[i] >= 0x8140)
				nTmp++;
		
		nFirstAddr = nTmp - nLenHz;
	}
	
	if (nLenHz >= nLenSpEng)
	{
		for (i = nFirstAddr; i < (nFirstAddr + nLenSpEng); i++)
			*(pSge->pwSpMixPeStr + i) = waSpEng[i - nFirstAddr];
			
		for (i = (nFirstAddr + nLenSpEng); i < (nSpTotRawLen - (nLenHz - nLenSpEng)); i++)
			*(pSge->pwSpMixPeStr + i) = *(pSge->pwSpMixPeStr + i + (nLenHz - nLenSpEng));
			
		for (i = (nSpTotRawLen - (nLenHz - nLenSpEng)); i < 256; i++)
			*(pSge->pwSpMixPeStr + i) = 0x0000;
	}
	else if (nLenHz < nLenSpEng)
	{
		for (i == (nSpTotRawLen + (nLenSpEng - nLenHz)); i < 256; i++)
			*(pSge->pwSpMixPeStr + i) = 0x0000;
			
		/* To be rewriten TO: i++ MXL: 1997-12-27 */
		for (i = nSpTotRawLen + (nLenSpEng - nLenHz) - 1; i >= (nFirstAddr + nLenSpEng); i--)
			*(pSge->pwSpMixPeStr + i) = *(pSge->pwSpMixPeStr + i - nLenSpEng + nLenHz);
			
		for (i = nFirstAddr; i < (nFirstAddr + nLenSpEng); i++)
			*(pSge->pwSpMixPeStr + i) = waSpEng[i - nFirstAddr];
	}
	
	return TRUE;
}


JINT OnSelectKeysym_SP(JINT* pNextKeysym, SesGuiElement* pSge)
{
	JINT   i, j, nTmp, nTmpLen, nTmpRes, nRes;
	JINT   nCurCandiNum;
	JINT   nChoiceMark;    /* nChoiceMark start from 1 to nCurCandiNum */
	CHAR   szYjStr[80];    /* ShuangPin Yinjie String (including [']) corressponding to current Selection */
	JINT   nLenThisSel;
	JWORD  wThisSel[9];
	JINT   nXrd;
	JINT   nYj, nYjLen;
	
	JINT   nOffset, nSpYjLen, w;        /* a nOffset was added to calculates the Position of Hanzi in pwSpMixPeStr  */
	
	nCurCandiNum = pSge->nViewCandiEnd - pSge->nViewCandiStart;
	
	if ((pNextKeysym[0] == IMXK_space) && (nCurCandiNum >= 1))
		pNextKeysym[0] = IMXK_1;
	else if ((pNextKeysym[0] == IMXK_space) && (nCurCandiNum == 0))
	{
#ifdef _DRAW_IM_WIN_H
		XBell (pDspIme, 100);
#endif
		return TRUE;
	}
	
	if ((pNextKeysym[0] > IMXK_0) && (pNextKeysym[0] <= (IMXK_0 + nCurCandiNum)))
	{
		for(i = 0; i < 9; i++)
			wThisSel[i] = 0x0000;
		nChoiceMark     = pNextKeysym[0] - IMXK_0;
		nXrd            = pSge->nViewCandiStart + nChoiceMark - 1;
		nLenThisSel     = GetXrdCandi(&(pSge->scSysCandi), &(pSge->ucUdcCandi), nXrd, wThisSel);

		for(i = 0; i < 80; i++)
			szYjStr[i]  = '\0';

		/* 考虑 XIAN 问题, 如果nXrd指示是在SingleHanzi, 则只取第一个音节串 */
		if (nXrd >= (pSge->ucUdcCandi.nNumSpecCandi + pSge->ucUdcCandi.nNumUdc28Candi + 
		             pSge->scSysCandi.nNumMhCandi   + pSge->scSysCandi.nNumDhCandi))
			nTmp = 1;
		else       /* 是双字或多字选择 */
			nTmp = nLenThisSel;

		/*
		**  BUG FIXED: nTmp May be 7, more example, "中华人民共和国",
		**             But OrgYj String is "zh h r m g". [0, 1, 2, 3, 4]
		**             nOrgYj[5] & nOrgYj[6] have been set to 0 in GetF9Yj,
		**             So, change the judgement condition
		**             FROM (j < nTmp) TO (j < nTmp) && (j < nLenYj) !!
		**                  ^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^
		**             MXL, 97-12-06.
		*/
		/* Empty FOR_j HERE!! Find where is the end of Hanzi */
		for (j = 0; pSge->pwSpMixPeStr[j] >= 0x0080; j++)
		{
			;
		}
		nOffset = j;        /* Offset of First Sp English char */
		
		w = 0;
		for (j = 0; (j < nTmp) && (j < pSge->scSysCandi.nLenYj); j++)
		{
			/* Here is a LAZY PATCH!! [Scott Ma 98-04-26]  */
			nSpYjLen = 0;
			if ((pSge->scSysCandi.nOrgYj[j + 1] & 0x000F0000) == 0x000E0000)    /* There is a ['] aheader */
			{
				nSpYjLen++;
			}
			else if ((pSge->scSysCandi.nOrgYj[j + 1] & 0x000F0000) == 0x000D0000)    /* There is a [#] aheader */
			{
				nSpYjLen++;
			}
			else if ((pSge->scSysCandi.nOrgYj[j + 1] & 0x000F0000) == 0x000C0000)    /* There is a [$] aheader */
			{
				nSpYjLen++;
			}

			nYj = pSge->scSysCandi.nOrgYj[j] & 0x01FF;
			if ((nYj >= 0) && (nYj < NUM_YINJIE) && (nYj != 450) && (nYj != 455) && (nYj != 462) && (nYj != 463) && (nYj != 464))
				nSpYjLen += 2;
			else
				nSpYjLen += 1;
				
			for (i = 0; i < nSpYjLen; i++)
				szYjStr[w++] = (CHAR)(pSge->pwSpMixPeStr[nOffset++]);
		}

#ifdef _DEBUG
		printf("TO BE REPLACED: nTmp is [%d],  [%s], nLenYj is %d\n", nTmp, szYjStr, pSge->scSysCandi.nLenYj);
#endif

		nRes = nTmpLen = JwordValidLen(pSge->pwSlctHz, 512);
		
		for(i = 0; i < nLenThisSel; i++)
			pSge->pwSlctHz[nTmpLen + i]        = wThisSel[i];
		pSge->pwSlctHz[nTmpLen + nLenThisSel]  = 0x0009;        /* Horizonal Tab Key */
		(pSge->nSlctSteps)++;

		/* Calc new pSge->nRawCaretPos */
		nTmp    = 0;
		nTmpLen = JwordValidLen(pSge->pwSlctHz, 512);
		for (i = 0; i < nTmpLen; i++)
			if (pSge->pwSlctHz[i] != 0x0009)
				nTmp++;
		pSge->nSpRawCaretPos = nTmp;

		nTmpRes  = JwordStrStrReplace(pSge->pwSpMixPeStr, StrToJword(szYjStr), (JWORD*)RecovDyz2244((UCHAR*)wThisSel), nLenThisSel);
		if (nTmpRes == FALSE)
			fprintf (stderr, "Failed in OnSelectKeysym(): JwordStrStrReplace\n");
		
		nTmpLen  = JwordValidLen(pSge->pwSpSlctRawPy, 512);
		nYjLen   = strlen(szYjStr);
		for (i = nTmpLen; i < (nTmpLen + nYjLen); i++)
			pSge->pwSpSlctRawPy[i] = (JWORD)szYjStr[i - nTmpLen];
		pSge->pwSpSlctRawPy[nTmpLen + nYjLen] = 0x0009;	/* Horizonal Tab Key */
		
		/* Recycle call to IMPinyinTrans() !!!! */
		pNextKeysym[0] = IMXK_REDRAW_INTERNAL;
		IMPinyinTrans(pNextKeysym, pSge);
	}
	else
	{
#ifdef _DRAW_IM_WIN_H
		XBell (pDspIme, 100);
#endif
		;
	}

	return TRUE;
}


/* 
 *  Prepare and fill pSge structure for given symbol type
 *  nSymbType from 0 to 12
 */
JINT PrepareSymbolSge(SesGuiElement* pSge, JINT nSymbType)
{
	JINT    i, nLen, nTmp;
	
	free (pSge->scSysCandi.pwMhCandi);
	free (pSge->scSysCandi.pwDhCandi);
	free (pSge->scSysCandi.pwShCandi);
	free (pSge->scSysCandi.pwGbkCandi);
	free (pSge->ucUdcCandi.pwUdc28Candi);
	
	pSge->scSysCandi.pwMhCandi    = NULL;
	pSge->scSysCandi.pwDhCandi    = NULL;
	pSge->scSysCandi.pwShCandi    = NULL;
	pSge->scSysCandi.pwGbkCandi   = NULL;
	pSge->ucUdcCandi.pwUdc28Candi = NULL;
	
	InitSge(pSge);
	
	nLen = JwordValidLen(pwNewpySym[nSymbType], 256);
	
	pSge->scSysCandi.nNumShCandi = nLen;
	pSge->scSysCandi.nSizShCandi = nLen * 2;     /* In Jword */
	pSge->scSysCandi.pwShCandi   = (JWORD*)malloc((nLen * 2  + MALIGN) * sizeof(JWORD));
	if (pSge->scSysCandi.pwShCandi == NULL)
	{
		fprintf(stderr, "Error!! Failed to Malloc() in Function PrepareSymbolSge().\n");
		return FALSE;
	}
	memset(pSge->scSysCandi.pwShCandi,  0x00, (nLen * 2  + MALIGN) * sizeof(JWORD));
	
	for (i = 0; i < nLen; i++)
		pSge->scSysCandi.pwShCandi[2 * i] = pwNewpySym[nSymbType][i];

	pSge->nViewCandiStart   = 0;
	pSge->nViewCandiEnd     = 0;
	pSge->nViewPage         = 0;
	ScrollViewCandiPage(&(pSge->scSysCandi), &(pSge->ucUdcCandi), pSge);

	if (pSge->nViewCandiStart == 0)
		pSge->nIconFlag &= (~F_PREVPAGE);
	else
		pSge->nIconFlag |= F_PREVPAGE;

	nTmp  = pSge->scSysCandi.nNumMhCandi   + pSge->scSysCandi.nNumDhCandi  +
	        pSge->scSysCandi.nNumShCandi   + pSge->scSysCandi.nNumGbkCandi + 
	        pSge->ucUdcCandi.nNumSpecCandi + pSge->ucUdcCandi.nNumUdc28Candi;
	if (pSge->nViewCandiEnd < nTmp)
		pSge->nIconFlag |= F_NEXTPAGE;
	else
		pSge->nIconFlag &= (~F_NEXTPAGE);
	
	return TRUE;
}


VOID ProcSymbIMKey(SesGuiElement* pSge, JINT nSymbType, JINT *pNextKeysym, ImToXSun *pIeh)
{
	JWORD  wThisSel[9];
	JINT   i, nCurCandiNum, nChoiceMark, nXrd, nLenThisSel;
	
	GetIehFromSge(pIeh, pSge);
	pIeh->nType = IMXSUN_TYPE_NORMAL;
	memset(pIeh->pwCommit, 0x00, UONE * sizeof(JWORD));
	
	if ((nSymbType != pSge->nKeyLayMode) || (pSge->nKeyLayMode != pSge->nPrevKeyLayMode))
	{
		PrepareSymbolSge(pSge, nSymbType);
		GetIehFromSge(pIeh, pSge);
		
		pIeh->nType = IMXSUN_TYPE_NORMAL;
		pSge->nKeyLayMode     = nSymbType;
		pSge->nPrevKeyLayMode = pSge->nKeyLayMode;
	}
	
	if (IsPageKeysym(pNextKeysym) == TRUE)
	{
		OnPageKeysym(pNextKeysym, pSge);
		GetIehFromSge(pIeh, pSge);
		pIeh->nType = IMXSUN_TYPE_NORMAL;
	}
	else if (IsSelectKeysym(pNextKeysym) == TRUE)
	{
		nCurCandiNum = pSge->nViewCandiEnd - pSge->nViewCandiStart;
		if (pNextKeysym[0] == IMXK_space)
			pNextKeysym[0] = IMXK_1;
			
		if ((pNextKeysym[0] > IMXK_0) && (pNextKeysym[0] <= (IMXK_0 + nCurCandiNum)))
		{
			memset(wThisSel, 0x00, 9 * 2);
			nChoiceMark     = pNextKeysym[0] - IMXK_0;
			nXrd            = pSge->nViewCandiStart + nChoiceMark - 1;
			nLenThisSel     = GetXrdCandi(&(pSge->scSysCandi), &(pSge->ucUdcCandi), nXrd, wThisSel);
			memset(pIeh->pwCommit, 0x00, 256 * 2);
			assert(nLenThisSel == 1);
			GetIehFromSge(pIeh, pSge);
			for (i = 0; i < nLenThisSel; i++)
				pIeh->pwCommit[i] = wThisSel[i];
			pIeh->nType = IMXSUN_TYPE_COMMITSYMBOL;
		}
		else
		{
			NULL;
#ifdef _DRAW_IM_WIN_H
			XBell (pDspIme, 100);
#endif
		}
	}
	else if ( (IsPageKeysym(pNextKeysym) != TRUE) || (IsSelectKeysym(pNextKeysym) != TRUE) )
	{
		NULL;
#ifdef _DRAW_IM_WIN_H
		XBell (pDspIme, 100);
#endif
	}
	return;
}


