Created
February 10, 2023 04:16
-
-
Save katahiromz/46d40dea26b191c8923de5ccd2bae310 to your computer and use it in GitHub Desktop.
2k-imm32-candinfo.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 2k-imm32-candinfo.cpp | |
C_ASSERT(sizeof(CANDIDATELIST) == 28); | |
#define ROUNDUP4(n) (((n) + 3) & ~3) /* DWORD alignment */ | |
#define CLIENTIMC_WIDE 0x1 | |
/* dwType for NtUserQueryInputContext */ | |
typedef enum _QUERY_INPUT_CONTEXT | |
{ | |
QIC_INPUTPROCESSID = 0, | |
QIC_INPUTTHREADID, | |
QIC_DEFAULTWINDOWIME, | |
QIC_DEFAULTIMC | |
} QUERY_INPUT_CONTEXT; | |
// @implemented | |
DWORD | |
CandidateListWideToAnsi(const CANDIDATELIST *pWideCL, LPCANDIDATELIST pAnsiCL, DWORD dwBufLen, UINT uCodePage) | |
{ | |
DWORD dwIndex, dwCount, dwTotalSize, ret; | |
LPDWORD pdw; | |
const WCHAR *pchW; | |
LPSTR pchA; | |
INT cchA, cbRemaining; | |
dwTotalSize = sizeof(CANDIDATELIST); | |
dwCount = pWideCL->dwCount; | |
if (dwCount > 0) | |
{ | |
dwTotalSize = sizeof(CANDIDATELIST) + (dwCount - 1) * sizeof(DWORD); | |
for (dwIndex = 0; dwIndex < dwCount; ++dwIndex) | |
{ | |
pchW = (const WCHAR *)((const BYTE *)pWideCL + pWideCL->dwOffset[dwIndex]); | |
cchA = WideCharToMultiByte(uCodePage, 0, pchW, -1, NULL, 0, NULL, NULL); | |
dwTotalSize += cchA; | |
} | |
} | |
ret = ROUNDUP4(dwTotalSize); | |
if (dwBufLen == 0) | |
return ret; | |
if (dwBufLen < ret) | |
return 0; | |
pAnsiCL->dwSize = dwBufLen; | |
pAnsiCL->dwStyle = pWideCL->dwStyle; | |
pAnsiCL->dwCount = dwCount; | |
pAnsiCL->dwSelection = pWideCL->dwSelection; | |
pAnsiCL->dwPageStart = pWideCL->dwPageStart; | |
pAnsiCL->dwPageSize = pWideCL->dwPageSize; | |
pdw = pAnsiCL->dwOffset; | |
*pdw = sizeof(CANDIDATELIST); | |
if (dwCount > 0) | |
*pdw = sizeof(CANDIDATELIST) + (dwCount - 1) * sizeof(DWORD); | |
cbRemaining = dwBufLen - *pdw; | |
for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pdw) | |
{ | |
ASSERT(cbRemaining > 0); | |
ASSERT(pdw == &pAnsiCL->dwOffset[dwIndex]); | |
pchW = (const WCHAR *)((const BYTE *)pWideCL + pWideCL->dwOffset[dwIndex]); | |
pchA = (LPSTR)((LPBYTE)pAnsiCL + *pdw); | |
cchA = WideCharToMultiByte(uCodePage, 0, pchW, -1, pchA, cbRemaining, NULL, NULL); | |
cbRemaining -= cchA; | |
if (dwIndex + 1 < dwCount) | |
pdw[1] = *pdw + cchA; | |
} | |
return dwBufLen; | |
} | |
// @implemented | |
DWORD | |
CandidateListAnsiToWide(const CANDIDATELIST *pAnsiCL, LPCANDIDATELIST pWideCL, DWORD dwBufLen, UINT uCodePage) | |
{ | |
DWORD ret, dwCount, dwTotalSize, dwIndex, cbW; | |
LPDWORD pdw; | |
const CHAR *pchA; | |
LPWSTR pchW; | |
INT cchW, cbRemaining; | |
dwTotalSize = sizeof(CANDIDATELIST); | |
dwCount = pAnsiCL->dwCount; | |
if (dwCount > 0) | |
{ | |
dwTotalSize = sizeof(CANDIDATELIST) + (dwCount - 1) * sizeof(DWORD); | |
for (dwIndex = 0; dwIndex < dwCount; ++dwIndex) | |
{ | |
pchA = (const CHAR *)((const BYTE *)pAnsiCL + pAnsiCL->dwOffset[dwIndex]); | |
cchW = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, pchA, -1, NULL, 0); | |
dwTotalSize += cchW * sizeof(WCHAR); | |
} | |
} | |
ret = ROUNDUP4(dwTotalSize); | |
if (dwBufLen == 0) | |
return ret; | |
if (dwBufLen < ret) | |
return 0; | |
pWideCL->dwSize = dwBufLen; | |
pWideCL->dwStyle = pAnsiCL->dwStyle; | |
pWideCL->dwCount = dwCount; | |
pWideCL->dwSelection = pAnsiCL->dwSelection; | |
pWideCL->dwPageStart = pAnsiCL->dwPageStart; | |
pWideCL->dwPageSize = pAnsiCL->dwPageSize; | |
pdw = pWideCL->dwOffset; | |
*pdw = sizeof(CANDIDATELIST); | |
if (dwCount > 0) | |
*pdw = sizeof(CANDIDATELIST) + (dwCount - 1) * sizeof(DWORD); | |
cbRemaining = dwBufLen - *pdw; | |
for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pdw) | |
{ | |
ASSERT(cbRemaining > 0); | |
ASSERT(pdw == &pWideCL->dwOffset[dwIndex]); | |
pchA = (const CHAR *)((const BYTE *)pAnsiCL + pAnsiCL->dwOffset[dwIndex]); | |
pchW = (LPWSTR)((LPBYTE)pWideCL + *pdw); | |
cchW = dwRemaining / sizeof(WCHAR); | |
cchW = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, pchA, -1, pchW, cchW); | |
cbW = cchW * sizeof(WCHAR); | |
cbRemaining -= cbW; | |
if (dwIndex + 1 < dwCount) | |
pdw[1] = *pdw + cbW; | |
} | |
return dwBufLen; | |
} | |
// @implemented | |
DWORD | |
ImmGetCandidateListCountAW(HIMC hIMC, LPDWORD lpdwListCount, BOOL bAnsi) | |
{ | |
PCLIENTIMC pClientImc; | |
LPINPUTCONTEXT pIC; | |
LPCANDIDATEINFO pCI; | |
DWORD dwSize, dwIndex, ret = 0; | |
LPCANDIDATELIST pWideCL, pAnsiCL; | |
if (lpdwListCount == NULL) | |
return 0; | |
*lpdwListCount = 0; | |
pClientImc = ImmLockClientImc(hIMC); | |
if (pClientImc == NULL) | |
return 0; | |
pIC = ImmLockIMC(hIMC); | |
if (pIC == NULL) | |
{ | |
ImmUnlockClientImc(&pClientImc); | |
return ret; | |
} | |
pCI = (LPCANDIDATEINFO)ImmLockIMCC(pIC->hCandInfo); | |
if (pCI) | |
{ | |
if (pCI->dwSize >= sizeof(CANDIDATEINFO)) | |
{ | |
/* Set the number of the list */ | |
*lpdwListCount = pCI->dwCount; | |
/* Returns the total size of the destination candidate info */ | |
if (bAnsi) | |
{ | |
if (pClientImc->dwFlags & CLIENTIMC_WIDE) | |
{ | |
ret = sizeof(CANDIDATEINFO) + ROUNDUP4(pCI->dwPrivateSize); | |
for (dwIndex = 0; dwIndex < pCI->dwCount; ++dwIndex) | |
{ | |
pAnsiCL = (LPCANDIDATELIST)((LPBYTE)pCI + pCI->dwOffset[dwIndex]); | |
dwSize = CandidateListAnsiToWide(pAnsiCL, NULL, 0, 0); | |
ret += dwSize; | |
} | |
} | |
else | |
{ | |
ret = pCI->dwSize; | |
} | |
} | |
else | |
{ | |
if (pClientImc->dwFlags & CLIENTIMC_WIDE) | |
{ | |
ret = pCI->dwSize; | |
} | |
else | |
{ | |
ret = sizeof(CANDIDATEINFO) + ROUNDUP4(pCI->dwPrivateSize); | |
for (dwIndex = 0; dwIndex < pCI->dwCount; ++dwIndex) | |
{ | |
pWideCL = (LPCANDIDATELIST)((LPBYTE)pCI + pCI->dwOffset[dwIndex]); | |
dwSize = CandidateListWideToAnsi(pWideCL, NULL, 0, 0); | |
ret += dwSize; | |
} | |
} | |
} | |
} | |
ImmUnlockIMCC(pIC->hCandInfo); | |
} | |
ImmUnlockIMC(hIMC); | |
ImmUnlockClientImc(&pClientImc); | |
return ret; | |
} | |
// @implemented | |
DWORD | |
ImmGetCandidateListAW(HIMC hIMC, DWORD dwIndex, LPCANDIDATELIST lpCandList, DWORD dwBufLen, BOOL bAnsi) | |
{ | |
PCLIENTIMC pClientImc; | |
LPINPUTCONTEXT pIC; | |
LPCANDIDATEINFO pCI; | |
LPCANDIDATELIST pSrcCL; | |
DWORD cbList, ret = 0; | |
pClientImc = ImmLockClientImc(hIMC); | |
if (pClientImc == NULL) | |
return 0; | |
pIC = ImmLockIMC(hIMC); | |
if (pIC == NULL) | |
{ | |
ImmUnlockClientImc(pClientImc); | |
return 0; | |
} | |
pCI = (LPCANDIDATEINFO)ImmLockIMCC(pIC->hCandInfo); | |
if (pCI) | |
{ | |
if (pCI->dwSize >= sizeof(CANDIDATEINFO) && dwIndex < pCI->dwCount) | |
{ | |
/* Get cbList from candidate info */ | |
pSrcCL = (LPCANDIDATELIST)((LPBYTE)pCI + pCI->dwOffset[dwIndex]); | |
if (!bAnsi) | |
{ | |
if (pClientImc->dwFlags & CLIENTIMC_WIDE) | |
{ | |
cbList = pSrcCL->dwSize; | |
} | |
else | |
{ | |
cbList = CandidateListAnsiToWide(pSrcCL, NULL, 0, 0); | |
} | |
} | |
else | |
{ | |
if (!(pClientImc->dwFlags & CLIENTIMC_WIDE)) | |
{ | |
cbList = pSrcCL->dwSize; | |
} | |
else | |
{ | |
cbList = CandidateListWideToAnsi(pSrcCL, NULL, 0, 0); | |
} | |
} | |
if (dwBufLen == 0 || cbList == 0) | |
{ | |
ret = cbList; /* Returns the list size */ | |
} | |
else if (lpCandidate && dwBufLen >= cbList) | |
{ | |
/* Copy/Convert the list to lpCandList */ | |
if (bAnsi) | |
{ | |
if (pClientImc->dwFlags & CLIENTIMC_WIDE) | |
{ | |
ret = CandidateListWideToAnsi(pSrcCL, lpCandList, cbList, 0); | |
} | |
else | |
{ | |
CopyMemory(lpCandList, pSrcCL, cbList); | |
ret = cbList; | |
} | |
} | |
else | |
{ | |
if (pClientImc->dwFlags & CLIENTIMC_WIDE) | |
{ | |
CopyMemory(lpCandList, pSrcCL, cbList); | |
ret = cbList; | |
} | |
else | |
{ | |
ret = CandidateListAnsiToWide(pSrcCL, lpCandList, cbList, 0); | |
} | |
} | |
} | |
} | |
ImmUnlockIMCC(pIC->hCandInfo); | |
} | |
ImmUnlockIMC(hIMC); | |
ImmUnlockClientImc(pClientImc); | |
return ret; | |
} | |
// @implemented | |
DWORD WINAPI ImmGetCandidateListA(HIMC hIMC, DWORD dwIndex, LPCANDIDATELIST lpCandList, DWORD dwBufLen) | |
{ | |
return ImmGetCandidateListAW(hIMC, dwIndex, lpCandList, dwBufLen, TRUE); | |
} | |
// @implemented | |
DWORD WINAPI ImmGetCandidateListW(HIMC hIMC, DWORD deIndex, LPCANDIDATELIST lpCandList, DWORD dwBufLen) | |
{ | |
return ImmGetCandidateListAW(hIMC, deIndex, lpCandList, dwBufLen, FALSE); | |
} | |
// @implemented | |
DWORD WINAPI ImmGetCandidateListCountA(HIMC hIMC, LPDWORD lpdwListCount) | |
{ | |
return ImmGetCandidateListCountAW(hIMC, lpdwListCount, TRUE); | |
} | |
// @implemented | |
DWORD WINAPI ImmGetCandidateListCountW(HIMC hIMC, LPDWORD lpdwListCount) | |
{ | |
return ImmGetCandidateListCountAW(hIMC, lpdwListCount, FALSE); | |
} | |
// @implemented | |
BOOL WINAPI ImmGetCandidateWindow(HIMC hIMC,DWORD dwIndex,LPCANDIDATEFORM lpCandidate) | |
{ | |
LPINPUTCONTEXT pIC = ImmLockIMC(hIMC); | |
if (pIC == NULL) | |
return FALSE; | |
//ImmUnlockIMC(hIMC); // これはWin2k側の間違いかworkaroundと思われる。Win2k3にはない。 | |
if (pIC->cfCandForm[dwIndex].dwIndex == (DWORD)-1) | |
{ | |
ImmUnlockIMC(hIMC); | |
return FALSE; | |
} | |
*lpCandidate = pIC->cfCandForm[dwIndex]; | |
ImmUnlockIMC(hIMC); | |
return TRUE; | |
} | |
// @implemented | |
BOOL WINAPI ImmSetCandidateWindow(HIMC hIMC, LPCANDIDATEFORM lpCandidate) | |
{ | |
HWND hwnd; | |
DWORD dwImeThreadId, dwCurThreadId; | |
LPINPUTCONTEXT pIC; | |
if (lpCandidate->dwIndex >= 4) | |
return FALSE; | |
dwImeThreadId = NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID); | |
dwCurThreadId = GetCurrentThreadId(); | |
if (dwImeThreadId != dwCurThreadId) | |
return FALSE; | |
pIC = ImmLockIMC(hIMC) | |
if (pIC == NULL) | |
return FALSE+ | |
pIC->cfCandForm[lpCandidate->dwIndex] = *lpCandidate; | |
hwnd = pIC->hWnd; | |
ImmUnlockIMC(hIMC); | |
Imm32MakeIMENotify(hIMC, hwnd, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS, | |
IMN_SETCANDIDATEPOS, (1 << lpCandidate->dwIndex)); | |
return TRUE; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment