https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8c6dcdcf81867b701ef88…
commit 8c6dcdcf81867b701ef8882565893ba8fa86d078
Author:     Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Wed Feb 2 11:58:31 2022 +0900
Commit:     GitHub <noreply(a)github.com>
CommitDate: Wed Feb 2 11:58:31 2022 +0900
    [USER32] Implement ImeWnd_OnImeSetContext (#4329)
    - Modify NtUserSetImeOwnerWindow prototype.
    - Add User32GetTopLevelWindow function.
    - Add ImeWnd_OnImeSetContext function.
    - Implement WM_IME_SETCONTEXT message handling of the IME window.
    CORE-11700
---
 sdk/include/ddk/immdev.h         |   6 ++
 sdk/include/psdk/imm.h           |   3 -
 win32ss/include/ntuser.h         |   4 +-
 win32ss/user/ntuser/ime.c        |   4 +-
 win32ss/user/ntuser/simplecall.c |   4 +
 win32ss/user/user32/misc/imm.c   | 171 ++++++++++++++++++++++++++++++++++++++-
 6 files changed, 181 insertions(+), 11 deletions(-)
diff --git a/sdk/include/ddk/immdev.h b/sdk/include/ddk/immdev.h
index 8addb828bb9..61641ba1633 100644
--- a/sdk/include/ddk/immdev.h
+++ b/sdk/include/ddk/immdev.h
@@ -24,6 +24,12 @@ extern "C" {
 #define IMC_GETSOFTKBDPOS               0x0013
 #define IMC_SETSOFTKBDPOS               0x0014
+#define IMMGWL_IMC       0
+#define IMMGWL_PRIVATE   (sizeof(LONG))
+
+#define IMMGWLP_IMC      0
+#define IMMGWLP_PRIVATE  (sizeof(LONG_PTR))
+
 typedef struct _tagINPUTCONTEXT {
     HWND                hWnd;
     BOOL                fOpen;
diff --git a/sdk/include/psdk/imm.h b/sdk/include/psdk/imm.h
index ebd3bb4cb47..83908c9c191 100644
--- a/sdk/include/psdk/imm.h
+++ b/sdk/include/psdk/imm.h
@@ -209,9 +209,6 @@ typedef struct tagCANDIDATEINFO {
     DWORD               dwPrivateOffset;
 } CANDIDATEINFO, *LPCANDIDATEINFO;
-#define IMMGWL_IMC                      0
-#define IMMGWL_PRIVATE                  (sizeof(LONG))
-
 /* IME Property bits */
 #define IME_PROP_END_UNLOAD             0x0001
 #define IME_PROP_KBD_CHAR_FIRST         0x0002
diff --git a/win32ss/include/ntuser.h b/win32ss/include/ntuser.h
index 705f5aa08a9..6f897a24736 100644
--- a/win32ss/include/ntuser.h
+++ b/win32ss/include/ntuser.h
@@ -3198,9 +3198,9 @@ NTAPI
 NtUserSetImeInfoEx(
     PIMEINFOEX pImeInfoEx);
-DWORD
+BOOL
 NTAPI
-NtUserSetImeOwnerWindow(PIMEINFOEX pImeInfoEx, BOOL fFlag);
+NtUserSetImeOwnerWindow(HWND hImeWnd, HWND hwndFocus);
 DWORD
 NTAPI
diff --git a/win32ss/user/ntuser/ime.c b/win32ss/user/ntuser/ime.c
index c492f07507d..5d01bf1397f 100644
--- a/win32ss/user/ntuser/ime.c
+++ b/win32ss/user/ntuser/ime.c
@@ -469,8 +469,8 @@ Quit:
     return ret;
 }
-DWORD APIENTRY
-NtUserSetImeOwnerWindow(PIMEINFOEX pImeInfoEx, BOOL fFlag)
+BOOL APIENTRY
+NtUserSetImeOwnerWindow(HWND hImeWnd, HWND hwndFocus)
 {
    STUB
    return 0;
diff --git a/win32ss/user/ntuser/simplecall.c b/win32ss/user/ntuser/simplecall.c
index 42feafd0f44..ed7583b0bac 100644
--- a/win32ss/user/ntuser/simplecall.c
+++ b/win32ss/user/ntuser/simplecall.c
@@ -660,6 +660,10 @@ NtUserCallHwndLock(
             co_IntUpdateWindows(Window, RDW_ALLCHILDREN, FALSE);
             Ret = TRUE;
             break;
+
+        case HWNDLOCK_ROUTINE_CHECKIMESHOWSTATUSINTHRD:
+            // TODO:
+            break;
     }
     UserDerefObjectCo(Window);
diff --git a/win32ss/user/user32/misc/imm.c b/win32ss/user/user32/misc/imm.c
index 7d84a2bb0f4..ee3f109419d 100644
--- a/win32ss/user/user32/misc/imm.c
+++ b/win32ss/user/user32/misc/imm.c
@@ -23,6 +23,19 @@ HINSTANCE ghImm32 = NULL;
 BOOL bImmInitializing = FALSE;
+INT gnImmUnknownFlag1 = -1;
+
+PWND FASTCALL User32GetTopLevelWindow(PWND pwnd)
+{
+    if (!pwnd)
+        return NULL;
+
+    while (pwnd->style & WS_CHILD)
+        pwnd = pwnd->spwndParent;
+
+    return pwnd;
+}
+
 /* define stub functions */
 #undef DEFINE_IMM_ENTRY
 #define DEFINE_IMM_ENTRY(type, name, params, retval, retkind) \
@@ -654,6 +667,157 @@ static LRESULT ImeWnd_OnImeSystem(PIMEUI pimeui, WPARAM wParam,
LPARAM lParam)
     return ret;
 }
+LRESULT ImeWnd_OnImeSetContext(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
+{
+    LRESULT ret;
+    HIMC hIMC;
+    LPINPUTCONTEXTDX pIC;
+    HWND hwndFocus, hwndOldImc, hwndNewImc, hImeWnd, hwndActive;
+    PWND pwndFocus, pwndOldImc, pwndNewImc, pImeWnd, pwndOwner;
+    COMPOSITIONFORM CompForm;
+
+    pimeui->fActivate = !!wParam;
+    hwndOldImc = pimeui->hwndIMC;
+
+    if (wParam)
+    {
+        if (!pimeui->hwndUI)
+            pimeui->hwndUI = User32CreateImeUIWindow(pimeui, pimeui->hKL);
+
+        if (gnImmUnknownFlag1 == -1)
+        {
+            gnImmUnknownFlag1 = (INT)NtUserGetThreadState(THREADSTATE_UNKNOWN17);
+            if (gnImmUnknownFlag1)
+                pimeui->fCtrlShowStatus = FALSE;
+        }
+
+        if (gnImmUnknownFlag1)
+        {
+            pwndOwner = pimeui->spwnd->spwndOwner;
+            if (pwndOwner)
+            {
+                User32UpdateImcOfImeUI(pimeui, pwndOwner->hImc);
+
+                if (pimeui->hwndUI)
+                    SetWindowLongPtrW(pimeui->hwndUI, IMMGWLP_IMC,
(LONG_PTR)pwndOwner->hImc);
+            }
+
+            return User32SendImeUIMessage(pimeui, WM_IME_SETCONTEXT, wParam, lParam,
TRUE);
+        }
+
+        hImeWnd = UserHMGetHandle(pimeui->spwnd);
+        hwndFocus = (HWND)NtUserQueryWindow(hImeWnd, QUERY_WINDOW_FOCUS);
+
+        hIMC = IMM_FN(ImmGetContext)(hwndFocus);
+
+        if (hIMC && !User32CanSetImeWindowToImc(hIMC, hImeWnd))
+        {
+            User32UpdateImcOfImeUI(pimeui, NULL);
+            return 0;
+        }
+
+        User32UpdateImcOfImeUI(pimeui, hIMC);
+
+        if (pimeui->hwndUI)
+            SetWindowLongPtrW(pimeui->hwndUI, IMMGWLP_IMC, (LONG_PTR)hIMC);
+
+        if (hIMC)
+        {
+            pIC = IMM_FN(ImmLockIMC)(hIMC);
+            if (!pIC)
+                return 0;
+
+            if (hwndFocus != pIC->hWnd)
+            {
+                IMM_FN(ImmUnlockIMC)(hIMC);
+                return 0;
+            }
+
+            if ((pIC->dwUIFlags & 0x40000) && hwndOldImc != hwndFocus)
+            {
+                RtlZeroMemory(&CompForm, sizeof(CompForm));
+                IMM_FN(ImmSetCompositionWindow)(hIMC, &CompForm);
+
+                pIC->dwUIFlags &= ~0x40000;
+            }
+
+            IMM_FN(ImmUnlockIMC)(hIMC);
+
+            hImeWnd = UserHMGetHandle(pimeui->spwnd);
+            if (NtUserSetImeOwnerWindow(hImeWnd, hwndFocus))
+                pimeui->hwndIMC = hwndFocus;
+        }
+        else
+        {
+            pimeui->hwndIMC = hwndFocus;
+
+            hImeWnd = UserHMGetHandle(pimeui->spwnd);
+            NtUserSetImeOwnerWindow(hImeWnd, NULL);
+        }
+    }
+
+    ret = User32SendImeUIMessage(pimeui, WM_IME_SETCONTEXT, wParam, lParam, TRUE);
+
+    if (!pimeui->spwnd)
+        return 0;
+
+    if (!pimeui->fCtrlShowStatus || !User32GetImeShowStatus())
+        return ret;
+
+    hImeWnd = UserHMGetHandle(pimeui->spwnd);
+    hwndFocus = (HWND)NtUserQueryWindow(hImeWnd, QUERY_WINDOW_FOCUS);
+    pwndFocus = ValidateHwnd(hwndFocus);
+
+    if (wParam)
+    {
+        if (pwndFocus && pimeui->spwnd->head.pti == pwndFocus->head.pti)
+        {
+            hwndNewImc = pimeui->hwndIMC;
+            if (pimeui->fShowStatus)
+            {
+                pwndNewImc = ValidateHwnd(hwndNewImc);
+                pwndOldImc = ValidateHwnd(hwndOldImc);
+                if (pwndNewImc && pwndOldImc && pwndNewImc != pwndOldImc
&&
+                    User32GetTopLevelWindow(pwndNewImc) !=
User32GetTopLevelWindow(pwndOldImc))
+                {
+                    User32NotifyOpenStatus(pimeui, hwndOldImc, FALSE);
+                    User32NotifyOpenStatus(pimeui, hwndNewImc, TRUE);
+                }
+            }
+            else
+            {
+                if (ValidateHwnd(hwndNewImc))
+                    User32NotifyOpenStatus(pimeui, hwndNewImc, TRUE);
+            }
+        }
+
+        pImeWnd = pimeui->spwnd;
+        hImeWnd = (pImeWnd ? UserHMGetHandle(pImeWnd) : NULL);
+        if (hImeWnd)
+            NtUserCallHwndLock(hImeWnd, HWNDLOCK_ROUTINE_CHECKIMESHOWSTATUSINTHRD);
+    }
+    else
+    {
+        pImeWnd = pimeui->spwnd;
+        hImeWnd = UserHMGetHandle(pImeWnd);
+        hwndActive = (HWND)NtUserQueryWindow(hImeWnd, QUERY_WINDOW_ACTIVE);
+        if (!pwndFocus || !hwndActive || pImeWnd->head.pti != pwndFocus->head.pti)
+        {
+            if (IsWindow(hwndOldImc))
+            {
+                User32NotifyOpenStatus(pimeui, hwndOldImc, FALSE);
+            }
+            else
+            {
+                pimeui->fShowStatus = FALSE;
+                User32SendImeUIMessage(pimeui, WM_IME_NOTIFY, IMN_CLOSESTATUSWINDOW, 0,
TRUE);
+            }
+        }
+    }
+
+    return ret;
+}
+
 LRESULT WINAPI ImeWndProc_common( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL
unicode ) // ReactOS
 {
     PWND pWnd;
@@ -673,7 +837,7 @@ LRESULT WINAPI ImeWndProc_common( HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lPa
           NtUserSetWindowFNID(hwnd, FNID_IME);
           pimeui = HeapAlloc( GetProcessHeap(), 0, sizeof(IMEUI) );
           pimeui->spwnd = pWnd;
-          SetWindowLongPtrW(hwnd, 0, (LONG_PTR)pimeui);
+          SetWindowLongPtrW(hwnd, IMMGWLP_IMC, (LONG_PTR)pimeui);
        }
        else
        {
@@ -740,7 +904,7 @@ LRESULT WINAPI ImeWndProc_common( HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lPa
         case WM_NCDESTROY:
             HeapFree(GetProcessHeap(), 0, pimeui);
-            SetWindowLongPtrW(hwnd, 0, 0);
+            SetWindowLongPtrW(hwnd, IMMGWLP_IMC, 0);
             NtUserSetWindowFNID(hwnd, FNID_DESTROY);
             break;
@@ -773,8 +937,7 @@ LRESULT WINAPI ImeWndProc_common( HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lPa
             break;
         case WM_IME_SETCONTEXT:
-            // TODO:
-            break;
+            return ImeWnd_OnImeSetContext(pimeui, wParam, lParam);
         case WM_IME_SYSTEM:
             return ImeWnd_OnImeSystem(pimeui, wParam, lParam);