📄 imeui.cpp
字号:
}
else {
while ( *psz && ( '0' <= *psz && *psz <= '9' ) )
{
ulRet = ulRet * 10 + ( *psz - '0' );
psz++;
}
}
return ulRet;
}
#ifdef UNICODE
#define GetCharCount(psz) lstrlen(psz)
#define GetCharCountFromBytes(psz,iBytes) (iBytes)
static void AW_SendCompString()
{
int i, iLen;
if ( ImeUiCallback_OnChar )
{
for ( i = 0; g_szCompositionString[i]; i++ )
{
ImeUiCallback_OnChar( g_szCompositionString[i] );
}
return;
}
BYTE szCompStr[COUNTOF(g_szCompositionString) * 2];
iLen = WideCharToMultiByte(g_uCodePage, 0, g_szCompositionString, -1,
(LPSTR)szCompStr, COUNTOF(szCompStr), NULL, NULL) - 1; // don't need to send NUL terminator;
for (i = 0; i < iLen; i++)
{
SendKeyMsg(g_hwndCurr, WM_CHAR, szCompStr[i]);
}
}
// The following AW_Imm* functions are there to support Win95/98 first version.
// They can be deleted if the game doesn't supports them (i.e. games requires Win98 SE or later).
static DWORD AW_GetCandidateList(HIMC himc, DWORD dwIndex, LPCANDIDATELIST* ppCandList)
{
DWORD dwBufLen = ImmGetCandidateListA( himc, dwIndex, NULL, 0 );
if (dwBufLen)
{
LPCANDIDATELIST pCandList = (LPCANDIDATELIST)ImeUiCallback_Malloc(dwBufLen);
if (pCandList) {
dwBufLen = ImmGetCandidateListA( himc, dwIndex, pCandList, dwBufLen );
if (dwBufLen) {
int i;
int wideBufLen = 0;
for (i = 0; i < (int)pCandList->dwCount; i++) {
wideBufLen += MultiByteToWideChar(g_uCodePage, 0, (LPSTR)pCandList + pCandList->dwOffset[i], -1, NULL, 0) * sizeof(WCHAR);
}
wideBufLen += pCandList->dwOffset[0];
*ppCandList = (LPCANDIDATELIST)ImeUiCallback_Malloc(wideBufLen);
LPCANDIDATELIST pCandListW = *ppCandList;
memcpy(pCandListW, pCandList, pCandList->dwOffset[0]);
LPWSTR pwz = (LPWSTR)((LPSTR)pCandListW + pCandList->dwOffset[0]);
for (i = 0; i < (int)pCandList->dwCount; i++) {
pCandListW->dwOffset[i] = (LPSTR)pwz - (LPSTR)pCandListW;
pwz += MultiByteToWideChar(g_uCodePage, 0, (LPSTR)pCandList + pCandList->dwOffset[i], -1, pwz, 256);
}
dwBufLen = wideBufLen;
}
ImeUiCallback_Free(pCandList);
}
}
return dwBufLen;
}
static LONG WINAPI AW_ImmGetCompositionString(HIMC himc, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
{
char pszMb[COUNTOF(g_szCompositionString) * 2];
DWORD dwRet = ImmGetCompositionStringA(himc, dwIndex, pszMb, sizeof(pszMb));
switch (dwIndex) {
case GCS_RESULTSTR:
case GCS_COMPSTR:
if (dwRet) {
pszMb[dwRet] = 0;
dwRet = (DWORD)MultiByteToWideChar(g_uCodePage, 0, pszMb, -1, (LPWSTR)lpBuf, dwBufLen);
if (dwRet) {
// Note that ImmGetCompositionString() returns number of bytes copied, regardless of the width of character.
dwRet = (dwRet - 1) * sizeof(WCHAR);
}
}
break;
case GCS_CURSORPOS:
dwRet /= 2;
break;
case GCS_COMPATTR: {
char pszMb2[COUNTOF(g_szCompositionString) * 2];
DWORD dwRet2 = ImmGetCompositionStringA(himc, GCS_COMPSTR, pszMb2, sizeof(pszMb2));
if (!dwRet2) {
dwRet2 = ImmGetCompositionStringA(himc, GCS_RESULTSTR, pszMb2, sizeof(pszMb2));
if (!dwRet2) {
return 0;
}
}
char* pOut = (char*)lpBuf;
for (DWORD i = 0; i < dwRet; i++) {
*pOut++ = pszMb[i]; // copy attribute
if (_IsLeadByte(pszMb2[i]))
i++;
}
dwRet = pOut - (char*)lpBuf;
}
break;
}
return dwRet;
}
#else // !UNICODE
// returns number of characters from number of bytes
static int GetCharCountFromBytes(LPCSTR pszString, int iBytes)
{
int iCount = 0;
int i;
for (i = 0; pszString[i] && i < iBytes; i++) {
iCount++;
if (_IsLeadByte(pszString[i]))
i++;
}
if (i != iBytes)
iCount = -iCount; // indicate error - iBytes specifies wrong boundary (i.e. the last byte is leadbyte)
return iCount;
}
static int GetCharCount(LPTSTR psz)
{
int i = 0;
while (*psz) {
if (_IsLeadByte(*psz)) {
psz++;
}
psz++;
i++;
}
return i;
}
static DWORD WA_GetCandidateList(HIMC himc, DWORD dwIndex, LPCANDIDATELIST* ppCandList)
{
DWORD dwBufLen = ImmGetCandidateListW( himc, dwIndex, NULL, 0 );
if (dwBufLen)
{
LPCANDIDATELIST pCandList = (LPCANDIDATELIST)ImeUiCallback_Malloc(dwBufLen);
if (pCandList)
{
dwBufLen = ImmGetCandidateListW( himc, dwIndex, pCandList, dwBufLen );
if (dwBufLen)
{
int i;
int mbBufLen = 0;
for ( i = 0; i < (int)pCandList->dwCount; i++ )
{
mbBufLen += WideCharToMultiByte( g_uCodePage, 0, (LPWSTR)((LPSTR)pCandList + pCandList->dwOffset[i]), -1, NULL, 0, NULL, NULL );
}
mbBufLen += pCandList->dwOffset[0];
*ppCandList = (LPCANDIDATELIST)ImeUiCallback_Malloc(mbBufLen);
LPCANDIDATELIST pCandListA = *ppCandList;
memcpy(pCandListA, pCandList, pCandList->dwOffset[0]);
LPSTR psz = (LPSTR)pCandListA + pCandList->dwOffset[0];
for (i = 0; i < (int)pCandList->dwCount; i++)
{
pCandListA->dwOffset[i] = (LPSTR)psz - (LPSTR)pCandListA;
psz += WideCharToMultiByte( g_uCodePage, 0, (LPWSTR)((LPSTR)pCandList + pCandList->dwOffset[i]), -1, psz, 256, NULL, NULL );
}
dwBufLen = mbBufLen;
}
ImeUiCallback_Free(pCandList);
}
}
return dwBufLen;
}
static LONG WINAPI WA_ImmGetCompositionString(HIMC himc, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
{
WCHAR pwzUc[COUNTOF(g_szCompositionString)];
DWORD dwRet = ImmGetCompositionStringW(himc, dwIndex, pwzUc, sizeof(pwzUc));
switch (dwIndex) {
case GCS_RESULTSTR:
case GCS_COMPSTR:
if (dwRet) {
pwzUc[dwRet / sizeof(WCHAR)] = 0;
dwRet = (DWORD)WideCharToMultiByte( g_uCodePage, 0, pwzUc, -1, (LPSTR)lpBuf, dwBufLen, NULL, NULL );
if (dwRet) {
dwRet = dwRet - 1;
}
}
break;
case GCS_CURSORPOS:
{
WCHAR pwzUc2[COUNTOF(g_szCompositionString)];
DWORD dwRet2 = ImmGetCompositionStringW(himc, GCS_COMPSTR, pwzUc2, sizeof(pwzUc2));
if (!dwRet2)
{
dwRet2 = ImmGetCompositionStringW(himc, GCS_RESULTSTR, pwzUc2, sizeof(pwzUc2));
if (!dwRet2)
{
return 0;
}
}
dwRet2 /= 2;
//The return value of WideCharToMultiByte() should probably be checked/asserted for success.
//bounds violation (overflow) 'pszMb[iRc]'
const int bufSize = COUNTOF(g_szCompositionString) * 2;
char pszMb[bufSize];
int iRc = WideCharToMultiByte( g_uCodePage, 0, pwzUc2, dwRet2, pszMb, sizeof( pszMb ), NULL, NULL );
assert( iRc > 0 ); //WideCharToMultiByte returns 0 if it failed, and it should *never* be negative in the first place
if (iRc >= bufSize) //if we wrote more bytes than the length of the buffer, we need to terminate it
{
pszMb[ bufSize - 1] = 0; //0 terminate the end of the buffer
}
else
{
pszMb[ iRc ] = 0;
}
char* psz = pszMb;
for ( dwRet2 = 0; dwRet2 != dwRet; dwRet2++ )
{
if ( _IsLeadByte( *psz ) )
psz++;
psz++;
}
dwRet = psz - pszMb;
}
break;
case GCS_COMPATTR: {
WCHAR pwzUc2[COUNTOF(g_szCompositionString)];
DWORD dwRet2 = ImmGetCompositionStringW(himc, GCS_COMPSTR, pwzUc2, sizeof(pwzUc2));
if (!dwRet2)
{
dwRet2 = ImmGetCompositionStringW(himc, GCS_RESULTSTR, pwzUc2, sizeof(pwzUc2));
if (!dwRet2)
{
return 0;
}
}
dwRet2 /= 2;
const int bufSize = COUNTOF(g_szCompositionString) * 2;
char pszMb[bufSize];
int iRc = WideCharToMultiByte( g_uCodePage, 0, pwzUc2, dwRet2, pszMb, sizeof( pszMb ), NULL, NULL );
assert( iRc > 0 ); //WideCharToMultiByte returns 0 if it failed, and it should *never* be negative in the first place
if (iRc >= bufSize) //if we wrote more bytes than the length of the buffer, we need to terminate it
{
pszMb[ bufSize - 1] = 0; //0 terminate the end of the buffer
}
else
{
pszMb[ iRc ] = 0;
}
char* pSrc = (char*)pwzUc;
char* pOut = (char*)lpBuf;
for (char* psz = pszMb; *psz; psz++, pSrc++)
{
*pOut++ = *pSrc; // copy attribute
if ( _IsLeadByte( *psz ) )
{
*pOut++ = *pSrc;
psz++;
}
// buffer overrun protection, pOut is incremented in the loop, but not part of the
// loop invariant test. To make the code more readable we have a test rather than
// rolling this into the for stmt.
if ((DWORD)(pOut-(char*)lpBuf) >=dwBufLen)
break;
}
dwRet = pOut - (char*)lpBuf;
}
break;
}
return dwRet;
}
#endif // UNICODE
static void ComposeCandidateLine( int index, LPCTSTR pszCandidate )
{
LPTSTR psz = g_szCandidate[index];
*psz++ = (TCHAR)( TEXT( '0' ) + ( ( index + g_iCandListIndexBase ) % 10 ) );
if ( g_bVerticalCand )
{
*psz++ = TEXT( ' ' );
}
while ( *pszCandidate && (COUNTOF(g_szCandidate[index]) > (psz-g_szCandidate[index])) )
{
*psz++ = *pszCandidate++;
}
*psz = 0;
}
static void SendCompString()
{
int i, iLen = lstrlen(g_szCompositionString);
if ( ImeUiCallback_OnChar )
{
LPCWSTR pwz;
#ifdef UNICODE
pwz = g_szCompositionString;
#else
WCHAR szUnicode[ COUNTOF( g_szCompositionString ) ];
pwz = szUnicode;
iLen = MultiByteToWideChar( g_uCodePage, 0, g_szCompositionString, -1, szUnicode, COUNTOF(szUnicode) ) - 1;
#endif
for ( i = 0; i < iLen; i++ )
{
ImeUiCallback_OnChar( pwz[i] );
}
return;
}
for ( i = 0; i < iLen; i++ )
{
SendKeyMsg(g_hwndCurr, WM_CHAR,
#ifdef UNICODE
(WPARAM)g_szCompositionString[i]
#else
(WPARAM)(BYTE)g_szCompositionString[i]
#endif
);
}
}
static DWORD GetCandidateList(HIMC himc, DWORD dwIndex, LPCANDIDATELIST* ppCandList)
{
DWORD dwBufLen = _ImmGetCandidateList( himc, dwIndex, NULL, 0 );
if ( dwBufLen )
{
*ppCandList = (LPCANDIDATELIST)ImeUiCallback_Malloc(dwBufLen);
dwBufLen = _ImmGetCandidateList( himc, dwIndex, *ppCandList, dwBufLen );
}
return dwBufLen;
}
static void SendControlKeys(UINT vk, UINT num)
{
if (num == 0)
return;
for (UINT i = 0; i < num ; i++) {
SendKeyMsg_DOWN(g_hwndCurr, vk);
}
SendKeyMsg_UP(g_hwndCurr, vk);
}
// send key messages to erase composition string.
static void CancelCompString(HWND hwnd, bool bUseBackSpace = true, int iNewStrLen = 0)
{
if (g_dwIMELevel != 3)
return;
int cc = GetCharCount(g_szCompositionString);
int i;
// move caret to the end of composition string
SendControlKeys(VK_RIGHT, cc - g_IMECursorChars);
if (bUseBackSpace || g_bInsertMode)
iNewStrLen = 0;
// The caller sets bUseBackSpace to false if there's possibility of sending
// new composition string to the app right after this function call.
//
// If the app is in overwriting mode and new comp string is
// shorter than current one, delete previous comp string
// till it's same long as the new one. Then move caret to the beginning of comp string.
// New comp string will overwrite old one.
if (iNewStrLen < cc)
{
for (i = 0; i < cc - iNewStrLen; i++)
{
SendKeyMsg_DOWN(hwnd, VK_BACK);
SendKeyMsg(hwnd, WM_CHAR, 8); //Backspace character
}
SendKeyMsg_UP(hwnd, VK_BACK);
}
else
iNewStrLen = cc;
SendControlKeys(VK_LEFT, iNewStrLen);
}
// initialize composition string data.
static void InitCompStringData(void)
{
g_IMECursorBytes = 0;
g_IMECursorChars = 0;
memset(&g_szCompositionString, 0, sizeof(g_szCompositionString));
memset(&g_szCompAttrString, 0, sizeof(g_szCompAttrString));
}
static void DrawCaret(DWORD x, DWORD y, DWORD height)
{
if (g_bCaretDraw && ImeUiCallback_DrawRect)
ImeUiCallback_DrawRect(x, y + gSkinIME.caretYMargin, x + gSkinIME.caretWidth, y + height - gSkinIME.caretYMargin, g_CaretInfo.colorComp);
}
//
// Apps that draw the composition string on top of composition string attribute
// in level 3 support should call this function twice in rendering a frame.
// // Draw edit box UI;
// ImeUi_RenderUI(true, false); // paint composition string attribute;
// // Draw text in the edit box;
// ImeUi_RenderUi(false, true); // paint the rest of IME UI;
//
void ImeUi_RenderUI(bool bDrawCompAttr, bool bDrawOtherUi)
{
if (!g_bInitialized || !g_bImeEnabled || !g_CaretInfo.pFont)
return;
if (!bDrawCompAttr && !bDrawOtherUi)
return; // error case
if (g_dwIMELevel == 2) {
if (!bDrawOtherUi)
return; // 1st call for level 3 support
}
if (bDrawOtherUi)
DrawImeIndicator();
DrawCompositionString( bDrawCompAttr );
if ( bDrawOtherUi )
DrawCandidateList();
}
static void DrawImeIndicator()
{
bool bOn = g_dwState != IMEUI_STATE_OFF;
IMEUI_VERTEX PieData[17];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -