mirror of
https://github.com/reactos/reactos.git
synced 2026-05-31 08:17:09 +08:00
[IMM32][NTUSER][SDK] Implement ImmSendIMEMessageExA/W (#8850)
Supporting Win3.x IMM. JIRA issue: CORE-19268 - Move <wine/ime.h> to psdk <ime.h>. - Add some constants to <imm32_undoc.h>. - Implement ImmSendIMEMessageExA and ImmSendIMEMessageExW functions.
This commit is contained in:
committed by
GitHub
parent
61fb4db34c
commit
215d409f52
@@ -210,6 +210,24 @@ typedef struct INPUTCONTEXTDX
|
||||
HIMCC hCtfImeContext;
|
||||
} INPUTCONTEXTDX, *PINPUTCONTEXTDX, NEAR *NPINPUTCONTEXTDX, FAR *LPINPUTCONTEXTDX;
|
||||
|
||||
/* INPUTCONTEXTDX.dwUIFlags flags */
|
||||
#define _IME_UI_HIDDEN 0x2
|
||||
#define _IME_UI_VERTICAL 0x4
|
||||
#define _IME_UI_NO_COMPFORM 0x8
|
||||
|
||||
/* ImmGetAppCompatFlags flags */
|
||||
#define _IME_APP_COMPAT_DIRECT_IME_SYSTEM 0x1
|
||||
#define _IME_APP_COMPAT_DIRECT_IME_FONT 0x80
|
||||
#define _IME_APP_COMPAT_PROCESS_BY_IME 0x10000
|
||||
#define _IME_APP_COMPAT_SPECIAL_IME 0x80000000
|
||||
|
||||
/* Extra conversion mode */
|
||||
#define _IME_CMODE_EXTENDED 0x80000000
|
||||
|
||||
/* Extra IME mode */
|
||||
#define _IME_MODE_KOR_SBCSCHAR 0x0002 /* For Korean */
|
||||
#define _IME_MODE_JPN_SBCSCHAR 0x0008 /* For Japanese */
|
||||
|
||||
typedef struct IME_SUBSTATE
|
||||
{
|
||||
struct IME_SUBSTATE *pNext;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
#include <wine/ime.h>
|
||||
#include <ime.h>
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(imm);
|
||||
|
||||
@@ -1164,10 +1164,10 @@ ImmSetCompositionWindow(
|
||||
pIC->cfCompForm = *lpCompForm;
|
||||
pIC->fdwInit |= INIT_COMPFORM;
|
||||
|
||||
if (pIC->dwUIFlags & 0x8)
|
||||
pIC->dwUIFlags &= ~0x8;
|
||||
if (pIC->dwUIFlags & _IME_UI_NO_COMPFORM)
|
||||
pIC->dwUIFlags &= ~_IME_UI_NO_COMPFORM;
|
||||
else
|
||||
pIC->dwUIFlags &= ~0x2;
|
||||
pIC->dwUIFlags &= ~_IME_UI_HIDDEN;
|
||||
|
||||
hWnd = pIC->hWnd;
|
||||
|
||||
@@ -1298,7 +1298,7 @@ ImmSetCompositionFontA(
|
||||
{
|
||||
LangID = LANGIDFROMLCID(GetSystemDefaultLCID());
|
||||
if (PRIMARYLANGID(LangID) == LANG_JAPANESE &&
|
||||
!(pIC->dwUIFlags & 2) &&
|
||||
!(pIC->dwUIFlags & _IME_UI_HIDDEN) &&
|
||||
pIC->cfCompForm.dwStyle != CFS_DEFAULT)
|
||||
{
|
||||
PostMessageA(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0);
|
||||
@@ -1357,7 +1357,7 @@ ImmSetCompositionFontW(
|
||||
{
|
||||
LangID = LANGIDFROMLCID(GetSystemDefaultLCID());
|
||||
if (PRIMARYLANGID(LangID) == LANG_JAPANESE &&
|
||||
!(pIC->dwUIFlags & 2) &&
|
||||
!(pIC->dwUIFlags & _IME_UI_HIDDEN) &&
|
||||
pIC->cfCompForm.dwStyle != CFS_DEFAULT)
|
||||
{
|
||||
PostMessageW(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0);
|
||||
|
||||
@@ -1018,7 +1018,7 @@ ImmUnlockClientImc(_Inout_ PCLIENTIMC pClientImc)
|
||||
ImmLocalFree(pClientImc);
|
||||
}
|
||||
|
||||
static HIMC
|
||||
HIMC
|
||||
ImmGetSaveContext(
|
||||
_In_opt_ HWND hWnd,
|
||||
_In_ DWORD dwContextFlags)
|
||||
@@ -1206,7 +1206,7 @@ ImmSetActiveContext(
|
||||
pIC->hWnd = hWnd;
|
||||
pClientImc->dwFlags |= CLIENTIMC_ACTIVE;
|
||||
|
||||
if (pIC->dwUIFlags & 2)
|
||||
if (pIC->dwUIFlags & _IME_UI_HIDDEN)
|
||||
dwShowFlags = (ISC_SHOWUIGUIDELINE | ISC_SHOWUIALLCANDIDATEWINDOW);
|
||||
|
||||
fOpen = pIC->fOpen;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
#include <wine/ime.h>
|
||||
#include <ime.h>
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(imm);
|
||||
|
||||
@@ -721,18 +721,15 @@ ImmGetVirtualKey(_In_ HWND hWnd)
|
||||
DWORD WINAPI
|
||||
ImmGetAppCompatFlags(_In_ HIMC hIMC)
|
||||
{
|
||||
PCLIENTIMC pClientIMC;
|
||||
DWORD dwFlags;
|
||||
|
||||
TRACE("(%p)\n", hIMC);
|
||||
|
||||
pClientIMC = ImmLockClientImc(hIMC);
|
||||
PCLIENTIMC pClientIMC = ImmLockClientImc(hIMC);
|
||||
if (IS_NULL_UNEXPECTEDLY(pClientIMC))
|
||||
return 0;
|
||||
|
||||
dwFlags = pClientIMC->dwCompatFlags;
|
||||
DWORD dwCompatFlags = pClientIMC->dwCompatFlags;
|
||||
ImmUnlockClientImc(pClientIMC);
|
||||
return (dwFlags | g_aimm_compat_flags);
|
||||
return (dwCompatFlags | g_aimm_compat_flags);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
@@ -817,7 +814,7 @@ ImmProcessKey(
|
||||
if (bHotKeyDone && ((vKey != VK_KANJI) || (dwHotKeyID != IME_JHOTKEY_CLOSE_OPEN)))
|
||||
ret |= IPHK_HOTKEY;
|
||||
|
||||
if ((ret & IPHK_PROCESSBYIME) && (ImmGetAppCompatFlags(hIMC) & 0x10000))
|
||||
if ((ret & IPHK_PROCESSBYIME) && (ImmGetAppCompatFlags(hIMC) & _IME_APP_COMPAT_PROCESS_BY_IME))
|
||||
{
|
||||
/* The key has been processed by IME's ImeProcessKey */
|
||||
LANGID wLangID = LANGIDFROMLCID(GetSystemDefaultLCID());
|
||||
|
||||
@@ -190,3 +190,8 @@ CtfImmSetLangBand(
|
||||
|
||||
DWORD
|
||||
WINNLSTranslateMessage(DWORD dwCount, LPTRANSMSG pEntries, HIMC hIMC, BOOL bAnsi, WORD wLang);
|
||||
|
||||
HIMC
|
||||
ImmGetSaveContext(
|
||||
_In_opt_ HWND hWnd,
|
||||
_In_ DWORD dwContextFlags);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
#include <wine/ime.h>
|
||||
#include <ime.h>
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(imm);
|
||||
|
||||
@@ -55,7 +55,7 @@ WINNLSTranslateMessageJ(DWORD dwCount, LPTRANSMSG pTrans, LPINPUTCONTEXTDX pIC,
|
||||
return 0;
|
||||
RtlCopyMemory(pTempList, pTrans, dwCount * sizeof(TRANSMSG));
|
||||
|
||||
if (pIC->dwUIFlags & 0x2)
|
||||
if (pIC->dwUIFlags & _IME_UI_HIDDEN)
|
||||
{
|
||||
// find WM_IME_ENDCOMPOSITION
|
||||
pEntry = pTempList;
|
||||
@@ -82,7 +82,7 @@ WINNLSTranslateMessageJ(DWORD dwCount, LPTRANSMSG pTrans, LPINPUTCONTEXTDX pIC,
|
||||
switch (pEntry->message)
|
||||
{
|
||||
case WM_IME_STARTCOMPOSITION:
|
||||
if (!(pIC->dwUIFlags & 0x2))
|
||||
if (!(pIC->dwUIFlags & _IME_UI_HIDDEN))
|
||||
{
|
||||
// send IR_OPENCONVERT
|
||||
if (pIC->cfCompForm.dwStyle != CFS_DEFAULT)
|
||||
@@ -93,7 +93,7 @@ WINNLSTranslateMessageJ(DWORD dwCount, LPTRANSMSG pTrans, LPINPUTCONTEXTDX pIC,
|
||||
break;
|
||||
|
||||
case WM_IME_ENDCOMPOSITION:
|
||||
if (pIC->dwUIFlags & 0x2)
|
||||
if (pIC->dwUIFlags & _IME_UI_HIDDEN)
|
||||
{
|
||||
// send IR_UNDETERMINE
|
||||
hGlobal = GlobalAlloc(GHND | GMEM_SHARE, sizeof(UNDETERMINESTRUCT));
|
||||
@@ -123,7 +123,7 @@ WINNLSTranslateMessageJ(DWORD dwCount, LPTRANSMSG pTrans, LPINPUTCONTEXTDX pIC,
|
||||
pTrans += dwNumber;
|
||||
|
||||
// send IR_CHANGECONVERT
|
||||
if (!(pIC->dwUIFlags & 0x2))
|
||||
if (!(pIC->dwUIFlags & _IME_UI_HIDDEN))
|
||||
{
|
||||
if (pIC->cfCompForm.dwStyle != CFS_DEFAULT)
|
||||
pSendMessage(hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0);
|
||||
@@ -133,7 +133,7 @@ WINNLSTranslateMessageJ(DWORD dwCount, LPTRANSMSG pTrans, LPINPUTCONTEXTDX pIC,
|
||||
case WM_IME_NOTIFY:
|
||||
if (pEntry->wParam == IMN_OPENCANDIDATE)
|
||||
{
|
||||
if (IsWindow(hWnd) && (pIC->dwUIFlags & 0x2))
|
||||
if (IsWindow(hWnd) && (pIC->dwUIFlags & _IME_UI_HIDDEN))
|
||||
{
|
||||
// send IMC_SETCANDIDATEPOS
|
||||
for (iCandForm = 0; iCandForm < MAX_CANDIDATEFORM; ++iCandForm)
|
||||
@@ -151,7 +151,7 @@ WINNLSTranslateMessageJ(DWORD dwCount, LPTRANSMSG pTrans, LPINPUTCONTEXTDX pIC,
|
||||
}
|
||||
}
|
||||
|
||||
if (!(pIC->dwUIFlags & 0x2))
|
||||
if (!(pIC->dwUIFlags & _IME_UI_HIDDEN))
|
||||
goto DoDefault;
|
||||
|
||||
// send a WM_IME_NOTIFY notification to the default ime window
|
||||
|
||||
@@ -6,15 +6,959 @@
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
#include <wine/ime.h>
|
||||
#include <ime.h>
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(imm);
|
||||
|
||||
#ifdef IMM_WIN3_SUPPORT /* 3.x support */
|
||||
|
||||
static DWORD Imm32TranslateIMESubFunctions(HWND hWnd, PIMESTRUCT pIme, BOOL bAnsi)
|
||||
static BOOL Imm32IsForegroundThread(HWND hWnd)
|
||||
{
|
||||
FIXME("(%p, %p, %d)\n", hWnd, pIme, bAnsi);
|
||||
HWND hwndFore = GetForegroundWindow();
|
||||
DWORD dwTID1 = IsWindow(hWnd) ? GetWindowThreadProcessId(hWnd, NULL) : GetCurrentThreadId();
|
||||
DWORD dwTID2 = GetWindowThreadProcessId(hwndFore, NULL);
|
||||
return dwTID1 == dwTID2;
|
||||
}
|
||||
|
||||
static BOOL Imm32PostImsMessage(HWND hWnd, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
HWND hwndIme = ImmGetDefaultIMEWnd(hWnd);
|
||||
if (!hwndIme)
|
||||
return FALSE;
|
||||
return PostMessageW(hwndIme, WM_IME_SYSTEM, wParam, lParam);
|
||||
}
|
||||
|
||||
static BOOL Imm32SetCandidateWindow(HWND hWnd, HIMC hIMC, PCANDIDATEFORM lpCandidate)
|
||||
{
|
||||
PINPUTCONTEXT pIC = ImmLockIMC(hIMC);
|
||||
if (!pIC)
|
||||
return FALSE;
|
||||
|
||||
BOOL ret;
|
||||
DWORD dwCompatFlags = ImmGetAppCompatFlags(hIMC);
|
||||
if (dwCompatFlags & _IME_APP_COMPAT_DIRECT_IME_SYSTEM)
|
||||
{
|
||||
RtlCopyMemory(&pIC->cfCandForm[lpCandidate->dwIndex], lpCandidate, sizeof(CANDIDATEFORM));
|
||||
ret = Imm32PostImsMessage(hWnd, IMS_SETCANDFORM, lpCandidate->dwIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ImmSetCandidateWindow(hIMC, lpCandidate);
|
||||
}
|
||||
|
||||
ImmUnlockIMC(hIMC);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL Imm32SetCompWindow(HWND hWnd, HIMC hIMC, PCOMPOSITIONFORM lpCompForm)
|
||||
{
|
||||
PINPUTCONTEXTDX pIC = (PINPUTCONTEXTDX)ImmLockIMC(hIMC);
|
||||
if (!pIC)
|
||||
return FALSE;
|
||||
|
||||
BOOL ret;
|
||||
DWORD dwCompatFlags = ImmGetAppCompatFlags(hIMC);
|
||||
if (dwCompatFlags & _IME_APP_COMPAT_DIRECT_IME_SYSTEM)
|
||||
{
|
||||
RtlCopyMemory(&pIC->cfCompForm, lpCompForm, sizeof(COMPOSITIONFORM));
|
||||
if (dwCompatFlags & _IME_APP_COMPAT_SPECIAL_IME)
|
||||
ret = PostMessageW(hWnd, WM_IME_SYSTEM, IMS_SETCOMPFORM, 0);
|
||||
else
|
||||
ret = Imm32PostImsMessage(hWnd, IMS_SETCOMPFORM, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
pIC->dwUIFlags |= _IME_UI_NO_COMPFORM;
|
||||
ret = ImmSetCompositionWindow(hIMC, lpCompForm);
|
||||
}
|
||||
|
||||
ImmUnlockIMC(hIMC);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* NOTE: K stands for Korean. J stands for Japanese. */
|
||||
static DWORD Imm32Get31ModeFrom40ModeK(DWORD fdwConversion)
|
||||
{
|
||||
DWORD flags = 0;
|
||||
if (!(fdwConversion & IME_CMODE_NATIVE))
|
||||
flags |= IME_MODE_ALPHANUMERIC;
|
||||
if (!(fdwConversion & IME_CMODE_FULLSHAPE))
|
||||
flags |= _IME_MODE_KOR_SBCSCHAR;
|
||||
if (fdwConversion & IME_CMODE_HANJACONVERT)
|
||||
flags |= IME_MODE_HANJACONVERT;
|
||||
return flags;
|
||||
}
|
||||
|
||||
static DWORD Imm32Get31ModeFrom40ModeJ(DWORD fdwConversion)
|
||||
{
|
||||
DWORD flags = 0;
|
||||
if (fdwConversion & IME_CMODE_NATIVE)
|
||||
{
|
||||
if ((fdwConversion & IME_CMODE_KATAKANA))
|
||||
flags |= IME_MODE_KATAKANA;
|
||||
else
|
||||
flags |= IME_MODE_HIRAGANA;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags |= IME_MODE_ALPHANUMERIC;
|
||||
}
|
||||
if (fdwConversion & IME_CMODE_FULLSHAPE)
|
||||
flags |= IME_MODE_DBCSCHAR;
|
||||
else
|
||||
flags |= _IME_MODE_JPN_SBCSCHAR;
|
||||
if (fdwConversion & IME_CMODE_ROMAN)
|
||||
flags |= IME_MODE_ROMAN;
|
||||
else
|
||||
flags |= IME_MODE_NOROMAN;
|
||||
if (fdwConversion & IME_CMODE_CHARCODE)
|
||||
flags |= IME_MODE_CODEINPUT;
|
||||
else
|
||||
flags |= IME_MODE_NOCODEINPUT;
|
||||
return flags;
|
||||
}
|
||||
|
||||
static LRESULT Imm32TransGetMode(HIMC hIMC)
|
||||
{
|
||||
DWORD fdwConversion = 0, fdwSentence;
|
||||
ImmGetConversionStatus(hIMC, &fdwConversion, &fdwSentence);
|
||||
return Imm32Get31ModeFrom40ModeK(fdwConversion) | _IME_CMODE_EXTENDED;
|
||||
}
|
||||
|
||||
static DWORD Imm32TransSetMode(HIMC hIMC, PIMESTRUCT pIme)
|
||||
{
|
||||
DWORD fdwConversion = 0, fdwSentence;
|
||||
ImmGetConversionStatus(hIMC, &fdwConversion, &fdwSentence);
|
||||
|
||||
DWORD dw31Mode = Imm32Get31ModeFrom40ModeK(fdwConversion);
|
||||
WPARAM wParam = pIme->wParam;
|
||||
if (!(wParam & _IME_MODE_KOR_SBCSCHAR))
|
||||
fdwConversion |= IME_CMODE_FULLSHAPE;
|
||||
|
||||
DWORD dwNewFlags = fdwConversion;
|
||||
const DWORD targetMask = IME_CMODE_NATIVE | IME_CMODE_KATAKANA | IME_CMODE_FULLSHAPE |
|
||||
IME_CMODE_HANJACONVERT;
|
||||
if (wParam & IME_MODE_ALPHANUMERIC)
|
||||
dwNewFlags &= ~targetMask;
|
||||
else
|
||||
dwNewFlags |= targetMask;
|
||||
|
||||
if (!ImmSetConversionStatus(hIMC, dwNewFlags, fdwSentence))
|
||||
return 0;
|
||||
return dw31Mode;
|
||||
}
|
||||
|
||||
static BOOL Imm32TransCodeConvert(HIMC hIMC, PIMESTRUCT pIme)
|
||||
{
|
||||
HKL hKL = GetKeyboardLayout(0);
|
||||
UINT uSubFunc = HIWORD(pIme->wParam);
|
||||
switch (uSubFunc)
|
||||
{
|
||||
case IME_BANJAtoJUNJA:
|
||||
case IME_JUNJAtoBANJA:
|
||||
case IME_JOHABtoKS:
|
||||
case IME_KStoJOHAB:
|
||||
return (BOOL)ImmEscapeW(hKL, hIMC, uSubFunc, pIme);
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static LRESULT Imm32TransGetOpenK(HWND hWnd, HIMC hIMC, PIMESTRUCT pIme, BOOL bAnsi)
|
||||
{
|
||||
RECT rc;
|
||||
GetWindowRect(hWnd, &rc);
|
||||
LPARAM OldlParam2 = pIme->lParam2;
|
||||
pIme->lParam2 = MAKELONG(rc.top, rc.left); /* Correct! */
|
||||
HKL hKL = GetKeyboardLayout(0);
|
||||
LRESULT result = ImmEscapeW(hKL, hIMC, IME_GETOPEN, pIme);
|
||||
pIme->lParam2 = OldlParam2;
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL Imm32TransGetOpenJ(HWND hWnd, HIMC hIMC, PIMESTRUCT pIme, BOOL bAnsi)
|
||||
{
|
||||
BOOL fOpen = ImmGetOpenStatus(hIMC);
|
||||
|
||||
LONG cbCompStr;
|
||||
if (bAnsi)
|
||||
cbCompStr = ImmGetCompositionStringA(hIMC, GCS_COMPSTR, NULL, 0);
|
||||
else
|
||||
cbCompStr = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0);
|
||||
|
||||
pIme->wCount = (cbCompStr > 0) ? cbCompStr : 0;
|
||||
return fOpen;
|
||||
}
|
||||
|
||||
static LRESULT Imm32TransSetOpenK(HWND hWnd, HIMC hIMC, PIMESTRUCT pIme)
|
||||
{
|
||||
HKL hKL = GetKeyboardLayout(0);
|
||||
return ImmEscapeW(hKL, hIMC, IME_SETOPEN, pIme);
|
||||
}
|
||||
|
||||
static BOOL Imm32TransSetOpenJ(HWND hWnd, HIMC hIMC, PIMESTRUCT pIme)
|
||||
{
|
||||
LRESULT fOldOpen = ImmGetOpenStatus(hIMC);
|
||||
|
||||
if (Imm32IsForegroundThread(NULL) || GetFocus())
|
||||
{
|
||||
ImmSetOpenStatus(hIMC, (BOOL)pIme->wParam);
|
||||
return fOldOpen;
|
||||
}
|
||||
|
||||
PINPUTCONTEXT pIC = ImmLockIMC(hIMC);
|
||||
if (!pIC)
|
||||
return fOldOpen;
|
||||
|
||||
BOOL bRequestOpen = !!pIme->wParam;
|
||||
if (pIC->fOpen != bRequestOpen)
|
||||
{
|
||||
pIC->fOpen = bRequestOpen;
|
||||
ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS);
|
||||
}
|
||||
|
||||
ImmUnlockIMC(hIMC);
|
||||
return fOldOpen;
|
||||
}
|
||||
|
||||
static UINT Imm32TransConvertList(HIMC hIMC, PIMESTRUCT pIme)
|
||||
{
|
||||
/* SECURITY: Check memory block size */
|
||||
const SIZE_T cbIme = GlobalSize(GlobalHandle(pIme));
|
||||
if (pIme->dchDest >= cbIme)
|
||||
return 0;
|
||||
|
||||
/* Get conversion list size */
|
||||
HKL hKL = GetKeyboardLayout(0);
|
||||
const CHAR *pszSource = (const CHAR *)pIme + pIme->dchSource;
|
||||
const UINT uBufLen = ImmGetConversionListA(hKL, hIMC, pszSource, NULL, 0, GCL_CONVERSION);
|
||||
if (!uBufLen)
|
||||
return 0;
|
||||
|
||||
/* Allocate */
|
||||
HGLOBAL hCandList = GlobalAlloc(GHND, uBufLen);
|
||||
if (!hCandList)
|
||||
return 0;
|
||||
|
||||
/* Lock */
|
||||
PCANDIDATELIST pCL = (PCANDIDATELIST)GlobalLock(hCandList);
|
||||
if (!pCL)
|
||||
{
|
||||
GlobalFree(hCandList);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the conversion list */
|
||||
UINT ret = ImmGetConversionListA(hKL, hIMC, pszSource, pCL, uBufLen, GCL_CONVERSION);
|
||||
|
||||
/* Store the conversion list into pIme */
|
||||
UINT wCount = 0;
|
||||
PCHAR pszDest = (PCHAR)pIme + pIme->dchDest;
|
||||
SIZE_T cbDestRemaining = cbIme - pIme->dchDest;
|
||||
for (DWORD i = 0; i < pCL->dwCount && (cbDestRemaining > 2); ++i)
|
||||
{
|
||||
const CHAR *pCandidate = (const CHAR *)pCL + pCL->dwOffset[i];
|
||||
*pszDest++ = pCandidate[0];
|
||||
*pszDest++ = pCandidate[1];
|
||||
|
||||
cbDestRemaining -= 2;
|
||||
wCount += 2;
|
||||
}
|
||||
pIme->wCount = wCount;
|
||||
|
||||
/* Add terminator safely */
|
||||
if (cbDestRemaining > 0)
|
||||
*pszDest = ANSI_NULL;
|
||||
|
||||
/* Clean up */
|
||||
GlobalUnlock(hCandList);
|
||||
GlobalFree(hCandList);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static LRESULT Imm32TransHanjaMode(HWND hWnd, HIMC hIMC, PIMESTRUCT pIme)
|
||||
{
|
||||
DWORD dwThreadId = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID);
|
||||
if (!dwThreadId)
|
||||
return 0;
|
||||
|
||||
HKL hKL = GetKeyboardLayout(dwThreadId);
|
||||
PIMEDPI pImeDpi = ImmLockImeDpi(hKL);
|
||||
if (!pImeDpi)
|
||||
return 0;
|
||||
|
||||
if (ImeDpi_IsUnicode(pImeDpi))
|
||||
{
|
||||
BYTE offset = HIBYTE(HIWORD(pIme->wParam));
|
||||
SIZE_T cbIme = sizeof(*pIme) + (SIZE_T)pIme->wCount;
|
||||
PCHAR pMbcsCh;
|
||||
WORD MbcsCh;
|
||||
|
||||
/* SECURITY: Check boundary */
|
||||
if ((SIZE_T)offset > cbIme || cbIme - (SIZE_T)offset < sizeof(MbcsCh))
|
||||
{
|
||||
ImmUnlockImeDpi(pImeDpi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pMbcsCh = (PCHAR)pIme + offset;
|
||||
RtlCopyMemory(&MbcsCh, pMbcsCh, sizeof(MbcsCh));
|
||||
pIme->wParam = MAKELONG(MbcsCh, HIWORD(pIme->wParam));
|
||||
|
||||
WCHAR wch = UNICODE_NULL;
|
||||
if (!MultiByteToWideChar(CP_ACP, 0, pMbcsCh, 2, &wch, 1))
|
||||
{
|
||||
ImmUnlockImeDpi(pImeDpi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
RtlCopyMemory(pMbcsCh, &wch, sizeof(wch));
|
||||
}
|
||||
|
||||
ImmUnlockImeDpi(pImeDpi);
|
||||
|
||||
hKL = GetKeyboardLayout(0);
|
||||
LRESULT ret = ImmEscapeW(hKL, hIMC, IME_ESC_HANJA_MODE, pIme);
|
||||
if (ret)
|
||||
SendMessageW(hWnd, WM_IME_NOTIFY, IMN_OPENCANDIDATE, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DWORD Imm32TransGetLevel(HWND hWnd)
|
||||
{
|
||||
DWORD result = NtUserGetAppImeLevel(hWnd);
|
||||
return result ? result : IME_RS_ERROR;
|
||||
}
|
||||
|
||||
static BOOL Imm32TransSetLevel(HWND hWnd, PIMESTRUCT pIme)
|
||||
{
|
||||
WPARAM wParam = pIme->wParam;
|
||||
return wParam && wParam <= 5 && NtUserSetAppImeLevel(hWnd, (DWORD)wParam);
|
||||
}
|
||||
|
||||
static BOOL Imm32TransGetMNTable(HIMC hIMC, PIMESTRUCT pIme)
|
||||
{
|
||||
#define INPUT_METHOD_BASE 100
|
||||
static const WORD g_MNTable[3][96] =
|
||||
{
|
||||
/* InputMethod = 100 (Wansung standard) */
|
||||
{
|
||||
0xA1A1, 0xA3A1, 0xA1A8, 0xA3A3, 0xA3A4, 0xA3A5, 0xA3A6, 0xA1AE,
|
||||
0xA3A8, 0xA3A9, 0xA3AA, 0xA3AB, 0xA3A7, 0xA3AD, 0xA3AE, 0xA3AF,
|
||||
0xA3B0, 0xA3B1, 0xA3B2, 0xA3B3, 0xA3B4, 0xA3B5, 0xA3B6, 0xA3B7,
|
||||
0xA3B8, 0xA3B9, 0xA3BA, 0xA3BB, 0xA3BC, 0xA3BD, 0xA3BE, 0xA3BF,
|
||||
0xA3C0, 0xA4B1, 0xA4D0, 0xA4BA, 0xA4B7, 0xA4A8, 0xA4A9, 0xA4BE,
|
||||
0xA4C7, 0xA4C1, 0xA4C3, 0xA4BF, 0xA4D3, 0xA4D1, 0xA4CC, 0xA4C2,
|
||||
0xA4C6, 0xA4B3, 0xA4A2, 0xA4A4, 0xA4B6, 0xA4C5, 0xA4BD, 0xA4B9,
|
||||
0xA4BC, 0xA4CB, 0xA4BB, 0xA3DB, 0xA1AC, 0xA3DD, 0xA3DE, 0xA3DF,
|
||||
0xA1A2, 0xA4B1, 0xA4D0, 0xA4BA, 0xA4B7, 0xA4A7, 0xA4A9, 0xA4BE,
|
||||
0xA4C7, 0xA4C1, 0xA4C3, 0xA4BF, 0xA4D3, 0xA4D1, 0xA4CC, 0xA4C0,
|
||||
0xA4C4, 0xA4B2, 0xA4A1, 0xA4A4, 0xA4B5, 0xA4C5, 0xA4BD, 0xA4B8,
|
||||
0xA4BC, 0xA4CB, 0xA4BB, 0xA3FB, 0xA3FC, 0xA3FD, 0xA1AD, 0x0000
|
||||
},
|
||||
/* InputMethod = 101 (Old Johab compatible) */
|
||||
{
|
||||
0xA1A1, 0xA4B8, 0xA1A8, 0xA3A3, 0xA3A4, 0xA3A5, 0xA3A6, 0xA1AE,
|
||||
0xA3A8, 0xA3A9, 0xA3AA, 0xA3AB, 0xA4BC, 0xA3AD, 0xA3AE, 0xA4C7,
|
||||
0xA4BB, 0xA4BE, 0xA4B6, 0xA4B2, 0xA4CB, 0xA4D0, 0xA4C1, 0xA4C6,
|
||||
0xA4D2, 0xA4CC, 0xA3BA, 0xA4B2, 0xA3B2, 0xA3BD, 0xA3B3, 0xA3BF,
|
||||
0xA3C0, 0xA4A7, 0xA3A1, 0xA4AB, 0xA4AA, 0xA4BB, 0xA4A2, 0xA3AF,
|
||||
0xA1AF, 0xA3B8, 0xA3B4, 0xA3B5, 0xA3B6, 0xA3B1, 0xA3B0, 0xA3B9,
|
||||
0xA3BE, 0xA4BD, 0xA4C2, 0xA4A6, 0xA4C3, 0xA3B7, 0xA4B0, 0xA4BC,
|
||||
0xA4B4, 0xA3BC, 0xA4BA, 0xA3DB, 0xA3DC, 0xA3DD, 0xA3DE, 0xA3DF,
|
||||
0xA1AE, 0xA4B7, 0xA4CC, 0xA4C4, 0xA4D3, 0xA4C5, 0xA4BF, 0xA4D1,
|
||||
0xA4A4, 0xA4B1, 0xA4B7, 0xA4A1, 0xA4B8, 0xA4BE, 0xA4B5, 0xA4BA,
|
||||
0xA4BD, 0xA4B5, 0xA4C0, 0xA4A4, 0xA4C3, 0xA4A7, 0xA4C7, 0xA4A9,
|
||||
0xA4A1, 0xA4A9, 0xA4B1, 0xA3FB, 0xA3FC, 0xA3FD, 0xA1AD, 0x0000
|
||||
},
|
||||
/* InputMethod = 102 (Extended array) */
|
||||
{
|
||||
0xA1A1, 0xA4A2, 0xA3AE, 0xA4B8, 0xA4AF, 0xA4AE, 0xA1B0, 0xA3AA,
|
||||
0xA1A2, 0xA1AD, 0xA1B1, 0xA3AB, 0xA4BC, 0xA3A9, 0xA3AE, 0xA4C7,
|
||||
0xA4BB, 0xA4BE, 0xA4B6, 0xA4B2, 0xA4CB, 0xA4D0, 0xA4C1, 0xA4C6,
|
||||
0xA4D2, 0xA4CC, 0xA3B4, 0xA4B2, 0xA3A7, 0xA1B5, 0xA3AE, 0xA3A1,
|
||||
0xA4AA, 0xA4A7, 0xA3BF, 0xA4BC, 0xA4AC, 0xA4A5, 0xA4AB, 0xA4C2,
|
||||
0xA3B0, 0xA3B7, 0xA3B1, 0xA3B2, 0xA3B3, 0xA1A8, 0xA3AD, 0xA3B8,
|
||||
0xA3B9, 0xA4BD, 0xA4B0, 0xA4A6, 0xA4AD, 0xA3B6, 0xA4A3, 0xA4BC,
|
||||
0xA4B4, 0xA3B5, 0xA4BA, 0xA3A8, 0xA3BA, 0xA1B4, 0xA3BD, 0xA3BB,
|
||||
0xA3AA, 0xA4B7, 0xA4CC, 0xA4C4, 0xA4D3, 0xA4C5, 0xA4BF, 0xA4D1,
|
||||
0xA4A4, 0xA4B1, 0xA4B7, 0xA4A1, 0xA4B8, 0xA4BE, 0xA4B5, 0xA4BA,
|
||||
0xA4BD, 0xA4B5, 0xA4C0, 0xA4A4, 0xA4C3, 0xA4A7, 0xA4C7, 0xA4A9,
|
||||
0xA4A1, 0xA4B1, 0xA4B1, 0xA3A5, 0xA3CC, 0xA3AF, 0xA1AD, 0x0000
|
||||
}
|
||||
};
|
||||
|
||||
UINT nInputMethod = GetProfileIntW(L"WANSUNG", L"InputMethod", INPUT_METHOD_BASE);
|
||||
UINT index = nInputMethod - INPUT_METHOD_BASE;
|
||||
if (index >= _countof(g_MNTable))
|
||||
index = 0;
|
||||
|
||||
PWORD pDst = (PWORD)pIme->lParam1;
|
||||
RtlCopyMemory(pDst, g_MNTable[index], sizeof(g_MNTable[0]));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static LRESULT Imm32TransMoveImeWindow(HWND hWnd, HIMC hIMC, PIMESTRUCT pIme)
|
||||
{
|
||||
if (pIme->wParam == 2)
|
||||
{
|
||||
POINT pt = { (SHORT)LOWORD(pIme->lParam1), (SHORT)HIWORD(pIme->lParam1) };
|
||||
ClientToScreen(hWnd, &pt);
|
||||
pIme->lParam1 = MAKELONG(pt.x, pt.y);
|
||||
}
|
||||
HKL hKL = GetKeyboardLayout(0);
|
||||
return ImmEscapeW(hKL, hIMC, IME_SETCONVERSIONWINDOW, pIme);
|
||||
}
|
||||
|
||||
static BOOL Imm32SetCompFont(HWND hWnd, HIMC hIMC, PLOGFONTW plfW)
|
||||
{
|
||||
PINPUTCONTEXT pIMC = ImmLockIMC(hIMC);
|
||||
if (!pIMC)
|
||||
return FALSE;
|
||||
|
||||
DWORD dwCompatFlags = ImmGetAppCompatFlags(hIMC);
|
||||
PCLIENTIMC pClientImc = ImmLockClientImc(hIMC);
|
||||
if (!pClientImc)
|
||||
{
|
||||
ImmUnlockIMC(hIMC);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL bIsUnicode = (pClientImc->dwFlags & CLIENTIMC_WIDE);
|
||||
ImmUnlockClientImc(pClientImc);
|
||||
|
||||
const LOGFONTW* pCurrentFontW;
|
||||
LOGFONTW currentLF;
|
||||
if (bIsUnicode)
|
||||
{
|
||||
pCurrentFontW = &pIMC->lfFont.W;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFontAnsiToWide(&pIMC->lfFont.A, ¤tLF);
|
||||
pCurrentFontW = ¤tLF;
|
||||
}
|
||||
|
||||
BOOL ret;
|
||||
if (memcmp(pCurrentFontW, plfW, offsetof(LOGFONTW, lfFaceName)) != 0 ||
|
||||
lstrcmpW(pCurrentFontW->lfFaceName, plfW->lfFaceName) != 0)
|
||||
{
|
||||
if (dwCompatFlags & _IME_APP_COMPAT_DIRECT_IME_SYSTEM)
|
||||
{
|
||||
pIMC->lfFont.W = *plfW;
|
||||
|
||||
if (dwCompatFlags & _IME_APP_COMPAT_DIRECT_IME_FONT)
|
||||
ret = Imm32PostImsMessage(hWnd, IMC_SETCOMPOSITIONFONT, 0);
|
||||
else
|
||||
ret = PostMessageW(hWnd, WM_IME_SYSTEM, IMC_SETCOMPOSITIONFONT, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ImmSetCompositionFontW(hIMC, plfW);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
ImmUnlockIMC(hIMC);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL Imm32FixLogFont(PLOGFONTW plfW, BOOL bVertical)
|
||||
{
|
||||
if (!plfW)
|
||||
return FALSE;
|
||||
|
||||
/* SECURITY: Avoid buffer overrun */
|
||||
plfW->lfFaceName[_countof(plfW->lfFaceName) - 1] = UNICODE_NULL;
|
||||
|
||||
if (bVertical)
|
||||
{
|
||||
plfW->lfEscapement = plfW->lfOrientation = 2700;
|
||||
|
||||
if (plfW->lfCharSet == SHIFTJIS_CHARSET && plfW->lfFaceName[0] != L'@')
|
||||
{
|
||||
size_t len = wcslen(plfW->lfFaceName);
|
||||
if (len >= (_countof(plfW->lfFaceName) - 1))
|
||||
return FALSE;
|
||||
|
||||
RtlMoveMemory(&plfW->lfFaceName[1], &plfW->lfFaceName[0], (len + 1) * sizeof(WCHAR));
|
||||
plfW->lfFaceName[0] = L'@';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
plfW->lfEscapement = plfW->lfOrientation = 0;
|
||||
|
||||
if (plfW->lfCharSet == SHIFTJIS_CHARSET && plfW->lfFaceName[0] == L'@')
|
||||
{
|
||||
size_t len = wcslen(plfW->lfFaceName);
|
||||
RtlMoveMemory(&plfW->lfFaceName[0], &plfW->lfFaceName[1], len * sizeof(WCHAR));
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
Imm32SetFontForVertical(HWND hWnd, HIMC hIMC, PINPUTCONTEXTDX pIC, BOOL bVertical)
|
||||
{
|
||||
LOGFONTW lfW;
|
||||
if (pIC->fdwInit & INIT_LOGFONT)
|
||||
{
|
||||
PCLIENTIMC pClientImc = ImmLockClientImc(hIMC);
|
||||
if (!pClientImc)
|
||||
return FALSE;
|
||||
BOOL bWide = !!(pClientImc->dwFlags & CLIENTIMC_WIDE);
|
||||
ImmUnlockClientImc(pClientImc);
|
||||
|
||||
if (bWide)
|
||||
lfW = pIC->lfFont.W;
|
||||
else
|
||||
LogFontAnsiToWide(&pIC->lfFont.A, &lfW);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetObjectW(GetStockObject(SYSTEM_FONT), sizeof(lfW), &lfW);
|
||||
}
|
||||
|
||||
if (!Imm32FixLogFont(&lfW, bVertical))
|
||||
return FALSE;
|
||||
|
||||
return Imm32SetCompFont(hWnd, hIMC, &lfW);
|
||||
}
|
||||
|
||||
static BOOL Imm32TransSetConversionWindow(HWND hWnd, HIMC hIMC, PIMESTRUCT pIme)
|
||||
{
|
||||
if (!Imm32IsForegroundThread(NULL) && !GetFocus())
|
||||
return TRUE; /* Ignore as success */
|
||||
|
||||
PINPUTCONTEXTDX pIC = (PINPUTCONTEXTDX)ImmLockIMC(hIMC);
|
||||
if (!pIC)
|
||||
return FALSE;
|
||||
|
||||
COMPOSITIONFORM cfComp;
|
||||
cfComp.dwStyle = 0;
|
||||
|
||||
POINT pt = { (SHORT)LOWORD(pIme->lParam1), (SHORT)HIWORD(pIme->lParam1) };
|
||||
RECT rcArea = { (SHORT)LOWORD(pIme->lParam2), (SHORT)HIWORD(pIme->lParam2),
|
||||
(SHORT)LOWORD(pIme->lParam3), (SHORT)HIWORD(pIme->lParam3) };
|
||||
|
||||
WPARAM wParam = pIme->wParam;
|
||||
HWND hwndIC = pIC->hWnd;
|
||||
|
||||
if (wParam & MCW_HIDDEN)
|
||||
{
|
||||
pIC->dwUIFlags |= _IME_UI_HIDDEN;
|
||||
ScreenToClient(hwndIC, &pt);
|
||||
MapWindowPoints(NULL, hwndIC, (PPOINT)&rcArea, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
pIC->dwUIFlags &= ~_IME_UI_HIDDEN;
|
||||
}
|
||||
|
||||
if (wParam & MCW_WINDOW)
|
||||
{
|
||||
BOOL bUseCrossWindowLogic = TRUE;
|
||||
|
||||
if (LOWORD(hWnd) == LOWORD(hwndIC))
|
||||
{
|
||||
PVOID pWndEntry = (hWnd && gpsi) ? ValidateHwnd(hWnd) : NULL;
|
||||
PVOID pWndICEntry = (hwndIC && gpsi) ? ValidateHwnd(hwndIC) : NULL;
|
||||
|
||||
if (pWndEntry == pWndICEntry)
|
||||
bUseCrossWindowLogic = FALSE;
|
||||
}
|
||||
|
||||
if (bUseCrossWindowLogic)
|
||||
{
|
||||
ClientToScreen(hWnd, &pt);
|
||||
ScreenToClient(hwndIC, &pt);
|
||||
|
||||
if (wParam & MCW_RECT)
|
||||
{
|
||||
cfComp.dwStyle = CFS_RECT;
|
||||
MapWindowPoints(hWnd, NULL, (PPOINT)&rcArea, 2);
|
||||
MapWindowPoints(NULL, hwndIC, (PPOINT)&rcArea, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
cfComp.dwStyle = CFS_POINT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wParam & MCW_SCREEN)
|
||||
{
|
||||
ScreenToClient(hwndIC, &pt);
|
||||
cfComp.dwStyle = (wParam & MCW_RECT) ? CFS_RECT : CFS_POINT;
|
||||
if (wParam & MCW_RECT)
|
||||
{
|
||||
MapWindowPoints(NULL, hwndIC, (PPOINT)&rcArea, 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cfComp.dwStyle = (wParam & MCW_RECT) ? CFS_RECT : CFS_POINT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wParam & MCW_VERTICAL)
|
||||
{
|
||||
if (!(pIC->dwUIFlags & _IME_UI_VERTICAL))
|
||||
{
|
||||
pIC->dwUIFlags |= _IME_UI_VERTICAL;
|
||||
Imm32SetFontForVertical(hWnd, hIMC, pIC, TRUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pIC->dwUIFlags & _IME_UI_VERTICAL)
|
||||
{
|
||||
pIC->dwUIFlags &= ~_IME_UI_VERTICAL;
|
||||
Imm32SetFontForVertical(hWnd, hIMC, pIC, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
cfComp.ptCurrentPos = pt;
|
||||
cfComp.rcArea = rcArea;
|
||||
|
||||
if (pIC->dwUIFlags & _IME_UI_HIDDEN)
|
||||
{
|
||||
pIC->cfCompForm.ptCurrentPos = pt;
|
||||
pIC->cfCompForm.rcArea = rcArea;
|
||||
|
||||
for (DWORD i = 0; i < MAX_CANDIDATEFORM; i++)
|
||||
{
|
||||
PCANDIDATEFORM pCF = &pIC->cfCandForm[i];
|
||||
if (pCF->dwIndex == (DWORD)-1)
|
||||
continue;
|
||||
|
||||
CANDIDATEFORM cf;
|
||||
cf.dwIndex = i;
|
||||
cf.dwStyle = CFS_EXCLUDE;
|
||||
cf.ptCurrentPos = pt;
|
||||
cf.rcArea = rcArea;
|
||||
Imm32SetCandidateWindow(hWnd, hIMC, &cf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Imm32SetCompWindow(hWnd, hIMC, &cfComp);
|
||||
}
|
||||
|
||||
ImmUnlockIMC(hIMC);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static DWORD Imm32TransGetConversionMode(HIMC hIMC)
|
||||
{
|
||||
DWORD fdwConversion = 0, fdwSentence;
|
||||
ImmGetConversionStatus(hIMC, &fdwConversion, &fdwSentence);
|
||||
return Imm32Get31ModeFrom40ModeJ(fdwConversion);
|
||||
}
|
||||
|
||||
static BOOL Imm32TransVKDBEMode(HIMC hIMC, UINT vKey)
|
||||
{
|
||||
DWORD fdwConversion, fdwSentence;
|
||||
BOOL ret = ImmGetConversionStatus(hIMC, &fdwConversion, &fdwSentence);
|
||||
if (!ret)
|
||||
return FALSE;
|
||||
|
||||
switch (vKey)
|
||||
{
|
||||
case VK_DBE_ALPHANUMERIC:
|
||||
fdwConversion &= ~IME_CMODE_LANGUAGE;
|
||||
break;
|
||||
case VK_DBE_KATAKANA:
|
||||
fdwConversion |= IME_CMODE_LANGUAGE;
|
||||
break;
|
||||
case VK_DBE_HIRAGANA:
|
||||
fdwConversion = (fdwConversion & ~IME_CMODE_LANGUAGE) | IME_CMODE_NATIVE;
|
||||
break;
|
||||
case VK_DBE_SBCSCHAR:
|
||||
fdwConversion &= ~IME_CMODE_FULLSHAPE;
|
||||
break;
|
||||
case VK_DBE_DBCSCHAR:
|
||||
fdwConversion |= IME_CMODE_FULLSHAPE;
|
||||
break;
|
||||
case VK_DBE_ROMAN:
|
||||
fdwConversion |= IME_CMODE_ROMAN;
|
||||
break;
|
||||
case VK_DBE_NOROMAN:
|
||||
fdwConversion &= ~IME_CMODE_ROMAN;
|
||||
break;
|
||||
case VK_DBE_CODEINPUT:
|
||||
fdwConversion |= IME_CMODE_CHARCODE;
|
||||
break;
|
||||
case VK_DBE_NOCODEINPUT:
|
||||
fdwConversion &= ~IME_CMODE_CHARCODE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ImmSetConversionStatus(hIMC, fdwConversion, fdwSentence);
|
||||
}
|
||||
|
||||
static BOOL Imm32TransSendVKey(HWND hWnd, HIMC hIMC, PIMESTRUCT pIme, BOOL bAnsi)
|
||||
{
|
||||
WPARAM wParam = pIme->wParam;
|
||||
|
||||
if (wParam >= VK_DBE_DETERMINESTRING)
|
||||
{
|
||||
if (wParam == VK_DBE_DETERMINESTRING)
|
||||
{
|
||||
HIMC hContext = ImmGetContext(hWnd);
|
||||
BOOL ret = (BOOL)ImmNotifyIME(hContext, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
|
||||
ImmReleaseContext(hWnd, hContext);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (wParam > VK_DBE_ENTERDLGCONVERSIONMODE && (wParam == 0xFFFF || (LONG)wParam == -1))
|
||||
{
|
||||
UINT wCount = pIme->wCount;
|
||||
if (wCount == 28 || (240 <= wCount && wCount <= 253))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (wParam >= VK_DBE_CODEINPUT)
|
||||
return Imm32TransVKDBEMode(hIMC, (UINT)wParam);
|
||||
|
||||
if (wParam == VK_CONVERT)
|
||||
return ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CONVERT, 0);
|
||||
|
||||
if (wParam < VK_DBE_ALPHANUMERIC)
|
||||
return FALSE;
|
||||
|
||||
if (wParam <= VK_DBE_NOROMAN)
|
||||
return Imm32TransVKDBEMode(hIMC, (UINT)wParam);
|
||||
|
||||
HKL hKL;
|
||||
UINT nImeConfig;
|
||||
if (wParam == VK_DBE_ENTERWORDREGISTERMODE)
|
||||
{
|
||||
hKL = GetKeyboardLayout(0);
|
||||
nImeConfig = IME_CONFIG_REGISTERWORD;
|
||||
}
|
||||
else if (wParam == VK_DBE_ENTERIMECONFIGMODE)
|
||||
{
|
||||
hKL = GetKeyboardLayout(0);
|
||||
nImeConfig = IME_CONFIG_GENERAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
|
||||
}
|
||||
|
||||
if (bAnsi)
|
||||
return ImmConfigureIMEA(hKL, hWnd, nImeConfig, NULL);
|
||||
return ImmConfigureIMEW(hKL, hWnd, nImeConfig, NULL);
|
||||
}
|
||||
|
||||
static DWORD Imm32TransSetConversionMode(HIMC hIMC, PIMESTRUCT pIme)
|
||||
{
|
||||
DWORD fdwOldConversion = 0, fdwSentence;
|
||||
if (!ImmGetConversionStatus(hIMC, &fdwOldConversion, &fdwSentence))
|
||||
return 0;
|
||||
|
||||
const DWORD mode31 = Imm32Get31ModeFrom40ModeJ(fdwOldConversion);
|
||||
const WPARAM wParam = pIme->wParam;
|
||||
DWORD dwNewValues = 0, dwMask = 0;
|
||||
|
||||
const DWORD langFlags = (IME_MODE_ALPHANUMERIC | IME_MODE_KATAKANA | IME_MODE_HIRAGANA);
|
||||
if (wParam & langFlags)
|
||||
{
|
||||
dwMask |= IME_CMODE_LANGUAGE;
|
||||
if (wParam & IME_MODE_KATAKANA)
|
||||
dwNewValues |= IME_CMODE_LANGUAGE;
|
||||
else if (wParam & IME_MODE_HIRAGANA)
|
||||
dwNewValues |= IME_CMODE_NATIVE;
|
||||
else
|
||||
dwNewValues |= IME_CMODE_ALPHANUMERIC;
|
||||
}
|
||||
|
||||
if (wParam & (IME_MODE_DBCSCHAR | _IME_MODE_JPN_SBCSCHAR))
|
||||
{
|
||||
dwMask |= IME_CMODE_FULLSHAPE;
|
||||
if (!(wParam & _IME_MODE_JPN_SBCSCHAR))
|
||||
dwNewValues |= IME_CMODE_FULLSHAPE;
|
||||
}
|
||||
|
||||
if (wParam & (IME_MODE_ROMAN | IME_MODE_NOROMAN))
|
||||
{
|
||||
dwMask |= IME_CMODE_ROMAN;
|
||||
if (wParam & IME_MODE_ROMAN)
|
||||
dwNewValues |= IME_CMODE_ROMAN;
|
||||
}
|
||||
|
||||
if (wParam & (IME_MODE_CODEINPUT | IME_MODE_NOCODEINPUT))
|
||||
{
|
||||
dwMask |= IME_CMODE_CHARCODE;
|
||||
if (wParam & IME_MODE_CODEINPUT)
|
||||
dwNewValues |= IME_CMODE_CHARCODE;
|
||||
}
|
||||
|
||||
DWORD fdwNewConversion = (fdwOldConversion & ~dwMask) | (dwNewValues & dwMask);
|
||||
|
||||
if (!ImmSetConversionStatus(hIMC, fdwNewConversion, fdwSentence))
|
||||
return 0;
|
||||
|
||||
return mode31;
|
||||
}
|
||||
|
||||
static BOOL Imm32TransEnterWordRegisterMode(HWND hWnd, PIMESTRUCT pIme, BOOL bAnsi)
|
||||
{
|
||||
HKL hKL = GetKeyboardLayout(0);
|
||||
if (!ImmIsIME(hKL))
|
||||
return FALSE;
|
||||
|
||||
HGLOBAL hReading = (HGLOBAL)pIme->lParam1, hWord = (HGLOBAL)pIme->lParam2;
|
||||
REGISTERWORDW rwInfo = { NULL };
|
||||
if (hReading)
|
||||
rwInfo.lpReading = GlobalLock(hReading);
|
||||
if (hWord)
|
||||
rwInfo.lpWord = GlobalLock(hWord);
|
||||
|
||||
BOOL ret;
|
||||
if (bAnsi)
|
||||
ret = ImmConfigureIMEA(hKL, hWnd, IME_CONFIG_REGISTERWORD, (PREGISTERWORDA)&rwInfo);
|
||||
else
|
||||
ret = ImmConfigureIMEW(hKL, hWnd, IME_CONFIG_REGISTERWORD, &rwInfo);
|
||||
|
||||
if (rwInfo.lpReading)
|
||||
GlobalUnlock(hReading);
|
||||
if (rwInfo.lpWord)
|
||||
GlobalUnlock(hWord);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL Imm32TransSetConversionFontEx(HWND hWnd, HIMC hIMC, PIMESTRUCT pIme, BOOL bAnsi)
|
||||
{
|
||||
PINPUTCONTEXTDX pIC = (PINPUTCONTEXTDX)ImmLockIMC(hIMC);
|
||||
if (!pIC)
|
||||
return FALSE;
|
||||
|
||||
PVOID pLogFont = GlobalLock((HGLOBAL)pIme->lParam1);
|
||||
if (!pLogFont)
|
||||
{
|
||||
ImmUnlockIMC(hIMC);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LOGFONTW lfW;
|
||||
if (bAnsi)
|
||||
LogFontAnsiToWide(pLogFont, &lfW);
|
||||
else
|
||||
RtlCopyMemory(&lfW, pLogFont, sizeof(LOGFONTW));
|
||||
|
||||
GlobalUnlock((HGLOBAL)pIme->lParam1);
|
||||
|
||||
BOOL bFixed = Imm32FixLogFont(&lfW, !!(pIC->dwUIFlags & _IME_UI_VERTICAL));
|
||||
ImmUnlockIMC(hIMC);
|
||||
|
||||
if (!bFixed)
|
||||
return FALSE;
|
||||
return Imm32SetCompFont(hWnd, hIMC, &lfW);
|
||||
}
|
||||
|
||||
static LRESULT Imm32TranslateIMESubFunctions(HWND hWnd, PIMESTRUCT pIme, BOOL bAnsi)
|
||||
{
|
||||
HIMC hImc = ImmGetSaveContext(hWnd, 1);
|
||||
if (!hImc)
|
||||
return 0;
|
||||
|
||||
const WORD wLang = PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID()));
|
||||
const BOOL bKorean = (wLang == LANG_KOREAN), bJapanese = (wLang == LANG_JAPANESE);
|
||||
const UINT fnc = pIme->fnc;
|
||||
switch (fnc)
|
||||
{
|
||||
case 3:
|
||||
return 1;
|
||||
case 4:
|
||||
if (bKorean)
|
||||
return Imm32TransSetOpenK(hWnd, hImc, pIme);
|
||||
return Imm32TransSetOpenJ(hWnd, hImc, pIme);
|
||||
case 5:
|
||||
if (bKorean)
|
||||
return Imm32TransGetOpenK(hWnd, hImc, pIme, bAnsi);
|
||||
return Imm32TransGetOpenJ(hWnd, hImc, pIme, bAnsi);
|
||||
case 6:
|
||||
return 0;
|
||||
case 7:
|
||||
return 0xA03;
|
||||
case 8:
|
||||
if (bKorean)
|
||||
return Imm32TransMoveImeWindow(hWnd, hImc, pIme);
|
||||
return Imm32TransSetConversionWindow(hWnd, hImc, pIme);
|
||||
case 16:
|
||||
if (bJapanese)
|
||||
return Imm32TransSetConversionMode(hImc, pIme);
|
||||
break;
|
||||
case 17:
|
||||
if (bKorean)
|
||||
return Imm32TransGetMode(hImc);
|
||||
if (bJapanese)
|
||||
return Imm32TransGetConversionMode(hImc);
|
||||
break;
|
||||
case 18:
|
||||
if (bKorean)
|
||||
return Imm32TransSetMode(hImc, pIme);
|
||||
break;
|
||||
case 19:
|
||||
if (bJapanese)
|
||||
return Imm32TransSendVKey(hWnd, hImc, pIme, bAnsi);
|
||||
break;
|
||||
case 24:
|
||||
if (bJapanese)
|
||||
return Imm32TransEnterWordRegisterMode(hWnd, pIme, bAnsi);
|
||||
break;
|
||||
case 25:
|
||||
if (bJapanese)
|
||||
return Imm32TransSetConversionFontEx(hWnd, hImc, pIme, bAnsi);
|
||||
break;
|
||||
case 32:
|
||||
if (bKorean)
|
||||
return Imm32TransCodeConvert(hImc, pIme) ? pIme->wParam : 0;
|
||||
break;
|
||||
case 34:
|
||||
if (bKorean)
|
||||
return Imm32TransConvertList(hImc, pIme);
|
||||
break;
|
||||
case 48:
|
||||
if (bKorean)
|
||||
return ImmEscapeW(GetKeyboardLayout(0), hImc, 0x30, pIme);
|
||||
break;
|
||||
case 49:
|
||||
if (bKorean)
|
||||
return Imm32TransHanjaMode(hWnd, hImc, pIme);
|
||||
break;
|
||||
case 64:
|
||||
if (bKorean)
|
||||
return Imm32TransGetLevel(hWnd);
|
||||
break;
|
||||
case 65:
|
||||
if (bKorean)
|
||||
return Imm32TransSetLevel(hWnd, pIme);
|
||||
break;
|
||||
case 66:
|
||||
if (bKorean)
|
||||
return Imm32TransGetMNTable(hImc, pIme);
|
||||
break;
|
||||
default:
|
||||
ERR("Unknown fnc %d\n", fnc);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
#include <win32k.h>
|
||||
#include <wine/ime.h>
|
||||
#include <ime.h>
|
||||
#include <cjkcode.h>
|
||||
|
||||
DBG_DEFAULT_CHANNEL(UserMisc);
|
||||
@@ -1117,6 +1117,20 @@ Quit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* https://learn.microsoft.com/en-us/windows/win32/api/ime/ns-ime-imestruct IME_SETLEVEL
|
||||
*
|
||||
* "Application IME Level" is a Korean-IME-specific concept, defined as below:
|
||||
*
|
||||
* Level | Meaning
|
||||
* ------+---------------------------------------------------------------------------------
|
||||
* 1 | No IME support. All IME-specific messages are ignored.
|
||||
* 2 | Partial IME support. Supports a subset of IME behavior including the position of
|
||||
* | the composition or candidate windows and the input mode or status.
|
||||
* 3 | Full IME support.
|
||||
* 4 | (Unknown)
|
||||
* 5 | (Unknown)
|
||||
*/
|
||||
BOOL
|
||||
NTAPI
|
||||
NtUserSetAppImeLevel(
|
||||
|
||||
Reference in New Issue
Block a user