[NTUSER] Implement NtUserAssociateInputContext (#4334)

- Add IntReAllocatePoolWithTag function in window.c.
- Define WINDOWLIST structure in "window.h".
- Add IntBuildHwndList and IntFreeHwndList helper functions in window.c.
- Add IntAssociateInputContext and IntAssociateInputContextEx helper functions in ime.c.
- Implement NtUserAssociateInputContext function.
CORE-11700
This commit is contained in:
Katayama Hirofumi MZ 2022-02-05 20:23:57 +09:00 committed by GitHub
parent bf16435303
commit f2c3167db3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 259 additions and 7 deletions

View file

@ -577,11 +577,10 @@ DWORD WINAPI ImeGetImeMenuItems(HIMC, DWORD, DWORD, LPIMEMENUITEMINFOW, LPIMEMEN
#define IME_REGWORD_STYLE_USER_FIRST 0x80000000
#define IME_REGWORD_STYLE_USER_LAST 0xFFFFFFFF
/* dwFlags for ImmAssociateContextEx */
#define IACE_CHILDREN 0x0001
#define IACE_DEFAULT 0x0010
#define IACE_IGNORENOCONTEXT 0x0020
#define IACE_CHILDREN 0x0001
#define IACE_DEFAULT 0x0010
#define IACE_IGNORENOCONTEXT 0x0020
/* dwFlags for ImmGetImeMenuItems */
#define IGIMIF_RIGHTMENU 0x0001

View file

@ -695,12 +695,97 @@ Quit:
return ret;
}
HIMC FASTCALL IntAssociateInputContext(PWND pWnd, PIMC pImc)
{
HIMC hOldImc = pWnd->hImc;
pWnd->hImc = (pImc ? UserHMGetHandle(pImc) : NULL);
return hOldImc;
}
DWORD FASTCALL IntAssociateInputContextEx(PWND pWnd, PIMC pIMC, DWORD dwFlags)
{
DWORD ret = 0;
PWINDOWLIST pwl;
BOOL bIgnoreNullImc = (dwFlags & IACE_IGNORENOCONTEXT);
PTHREADINFO pti = pWnd->head.pti;
PWND pwndTarget, pwndFocus = pti->MessageQueue->spwndFocus;
HWND *phwnd;
HIMC hIMC;
if (dwFlags & IACE_DEFAULT)
{
pIMC = pti->spDefaultImc;
}
else
{
if (pIMC && pti != pIMC->head.pti)
return 2;
}
if (pWnd->head.pti->ppi != GetW32ThreadInfo()->ppi ||
(pIMC && pIMC->head.rpdesk != pWnd->head.rpdesk))
{
return 2;
}
if ((dwFlags & IACE_CHILDREN) && pWnd->spwndChild)
{
pwl = IntBuildHwndList(pWnd->spwndChild, IACE_CHILDREN | IACE_LIST, pti);
if (pwl)
{
for (phwnd = pwl->ahwnd; *phwnd != HWND_TERMINATOR; ++phwnd)
{
pwndTarget = ValidateHwndNoErr(*phwnd);
if (!pwndTarget)
continue;
hIMC = (pIMC ? UserHMGetHandle(pIMC) : NULL);
if (pwndTarget->hImc == hIMC || (bIgnoreNullImc && !pwndTarget->hImc))
continue;
IntAssociateInputContext(pwndTarget, pIMC);
if (pwndTarget == pwndFocus)
ret = 1;
}
IntFreeHwndList(pwl);
}
}
if (!bIgnoreNullImc || pWnd->hImc)
{
hIMC = (pIMC ? UserHMGetHandle(pIMC) : NULL);
if (pWnd->hImc != hIMC)
{
IntAssociateInputContext(pWnd, pIMC);
if (pWnd == pwndFocus)
ret = 1;
}
}
return ret;
}
DWORD
APIENTRY
NtUserAssociateInputContext(HWND hWnd, HIMC hIMC, DWORD dwFlags)
{
STUB
return 0;
DWORD ret = 2;
PWND pWnd;
PIMC pIMC;
UserEnterExclusive();
pWnd = ValidateHwndNoErr(hWnd);
if (!pWnd || !IS_IMM_MODE())
goto Quit;
pIMC = (hIMC ? UserGetObjectNoErr(gHandleTable, hIMC, TYPE_INPUTCONTEXT) : NULL);
ret = IntAssociateInputContextEx(pWnd, pIMC, dwFlags);
Quit:
UserLeave();
return ret;
}
BOOL FASTCALL UserUpdateInputContext(PIMC pIMC, DWORD dwType, DWORD_PTR dwValue)

View file

@ -3,7 +3,8 @@
* PROJECT: ReactOS Win32k subsystem
* PURPOSE: Windows
* FILE: win32ss/user/ntuser/window.c
* PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
* PROGRAMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
* Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
*/
#include <win32k.h>
@ -11,8 +12,28 @@ DBG_DEFAULT_CHANNEL(UserWnd);
INT gNestedWindowLimit = 50;
PWINDOWLIST gpwlList = NULL;
PWINDOWLIST gpwlCache = NULL;
/* HELPER FUNCTIONS ***********************************************************/
PVOID FASTCALL
IntReAllocatePoolWithTag(
POOL_TYPE PoolType,
PVOID pOld,
SIZE_T cbOld,
SIZE_T cbNew,
ULONG Tag)
{
PVOID pNew = ExAllocatePoolWithTag(PoolType, cbNew, Tag);
if (!pNew)
return NULL;
RtlCopyMemory(pNew, pOld, min(cbOld, cbNew));
ExFreePoolWithTag(pOld, Tag);
return pNew;
}
BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam)
{
WORD Action = LOWORD(wParam);
@ -1320,6 +1341,133 @@ IntUnlinkWindow(PWND Wnd)
Wnd->spwndPrev = Wnd->spwndNext = NULL;
}
BOOL FASTCALL IntGrowHwndList(PWINDOWLIST *ppwl)
{
PWINDOWLIST pwlOld, pwlNew;
SIZE_T ibOld, ibNew;
#define GROW_COUNT 8
pwlOld = *ppwl;
ibOld = (LPBYTE)pwlOld->phwndLast - (LPBYTE)pwlOld;
ibNew = ibOld + GROW_COUNT * sizeof(HWND);
#undef GROW_COUNT
pwlNew = IntReAllocatePoolWithTag(PagedPool, pwlOld, ibOld, ibNew, USERTAG_WINDOWLIST);
if (!pwlNew)
return FALSE;
pwlNew->phwndLast = (HWND *)((LPBYTE)pwlNew + ibOld);
pwlNew->phwndEnd = (HWND *)((LPBYTE)pwlNew + ibNew);
*ppwl = pwlNew;
return TRUE;
}
PWINDOWLIST FASTCALL IntPopulateHwndList(PWINDOWLIST pwl, PWND pwnd, DWORD dwFlags)
{
ASSERT(!WL_IS_BAD(pwl));
for (; pwnd; pwnd = pwnd->spwndNext)
{
if (!pwl->pti || pwl->pti == pwnd->head.pti)
{
*(pwl->phwndLast) = UserHMGetHandle(pwnd);
++(pwl->phwndLast);
if (pwl->phwndLast == pwl->phwndEnd && !IntGrowHwndList(&pwl))
break;
}
if ((dwFlags & IACE_CHILDREN) && pwnd->spwndChild)
{
pwl = IntPopulateHwndList(pwl, pwnd->spwndChild, IACE_CHILDREN | IACE_LIST);
if (WL_IS_BAD(pwl))
break;
}
if (!(dwFlags & IACE_LIST))
break;
}
return pwl;
}
PWINDOWLIST FASTCALL IntBuildHwndList(PWND pwnd, DWORD dwFlags, PTHREADINFO pti)
{
PWINDOWLIST pwl;
DWORD cbWL;
if (gpwlCache)
{
pwl = gpwlCache;
gpwlCache = NULL;
}
else
{
#define INITIAL_COUNT 32
cbWL = sizeof(WINDOWLIST) + (INITIAL_COUNT - 1) * sizeof(HWND);
pwl = ExAllocatePoolWithTag(PagedPool, cbWL, USERTAG_WINDOWLIST);
if (!pwl)
return NULL;
pwl->phwndEnd = &pwl->ahwnd[INITIAL_COUNT];
#undef INITIAL_COUNT
}
pwl->pti = pti;
pwl->phwndLast = pwl->ahwnd;
pwl = IntPopulateHwndList(pwl, pwnd, dwFlags);
if (WL_IS_BAD(pwl))
{
ExFreePoolWithTag(pwl, USERTAG_WINDOWLIST);
return NULL;
}
*(pwl->phwndLast) = HWND_TERMINATOR;
if (dwFlags & 0x8)
{
// TODO:
}
pwl->pti = GetW32ThreadInfo();
pwl->pNextList = gpwlList;
gpwlList = pwl;
return pwl;
}
VOID FASTCALL IntFreeHwndList(PWINDOWLIST pwlTarget)
{
PWINDOWLIST pwl, *ppwl;
for (ppwl = &gpwlList; *ppwl; ppwl = &(*ppwl)->pNextList)
{
if (*ppwl != pwlTarget)
continue;
*ppwl = pwlTarget->pNextList;
if (gpwlCache)
{
if (WL_CAPACITY(pwlTarget) > WL_CAPACITY(gpwlCache))
{
pwl = gpwlCache;
gpwlCache = pwlTarget;
ExFreePoolWithTag(pwl, USERTAG_WINDOWLIST);
}
else
{
ExFreePoolWithTag(pwlTarget, USERTAG_WINDOWLIST);
}
}
else
{
gpwlCache = pwlTarget;
}
break;
}
}
/* FUNCTIONS *****************************************************************/
/*

View file

@ -79,4 +79,24 @@ LONG_PTR FASTCALL co_UserSetWindowLongPtr(HWND, DWORD, LONG_PTR, BOOL);
HWND FASTCALL IntGetWindow(HWND,UINT);
LRESULT co_UserFreeWindow(PWND,PPROCESSINFO,PTHREADINFO,BOOLEAN);
#define HWND_TERMINATOR ((HWND)(ULONG_PTR)1)
typedef struct tagWINDOWLIST
{
struct tagWINDOWLIST *pNextList;
HWND *phwndLast;
HWND *phwndEnd;
PTHREADINFO pti;
HWND ahwnd[ANYSIZE_ARRAY]; /* Terminated by HWND_TERMINATOR */
} WINDOWLIST, *PWINDOWLIST;
#define WL_IS_BAD(pwl) ((pwl)->phwndEnd <= (pwl)->phwndLast)
#define WL_CAPACITY(pwl) ((pwl)->phwndEnd - &((pwl)->ahwnd[0]))
PWINDOWLIST FASTCALL IntBuildHwndList(PWND pwnd, DWORD dwFlags, PTHREADINFO pti);
VOID FASTCALL IntFreeHwndList(PWINDOWLIST pwlTarget);
/* Undocumented dwFlags for IntBuildHwndList */
#define IACE_LIST 0x0002
/* EOF */