[USER32][IMM32][SDK] Support WM_IME_SYSTEM.0x1D (#8088)

Splitted from #8080. The message
handling of WM_IME_SYSTEM.0x1D
is needed for IME menu handling.
JIRA issue: CORE-20142
- Define IMS_IMEMENUITEMSELECTED
  (0x1D) in <immdev.h>.
- Add WM_IME_SYSTEM.0x1D handling
  in ImeWnd_OnImeSystem function.
- Rename and extend
  User32GetImmFileName function as
  User32GetSystemFilePath, with
  adding a filename parameter.
This commit is contained in:
Katayama Hirofumi MZ 2025-06-07 06:51:46 +09:00 committed by GitHub
parent 5b4d1dbd4b
commit 2335229c32
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 83 additions and 45 deletions

View file

@ -110,6 +110,7 @@ typedef struct tagGUIDELINE {
#define IMS_IMEDEACTIVATE 0x18 #define IMS_IMEDEACTIVATE 0x18
#define IMS_ACTIVATELAYOUT 0x19 #define IMS_ACTIVATELAYOUT 0x19
#define IMS_GETIMEMENU 0x1C #define IMS_GETIMEMENU 0x1C
#define IMS_IMEMENUITEMSELECTED 0x1D
#define IMS_GETCONTEXT 0x1E #define IMS_GETCONTEXT 0x1E
#define IMS_SENDNOTIFICATION 0x1F #define IMS_SENDNOTIFICATION 0x1F
#define IMS_COMPLETECOMPSTR 0x20 #define IMS_COMPLETECOMPSTR 0x20

View file

@ -610,12 +610,15 @@ ImmGetImeMenuItemsAW(
/* Get IME menu items from the IME */ /* Get IME menu items from the IME */
ret = pImeDpi->ImeGetImeMenuItems(hIMC, dwFlags, dwType, pNewParent, pNewItems, dwSize); ret = pImeDpi->ImeGetImeMenuItems(hIMC, dwFlags, dwType, pNewParent, pNewItems, dwSize);
if (!ret || !lpImeMenuItems) if (!ret)
{ {
ERR("%d, %p\n", ret, lpImeMenuItems); ERR("ImeGetImeMenuItems failed\n");
goto Quit; goto Quit;
} }
if (!lpImeMenuItems)
goto Quit;
if (bImcIsAnsi != bTargetIsAnsi) /* Are text types different? */ if (bImcIsAnsi != bTargetIsAnsi) /* Are text types different? */
{ {
if (bTargetIsAnsi) if (bTargetIsAnsi)

View file

@ -128,7 +128,7 @@ VOID DeleteFrameBrushes(VOID);
BOOL WINAPI GdiValidateHandle(HGDIOBJ); BOOL WINAPI GdiValidateHandle(HGDIOBJ);
HANDLE FASTCALL UserGetProp(HWND hWnd, ATOM Atom, BOOLEAN SystemProp); HANDLE FASTCALL UserGetProp(HWND hWnd, ATOM Atom, BOOLEAN SystemProp);
BOOL WINAPI InitializeImmEntryTable(VOID); BOOL WINAPI InitializeImmEntryTable(VOID);
HRESULT User32GetImmFileName(_Out_ LPWSTR lpBuffer, _In_ size_t cchBuffer); HRESULT User32GetSystemFilePath(_Out_writes_(cchBuffer) PWSTR lpBuffer, _In_ SIZE_T cchBuffer, _In_ PCWSTR pszFileName);
BOOL WINAPI UpdatePerUserImmEnabling(VOID); BOOL WINAPI UpdatePerUserImmEnabling(VOID);
VOID APIENTRY CliImmInitializeHotKeys(DWORD dwAction, HKL hKL); VOID APIENTRY CliImmInitializeHotKeys(DWORD dwAction, HKL hKL);
VOID IntLoadPreloadKeyboardLayouts(VOID); VOID IntLoadPreloadKeyboardLayouts(VOID);

View file

@ -537,7 +537,7 @@ DllMain(
{ {
WCHAR szImmFile[MAX_PATH]; WCHAR szImmFile[MAX_PATH];
InitializeImmEntryTable(); InitializeImmEntryTable();
User32GetImmFileName(szImmFile, _countof(szImmFile)); User32GetSystemFilePath(szImmFile, _countof(szImmFile), L"imm32.dll");
hImm32 = GetModuleHandleW(szImmFile); hImm32 = GetModuleHandleW(szImmFile);
} }

View file

@ -1,10 +1,9 @@
/* /*
* COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS user32.dll
* PROJECT: ReactOS user32.dll * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* FILE: win32ss/user/user32/misc/imm.c * PURPOSE: User32.dll Imm functions
* PURPOSE: User32.dll Imm functions * COPYRIGHT: Copyright Dmitry Chapyshev (dmitry@reactos.org)
* PROGRAMMERS: Dmitry Chapyshev (dmitry@reactos.org) * Copyright Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
* Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
*/ */
#include <user32.h> #include <user32.h>
@ -17,11 +16,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(user32);
#define MAX_CANDIDATEFORM 4 #define MAX_CANDIDATEFORM 4
/* Is != NULL when we have loaded the IMM ourselves */ /* Is != NULL when we have loaded the IMM ourselves */
HINSTANCE ghImm32 = NULL; // Win: ghImm32 HINSTANCE ghImm32 = NULL;
BOOL gbImmInitializing = FALSE; // Win: bImmInitializing BOOL gbImmInitializing = FALSE;
INT gfConIme = -1; // Win: gfConIme INT gfConIme = -1;
HWND FASTCALL IntGetTopLevelWindow(HWND hWnd) HWND FASTCALL IntGetTopLevelWindow(HWND hWnd)
{ {
@ -43,7 +42,6 @@ HWND FASTCALL IntGetTopLevelWindow(HWND hWnd)
static type WINAPI IMMSTUB_##name params { IMM_RETURN_##retkind((type)retval); } static type WINAPI IMMSTUB_##name params { IMM_RETURN_##retkind((type)retval); }
#include "immtable.h" #include "immtable.h"
// Win: gImmApiEntries
Imm32ApiTable gImmApiEntries = { Imm32ApiTable gImmApiEntries = {
/* initialize by stubs */ /* initialize by stubs */
#undef DEFINE_IMM_ENTRY #undef DEFINE_IMM_ENTRY
@ -52,21 +50,25 @@ Imm32ApiTable gImmApiEntries = {
#include "immtable.h" #include "immtable.h"
}; };
// Win: GetImmFileName
HRESULT HRESULT
User32GetImmFileName(_Out_ LPWSTR lpBuffer, _In_ size_t cchBuffer) User32GetSystemFilePath(
_Out_writes_(cchBuffer) PWSTR lpBuffer,
_In_ SIZE_T cchBuffer,
_In_ PCWSTR pszFileName)
{ {
UINT length = GetSystemDirectoryW(lpBuffer, cchBuffer); UINT length = GetSystemDirectoryW(lpBuffer, cchBuffer);
if (length && length < cchBuffer) if (length && length < cchBuffer)
{ {
StringCchCatW(lpBuffer, cchBuffer, L"\\"); StringCchCatW(lpBuffer, cchBuffer, L"\\");
return StringCchCatW(lpBuffer, cchBuffer, L"imm32.dll"); return StringCchCatW(lpBuffer, cchBuffer, pszFileName);
} }
return StringCchCopyW(lpBuffer, cchBuffer, L"imm32.dll"); DWORD dwError = GetLastError();
ERR("GetSystemDirectoryW failed (error %lu)\n", dwError);
StringCchCopyW(lpBuffer, cchBuffer, pszFileName);
return HRESULT_FROM_WIN32(dwError);
} }
// @unimplemented // @unimplemented
// Win: _InitializeImmEntryTable
static BOOL IntInitializeImmEntryTable(VOID) static BOOL IntInitializeImmEntryTable(VOID)
{ {
WCHAR ImmFile[MAX_PATH]; WCHAR ImmFile[MAX_PATH];
@ -76,8 +78,8 @@ static BOOL IntInitializeImmEntryTable(VOID)
if (IMM_FN(ImmWINNLSEnableIME) != IMMSTUB_ImmWINNLSEnableIME) if (IMM_FN(ImmWINNLSEnableIME) != IMMSTUB_ImmWINNLSEnableIME)
return TRUE; return TRUE;
User32GetImmFileName(ImmFile, _countof(ImmFile)); User32GetSystemFilePath(ImmFile, _countof(ImmFile), L"imm32.dll");
TRACE("File %S\n", ImmFile); TRACE("File %s\n", debugstr_w(ImmFile));
/* If IMM32 is already loaded, use it without increasing reference count. */ /* If IMM32 is already loaded, use it without increasing reference count. */
if (imm32 == NULL) if (imm32 == NULL)
@ -115,14 +117,12 @@ static BOOL IntInitializeImmEntryTable(VOID)
return TRUE; return TRUE;
} }
// Win: InitializeImmEntryTable
BOOL WINAPI InitializeImmEntryTable(VOID) BOOL WINAPI InitializeImmEntryTable(VOID)
{ {
gbImmInitializing = TRUE; gbImmInitializing = TRUE;
return IntInitializeImmEntryTable(); return IntInitializeImmEntryTable();
} }
// Win: User32InitializeImmEntryTable
BOOL WINAPI User32InitializeImmEntryTable(DWORD magic) BOOL WINAPI User32InitializeImmEntryTable(DWORD magic)
{ {
TRACE("Imm (%x)\n", magic); TRACE("Imm (%x)\n", magic);
@ -139,7 +139,7 @@ BOOL WINAPI User32InitializeImmEntryTable(DWORD magic)
if (ghImm32 == NULL && !gbImmInitializing) if (ghImm32 == NULL && !gbImmInitializing)
{ {
WCHAR ImmFile[MAX_PATH]; WCHAR ImmFile[MAX_PATH];
User32GetImmFileName(ImmFile, _countof(ImmFile)); User32GetSystemFilePath(ImmFile, _countof(ImmFile), L"imm32.dll");
ghImm32 = LoadLibraryW(ImmFile); ghImm32 = LoadLibraryW(ImmFile);
if (ghImm32 == NULL) if (ghImm32 == NULL)
{ {
@ -151,21 +151,18 @@ BOOL WINAPI User32InitializeImmEntryTable(DWORD magic)
return IMM_FN(ImmRegisterClient)(&gSharedInfo, ghImm32); return IMM_FN(ImmRegisterClient)(&gSharedInfo, ghImm32);
} }
// Win: ImeIsUsableContext
static BOOL User32CanSetImeWindowToImc(HIMC hIMC, HWND hImeWnd) static BOOL User32CanSetImeWindowToImc(HIMC hIMC, HWND hImeWnd)
{ {
PIMC pIMC = ValidateHandle(hIMC, TYPE_INPUTCONTEXT); PIMC pIMC = ValidateHandle(hIMC, TYPE_INPUTCONTEXT);
return pIMC && (!pIMC->hImeWnd || pIMC->hImeWnd == hImeWnd || !ValidateHwnd(pIMC->hImeWnd)); return pIMC && (!pIMC->hImeWnd || pIMC->hImeWnd == hImeWnd || !ValidateHwnd(pIMC->hImeWnd));
} }
// Win: GetIMEShowStatus
static BOOL User32GetImeShowStatus(VOID) static BOOL User32GetImeShowStatus(VOID)
{ {
return (BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_GETIMESHOWSTATUS); return (BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_GETIMESHOWSTATUS);
} }
/* Sends a message to the IME UI window. */ /* Sends a message to the IME UI window. */
/* Win: SendMessageToUI(pimeui, uMsg, wParam, lParam, !unicode) */
static LRESULT static LRESULT
User32SendImeUIMessage(PIMEUI pimeui, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL unicode) User32SendImeUIMessage(PIMEUI pimeui, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL unicode)
{ {
@ -195,7 +192,6 @@ User32SendImeUIMessage(PIMEUI pimeui, UINT uMsg, WPARAM wParam, LPARAM lParam, B
return ret; return ret;
} }
// Win: SendOpenStatusNotify
static VOID User32NotifyOpenStatus(PIMEUI pimeui, HWND hwndIMC, BOOL bOpen) static VOID User32NotifyOpenStatus(PIMEUI pimeui, HWND hwndIMC, BOOL bOpen)
{ {
WPARAM wParam = (bOpen ? IMN_OPENSTATUSWINDOW : IMN_CLOSESTATUSWINDOW); WPARAM wParam = (bOpen ? IMN_OPENSTATUSWINDOW : IMN_CLOSESTATUSWINDOW);
@ -210,7 +206,6 @@ static VOID User32NotifyOpenStatus(PIMEUI pimeui, HWND hwndIMC, BOOL bOpen)
User32SendImeUIMessage(pimeui, WM_IME_NOTIFY, wParam, 0, TRUE); User32SendImeUIMessage(pimeui, WM_IME_NOTIFY, wParam, 0, TRUE);
} }
// Win: ImeMarkUsedContext
static VOID User32SetImeWindowOfImc(HIMC hIMC, HWND hImeWnd) static VOID User32SetImeWindowOfImc(HIMC hIMC, HWND hImeWnd)
{ {
PIMC pIMC = ValidateHandle(hIMC, TYPE_INPUTCONTEXT); PIMC pIMC = ValidateHandle(hIMC, TYPE_INPUTCONTEXT);
@ -220,7 +215,6 @@ static VOID User32SetImeWindowOfImc(HIMC hIMC, HWND hImeWnd)
NtUserUpdateInputContext(hIMC, UIC_IMEWINDOW, (ULONG_PTR)hImeWnd); NtUserUpdateInputContext(hIMC, UIC_IMEWINDOW, (ULONG_PTR)hImeWnd);
} }
// Win: ImeSetImc
static VOID User32UpdateImcOfImeUI(PIMEUI pimeui, HIMC hNewIMC) static VOID User32UpdateImcOfImeUI(PIMEUI pimeui, HIMC hNewIMC)
{ {
HWND hImeWnd; HWND hImeWnd;
@ -242,7 +236,6 @@ static VOID User32UpdateImcOfImeUI(PIMEUI pimeui, HIMC hNewIMC)
} }
/* Handles WM_IME_NOTIFY message of the default IME window. */ /* Handles WM_IME_NOTIFY message of the default IME window. */
/* Win: ImeNotifyHandler */
static LRESULT ImeWnd_OnImeNotify(PIMEUI pimeui, WPARAM wParam, LPARAM lParam) static LRESULT ImeWnd_OnImeNotify(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
{ {
LRESULT ret = 0; LRESULT ret = 0;
@ -293,7 +286,6 @@ static LRESULT ImeWnd_OnImeNotify(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
} }
/* Creates the IME UI window. */ /* Creates the IME UI window. */
/* Win: CreateIMEUI */
static HWND User32CreateImeUIWindow(PIMEUI pimeui, HKL hKL) static HWND User32CreateImeUIWindow(PIMEUI pimeui, HKL hKL)
{ {
IMEINFOEX ImeInfoEx; IMEINFOEX ImeInfoEx;
@ -339,7 +331,6 @@ Quit:
} }
/* Initializes the default IME window. */ /* Initializes the default IME window. */
/* Win: ImeWndCreateHandler */
static INT ImeWnd_OnCreate(PIMEUI pimeui, LPCREATESTRUCT lpCS) static INT ImeWnd_OnCreate(PIMEUI pimeui, LPCREATESTRUCT lpCS)
{ {
PWND pParentWnd, pWnd = pimeui->spwnd; PWND pParentWnd, pWnd = pimeui->spwnd;
@ -371,7 +362,6 @@ static INT ImeWnd_OnCreate(PIMEUI pimeui, LPCREATESTRUCT lpCS)
} }
/* Destroys the IME UI window. */ /* Destroys the IME UI window. */
/* Win: DestroyIMEUI */
static VOID User32DestroyImeUIWindow(PIMEUI pimeui) static VOID User32DestroyImeUIWindow(PIMEUI pimeui)
{ {
HWND hwndUI = pimeui->hwndUI; HWND hwndUI = pimeui->hwndUI;
@ -387,7 +377,6 @@ static VOID User32DestroyImeUIWindow(PIMEUI pimeui)
} }
/* Handles WM_IME_SELECT message of the default IME window. */ /* Handles WM_IME_SELECT message of the default IME window. */
/* Win: ImeSelectHandler */
static VOID ImeWnd_OnImeSelect(PIMEUI pimeui, WPARAM wParam, LPARAM lParam) static VOID ImeWnd_OnImeSelect(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
{ {
HKL hKL; HKL hKL;
@ -422,7 +411,6 @@ static VOID ImeWnd_OnImeSelect(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
} }
/* Handles WM_IME_CONTROL message of the default IME window. */ /* Handles WM_IME_CONTROL message of the default IME window. */
/* Win: ImeControlHandler(pimeui, wParam, lParam, !unicode) */
static LRESULT static LRESULT
ImeWnd_OnImeControl(PIMEUI pimeui, WPARAM wParam, LPARAM lParam, BOOL unicode) ImeWnd_OnImeControl(PIMEUI pimeui, WPARAM wParam, LPARAM lParam, BOOL unicode)
{ {
@ -558,7 +546,6 @@ ImeWnd_OnImeControl(PIMEUI pimeui, WPARAM wParam, LPARAM lParam, BOOL unicode)
} }
/* Modify the IME activation status. */ /* Modify the IME activation status. */
/* Win: FocusSetIMCContext */
static VOID FASTCALL User32SetImeActivenessOfWindow(HWND hWnd, BOOL bActive) static VOID FASTCALL User32SetImeActivenessOfWindow(HWND hWnd, BOOL bActive)
{ {
HIMC hIMC; HIMC hIMC;
@ -574,7 +561,6 @@ static VOID FASTCALL User32SetImeActivenessOfWindow(HWND hWnd, BOOL bActive)
IMM_FN(ImmReleaseContext)(hWnd, hIMC); IMM_FN(ImmReleaseContext)(hWnd, hIMC);
} }
/* Win: CtfLoadThreadLayout */
VOID FASTCALL CtfLoadThreadLayout(PIMEUI pimeui) VOID FASTCALL CtfLoadThreadLayout(PIMEUI pimeui)
{ {
IMM_FN(CtfImmTIMActivate)(pimeui->hKL); IMM_FN(CtfImmTIMActivate)(pimeui->hKL);
@ -636,6 +622,59 @@ ImeWnd_SwitchSoftKbdProc(_In_ HIMC hIMC, _In_ LPARAM lParam)
return TRUE; return TRUE;
} }
// indicdll!12
typedef VOID (CALLBACK *FN_GetPenMenuData)(PUINT pnID, PDWORD_PTR pdwMenuData);
static FN_GetPenMenuData s_pGetPenMenuData = NULL;
#define IFN_GetPenMenuData 12
static BOOL CALLBACK
User32GetPenMenuData(_Out_ PUINT pnID, _Out_ PDWORD_PTR pdwMenuData)
{
if (!s_pGetPenMenuData)
{
WCHAR szPath[MAX_PATH];
HMODULE hIndicDll = GetModuleHandleW(L"indicdll.dll");
if (!hIndicDll)
{
User32GetSystemFilePath(szPath, _countof(szPath), L"indicdll.dll");
hIndicDll = LoadLibraryW(szPath);
}
if (!hIndicDll)
{
ERR("indicdll.dll not loaded: %s\n", debugstr_w(szPath));
return FALSE;
}
s_pGetPenMenuData =
(FN_GetPenMenuData)GetProcAddress(hIndicDll, MAKEINTRESOURCEA(IFN_GetPenMenuData));
}
if (!s_pGetPenMenuData)
return FALSE;
s_pGetPenMenuData(pnID, pdwMenuData);
return TRUE;
}
// IMS_IMEMENUITEMSELECTED
static VOID
User32ImeMenuItemSelected(HWND hwndTarget)
{
if (!IsWindow(hwndTarget))
return;
HIMC hIMC = IMM_FN(ImmGetContext)(hwndTarget);
if (!hIMC)
return;
UINT nID = 0;
DWORD_PTR dwMenuData = 0;
if (User32GetPenMenuData(&nID, &dwMenuData))
IMM_FN(ImmNotifyIME)(hIMC, NI_IMEMENUSELECTED, nID, dwMenuData);
IMM_FN(ImmReleaseContext)(hwndTarget, hIMC);
}
/* Handles WM_IME_SYSTEM message of the default IME window. */ /* Handles WM_IME_SYSTEM message of the default IME window. */
static LRESULT ImeWnd_OnImeSystem(PIMEUI pimeui, WPARAM wParam, LPARAM lParam) static LRESULT ImeWnd_OnImeSystem(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
{ {
@ -765,8 +804,8 @@ static LRESULT ImeWnd_OnImeSystem(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
ret = IMM_FN(ImmPutImeMenuItemsIntoMappedFile)((HIMC)lParam); ret = IMM_FN(ImmPutImeMenuItemsIntoMappedFile)((HIMC)lParam);
break; break;
case 0x1D: case IMS_IMEMENUITEMSELECTED:
FIXME("\n"); User32ImeMenuItemSelected((HWND)lParam);
break; break;
case IMS_GETCONTEXT: case IMS_GETCONTEXT:
@ -792,7 +831,6 @@ static LRESULT ImeWnd_OnImeSystem(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
} }
/* Handles WM_IME_SETCONTEXT message of the default IME window. */ /* Handles WM_IME_SETCONTEXT message of the default IME window. */
/* Win: ImeSetContextHandler */
LRESULT ImeWnd_OnImeSetContext(PIMEUI pimeui, WPARAM wParam, LPARAM lParam) LRESULT ImeWnd_OnImeSetContext(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
{ {
LRESULT ret; LRESULT ret;
@ -947,7 +985,6 @@ LRESULT ImeWnd_OnImeSetContext(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
} }
/* The window procedure of the default IME window */ /* The window procedure of the default IME window */
/* Win: ImeWndProcWorker(pWnd, msg, wParam, lParam, !unicode) */
LRESULT WINAPI LRESULT WINAPI
ImeWndProc_common(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicode) // ReactOS ImeWndProc_common(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicode) // ReactOS
{ {
@ -1103,19 +1140,16 @@ Finish:
return DefWindowProcA(hwnd, msg, wParam, lParam); return DefWindowProcA(hwnd, msg, wParam, lParam);
} }
// Win: ImeWndProcA
LRESULT WINAPI ImeWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) LRESULT WINAPI ImeWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{ {
return ImeWndProc_common(hwnd, msg, wParam, lParam, FALSE); return ImeWndProc_common(hwnd, msg, wParam, lParam, FALSE);
} }
// Win: ImeWndProcW
LRESULT WINAPI ImeWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) LRESULT WINAPI ImeWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{ {
return ImeWndProc_common(hwnd, msg, wParam, lParam, TRUE); return ImeWndProc_common(hwnd, msg, wParam, lParam, TRUE);
} }
// Win: UpdatePerUserImmEnabling
BOOL WINAPI UpdatePerUserImmEnabling(VOID) BOOL WINAPI UpdatePerUserImmEnabling(VOID)
{ {
HMODULE imm32; HMODULE imm32;