https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f2c3167db312c67c673b1…
commit f2c3167db312c67c673b1093230f4eb6de25c131
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Sat Feb 5 20:23:57 2022 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Sat Feb 5 20:23:57 2022 +0900
[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
---
sdk/include/psdk/imm.h | 7 +-
win32ss/user/ntuser/ime.c | 89 ++++++++++++++++++++++++-
win32ss/user/ntuser/window.c | 150 ++++++++++++++++++++++++++++++++++++++++++-
win32ss/user/ntuser/window.h | 20 ++++++
4 files changed, 259 insertions(+), 7 deletions(-)
diff --git a/sdk/include/psdk/imm.h b/sdk/include/psdk/imm.h
index 83908c9c191..95ac099d2e3 100644
--- a/sdk/include/psdk/imm.h
+++ b/sdk/include/psdk/imm.h
@@ -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
diff --git a/win32ss/user/ntuser/ime.c b/win32ss/user/ntuser/ime.c
index 0e7d4cf66e6..06b7eabe5fe 100644
--- a/win32ss/user/ntuser/ime.c
+++ b/win32ss/user/ntuser/ime.c
@@ -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)
diff --git a/win32ss/user/ntuser/window.c b/win32ss/user/ntuser/window.c
index d9cba3219d6..f3aeab5d344 100644
--- a/win32ss/user/ntuser/window.c
+++ b/win32ss/user/ntuser/window.c
@@ -3,7 +3,8 @@
* PROJECT: ReactOS Win32k subsystem
* PURPOSE: Windows
* FILE: win32ss/user/ntuser/window.c
- * PROGRAMER: Casper S. Hornstrup (chorns(a)users.sourceforge.net)
+ * PROGRAMERS: Casper S. Hornstrup (chorns(a)users.sourceforge.net)
+ * Katayama Hirofumi MZ (katayama.hirofumi.mz(a)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 *****************************************************************/
/*
diff --git a/win32ss/user/ntuser/window.h b/win32ss/user/ntuser/window.h
index f2cd877b289..fd63e1c920f 100644
--- a/win32ss/user/ntuser/window.h
+++ b/win32ss/user/ntuser/window.h
@@ -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 */