WindowsXP-SP1/windows/feime/ddk/cht/eudc/imeeudc.c
2020-09-30 16:53:49 +02:00

2008 lines
59 KiB
C

/*++
Copyright (c) 1990-1998 Microsoft Corporation, All Rights Reserved
Module Name:
IMEEUDC.c
++*/
#include <windows.h>
#include <commdlg.h>
#include <imm.h>
#include "imeeudc.h"
//
// J. J. Lee 9-29-1994
//
// UI of this program
// +--------------------------------------------------+
// +--------------------------------------------------+
// | |
// | +------------+ |
// | | FA40 | |
// | +------------+ |
// | |
// | +------------+ +-----+ |
// | (IMEName iStartIME + 0) | GOLD | | ^ | |
// | +------------+ | | | |
// | | | |
// | +------------+ |scrol| |
// | (IMEName iStartIME + 1) | WOOD | | bar | |
// | +------------+ | | |
// | | | |
// | +------------+ | | | |
// | (IMEName iStartIME + 2) | WATER | | V | |
// | +------------+ +-----+ |
// | |
// | +----------+ +-----------+ |
// | | Register | | Abort | |
// | +----------+ +-----------+ |
// | |
// +--------------------------------------------------+
//
// The scroll bar only appear when there are more than 3 IMEs
//
// This is a sample code for EUDC regsiter a new created word into IMEs
typedef struct _tagREGWORDSTRUCT {
HKL hKL;
BOOL bUpdate;
TCHAR szIMEName[16];
UINT uIMENameLen;
TCHAR szReading[14];
DWORD dwReadingLen;
} REGWORDSTRUCT;
typedef REGWORDSTRUCT FAR *LPREGWORDSTRUCT;
typedef struct _tagIMELINKREGWORD {
HIMC hOldIMC;
HIMC hRegWordIMC;
BOOL fCompMsg;
UINT nEudcIMEs;
UINT nCurrIME;
TCHAR szEudcCodeString[4];
REGWORDSTRUCT sRegWordStruct[1];
} IMELINKREGWORD;
typedef IMELINKREGWORD FAR *LPIMELINKREGWORD;
typedef struct _tagIMERADICALRECT {
UINT nStartIME;
UINT nPerPageIMEs;
SIZE lTextSize;
SIZE lCurrReadingExtent;
HWND hRegWordButton;
HWND hScrollWnd;
RECT rcRadical[1];
} IMERADICALRECT;
typedef IMERADICALRECT FAR *LPIMERADICALRECT;
static const TCHAR szAppName[] = TEXT("EUDC");
static const TCHAR szMenuName[] = TEXT("ImeEudcMenu");
static const TCHAR szRegWordCls[] = TEXT("Radical");
static const TCHAR szImeLinkDlg[] = TEXT("ImeLinkDlg");
typedef struct _tagCOUNTRYSETTING {
UINT uCodePage;
LPCTSTR szCodePage;
} COUNTRYSETTING;
static const COUNTRYSETTING sCountry[] = {
{
BIG5_CP, TEXT("BIG5")
}
, {
ALT_BIG5_CP, TEXT("BIG5")
}
#if defined(UNICODE)
, {
UNICODE_CP, TEXT("UNICODE")
}
#endif
, {
GB2312_CP, TEXT("GB2312")
}
};
static HINSTANCE hAppInst;
/************************************************************/
/* SwitchToThisIME */
/************************************************************/
void SwitchToThisIME(
HWND hWnd,
UINT uIndex)
{
LPIMELINKREGWORD lpImeLinkRegWord;
LPREGWORDSTRUCT lpRegWordStructTmp;
LPIMERADICALRECT lpImeLinkRadical;
DWORD fdwConversionMode, fdwSentenceMode;
lpImeLinkRegWord = (LPIMELINKREGWORD)GetWindowLongPtr(hWnd,
GWL_IMELINKREGWORD);
if (lpImeLinkRegWord->nCurrIME == uIndex) {
return;
}
if (uIndex >= lpImeLinkRegWord->nEudcIMEs) {
MessageBeep((UINT)-1);
return;
}
lpImeLinkRadical = (LPIMERADICALRECT)GetWindowLongPtr(hWnd,
GWL_RADICALRECT);
if (uIndex < lpImeLinkRadical->nStartIME) {
lpImeLinkRadical->nStartIME = uIndex;
} else if ((uIndex - lpImeLinkRadical->nStartIME) >=
lpImeLinkRadical->nPerPageIMEs) {
lpImeLinkRadical->nStartIME = uIndex -
(lpImeLinkRadical->nPerPageIMEs - 1);
} else {
}
// avoid clear composition string
SendMessage(hWnd, WM_EUDC_COMPMSG, 0, FALSE);
lpRegWordStructTmp = &lpImeLinkRegWord->sRegWordStruct[uIndex];
// switch to this IME
ActivateKeyboardLayout(lpRegWordStructTmp->hKL, 0);
ImmGetConversionStatus(lpImeLinkRegWord->hRegWordIMC,
&fdwConversionMode, &fdwSentenceMode);
fdwConversionMode = (fdwConversionMode | IME_CMODE_EUDC |
IME_CMODE_NATIVE) | (fdwConversionMode & IME_CMODE_SOFTKBD);
ImmSetConversionStatus(lpImeLinkRegWord->hRegWordIMC,
fdwConversionMode, fdwSentenceMode);
SendMessage(hWnd, WM_EUDC_COMPMSG, 0, TRUE);
lpImeLinkRegWord->nCurrIME = uIndex;
if(lpImeLinkRadical->hScrollWnd){
SCROLLINFO scInfo;
scInfo.cbSize = sizeof(SCROLLINFO);
scInfo.fMask = SIF_POS;
scInfo.nPos = lpImeLinkRegWord->nCurrIME;
SetScrollInfo(lpImeLinkRadical->hScrollWnd,
SB_CTL, &scInfo, FALSE);
}
InvalidateRect(hWnd, NULL, TRUE);
*(LPTSTR)&lpRegWordStructTmp->szReading[
lpRegWordStructTmp->dwReadingLen] = '\0';
ImmSetCompositionString(lpImeLinkRegWord->hRegWordIMC, SCS_SETSTR,
NULL, 0, lpRegWordStructTmp->szReading,
lpRegWordStructTmp->dwReadingLen * sizeof(TCHAR));
SetFocus(hWnd);
return;
}
/************************************************************/
/* RegWordCreate */
/************************************************************/
LPIMELINKREGWORD RegWordCreate(
HWND hWnd)
{
HWND hEudcEditWnd;
UINT nLayouts;
HKL FAR *lphKL;
UINT i, nIMEs;
DWORD dwSize;
LPIMELINKREGWORD lpImeLinkRegWord;
LPREGWORDSTRUCT lpRegWordStructTmp;
TCHAR szStrBuf[16];
HDC hDC;
SIZE lTextSize;
RECT rcRect;
LPIMERADICALRECT lpImeLinkRadical;
TCHAR szTitle[32];
TCHAR szMessage[256];
hEudcEditWnd = GetWindow(GetParent(hWnd), GW_OWNER);
nLayouts = GetKeyboardLayoutList(0, NULL);
lphKL = GlobalAlloc(GPTR, sizeof(HKL) * nLayouts);
if (!lphKL) {
return (NULL);
}
lpImeLinkRegWord = NULL;
// get all keyboard layouts, it will include all IMEs
GetKeyboardLayoutList(nLayouts, lphKL);
for (i = 0, nIMEs = 0; i < nLayouts; i++) {
BOOL fRet;
HKL hKL;
TCHAR szImeEudcDic[80];
hKL = *(lphKL + i);
fRet = ImmIsIME(hKL);
if (!fRet) { // this is not an IME
continue;
}
szImeEudcDic[0] = '\0';
fRet = (BOOL) ImmEscape(hKL, (HIMC)NULL, IME_ESC_GET_EUDC_DICTIONARY,
szImeEudcDic);
if (!fRet) {
continue;
} else if (szImeEudcDic[0]) {
} else {
continue;
}
*(lphKL + nIMEs) = hKL; // write back to the same buffer
nIMEs++;
}
if (!nIMEs) {
LoadString(hAppInst, IDS_NOIME_TITLE, szTitle, sizeof(szTitle) / sizeof(TCHAR));
LoadString(hAppInst, IDS_NOIME_MSG, szMessage, sizeof(szMessage) / sizeof(TCHAR));
MessageBox(hEudcEditWnd, szMessage, szTitle, MB_OK);
goto RegWordCreateFreeHKL;
}
// now there are nIMEs can support IME EUDC dictionary
dwSize = sizeof(IMELINKREGWORD) - sizeof(REGWORDSTRUCT) +
sizeof(REGWORDSTRUCT) * nIMEs;
lpImeLinkRegWord = (LPIMELINKREGWORD)GlobalAlloc(GPTR, dwSize);
if (!lpImeLinkRegWord) {
LoadString(hAppInst, IDS_NOMEM_TITLE, szTitle, sizeof(szTitle) / sizeof(TCHAR));
LoadString(hAppInst, IDS_NOMEM_MSG, szMessage, sizeof(szMessage) / sizeof(TCHAR));
MessageBox(hEudcEditWnd, szMessage, szTitle, MB_OK);
goto RegWordCreateFreeHKL;
}
lpImeLinkRegWord->nEudcIMEs = nIMEs;
lpRegWordStructTmp = &lpImeLinkRegWord->sRegWordStruct[0];
for (i = 0; i < nIMEs; i++) {
LRESULT lRet;
#ifndef UNICODE
UINT j, uInternal;
#endif
UINT uReadingSize;
lpRegWordStructTmp->hKL = *(lphKL + i);
lRet = ImmEscape(lpRegWordStructTmp->hKL, (HIMC)NULL,
IME_ESC_MAX_KEY, NULL);
if (!lRet) {
// error message - can not support this IME!
lpImeLinkRegWord->nEudcIMEs--;
continue;
}
uReadingSize = sizeof(TCHAR);
#ifndef UNICODE
for (j = 0; j < 256; j++) {
uInternal = ImmEscape(lpRegWordStructTmp->hKL, (HIMC)NULL,
IME_ESC_SEQUENCE_TO_INTERNAL, &j);
if (uInternal > 255) {
uReadingSize = sizeof(WCHAR);
break;
}
}
#endif
if (lRet * uReadingSize > sizeof(lpRegWordStructTmp->szReading) - sizeof(TCHAR)) {
// error case, we can not support this IME
// we should count this into data structure
// error message - the reading of this IME is too long!
lpImeLinkRegWord->nEudcIMEs--;
continue;
}
lRet = ImmEscape(lpRegWordStructTmp->hKL, (HIMC)NULL,
IME_ESC_IME_NAME, lpRegWordStructTmp->szIMEName);
if (!lRet) {
// error message - can not support this IME!
lpImeLinkRegWord->nEudcIMEs--;
continue;
}
// avoid length problem
lpRegWordStructTmp->szIMEName[
sizeof(lpRegWordStructTmp->szIMEName) / sizeof(TCHAR) - 1] = '\0';
lpRegWordStructTmp->uIMENameLen =
lstrlen(lpRegWordStructTmp->szIMEName);
lpRegWordStructTmp++;
}
if (!lpImeLinkRegWord->nEudcIMEs) {
LoadString(hAppInst, IDS_NOIME_TITLE, szTitle, sizeof(szTitle) / sizeof(TCHAR));
LoadString(hAppInst, IDS_NOIME_MSG, szMessage, sizeof(szMessage) / sizeof(TCHAR));
MessageBox(hEudcEditWnd, szMessage, szTitle, MB_OK);
goto RegWordCreateFreeRegWord;
}
LoadString(hAppInst, IDS_CHINESE_CHAR, szStrBuf, sizeof(szStrBuf) / sizeof(TCHAR));
hDC = GetDC(NULL);
GetTextExtentPoint(hDC, szStrBuf, lstrlen(szStrBuf), &lTextSize);
ReleaseDC(NULL, hDC);
// decide the rectangle of IME radical
GetWindowRect(hWnd, &rcRect);
// we can show how many IME per page
nIMEs = (rcRect.bottom - rcRect.top) / (2 * lTextSize.cy);
if (lpImeLinkRegWord->nEudcIMEs <= nIMEs) {
// all IMEs can fit in one page
nIMEs = lpImeLinkRegWord->nEudcIMEs;
}
dwSize = sizeof(IMERADICALRECT) - sizeof(RECT) + sizeof(RECT) *
RECT_NUMBER * nIMEs;
lpImeLinkRadical = (LPIMERADICALRECT)GlobalAlloc(GPTR, dwSize);
if (!lpImeLinkRadical) {
// we can not handle any IME
lpImeLinkRegWord->nEudcIMEs = 0;
LoadString(hAppInst, IDS_NOMEM_TITLE, szTitle, sizeof(szTitle) / sizeof(TCHAR));
LoadString(hAppInst, IDS_NOMEM_MSG, szMessage, sizeof(szMessage) / sizeof(TCHAR));
MessageBox(hEudcEditWnd, szMessage, szTitle, MB_OK);
goto RegWordCreateFreeRegWord;
}
lpImeLinkRadical->nStartIME = 0;
lpImeLinkRadical->nPerPageIMEs = nIMEs;
lpImeLinkRadical->lTextSize = lTextSize;
if (lpImeLinkRegWord->nEudcIMEs > nIMEs) {
// IMEs more than one page, add scroll bar
SCROLLINFO scInfo;
// IMEs more than one page, add scroll bar
lpImeLinkRadical->hScrollWnd = CreateWindowEx(0,
TEXT("scrollbar"), NULL,
WS_CHILD|WS_VISIBLE|SBS_VERT,
rcRect.right - rcRect.left - lTextSize.cx, 0,
lTextSize.cx, rcRect.bottom - rcRect.top,
hWnd, 0, hAppInst, NULL);
scInfo.cbSize = sizeof(SCROLLINFO);
scInfo.fMask = SIF_ALL;
scInfo.nMin = 0;
scInfo.nMax = lpImeLinkRegWord->nEudcIMEs - 1 + (nIMEs - 1);
scInfo.nPage = nIMEs;
scInfo.nPos = 0;
scInfo.nTrackPos = 0;
SetScrollInfo(lpImeLinkRadical->hScrollWnd, SB_CTL, &scInfo, FALSE);
}
// decide the UI dimension
for (i = 0; i < nIMEs; i++) {
UINT j, k;
// rectangle for IME name
j = i * RECT_NUMBER + RECT_IMENAME;
lpImeLinkRadical->rcRadical[j].left = lTextSize.cx;
// add UI margin - UI_MARGIN
lpImeLinkRadical->rcRadical[j].top = lTextSize.cy * (i * 4 + 1) / 2 -
UI_MARGIN;
lpImeLinkRadical->rcRadical[j].right =
lpImeLinkRadical->rcRadical[j].left + lTextSize.cx * 4;
// add UI margin - UI_MARGIN * 2
lpImeLinkRadical->rcRadical[j].bottom =
lpImeLinkRadical->rcRadical[j].top + lTextSize.cy +
UI_MARGIN * 2;
// rectangle for radical
k = i * RECT_NUMBER + RECT_RADICAL;
lpImeLinkRadical->rcRadical[k].left =
lpImeLinkRadical->rcRadical[j].right + lTextSize.cx;
// add UI margin - UI_MARGIN
lpImeLinkRadical->rcRadical[k].top =
lpImeLinkRadical->rcRadical[j].top;
lpImeLinkRadical->rcRadical[k].right =
lpImeLinkRadical->rcRadical[k].left + lTextSize.cx *
(sizeof(lpRegWordStructTmp->szReading) / sizeof(TCHAR) / 2 - 1);
// add UI margin - UI_MARGIN * 2
lpImeLinkRadical->rcRadical[k].bottom =
lpImeLinkRadical->rcRadical[k].top + lTextSize.cy +
UI_MARGIN * 2;
}
SetWindowLongPtr(hWnd, GWL_RADICALRECT, (LONG_PTR)lpImeLinkRadical);
RegWordCreateFreeRegWord:
if (!lpImeLinkRegWord->nEudcIMEs) {
GlobalFree((HGLOBAL)lpImeLinkRegWord);
lpImeLinkRegWord = NULL;
}
RegWordCreateFreeHKL:
GlobalFree((HGLOBAL)lphKL);
return (lpImeLinkRegWord);
}
/************************************************************/
/* WmImeComposition */
/************************************************************/
void WmImeComposition(
HWND hWnd,
LPARAM lParam)
{
LPIMELINKREGWORD lpImeLinkRegWord;
LPREGWORDSTRUCT lpRegWordStructTmp;
LONG lRet;
BOOL bUpdate;
TCHAR szReading[sizeof(lpRegWordStructTmp->szReading)];
lpImeLinkRegWord = (LPIMELINKREGWORD)GetWindowLongPtr(hWnd,
GWL_IMELINKREGWORD);
lpRegWordStructTmp = &lpImeLinkRegWord->sRegWordStruct[
lpImeLinkRegWord->nCurrIME];
lRet = ImmGetCompositionString(lpImeLinkRegWord->hRegWordIMC,
GCS_COMPREADSTR, szReading, sizeof(szReading));
if (lRet < 0) {
lpRegWordStructTmp->bUpdate = UPDATE_ERROR;
return;
}
if (lRet > (sizeof(szReading) - sizeof(TCHAR))) {
lRet = sizeof(szReading) - sizeof(TCHAR);
}
szReading[lRet / sizeof(TCHAR)] = '\0';
if (lpRegWordStructTmp->dwReadingLen != (DWORD)lRet / sizeof(TCHAR)) {
bUpdate = TRUE;
} else if (lstrcmp(lpRegWordStructTmp->szReading, szReading)) {
bUpdate = TRUE;
} else {
bUpdate = FALSE;
}
if (bUpdate) {
LPIMERADICALRECT lpImeLinkRadical;
UINT i;
UINT j, k;
lpImeLinkRadical = (LPIMERADICALRECT)GetWindowLongPtr(hWnd,
GWL_RADICALRECT);
lstrcpy(lpRegWordStructTmp->szReading, szReading);
if (lParam & GCS_RESULTSTR) {
lpRegWordStructTmp->bUpdate = UPDATE_FINISH;
} else {
lpRegWordStructTmp->bUpdate = UPDATE_START;
}
lpRegWordStructTmp->dwReadingLen = (DWORD)lRet / sizeof(TCHAR);
if (!IsWindowEnabled(lpImeLinkRadical->hRegWordButton)) {
EnableWindow(lpImeLinkRadical->hRegWordButton, TRUE);
}
i = lpImeLinkRegWord->nCurrIME - lpImeLinkRadical->nStartIME;
j = i * RECT_NUMBER + RECT_IMENAME;
InvalidateRect(hWnd, &lpImeLinkRadical->rcRadical[j], FALSE);
k = i * RECT_NUMBER + RECT_RADICAL;
InvalidateRect(hWnd, &lpImeLinkRadical->rcRadical[k], FALSE);
} else if (lParam & GCS_RESULTSTR) {
LPIMERADICALRECT lpImeLinkRadical;
UINT i;
UINT j, k;
lpImeLinkRadical = (LPIMERADICALRECT)GetWindowLongPtr(hWnd,
GWL_RADICALRECT);
if (lpRegWordStructTmp->bUpdate) {
lpRegWordStructTmp->bUpdate = UPDATE_FINISH;
}
i = lpImeLinkRegWord->nCurrIME - lpImeLinkRadical->nStartIME;
j = i * RECT_NUMBER + RECT_IMENAME;
InvalidateRect(hWnd, &lpImeLinkRadical->rcRadical[j], FALSE);
k = i * RECT_NUMBER + RECT_RADICAL;
InvalidateRect(hWnd, &lpImeLinkRadical->rcRadical[k], FALSE);
} else {
}
return;
}
/************************************************************/
/* lstrcmpn */
/************************************************************/
int lstrcmpn(
LPCTSTR lpctszStr1,
LPCTSTR lpctszStr2,
int cCount)
{
int i;
for (i = 0; i < cCount; i++) {
int iCmp = *lpctszStr1++ - *lpctszStr2++;
if (iCmp) { return iCmp; }
}
return 0;
}
/************************************************************/
/* EnumReading */
/************************************************************/
int CALLBACK EnumReading(
LPCTSTR lpszReading,
DWORD dwStyle,
LPCTSTR lpszString,
LPREGWORDSTRUCT lpRegWordStructTmp)
{
int iLen;
DWORD dwZeroSeq;
LRESULT lRet;
TCHAR tszZeroSeq[8];
iLen = lstrlen(lpszReading);
if (iLen * sizeof(TCHAR) > sizeof(lpRegWordStructTmp->szReading) -
sizeof(WORD)) {
return (0);
}
lpRegWordStructTmp->dwReadingLen = (DWORD)iLen;
lstrcpy(lpRegWordStructTmp->szReading, lpszReading);
dwZeroSeq = 0;
lRet = ImmEscape(lpRegWordStructTmp->hKL, (HIMC)NULL,
IME_ESC_SEQUENCE_TO_INTERNAL, &dwZeroSeq);
if (!lRet) { return (1); }
iLen = 0;
if (LOWORD(lRet)) {
#ifdef UNICODE
tszZeroSeq[iLen++] = LOWORD(lRet);
#else
if (LOWORD(lRet) > 0xFF) {
tszZeroSeq[iLen++] = HIBYTE(LOWORD(lRet));
tszZeroSeq[iLen++] = LOBYTE(LOWORD(lRet));
} else {
tszZeroSeq[iLen++] = LOBYTE(LOWORD(lRet));
}
#endif
}
if (HIWORD(lRet) == 0xFFFF) {
// This is caused by sign extent in Win9x in the return value of
// ImmEscape, it causes an invalid internal code.
} else if (HIWORD(lRet)) {
#ifdef UNICODE
tszZeroSeq[iLen++] = HIWORD(lRet);
#else
if (HIWORD(lRet) > 0xFF) {
tszZeroSeq[iLen++] = HIBYTE(HIWORD(lRet));
tszZeroSeq[iLen++] = LOBYTE(HIWORD(lRet));
} else {
tszZeroSeq[iLen++] = LOBYTE(HIWORD(lRet));
}
#endif
} else {
}
for (; lpRegWordStructTmp->dwReadingLen > 0;
lpRegWordStructTmp->dwReadingLen -= iLen) {
if (lstrcmpn(&lpRegWordStructTmp->szReading[
lpRegWordStructTmp->dwReadingLen - iLen], tszZeroSeq, iLen) != 0) {
break;
}
}
lpRegWordStructTmp->szReading[lpRegWordStructTmp->dwReadingLen] = '\0';
return (1);
}
/************************************************************/
/* EudcCode */
/************************************************************/
void EudcCode(
HWND hWnd,
UINT uCode)
{
LPIMELINKREGWORD lpImeLinkRegWord;
LPREGWORDSTRUCT lpRegWordStructTmp;
UINT i;
lpImeLinkRegWord = (LPIMELINKREGWORD)GetWindowLongPtr(hWnd,
GWL_IMELINKREGWORD);
#ifdef UNICODE
lpImeLinkRegWord->szEudcCodeString[0] = (WCHAR)uCode;
#else
lpImeLinkRegWord->szEudcCodeString[0] = HIBYTE(uCode);
lpImeLinkRegWord->szEudcCodeString[1] = LOBYTE(uCode);
#endif
lpImeLinkRegWord->szEudcCodeString[2] =
lpImeLinkRegWord->szEudcCodeString[3] = '\0';
lpRegWordStructTmp = &lpImeLinkRegWord->sRegWordStruct[0];
for (i = 0; i < lpImeLinkRegWord->nEudcIMEs; i++) {
lpRegWordStructTmp->bUpdate = UPDATE_NONE;
lpRegWordStructTmp->szReading[0] = '\0';
lpRegWordStructTmp->dwReadingLen = 0;
ImmEnumRegisterWord(lpRegWordStructTmp->hKL, EnumReading,
NULL, IME_REGWORD_STYLE_EUDC,
lpImeLinkRegWord->szEudcCodeString,
lpRegWordStructTmp);
lpRegWordStructTmp->dwReadingLen = lstrlen(lpRegWordStructTmp->szReading);
lpRegWordStructTmp++;
}
lpRegWordStructTmp = &lpImeLinkRegWord->sRegWordStruct[
lpImeLinkRegWord->nCurrIME];
ImmSetCompositionString(lpImeLinkRegWord->hRegWordIMC, SCS_SETSTR,
NULL, 0, lpRegWordStructTmp->szReading,
lpRegWordStructTmp->dwReadingLen * sizeof(TCHAR));
InvalidateRect(hWnd, NULL, FALSE);
return;
}
/************************************************************/
/* ChangeToOtherIME */
/************************************************************/
void ChangeToOtherIME(
HWND hWnd,
LPARAM lMousePos)
{
POINT ptMouse;
LPIMERADICALRECT lpImeLinkRadical;
UINT i;
BOOL bFound;
ptMouse.x = LOWORD(lMousePos);
ptMouse.y = HIWORD(lMousePos);
lpImeLinkRadical = (LPIMERADICALRECT)GetWindowLongPtr(hWnd,
GWL_RADICALRECT);
bFound = FALSE;
for (i = 0; i < lpImeLinkRadical->nPerPageIMEs; i++) {
UINT j;
j = i * RECT_NUMBER + RECT_RADICAL;
if (PtInRect(&lpImeLinkRadical->rcRadical[j], ptMouse)) {
bFound = TRUE;
break;
}
}
if (!bFound) {
return;
}
SwitchToThisIME(hWnd, lpImeLinkRadical->nStartIME + i);
return;
}
/************************************************************/
/* ScrollIME */
/************************************************************/
void ScrollIME(
HWND hWnd,
WPARAM wParam)
{
LPIMELINKREGWORD lpImeLinkRegWord;
LPIMERADICALRECT lpImeLinkRadical;
int iLines;
UINT uIndex;
lpImeLinkRegWord = (LPIMELINKREGWORD)GetWindowLongPtr(hWnd,
GWL_IMELINKREGWORD);
lpImeLinkRadical = (LPIMERADICALRECT)GetWindowLongPtr(hWnd,
GWL_RADICALRECT);
switch (LOWORD(wParam)) {
case SB_PAGEDOWN:
// scroll (page size - 1)
iLines = lpImeLinkRadical->nPerPageIMEs - 1;
break;
case SB_LINEDOWN:
iLines = 1;
break;
case SB_PAGEUP:
// scroll (page size - 1)
iLines = 1 - lpImeLinkRadical->nPerPageIMEs;
break;
case SB_LINEUP:
iLines = -1;
break;
case SB_TOP:
// swicth to the first one
SwitchToThisIME(hWnd, 0);
return;
case SB_BOTTOM:
// swicth to the last one
SwitchToThisIME(hWnd, lpImeLinkRegWord->nEudcIMEs - 1);
return;
case SB_THUMBPOSITION:
SwitchToThisIME(hWnd, HIWORD(wParam));
return;
default:
return;
}
uIndex = lpImeLinkRegWord->nCurrIME;
if (iLines > 0) {
uIndex += (UINT)iLines;
if (uIndex >= lpImeLinkRegWord->nEudcIMEs) {
// should not exceed the total IMEs
uIndex = lpImeLinkRegWord->nEudcIMEs - 1;
}
} else {
UINT uLines;
uLines = -iLines;
if (uLines > uIndex) {
uIndex = 0;
} else {
uIndex -= uLines;
}
}
SwitchToThisIME(hWnd, uIndex);
return;
}
/************************************************************/
/* ScrollIMEByKey */
/************************************************************/
void ScrollIMEByKey(
HWND hWnd,
WPARAM wParam)
{
switch (wParam) {
case VK_NEXT:
ScrollIME(hWnd, SB_PAGEDOWN);
break;
case VK_DOWN: // can not work because dialog do not pass this key to us
ScrollIME(hWnd, SB_LINEDOWN);
break;
case VK_PRIOR:
ScrollIME(hWnd, SB_PAGEUP);
break;
case VK_UP: // can not work because dialog do not pass this key to us
ScrollIME(hWnd, SB_LINEUP);
break;
default:
return;
}
return;
}
/************************************************************/
/* RegWordGetFocus */
/************************************************************/
void RegWordGetFocus(
HWND hWnd)
{
LPIMELINKREGWORD lpImeLinkRegWord;
LPIMERADICALRECT lpImeLinkRadical;
UINT i;
lpImeLinkRegWord = (LPIMELINKREGWORD)GetWindowLongPtr(hWnd,
GWL_IMELINKREGWORD);
lpImeLinkRadical = (LPIMERADICALRECT)GetWindowLongPtr(hWnd,
GWL_RADICALRECT);
CreateCaret(hWnd, NULL, 2, lpImeLinkRadical->lTextSize.cy +
CARET_MARGIN * 2);
if (lpImeLinkRegWord->nCurrIME < lpImeLinkRadical->nStartIME) {
lpImeLinkRegWord->nCurrIME = lpImeLinkRadical->nStartIME;
} else if ((lpImeLinkRegWord->nCurrIME - lpImeLinkRadical->nStartIME) >=
lpImeLinkRadical->nPerPageIMEs) {
lpImeLinkRegWord->nCurrIME = lpImeLinkRadical->nStartIME +
lpImeLinkRadical->nPerPageIMEs - 1;
} else {
}
i = lpImeLinkRegWord->nCurrIME - lpImeLinkRadical->nStartIME;
i = (i * RECT_NUMBER) + RECT_RADICAL;
SetCaretPos(lpImeLinkRadical->rcRadical[i].left +
lpImeLinkRadical->lCurrReadingExtent.cx + 2,
lpImeLinkRadical->rcRadical[i].top + UI_MARGIN - CARET_MARGIN);
ShowCaret(hWnd);
return;
}
/************************************************************/
/* RegWordPaint */
/************************************************************/
void RegWordPaint(
HWND hWnd)
{
LPIMERADICALRECT lpImeLinkRadical;
LPIMELINKREGWORD lpImeLinkRegWord;
LPREGWORDSTRUCT lpRegWordStructTmp;
HDC hDC;
PAINTSTRUCT ps;
UINT i;
UINT nShowIMEs;
lpImeLinkRadical = (LPIMERADICALRECT)GetWindowLongPtr(hWnd,
GWL_RADICALRECT);
lpImeLinkRegWord = (LPIMELINKREGWORD)GetWindowLongPtr(hWnd,
GWL_IMELINKREGWORD);
lpRegWordStructTmp = &lpImeLinkRegWord->sRegWordStruct[
lpImeLinkRadical->nStartIME];
HideCaret(hWnd);
hDC = BeginPaint(hWnd, &ps);
// we only can show up to the final one
nShowIMEs = lpImeLinkRegWord->nEudcIMEs - lpImeLinkRadical->nStartIME;
if (nShowIMEs > lpImeLinkRadical->nPerPageIMEs) {
// we only can show one page a time
nShowIMEs = lpImeLinkRadical->nPerPageIMEs;
}
for (i = 0; i < nShowIMEs; i++) {
RECT rcSunken;
UINT j, k;
k = i * RECT_NUMBER + RECT_RADICAL;
rcSunken = lpImeLinkRadical->rcRadical[k];
rcSunken.left -= 2;
rcSunken.top -= 2;
rcSunken.right += 2;
rcSunken.bottom += 2;
DrawEdge(hDC, &rcSunken, BDR_SUNKENOUTER, BF_RECT);
SetBkColor(hDC, GetSysColor(COLOR_BTNFACE));
if (lpRegWordStructTmp->bUpdate == UPDATE_ERROR) {
// red text for error
SetTextColor(hDC, RGB(0xFF, 0x00, 0x00));
} else if (lpRegWordStructTmp->bUpdate == UPDATE_START) {
// yellow text for not finished
SetTextColor(hDC, RGB(0xFF, 0xFF, 0x00));
} else if (lpRegWordStructTmp->bUpdate == UPDATE_REGISTERED) {
// green text for registered
SetTextColor(hDC, RGB(0x00, 0x80, 0x00));
} else {
SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
}
j = i * RECT_NUMBER + RECT_IMENAME;
ExtTextOut(hDC, lpImeLinkRadical->rcRadical[j].left,
lpImeLinkRadical->rcRadical[j].top,
ETO_OPAQUE|ETO_CLIPPED, &lpImeLinkRadical->rcRadical[j],
lpRegWordStructTmp->szIMEName,
lpRegWordStructTmp->uIMENameLen, NULL);
if ((lpImeLinkRegWord->nCurrIME - lpImeLinkRadical->nStartIME) == i) {
SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
GetTextExtentPoint(hDC, lpRegWordStructTmp->szReading,
lpRegWordStructTmp->dwReadingLen,
&lpImeLinkRadical->lCurrReadingExtent);
SetCaretPos(lpImeLinkRadical->rcRadical[k].left +
lpImeLinkRadical->lCurrReadingExtent.cx + 2,
lpImeLinkRadical->rcRadical[k].top + UI_MARGIN - CARET_MARGIN);
} else {
SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
}
ExtTextOut(hDC, lpImeLinkRadical->rcRadical[k].left,
lpImeLinkRadical->rcRadical[k].top + UI_MARGIN,
ETO_OPAQUE, &lpImeLinkRadical->rcRadical[k],
lpRegWordStructTmp->szReading,
lpRegWordStructTmp->dwReadingLen, NULL);
lpRegWordStructTmp++;
}
EndPaint(hWnd, &ps);
ShowCaret(hWnd);
return;
}
/************************************************************/
/* RegWordWndProc */
/************************************************************/
LRESULT CALLBACK RegWordWndProc(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uMsg) {
case WM_CREATE:
{
LPIMELINKREGWORD lpImeLinkRegWord;
UINT uIndex;
// initialize to 0
SetWindowLongPtr(hWnd, GWL_IMELINKREGWORD, 0L);
SetWindowLongPtr(hWnd, GWL_RADICALRECT, 0L);
lpImeLinkRegWord = RegWordCreate(hWnd);
if (!lpImeLinkRegWord) {
return (-1);
}
lpImeLinkRegWord->fCompMsg = TRUE;
lpImeLinkRegWord->nCurrIME = 0xFFFFFFFF;
lpImeLinkRegWord->hRegWordIMC = ImmCreateContext();
if (!lpImeLinkRegWord->hRegWordIMC) {
return (-1);
}
lpImeLinkRegWord->hOldIMC = ImmAssociateContext(hWnd,
lpImeLinkRegWord->hRegWordIMC);
SetWindowLongPtr(hWnd, GWL_IMELINKREGWORD, (LONG_PTR)lpImeLinkRegWord);
uIndex = 0;
SwitchToThisIME(hWnd, 0);
// the switch will fail, if the window is disable, try again
PostMessage(hWnd, WM_EUDC_SWITCHIME, 0, uIndex);
}
break;
case WM_EUDC_COMPMSG:
{
LPIMELINKREGWORD lpImeLinkRegWord;
lpImeLinkRegWord = (LPIMELINKREGWORD)GetWindowLongPtr(hWnd,
GWL_IMELINKREGWORD);
lpImeLinkRegWord->fCompMsg = (BOOL)lParam;
}
break;
case WM_EUDC_SWITCHIME:
{
LPIMELINKREGWORD lpImeLinkRegWord;
lpImeLinkRegWord = (LPIMELINKREGWORD)GetWindowLongPtr(hWnd,
GWL_IMELINKREGWORD);
lpImeLinkRegWord->nCurrIME = 0xFFFFFFFF;
SwitchToThisIME(hWnd, (UINT)lParam);
}
break;
case WM_IME_STARTCOMPOSITION:
case WM_IME_ENDCOMPOSITION:
break;
case WM_IME_COMPOSITION:
{
LPIMELINKREGWORD lpImeLinkRegWord;
lpImeLinkRegWord = (LPIMELINKREGWORD)GetWindowLongPtr(hWnd,
GWL_IMELINKREGWORD);
if (lpImeLinkRegWord->fCompMsg) {
WmImeComposition(hWnd, lParam);
}
}
break;
case WM_IME_NOTIFY:
switch (wParam) {
case IMN_OPENSTATUSWINDOW:
case IMN_CLOSESTATUSWINDOW:
case IMN_OPENCANDIDATE:
case IMN_CHANGECANDIDATE:
case IMN_CLOSECANDIDATE:
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
break;
case WM_IME_SETCONTEXT:
return DefWindowProc(hWnd, uMsg, wParam, lParam & ~(ISC_SHOWUIALL));
case WM_EUDC_REGISTER_BUTTON:
{
LPIMERADICALRECT lpImeRadicalRect;
lpImeRadicalRect = (LPIMERADICALRECT)GetWindowLongPtr(hWnd,
GWL_RADICALRECT);
lpImeRadicalRect->hRegWordButton = (HWND)lParam;
}
break;
case WM_EUDC_CODE:
EudcCode(hWnd, (UINT)lParam);
break;
case WM_LBUTTONDOWN:
ChangeToOtherIME(hWnd, lParam);
break;
case WM_VSCROLL:
ScrollIME(hWnd, wParam);
break;
case WM_KEYDOWN:
ScrollIMEByKey(hWnd, wParam);
break;
case WM_SETFOCUS:
RegWordGetFocus(hWnd);
break;
case WM_KILLFOCUS:
DestroyCaret();
break;
case WM_PAINT:
RegWordPaint(hWnd);
break;
case WM_DESTROY:
{
LPIMERADICALRECT lpImeRadicalRect;
LPIMELINKREGWORD lpImeLinkRegWord;
lpImeRadicalRect = (LPIMERADICALRECT)GetWindowLongPtr(hWnd,
GWL_RADICALRECT);
if (lpImeRadicalRect) {
GlobalFree((HGLOBAL)lpImeRadicalRect);
}
lpImeLinkRegWord = (LPIMELINKREGWORD)GetWindowLongPtr(hWnd,
GWL_IMELINKREGWORD);
if (!lpImeLinkRegWord) {
break;
}
ImmAssociateContext(hWnd, lpImeLinkRegWord->hOldIMC);
ImmDestroyContext(lpImeLinkRegWord->hRegWordIMC);
GlobalFree((HGLOBAL)lpImeLinkRegWord);
}
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return (0L);
}
/************************************************************/
/* RegisterThisEudc */
/************************************************************/
int RegisterThisEudc(
HWND hWnd)
{
LPIMELINKREGWORD lpImeLinkRegWord;
LPREGWORDSTRUCT lpRegWordStructTmp;
UINT i;
int iRet;
lpImeLinkRegWord = (LPIMELINKREGWORD)GetWindowLongPtr(hWnd,
GWL_IMELINKREGWORD);
lpRegWordStructTmp = &lpImeLinkRegWord->sRegWordStruct[0];
iRet = -1;
for (i = 0; i < lpImeLinkRegWord->nEudcIMEs; i++, lpRegWordStructTmp++) {
if (lpRegWordStructTmp->bUpdate == UPDATE_NONE) {
} else if (lpRegWordStructTmp->bUpdate != UPDATE_FINISH) {
TCHAR szStrBuf[128];
int iYesNo;
if (iRet != -1) {
continue;
}
LoadString(hAppInst, IDS_QUERY_NOTFINISH, szStrBuf,
sizeof(szStrBuf) / sizeof(TCHAR));
iYesNo = MessageBox(hWnd, szStrBuf,
lpRegWordStructTmp->szIMEName,
MB_APPLMODAL|MB_YESNO|MB_DEFBUTTON1);
if (iYesNo == IDYES) {
iRet = i;
}
} else {
BOOL fRet;
TCHAR szStrBuf[128];
int iYesNo;
fRet = ImmRegisterWord(lpRegWordStructTmp->hKL,
lpRegWordStructTmp->szReading, IME_REGWORD_STYLE_EUDC,
lpImeLinkRegWord->szEudcCodeString);
if (fRet) {
lpRegWordStructTmp->bUpdate = UPDATE_REGISTERED;
continue;
} else {
lpRegWordStructTmp->bUpdate = UPDATE_ERROR;
}
if (iRet != -1) {
continue;
}
LoadString(hAppInst, IDS_QUERY_REGISTER, szStrBuf,
sizeof(szStrBuf) / sizeof(TCHAR));
iYesNo = MessageBox(hWnd, szStrBuf,
lpRegWordStructTmp->szIMEName,
MB_APPLMODAL|MB_YESNO|MB_DEFBUTTON1);
if (iYesNo == IDYES) {
iRet = i;
}
}
}
InvalidateRect(hWnd, NULL, FALSE);
return (iRet);
}
/************************************************************/
/* CodePageInfo() */
/************************************************************/
int CodePageInfo(
UINT uCodePage)
{
int i;
for (i = 0; i < sizeof(sCountry) / sizeof(COUNTRYSETTING); i++) {
if (sCountry[i].uCodePage == uCodePage) {
return(i);
}
}
return (-1);
}
/************************************************************/
/* ImeLinkDlgProc */
/************************************************************/
INT_PTR CALLBACK ImeLinkDlgProc(
HWND hDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uMsg) {
case WM_INITDIALOG:
{
HWND hRadicalWnd, hRegWordButton;
int cbString;
#ifdef UNICODE // this code could not run under non NATIVE platforms
UINT uCodePage, uNativeCode;
int i;
#endif
TCHAR szTitle[128];
cbString = GetWindowText(hDlg, szTitle, sizeof(szTitle) /
sizeof(TCHAR));
#ifdef UNICODE
uCodePage = GetACP();
i = CodePageInfo(uCodePage);
if (uCodePage == UNICODE_CP || i == -1) {
wsprintf(&szTitle[cbString], TEXT("%4X"), (UINT)lParam);
} else {
uNativeCode = 0;
WideCharToMultiByte(uCodePage, WC_COMPOSITECHECK,
(LPCWSTR)&lParam, 1,
(LPSTR)&uNativeCode, sizeof(uNativeCode),
NULL, NULL);
// convert to multi byte string
uNativeCode = LOBYTE(uNativeCode) << 8 | HIBYTE(uNativeCode);
wsprintf(&szTitle[cbString], TEXT("%4X (%s - %4X)"),
(UINT)lParam, sCountry[i].szCodePage, (UINT)uNativeCode);
}
#else
wsprintf(&szTitle[cbString], TEXT("%4X"), (UINT)lParam);
#endif
SetWindowText(hDlg, szTitle);
hRadicalWnd = GetDlgItem(hDlg, IDD_RADICAL);
SendMessage(hRadicalWnd, WM_EUDC_CODE, 0, lParam);
hRegWordButton = GetDlgItem(hDlg, IDOK);
EnableWindow(hRegWordButton, FALSE);
SendMessage(hRadicalWnd, WM_EUDC_REGISTER_BUTTON, 0,
(LPARAM)hRegWordButton);
}
return (TRUE); // do not want to set focus to special control
case WM_COMMAND:
switch (wParam) {
case IDOK:
{
HWND hRadicalWnd;
hRadicalWnd = GetDlgItem(hDlg, IDD_RADICAL);
if (RegisterThisEudc(hRadicalWnd) == -1) {
EndDialog(hDlg, TRUE);
} else {
SetFocus(hRadicalWnd);
}
}
break;
case IDCANCEL:
EndDialog(hDlg, FALSE);
break;
default:
return (FALSE);
}
return (TRUE);
case WM_IME_NOTIFY:
// we need to hook these messages from frame window also
// otherwise sometime the OPENSTATUS will send to the frame
// window and the child - hRadicalWnd will not get these messages
switch (wParam) {
case IMN_OPENSTATUSWINDOW:
case IMN_CLOSESTATUSWINDOW:
return (TRUE);
default:
return (FALSE);
}
default:
return (FALSE);
}
return (TRUE);
}
/************************************************************/
/* ImeLink */
/************************************************************/
void ImeLink(
HWND hWnd,
UINT uCode)
{
static BOOL bFirstTime = TRUE;
UINT nLayouts;
HKL FAR *lphKL;
TCHAR szTitle[32];
TCHAR szMessage[256];
UINT i, nIMEs;
WNDCLASSEX wcClass;
HKL hOldKL;
nLayouts = GetKeyboardLayoutList(0, NULL);
lphKL = GlobalAlloc(GPTR, sizeof(HKL) * nLayouts);
if (!lphKL) {
LoadString(hAppInst, IDS_NOMEM_TITLE, szTitle, sizeof(szTitle) / sizeof(TCHAR));
LoadString(hAppInst, IDS_NOMEM_MSG, szMessage, sizeof(szMessage) / sizeof(TCHAR));
MessageBox(hWnd, szMessage, szTitle, MB_OK);
return;
}
// MSVC may have problem for recusive modal dialog box,
// I mean create a modal dialog box within a modal dialog box.
// so we need to move the code from RegWordCreate() to here to
// prevent creating a modal dialog form a modal dialog.
// The ImmConfigureIME API call is possible to create a modal dialog.
// get all keyboard layouts, it will include all IMEs
GetKeyboardLayoutList(nLayouts, lphKL);
for (i = 0, nIMEs = 0; i < nLayouts; i++) {
BOOL fRet;
HKL hKL;
TCHAR szImeEudcDic[80];
hKL = *(lphKL + i);
fRet = ImmIsIME(hKL);
if (!fRet) { // this is not an IME
continue;
}
szImeEudcDic[0] = '\0';
fRet = (BOOL) ImmEscape(hKL, (HIMC)NULL, IME_ESC_GET_EUDC_DICTIONARY,
szImeEudcDic);
if (!fRet) {
continue;
}
if (szImeEudcDic[0]) {
fRet = TRUE;
} else if (!bFirstTime) {
} else {
fRet = ImmConfigureIME(hKL, hWnd, IME_CONFIG_SELECTDICTIONARY, NULL);
}
if (!fRet) {
// this IME do not have an IME EUDC dictionary
continue;
}
if (szImeEudcDic[0] == '\0') {
// check whether we really get a dictionary
fRet = (BOOL) ImmEscape(hKL, (HIMC)NULL, IME_ESC_GET_EUDC_DICTIONARY,
szImeEudcDic);
if (!fRet) {
continue;
} else if (szImeEudcDic[0] == '\0') {
continue;
} else {
}
} else {
}
nIMEs++;
}
GlobalFree((HGLOBAL)lphKL);
if (bFirstTime) {
bFirstTime = FALSE;
}
if (!nIMEs) {
LoadString(hAppInst, IDS_NOIME_TITLE, szTitle, sizeof(szTitle) / sizeof(TCHAR));
LoadString(hAppInst, IDS_NOIME_MSG, szMessage, sizeof(szMessage) / sizeof(TCHAR));
MessageBox(hWnd, szMessage, szTitle, MB_OK);
return;
}
if (!GetClassInfoEx(hAppInst, szRegWordCls, &wcClass)) {
wcClass.cbSize = sizeof(WNDCLASSEX);
wcClass.style = CS_HREDRAW|CS_VREDRAW;
wcClass.lpfnWndProc = RegWordWndProc;
wcClass.cbClsExtra = 0;
wcClass.cbWndExtra = GWL_SIZE;
wcClass.hInstance = hAppInst;
wcClass.hIcon = NULL;
wcClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wcClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wcClass.lpszMenuName = NULL;
wcClass.lpszClassName = szRegWordCls;
wcClass.hIconSm = NULL;
RegisterClassEx(&wcClass);
}
hOldKL = GetKeyboardLayout(0);
DialogBoxParam(hAppInst, szImeLinkDlg, hWnd, ImeLinkDlgProc,
(LPARAM)uCode);
ActivateKeyboardLayout(hOldKL, 0);
return;
}
/************************************************************/
/* MatchImeName() */
/************************************************************/
HKL MatchImeName(
LPCTSTR szStr)
{
TCHAR szImeName[16];
int nLayout;
HKL hKL;
HGLOBAL hMem;
HKL FAR * lpMem;
int i;
nLayout = GetKeyboardLayoutList(0, NULL);
// alloc temp buffer
hMem = GlobalAlloc(GHND, sizeof(HKL) * nLayout);
if (!hMem) {
return (NULL);
}
lpMem = (HKL FAR *)GlobalLock(hMem);
if (!lpMem) {
GlobalFree(hMem);
return (NULL);
}
// get all keyboard layouts, it includes all IMEs
GetKeyboardLayoutList(nLayout, lpMem);
for (i = 0; i < nLayout; i++) {
BOOL fRet;
hKL = *(lpMem + i);
fRet = (BOOL) ImmEscape(hKL, (HIMC)NULL, IME_ESC_IME_NAME, szImeName);
if (!fRet) { // this hKL can not ask name
continue;
}
if (lstrcmp(szStr, szImeName) == 0) {
goto MatchOvr;
}
}
hKL = NULL;
MatchOvr:
GlobalUnlock(hMem);
GlobalFree(hMem);
return (hKL);
}
/************************************************************/
/* RegisterTable() */
/************************************************************/
HKL RegisterTable(
HWND hWnd,
LPUSRDICIMHDR lpIsvUsrDic,
DWORD dwFileSize,
UINT uCodePage)
{
HKL hKL;
HDC hDC;
SIZE lTextSize;
RECT rcProcess;
DWORD i;
LPBYTE lpCurr, lpEnd;
BOOL fRet;
TCHAR szStr[16];
TCHAR szProcessFmt[32];
TCHAR szResult[2][32];
TCHAR szProcessInfo[48];
WORD wInternalCode[256];
WORD wAltInternalCode[256];
#ifdef UNICODE
if (uCodePage == UNICODE_CP) {
LPUNATSTR lpszMethodName;
lpszMethodName = (LPUNATSTR)lpIsvUsrDic->achMethodName;
for (i = 0; i < sizeof(lpIsvUsrDic->achMethodName) / sizeof(TCHAR); i++) {
szStr[i] = *lpszMethodName++;
}
szStr[i] = '\0';
} else {
UINT uLen;
uLen = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED,
(LPCSTR)lpIsvUsrDic->achMethodName,
sizeof(lpIsvUsrDic->achMethodName),
szStr,
sizeof(szStr) / sizeof(TCHAR));
szStr[uLen] = '\0';
}
#else
for (i = 0; i < sizeof(lpIsvUsrDic->achMethodName); i++) {
szStr[i] = lpIsvUsrDic->achMethodName[i];
}
szStr[i] = '\0';
#endif
hKL = MatchImeName(szStr);
if (!hKL) {
return (hKL);
}
LoadString(hAppInst, IDS_PROCESS_FMT, szProcessFmt, sizeof(szProcessFmt) / sizeof(TCHAR));
LoadString(hAppInst, IDS_RESULT_FAIL, szResult[0], sizeof(szResult[0]) / sizeof(TCHAR));
LoadString(hAppInst, IDS_RESULT_SUCCESS, szResult[1], sizeof(szResult[1]) / sizeof(TCHAR));
LoadString(hAppInst, IDS_CHINESE_CHAR, szStr, sizeof(szStr) / sizeof(TCHAR));
hDC = GetDC(NULL);
GetTextExtentPoint(hDC, szStr, sizeof(WORD)/sizeof(TCHAR),
&lTextSize);
ReleaseDC(NULL, hDC);
// show the processing in somewhere, don't need to be same as this
rcProcess.left = 1;
rcProcess.top = 1;
rcProcess.right = rcProcess.left + lTextSize.cx *
sizeof(szProcessInfo) / sizeof(WORD);
rcProcess.bottom = rcProcess.top + lTextSize.cy;
// convert sequence code to internal code
for (i = 0; i < sizeof(wInternalCode) / sizeof(WORD); i++) {
LRESULT lRet;
lRet = ImmEscape(hKL, (HIMC)NULL,
IME_ESC_SEQUENCE_TO_INTERNAL, &i);
if (HIWORD(lRet) == 0xFFFF) {
// This is caused by sign extent in Win9x in the return value of
// ImmEscape, it causes an invalid internal code.
wAltInternalCode[i] = 0;
} else {
wAltInternalCode[i] = HIWORD(lRet);
}
wInternalCode[i] = LOWORD(lRet);
#ifndef UNICODE
if (wAltInternalCode[i] > 0xFF) {
// convert to multi byte string
wAltInternalCode[i] = LOBYTE(wAltInternalCode[i]) << 8 |
HIBYTE(wAltInternalCode[i]);
}
if (wInternalCode[i] > 0xFF) {
// convert to multi byte string
wInternalCode[i] = LOBYTE(wInternalCode[i]) << 8 |
HIBYTE(wInternalCode[i]);
}
#endif
}
// check for each record and register it
// get to the first record and skip the Bank ID
lpCurr = (LPBYTE)(lpIsvUsrDic + 1) + sizeof(WORD);
lpEnd = (LPBYTE)lpIsvUsrDic + dwFileSize;
for (; lpCurr < lpEnd;
// internal code + sequence code + Bank ID of next record
lpCurr += sizeof(WORD) + lpIsvUsrDic->cMethodKeySize + sizeof(WORD)) {
int j;
// quick way to init \0 for the register string
*(LPDWORD)szStr = 0;
#ifdef UNICODE
if (uCodePage == UNICODE_CP) {
szStr[0] = *(LPUNATSTR)lpCurr;
} else {
CHAR szMultiByte[4];
szMultiByte[0] = HIBYTE(*(LPUNATSTR)lpCurr);
szMultiByte[1] = LOBYTE(*(LPUNATSTR)lpCurr);
MultiByteToWideChar(uCodePage, MB_PRECOMPOSED,
szMultiByte, 2, szStr, 2);
}
#else
szStr[1] = *lpCurr;
szStr[0] = *(lpCurr + 1);
#endif
for (i = 0, j = 0; i < lpIsvUsrDic->cMethodKeySize; i++) {
if (!wAltInternalCode[*(LPBYTE)(lpCurr + sizeof(WORD) + i)]) {
} else if (wAltInternalCode[*(LPBYTE)(lpCurr + sizeof(WORD) + i)] < 0xFF) {
*(LPTSTR)&szStr[4 + j] = (TCHAR)
wAltInternalCode[*(LPBYTE)(lpCurr + sizeof(WORD) + i)];
j += sizeof(TCHAR) / sizeof(TCHAR);
} else {
*(LPWSTR)&szStr[4 + j] = (WCHAR)
wAltInternalCode[*(LPBYTE)(lpCurr + sizeof(WORD) + i)];
j += sizeof(WCHAR) / sizeof(TCHAR);
}
if (wInternalCode[*(LPBYTE)(lpCurr + sizeof(WORD) + i)] < 0xFF) {
*(LPTSTR)&szStr[4 + j] = (TCHAR)
wInternalCode[*(LPBYTE)(lpCurr + sizeof(WORD) + i)];
j += sizeof(TCHAR) / sizeof(TCHAR);
} else {
*(LPWSTR)&szStr[4 + j] = (WCHAR)
wInternalCode[*(LPBYTE)(lpCurr + sizeof(WORD) + i)];
j += sizeof(WCHAR) / sizeof(TCHAR);
}
}
szStr[4 + j] = szStr[4 + j + 1] = szStr[4 + j + 2] = '\0';
fRet = ImmRegisterWord(hKL, &szStr[4], IME_REGWORD_STYLE_EUDC,
szStr);
wsprintf(szProcessInfo, szProcessFmt, (LPTSTR)szStr,
(LPTSTR)&szStr[4], szResult[fRet]);
hDC = GetDC(hWnd);
// show the process information
ExtTextOut(hDC, rcProcess.left, rcProcess.top, ETO_OPAQUE,
&rcProcess, szProcessInfo, lstrlen(szProcessInfo),
NULL);
ReleaseDC(NULL, hDC);
if (!fRet) {
// wait 3 seconds for fail case
Sleep(3000);
}
}
return (hKL);
}
/************************************************************/
/* BatchImeLink() */
/************************************************************/
void BatchImeLink(
HWND hWnd)
{
HANDLE hIsvUsrDicFile, hIsvUsrDic;
LPUSRDICIMHDR lpIsvUsrDic;
TCHAR chReplace;
int i, cbString;
DWORD dwSize, dwFileSize;
LPTSTR szTitle, szMessage;
int iTitle, iMessage;
OPENFILENAME ofn;
TCHAR szFilter[64];
TCHAR szFileName[MAX_PATH];
TCHAR szDirName[MAX_PATH];
// try to share the buffer
szTitle = szFilter;
iTitle = sizeof(szFilter) / sizeof(TCHAR);
szMessage = szDirName;
iMessage = sizeof(szDirName) / sizeof(TCHAR);
// internal error, the data structure need byte alignment
// it should not use WORD or DWORD alignment
if (sizeof(USRDICIMHDR) != 256) {
LoadString(hAppInst, IDS_INTERNAL_TITLE, szTitle, iTitle);
LoadString(hAppInst, IDS_INTERNAL_MSG, szMessage, iMessage);
MessageBox(hWnd, szMessage, szTitle, MB_OK);
return;
}
// do we need to set a new file name
cbString = LoadString(hAppInst, IDS_ISV_FILE_FILTER, szFilter,
sizeof(szFilter) / sizeof(TCHAR));
chReplace = szFilter[cbString - 1];
for (i = 0; szFilter[i]; i++) {
if (szFilter[i] == chReplace) {
szFilter[i] = '\0';
}
}
GetWindowsDirectory(szDirName, sizeof(szDirName) / sizeof(TCHAR));
lstrcpy(szFileName, TEXT("*.TBL"));
// prompt a open file dialog
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hWnd;
ofn.lpstrFilter = szFilter;
ofn.lpstrCustomFilter = NULL;
ofn.nMaxCustFilter = 0;
ofn.nFilterIndex = 1;
ofn.lpstrFile = szFileName;
ofn.nMaxFile = sizeof(szFileName) / sizeof(TCHAR);
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = szDirName;
ofn.lpstrTitle = NULL;;
ofn.Flags = OFN_NOCHANGEDIR|OFN_HIDEREADONLY|OFN_CREATEPROMPT|
OFN_PATHMUSTEXIST;
ofn.lpstrDefExt = NULL;
if (!GetOpenFileName(&ofn)) {
return;
}
hIsvUsrDicFile = CreateFile(ofn.lpstrFile, GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hIsvUsrDicFile == INVALID_HANDLE_VALUE) {
LoadString(hAppInst, IDS_NOTOPEN_TITLE, szTitle, iTitle);
LoadString(hAppInst, IDS_NOTOPEN_MSG, szMessage, iMessage);
MessageBox(hWnd, szMessage, szTitle,
MB_OK|MB_ICONHAND|MB_TASKMODAL|MB_TOPMOST);
return;
}
#if 0
for (i = 0; i < sizeof(szFileName); i++) {
if (szFileName[i] == '\\') {
szFileName[i] = ' ';
}
}
#endif
hIsvUsrDic = CreateFileMapping((HANDLE)hIsvUsrDicFile, NULL,
PAGE_READONLY, 0, 0, NULL);
if (!hIsvUsrDic) {
LoadString(hAppInst, IDS_NOTOPEN_TITLE, szTitle, iTitle);
LoadString(hAppInst, IDS_NOTOPEN_MSG, szMessage, iMessage);
MessageBox(hWnd, szMessage, szTitle,
MB_OK|MB_ICONHAND|MB_TASKMODAL|MB_TOPMOST);
goto BatchCloseUsrDicFile;
}
lpIsvUsrDic = MapViewOfFile(hIsvUsrDic, FILE_MAP_READ, 0, 0, 0);
if (!lpIsvUsrDic) {
LoadString(hAppInst, IDS_NOTOPEN_TITLE, szTitle, iTitle);
LoadString(hAppInst, IDS_NOTOPEN_MSG, szMessage, iMessage);
MessageBox(hWnd, szMessage, szTitle,
MB_OK|MB_ICONHAND|MB_TASKMODAL|MB_TOPMOST);
goto BatchCloseUsrDic;
}
dwSize = lpIsvUsrDic->ulTableCount * (sizeof(WORD) + sizeof(WORD) +
lpIsvUsrDic->cMethodKeySize) + 256;
dwFileSize = GetFileSize(hIsvUsrDicFile, (LPDWORD)NULL);
#if 0 // temp code
dwSize = dwFileSize;
#endif
if (dwSize != dwFileSize) {
LoadString(hAppInst, IDS_FILESIZE_TITLE, szTitle, iTitle);
LoadString(hAppInst, IDS_FILESIZE_MSG, szMessage, iMessage);
MessageBox(hWnd, szMessage, szTitle, MB_OK);
} else if (lpIsvUsrDic->uHeaderSize != 256) {
LoadString(hAppInst, IDS_HEADERSIZE_TITLE, szTitle, iTitle);
LoadString(hAppInst, IDS_HEADERSIZE_MSG, szMessage, iMessage);
MessageBox(hWnd, szMessage, szTitle, MB_OK);
} else if (lpIsvUsrDic->uInfoSize != 13) {
LoadString(hAppInst, IDS_INFOSIZE_TITLE, szTitle, iTitle);
LoadString(hAppInst, IDS_INFOSIZE_MSG, szMessage, iMessage);
MessageBox(hWnd, szMessage, szTitle, MB_OK);
} else if (CodePageInfo(lpIsvUsrDic->idCP) == -1) {
LoadString(hAppInst, IDS_CODEPAGE_TITLE, szTitle, iTitle);
LoadString(hAppInst, IDS_CODEPAGE_MSG, szMessage, iMessage);
MessageBox(hWnd, szMessage, szTitle, MB_OK);
} else if (*(LPUNADWORD)lpIsvUsrDic->idUserCharInfoSign != SIGN_CWIN) {
// != CWIN
LoadString(hAppInst, IDS_CWINSIGN_TITLE, szTitle, iTitle);
LoadString(hAppInst, IDS_CWINSIGN_MSG, szMessage, iMessage);
MessageBox(hWnd, szMessage, szTitle, MB_OK);
} else if (*(LPUNADWORD)((LPBYTE)lpIsvUsrDic->idUserCharInfoSign +
sizeof(DWORD)) != SIGN__TBL) {
// != _TBL
LoadString(hAppInst, IDS_CWINSIGN_TITLE, szTitle, iTitle);
LoadString(hAppInst, IDS_CWINSIGN_MSG, szMessage, iMessage);
MessageBox(hWnd, szMessage, szTitle, MB_OK);
} else if (!RegisterTable(hWnd, lpIsvUsrDic, dwFileSize, lpIsvUsrDic->idCP)) {
LoadString(hAppInst, IDS_UNMATCHED_TITLE, szTitle, iTitle);
LoadString(hAppInst, IDS_UNMATCHED_MSG, szMessage, iMessage);
MessageBox(hWnd, szMessage, szTitle, MB_OK);
} else {
// OK
}
UnmapViewOfFile(lpIsvUsrDic);
BatchCloseUsrDic:
CloseHandle(hIsvUsrDic);
BatchCloseUsrDicFile:
CloseHandle(hIsvUsrDicFile);
return;
}
/************************************************************/
/* WndProc() */
/************************************************************/
LRESULT CALLBACK WndProc( // this is the window procedure of
// EUDC editor
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
#ifdef UNICODE
static UINT uCode = 0xE000;
#else
static UINT uCode = 0xFA40;
#endif
switch (uMsg) {
case WM_COMMAND:
switch (wParam) {
case IDM_NEW_EUDC:
uCode++;
break;
case IDM_IME_LINK:
ImeLink(hWnd, uCode);
break;
case IDM_BATCH_IME_LINK:
BatchImeLink(hWnd);
break;
default:
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return (0L);
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return (0L);
}
/************************************************************/
/* WinMain() */
/************************************************************/
int WINAPI WinMain(
HINSTANCE hInst,
HINSTANCE hPrevInst,
LPSTR lpszCmdLine,
int nCmdShow)
{
WNDCLASS wcClass;
HWND hWnd;
MSG sMsg;
hAppInst = hInst;
wcClass.style = CS_HREDRAW|CS_VREDRAW;
wcClass.lpfnWndProc = WndProc;
wcClass.cbClsExtra = 0;
wcClass.cbWndExtra = 0;
wcClass.hInstance = hAppInst;
wcClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wcClass.hbrBackground = GetStockObject(LTGRAY_BRUSH);
wcClass.lpszMenuName = szMenuName;
wcClass.lpszClassName = szAppName;
RegisterClass(&wcClass);
hWnd = CreateWindowEx(WS_EX_WINDOWEDGE,
szAppName,
TEXT("Fake EUDC Editor"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hAppInst, NULL);
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
if (!hWnd) {
return (0);
}
while (GetMessage(&sMsg, NULL, 0, 0)) {
TranslateMessage(&sMsg);
DispatchMessage(&sMsg);
}
return ((int) sMsg.wParam);
}