https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8f719cb97e8e2148ef149…
commit 8f719cb97e8e2148ef149edb984e60a9a95b30c2
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Sat Apr 23 07:11:48 2022 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Sat Apr 23 07:11:48 2022 +0900
[NTUSER][IMM32] Create the default IME window! (retry) (#4463)
The default IME window has to be created for each top-level window in specific
condition. It is needed for implementing Japanese input.
- Add IntFocusSetInputContext helper function.
- Call IntFocusSetInputContext after sending WM_KILLFOCUS message.
- Add IntWantImeWindow, co_IntCreateDefaultImeWindow, and IntDestroyOwnedWindows
helper functions.
- Create the default IME window (spwndDefaultIme) for the specified window at
IntCreateWindow.
- Fix Imm32InternalLockIMC function.
CORE-11700
---
dll/win32/imm32/imm.c | 19 ++++---
sdk/include/ddk/immdev.h | 5 ++
win32ss/user/ntuser/focus.c | 60 +++++++++++++++++++++-
win32ss/user/ntuser/ime.c | 112 +++++++++++++++++++++++++++++++++++++++--
win32ss/user/ntuser/window.c | 109 +++++++++++++++++++++++++++------------
win32ss/user/ntuser/window.h | 2 +
win32ss/user/user32/misc/imm.c | 6 +--
7 files changed, 265 insertions(+), 48 deletions(-)
diff --git a/dll/win32/imm32/imm.c b/dll/win32/imm32/imm.c
index 5d199630229..45328abb595 100644
--- a/dll/win32/imm32/imm.c
+++ b/dll/win32/imm32/imm.c
@@ -830,7 +830,13 @@ LPINPUTCONTEXT APIENTRY Imm32InternalLockIMC(HIMC hIMC, BOOL
fSelect)
RtlEnterCriticalSection(&pClientImc->cs);
if (pClientImc->hInputContext)
- goto Finish;
+ {
+ pIC = LocalLock(pClientImc->hInputContext);
+ if (pIC)
+ goto Success;
+ else
+ goto Failure;
+ }
dwThreadId = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID);
if (dwThreadId == GetCurrentThreadId() && Imm32IsCiceroMode() &&
!Imm32Is16BitMode())
@@ -847,14 +853,14 @@ LPINPUTCONTEXT APIENTRY Imm32InternalLockIMC(HIMC hIMC, BOOL
fSelect)
}
if (!NtUserQueryInputContext(hIMC, QIC_DEFAULTWINDOWIME))
- goto Quit;
+ goto Failure;
hIC = LocalAlloc(LHND, sizeof(INPUTCONTEXTDX));
pIC = LocalLock(hIC);
if (!pIC)
{
LocalFree(hIC);
- goto Quit;
+ goto Failure;
}
pClientImc->hInputContext = hIC;
@@ -862,17 +868,17 @@ LPINPUTCONTEXT APIENTRY Imm32InternalLockIMC(HIMC hIMC, BOOL
fSelect)
if (!Imm32CreateInputContext(hIMC, pIC, pClientImc, hNewKL, fSelect))
{
pClientImc->hInputContext = LocalFree(pClientImc->hInputContext);
- goto Quit;
+ goto Failure;
}
-Finish:
+Success:
CtfImmTIMCreateInputContext(hIMC);
RtlLeaveCriticalSection(&pClientImc->cs);
InterlockedIncrement(&pClientImc->cLockObj);
ImmUnlockClientImc(pClientImc);
return pIC;
-Quit:
+Failure:
RtlLeaveCriticalSection(&pClientImc->cs);
ImmUnlockClientImc(pClientImc);
return NULL;
@@ -1243,6 +1249,7 @@ BOOL WINAPI ImmSetActiveContextConsoleIME(HWND hwnd, BOOL fFlag)
BOOL WINAPI User32InitializeImmEntryTable(DWORD);
+// Win: ImmDllInitialize
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
HKL hKL;
diff --git a/sdk/include/ddk/immdev.h b/sdk/include/ddk/immdev.h
index 61641ba1633..58bbc1dc1d6 100644
--- a/sdk/include/ddk/immdev.h
+++ b/sdk/include/ddk/immdev.h
@@ -24,6 +24,11 @@ extern "C" {
#define IMC_GETSOFTKBDPOS 0x0013
#define IMC_SETSOFTKBDPOS 0x0014
+/* wParam for WM_IME_SYSTEM */
+#define IMS_IMEACTIVATE 0x17
+#define IMS_IMEDEACTIVATE 0x18
+#define IMS_ACTIVATELAYOUT 0x19
+
#define IMMGWL_IMC 0
#define IMMGWL_PRIVATE (sizeof(LONG))
diff --git a/win32ss/user/ntuser/focus.c b/win32ss/user/ntuser/focus.c
index a9ea0965177..7ecb9c88f73 100644
--- a/win32ss/user/ntuser/focus.c
+++ b/win32ss/user/ntuser/focus.c
@@ -7,6 +7,7 @@
*/
#include <win32k.h>
+#include <ddk/immdev.h>
DBG_DEFAULT_CHANNEL(UserFocus);
PUSER_MESSAGE_QUEUE gpqForeground = NULL;
@@ -145,11 +146,47 @@ co_IntSendDeactivateMessages(HWND hWndPrev, HWND hWnd, BOOL Clear)
return Ret;
}
+// Win: xxxFocusSetInputContext
+VOID IntFocusSetInputContext(PWND pWnd, BOOL bActivate, BOOL bCallback)
+{
+ PTHREADINFO pti;
+ PWND pImeWnd;
+ USER_REFERENCE_ENTRY Ref;
+ HWND hImeWnd;
+ WPARAM wParam;
+ LPARAM lParam;
+
+ if (!pWnd || !pWnd->pcls || IS_WND_IMELIKE(pWnd))
+ return;
+
+ pti = pWnd->head.pti;
+ if (!pti || (pti->TIF_flags & TIF_INCLEANUP))
+ return;
+
+ pImeWnd = pti->spwndDefaultIme;
+ if (!pImeWnd)
+ return;
+
+ UserRefObjectCo(pImeWnd, &Ref);
+
+ hImeWnd = UserHMGetHandle(pImeWnd);
+ wParam = (bActivate ? IMS_IMEACTIVATE : IMS_IMEDEACTIVATE);
+ lParam = (LPARAM)UserHMGetHandle(pWnd);
+
+ if (bCallback)
+ co_IntSendMessageWithCallBack(hImeWnd, WM_IME_SYSTEM, wParam, lParam, NULL, 0,
NULL);
+ else
+ co_IntSendMessage(hImeWnd, WM_IME_SYSTEM, wParam, lParam);
+
+ UserDerefObjectCo(pImeWnd);
+}
+
//
// Deactivating the foreground message queue.
//
// Release Active, Capture and Focus Windows associated with this message queue.
//
+// Win: xxxDeactivate
BOOL FASTCALL
IntDeactivateWindow(PTHREADINFO pti, HANDLE tid)
{
@@ -297,6 +334,10 @@ IntDeactivateWindow(PTHREADINFO pti, HANDLE tid)
UserRefObjectCo(pwndFocus, &Ref);
co_IntSendMessage(UserHMGetHandle(pwndFocus), WM_KILLFOCUS, 0, 0);
+ if (IS_IMM_MODE())
+ {
+ IntFocusSetInputContext(pwndFocus, FALSE, FALSE);
+ }
UserDerefObjectCo(pwndFocus);
}
@@ -569,11 +610,13 @@ co_IntSendActivateMessages(PWND WindowPrev, PWND Window, BOOL
MouseActivate, BOO
return InAAPM;
}
+// Win: xxxSendFocusMessages
VOID FASTCALL
IntSendFocusMessages( PTHREADINFO pti, PWND pWnd)
{
PWND pWndPrev;
PUSER_MESSAGE_QUEUE ThreadQueue = pti->MessageQueue; // Queue can change...
+ HWND hwndPrev;
ThreadQueue->QF_flags &= ~QF_FOCUSNULLSINCEACTIVE;
if (!pWnd && ThreadQueue->spwndActive)
@@ -593,12 +636,22 @@ IntSendFocusMessages( PTHREADINFO pti, PWND pWnd)
if (pWndPrev)
{
co_IntSendMessage(UserHMGetHandle(pWndPrev), WM_KILLFOCUS,
(WPARAM)UserHMGetHandle(pWnd), 0);
+ if (IS_IMM_MODE())
+ {
+ IntFocusSetInputContext(pWndPrev, FALSE, FALSE);
+ }
}
if (ThreadQueue->spwndFocus == pWnd)
{
+ if (IS_IMM_MODE())
+ {
+ IntFocusSetInputContext(pWnd, TRUE, FALSE);
+ }
+
IntNotifyWinEvent(EVENT_OBJECT_FOCUS, pWnd, OBJID_CLIENT, CHILDID_SELF, 0);
- co_IntSendMessage(UserHMGetHandle(pWnd), WM_SETFOCUS, (WPARAM)(pWndPrev ?
UserHMGetHandle(pWndPrev) : NULL), 0);
+ hwndPrev = (pWndPrev ? UserHMGetHandle(pWndPrev) : NULL);
+ co_IntSendMessage(UserHMGetHandle(pWnd), WM_SETFOCUS, (WPARAM)hwndPrev, 0);
}
}
else
@@ -608,6 +661,10 @@ IntSendFocusMessages( PTHREADINFO pti, PWND pWnd)
IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
co_IntSendMessage(UserHMGetHandle(pWndPrev), WM_KILLFOCUS, 0, 0);
+ if (IS_IMM_MODE())
+ {
+ IntFocusSetInputContext(pWndPrev, FALSE, FALSE);
+ }
}
}
}
@@ -1241,6 +1298,7 @@ UserSetActiveWindow( _In_opt_ PWND Wnd )
return FALSE;
}
+// Win: PWND xxxSetFocus(Window)
HWND FASTCALL
co_UserSetFocus(PWND Window)
{
diff --git a/win32ss/user/ntuser/ime.c b/win32ss/user/ntuser/ime.c
index e869608724f..f8cd3778512 100644
--- a/win32ss/user/ntuser/ime.c
+++ b/win32ss/user/ntuser/ime.c
@@ -1889,7 +1889,110 @@ BOOL IntFindNonImeRelatedWndOfSameThread(PWND pwndParent, PWND
pwndTarget)
return FALSE;
}
-// Can we destroy the default IME window for the target child window?
+// Determines whether the target window needs the IME window.
+// Win: WantImeWindow(pwndParent, pwndTarget)
+BOOL FASTCALL IntWantImeWindow(PWND pwndTarget)
+{
+ PDESKTOP rpdesk;
+ PWINSTATION_OBJECT rpwinstaParent;
+ PWND pwndNode, pwndParent = pwndTarget->spwndParent;
+
+ if (gptiCurrent->TIF_flags & TIF_DISABLEIME)
+ return FALSE;
+
+ if (IS_WND_IMELIKE(pwndTarget))
+ return FALSE;
+
+ if (pwndTarget->fnid == FNID_DESKTOP || pwndTarget->fnid == FNID_MESSAGEWND)
+ return FALSE;
+
+ if (pwndTarget->state & WNDS_SERVERSIDEWINDOWPROC)
+ return FALSE;
+
+ rpdesk = pwndTarget->head.rpdesk;
+ if (!rpdesk)
+ return FALSE;
+
+ rpwinstaParent = rpdesk->rpwinstaParent;
+ if (!rpwinstaParent || (rpwinstaParent->Flags & WSS_NOIO))
+ return FALSE;
+
+ for (pwndNode = pwndParent; pwndNode; pwndNode = pwndNode->spwndParent)
+ {
+ if (rpdesk != pwndNode->head.rpdesk)
+ break;
+
+ if (pwndNode == rpdesk->spwndMessage)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// Create the default IME window for the target window.
+// Win: xxxCreateDefaultImeWindow(pwndTarget, ATOM, hInst)
+PWND FASTCALL co_IntCreateDefaultImeWindow(PWND pwndTarget, HINSTANCE hInst)
+{
+ LARGE_UNICODE_STRING WindowName;
+ UNICODE_STRING ClassName;
+ PWND pImeWnd;
+ PIMEUI pimeui;
+ CREATESTRUCTW Cs;
+ USER_REFERENCE_ENTRY Ref;
+ PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+ HANDLE pid = PsGetThreadProcessId(pti->pEThread);
+
+ if (!(pti->spDefaultImc) && pid == gpidLogon)
+ UserCreateInputContext(0);
+
+ if (!(pti->spDefaultImc) || IS_WND_IMELIKE(pwndTarget) ||
!(pti->rpdesk->pheapDesktop))
+ return NULL;
+
+ if (IS_WND_CHILD(pwndTarget) && !(pwndTarget->style & WS_VISIBLE)
&&
+ pwndTarget->spwndParent->head.pti->ppi != pti->ppi)
+ {
+ return NULL;
+ }
+
+ RtlInitLargeUnicodeString(&WindowName, L"Default IME", 0);
+
+ ClassName.Buffer = (PWCH)(ULONG_PTR)gpsi->atomSysClass[ICLS_IME];
+ ClassName.Length = 0;
+ ClassName.MaximumLength = 0;
+
+ UserRefObjectCo(pwndTarget, &Ref);
+
+ RtlZeroMemory(&Cs, sizeof(Cs));
+ Cs.style = WS_POPUP | WS_DISABLED;
+ Cs.hInstance = hInst;
+ Cs.hwndParent = UserHMGetHandle(pwndTarget);
+ Cs.lpszName = WindowName.Buffer;
+ Cs.lpszClass = ClassName.Buffer;
+
+ // NOTE: LARGE_UNICODE_STRING is compatible to LARGE_STRING.
+ pImeWnd = co_UserCreateWindowEx(&Cs, &ClassName,
(PLARGE_STRING)&WindowName, NULL, WINVER);
+ if (pImeWnd)
+ {
+ pimeui = ((PIMEWND)pImeWnd)->pimeui;
+ _SEH2_TRY
+ {
+ ProbeForWrite(pimeui, sizeof(IMEUI), 1);
+ pimeui->fDefault = TRUE;
+ if (IS_WND_CHILD(pwndTarget) &&
pwndTarget->spwndParent->head.pti != pti)
+ pimeui->fChildThreadDef = TRUE;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ NOTHING;
+ }
+ _SEH2_END;
+ }
+
+ UserDerefObjectCo(pwndTarget);
+ return pImeWnd;
+}
+
+// Determines whether the system can destroy the default IME window for the target child
window.
// Win: ImeCanDestroyDefIMEforChild
BOOL FASTCALL IntImeCanDestroyDefIMEforChild(PWND pImeWnd, PWND pwndTarget)
{
@@ -1911,7 +2014,7 @@ BOOL FASTCALL IntImeCanDestroyDefIMEforChild(PWND pImeWnd, PWND
pwndTarget)
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- ;
+ NOTHING;
}
_SEH2_END;
@@ -1934,8 +2037,7 @@ BOOL FASTCALL IntImeCanDestroyDefIMEforChild(PWND pImeWnd, PWND
pwndTarget)
return TRUE;
}
-// Can we destroy the default IME window for the non-child target window?
-// If so, this function sets spwndOwner to NULL.
+// Determines whether the system can destroy the default IME window for the non-child
target window.
// Win: ImeCanDestroyDefIME
BOOL FASTCALL IntImeCanDestroyDefIME(PWND pImeWnd, PWND pwndTarget)
{
@@ -1957,7 +2059,7 @@ BOOL FASTCALL IntImeCanDestroyDefIME(PWND pImeWnd, PWND pwndTarget)
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- ;
+ NOTHING;
}
_SEH2_END;
diff --git a/win32ss/user/ntuser/window.c b/win32ss/user/ntuser/window.c
index 9ec554b4a24..a740fcc11e8 100644
--- a/win32ss/user/ntuser/window.c
+++ b/win32ss/user/ntuser/window.c
@@ -8,6 +8,7 @@
*/
#include <win32k.h>
+#include <ddk/immdev.h>
DBG_DEFAULT_CHANNEL(UserWnd);
INT gNestedWindowLimit = 50;
@@ -658,8 +659,16 @@ LRESULT co_UserFreeWindow(PWND Window,
ThreadData->rpdesk->rpwinstaParent->ShellListView = NULL;
}
+ if (ThreadData->spwndDefaultIme &&
+ ThreadData->spwndDefaultIme->spwndOwner == Window)
+ {
+ ThreadData->spwndDefaultIme->spwndOwner = NULL;
+ }
+
if (IS_IMM_MODE() && Window == ThreadData->spwndDefaultIme)
+ {
UserAssignmentUnlock((PVOID*)&(ThreadData->spwndDefaultIme));
+ }
/* Fixes dialog test_focus breakage due to r66237. */
if (ThreadData->MessageQueue->spwndFocus == Window)
@@ -1775,7 +1784,7 @@ PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
{
PWND pWnd = NULL;
HWND hWnd;
- PTHREADINFO pti = NULL;
+ PTHREADINFO pti;
BOOL MenuChanged;
BOOL bUnicodeWindow;
PCALLPROCDATA pcpd;
@@ -2027,6 +2036,28 @@ PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
pWnd->strName.MaximumLength = WindowName->Length + sizeof(UNICODE_NULL);
}
+ /* Create the IME window for pWnd */
+ if (IS_IMM_MODE() && !(pti->spwndDefaultIme) &&
IntWantImeWindow(pWnd))
+ {
+ PWND pwndDefaultIme = co_IntCreateDefaultImeWindow(pWnd, pWnd->hModule);
+ UserAssignmentLock((PVOID*)&(pti->spwndDefaultIme), pwndDefaultIme);
+
+ if (pwndDefaultIme && (pti->pClientInfo->CI_flags &
CI_IMMACTIVATE))
+ {
+ USER_REFERENCE_ENTRY Ref;
+ HKL hKL;
+
+ UserRefObjectCo(pwndDefaultIme, &Ref);
+
+ hKL = pti->KeyboardLayout->hkl;
+ co_IntSendMessage(UserHMGetHandle(pwndDefaultIme), WM_IME_SYSTEM,
+ IMS_ACTIVATELAYOUT, (LPARAM)hKL);
+ pti->pClientInfo->CI_flags &= ~CI_IMMACTIVATE;
+
+ UserDerefObjectCo(pwndDefaultIme);
+ }
+ }
+
/* Correct the window style. */
if ((pWnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
{
@@ -2133,7 +2164,6 @@ Error:
/*
* @implemented
- * Win: xxxCreateWindowEx
*/
PWND FASTCALL
co_UserCreateWindowEx(CREATESTRUCTW* Cs,
@@ -2748,6 +2778,49 @@ cleanup:
return hwnd;
}
+// Win: xxxDW_DestroyOwnedWindows
+VOID FASTCALL IntDestroyOwnedWindows(PWND Window)
+{
+ HWND* List;
+ HWND* phWnd;
+ PWND pWnd;
+ PTHREADINFO pti = Window->head.pti;
+ USER_REFERENCE_ENTRY Ref;
+
+ List = IntWinListOwnedPopups(Window);
+ if (!List)
+ return;
+
+ for (phWnd = List; *phWnd; ++phWnd)
+ {
+ pWnd = ValidateHwndNoErr(*phWnd);
+ if (pWnd == NULL)
+ continue;
+ ASSERT(pWnd->spwndOwner == Window);
+ ASSERT(pWnd != Window);
+
+ if (IS_IMM_MODE() && !(pti->TIF_flags & TIF_INCLEANUP) &&
+ pWnd == pti->spwndDefaultIme)
+ {
+ continue;
+ }
+
+ pWnd->spwndOwner = NULL;
+ if (IntWndBelongsToThread(pWnd, PsGetCurrentThreadWin32Thread()))
+ {
+ UserRefObjectCo(pWnd, &Ref); // Temp HACK?
+ co_UserDestroyWindow(pWnd);
+ UserDerefObjectCo(pWnd); // Temp HACK?
+ }
+ else
+ {
+ ERR("IntWndBelongsToThread(0x%p) is FALSE, ignoring.\n", pWnd);
+ }
+ }
+
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+}
+
// Win: xxxDestroyWindow
BOOLEAN co_UserDestroyWindow(PVOID Object)
{
@@ -2876,37 +2949,7 @@ BOOLEAN co_UserDestroyWindow(PVOID Object)
/* Recursively destroy owned windows */
if (!(Window->style & WS_CHILD))
{
- HWND* List;
- HWND* phWnd;
- PWND pWnd;
-
- List = IntWinListOwnedPopups(Window);
- if (List)
- {
- for (phWnd = List; *phWnd; ++phWnd)
- {
- pWnd = ValidateHwndNoErr(*phWnd);
- if (pWnd == NULL)
- continue;
- ASSERT(pWnd->spwndOwner == Window);
- ASSERT(pWnd != Window);
-
- pWnd->spwndOwner = NULL;
- if (IntWndBelongsToThread(pWnd, PsGetCurrentThreadWin32Thread()))
- {
- USER_REFERENCE_ENTRY Ref;
- UserRefObjectCo(pWnd, &Ref); // Temp HACK?
- co_UserDestroyWindow(pWnd);
- UserDerefObjectCo(pWnd); // Temp HACK?
- }
- else
- {
- ERR("IntWndBelongsToThread(0x%p) is FALSE, ignoring.\n",
pWnd);
- }
- }
-
- ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
- }
+ IntDestroyOwnedWindows(Window);
}
/* Generate mouse move message for the next window */
diff --git a/win32ss/user/ntuser/window.h b/win32ss/user/ntuser/window.h
index 86daff24d97..a093e4e4ee8 100644
--- a/win32ss/user/ntuser/window.h
+++ b/win32ss/user/ntuser/window.h
@@ -112,6 +112,8 @@ VOID FASTCALL IntFreeHwndList(PWINDOWLIST pwlTarget);
(((pWnd)->pcls->style & CS_IME) || \
((pWnd)->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]))
+BOOL FASTCALL IntWantImeWindow(PWND pwndTarget);
+PWND FASTCALL co_IntCreateDefaultImeWindow(PWND pwndTarget, HINSTANCE hInst);
BOOL FASTCALL IntImeCanDestroyDefIMEforChild(PWND pImeWnd, PWND pwndTarget);
BOOL FASTCALL IntImeCanDestroyDefIME(PWND pImeWnd, PWND pwndTarget);
diff --git a/win32ss/user/user32/misc/imm.c b/win32ss/user/user32/misc/imm.c
index 6fa8eafd1d6..f14db5ddf15 100644
--- a/win32ss/user/user32/misc/imm.c
+++ b/win32ss/user/user32/misc/imm.c
@@ -664,15 +664,15 @@ static LRESULT ImeWnd_OnImeSystem(PIMEUI pimeui, WPARAM wParam,
LPARAM lParam)
// TODO:
break;
- case 0x17:
+ case IMS_IMEACTIVATE:
User32SetImeActivenessOfWindow((HWND)lParam, TRUE);
break;
- case 0x18:
+ case IMS_IMEDEACTIVATE:
User32SetImeActivenessOfWindow((HWND)lParam, FALSE);
break;
- case 0x19:
+ case IMS_ACTIVATELAYOUT:
ret = IMM_FN(ImmActivateLayout)((HKL)lParam);
break;