mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 20:35:43 +00:00
[NTUSER][USER32] Implement IME status (#4472)
- Add IntCheckImeShowStatus, IntSendMessageToUI, IntSendOpenStatusNotify, IntNotifyImeShowStatus, and xxxBroadcastImeShowStatusChange helper functions. - Renaming: s/X_ROUTINE_IMESHOWSTATUSCHANGE/TWOPARAM_ROUTINE_IMESHOWSTATUSCHANGE/ - Implement NtUserCallNoParam.NOPARAM_ROUTINE_GETIMESHOWSTATUS. - Implement NtUserCallHwndParamLock.TWOPARAM_ROUTINE_IMESHOWSTATUSCHANGE. - Fix hung in User32GetTopLevelWindow and rename it as IntGetTopLevelWindow. CORE-11700
This commit is contained in:
parent
a849125947
commit
242e0b4303
5 changed files with 290 additions and 18 deletions
|
@ -1727,7 +1727,7 @@ enum SimpleCallRoutines
|
||||||
HWNDLOCK_ROUTINE_SETSYSMENU,
|
HWNDLOCK_ROUTINE_SETSYSMENU,
|
||||||
HWNDLOCK_ROUTINE_UPDATECKIENTRECT,
|
HWNDLOCK_ROUTINE_UPDATECKIENTRECT,
|
||||||
HWNDLOCK_ROUTINE_UPDATEWINDOW,
|
HWNDLOCK_ROUTINE_UPDATEWINDOW,
|
||||||
X_ROUTINE_IMESHOWSTATUSCHANGE,
|
TWOPARAM_ROUTINE_IMESHOWSTATUSCHANGE,
|
||||||
TWOPARAM_ROUTINE_ENABLEWINDOW,
|
TWOPARAM_ROUTINE_ENABLEWINDOW,
|
||||||
TWOPARAM_ROUTINE_REDRAWTITLE,
|
TWOPARAM_ROUTINE_REDRAWTITLE,
|
||||||
TWOPARAM_ROUTINE_SHOWOWNEDPOPUPS,
|
TWOPARAM_ROUTINE_SHOWOWNEDPOPUPS,
|
||||||
|
|
|
@ -41,6 +41,7 @@ DBG_DEFAULT_CHANNEL(UserMisc);
|
||||||
HIMC ghIMC = NULL;
|
HIMC ghIMC = NULL;
|
||||||
BOOL gfImeOpen = (BOOL)-1;
|
BOOL gfImeOpen = (BOOL)-1;
|
||||||
DWORD gdwImeConversion = (DWORD)-1;
|
DWORD gdwImeConversion = (DWORD)-1;
|
||||||
|
BOOL gfIMEShowStatus = (BOOL)-1;
|
||||||
|
|
||||||
typedef struct tagIMEHOTKEY
|
typedef struct tagIMEHOTKEY
|
||||||
{
|
{
|
||||||
|
@ -2105,4 +2106,268 @@ BOOL FASTCALL IntImeCanDestroyDefIME(PWND pImeWnd, PWND pwndTarget)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update IMEUI.fShowStatus flags and Send the WM_IME_NOTIFY messages.
|
||||||
|
// Win: xxxCheckImeShowStatus
|
||||||
|
BOOL FASTCALL IntCheckImeShowStatus(PWND pwndIme, PTHREADINFO pti)
|
||||||
|
{
|
||||||
|
BOOL ret = FALSE, bDifferent;
|
||||||
|
PWINDOWLIST pwl;
|
||||||
|
HWND *phwnd;
|
||||||
|
PWND pwndNode, pwndIMC;
|
||||||
|
PTHREADINFO ptiCurrent = GetW32ThreadInfo();
|
||||||
|
PIMEUI pimeui;
|
||||||
|
IMEUI SafeImeUI;
|
||||||
|
|
||||||
|
if (pwndIme->state2 & WNDS2_INDESTROY)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
// Build a window list
|
||||||
|
pwl = IntBuildHwndList(pwndIme->spwndParent->spwndChild, IACE_LIST, NULL);
|
||||||
|
if (!pwl)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
for (phwnd = pwl->ahwnd; *phwnd != HWND_TERMINATOR; ++phwnd)
|
||||||
|
{
|
||||||
|
pwndNode = ValidateHwndNoErr(*phwnd);
|
||||||
|
|
||||||
|
if (!pwndNode || pwndIme == pwndNode)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pwndNode->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME] ||
|
||||||
|
(pwndNode->state2 & WNDS2_INDESTROY))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pimeui = ((PIMEWND)pwndNode)->pimeui;
|
||||||
|
if (!pimeui || pimeui == (PIMEUI)-1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pti && pti != pwndNode->head.pti)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Attach to the process if necessary
|
||||||
|
bDifferent = FALSE;
|
||||||
|
if (pwndNode->head.pti->ppi != ptiCurrent->ppi)
|
||||||
|
{
|
||||||
|
KeAttachProcess(&(pwndNode->head.pti->ppi->peProcess->Pcb));
|
||||||
|
bDifferent = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get pwndIMC and update IMEUI.fShowStatus flag
|
||||||
|
_SEH2_TRY
|
||||||
|
{
|
||||||
|
ProbeForWrite(pimeui, sizeof(IMEUI), 1);
|
||||||
|
SafeImeUI = *pimeui;
|
||||||
|
if (SafeImeUI.fShowStatus)
|
||||||
|
{
|
||||||
|
pwndIMC = ValidateHwndNoErr(pimeui->hwndIMC);
|
||||||
|
if (pwndIMC)
|
||||||
|
pimeui->fShowStatus = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pwndIMC = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
pwndIMC = NULL;
|
||||||
|
}
|
||||||
|
_SEH2_END;
|
||||||
|
|
||||||
|
// Detach from the process if necessary
|
||||||
|
if (bDifferent)
|
||||||
|
KeDetachProcess();
|
||||||
|
|
||||||
|
// Send the WM_IME_NOTIFY message
|
||||||
|
if (pwndIMC && pwndIMC->head.pti && !(pwndIMC->head.pti->TIF_flags & TIF_INCLEANUP))
|
||||||
|
{
|
||||||
|
HWND hImeWnd;
|
||||||
|
USER_REFERENCE_ENTRY Ref;
|
||||||
|
|
||||||
|
UserRefObjectCo(pwndIMC, &Ref);
|
||||||
|
|
||||||
|
hImeWnd = UserHMGetHandle(pwndIMC);
|
||||||
|
co_IntSendMessage(hImeWnd, WM_IME_NOTIFY, IMN_CLOSESTATUSWINDOW, 0);
|
||||||
|
|
||||||
|
UserDerefObjectCo(pwndIMC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free the window list
|
||||||
|
IntFreeHwndList(pwl);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send a UI message.
|
||||||
|
// Win: xxxSendMessageToUI
|
||||||
|
LRESULT FASTCALL
|
||||||
|
IntSendMessageToUI(PTHREADINFO ptiIME, PIMEUI pimeui, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
PWND pwndUI;
|
||||||
|
LRESULT ret = 0;
|
||||||
|
IMEUI SafeImeUI;
|
||||||
|
BOOL bDifferent = FALSE;
|
||||||
|
USER_REFERENCE_ENTRY Ref;
|
||||||
|
|
||||||
|
// Attach to the process if necessary
|
||||||
|
if (ptiIME != GetW32ThreadInfo())
|
||||||
|
{
|
||||||
|
bDifferent = TRUE;
|
||||||
|
KeAttachProcess(&(ptiIME->ppi->peProcess->Pcb));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the pwndUI
|
||||||
|
_SEH2_TRY
|
||||||
|
{
|
||||||
|
ProbeForRead(pimeui, sizeof(IMEUI), 1);
|
||||||
|
SafeImeUI = *pimeui;
|
||||||
|
pwndUI = ValidateHwndNoErr(SafeImeUI.hwndUI);
|
||||||
|
}
|
||||||
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
pwndUI = NULL;
|
||||||
|
}
|
||||||
|
_SEH2_END;
|
||||||
|
|
||||||
|
if (!pwndUI)
|
||||||
|
goto Quit;
|
||||||
|
|
||||||
|
// Increment the recursion count of the IME procedure.
|
||||||
|
// See also ImeWndProc_common of user32.
|
||||||
|
_SEH2_TRY
|
||||||
|
{
|
||||||
|
ProbeForWrite(&pimeui->nCntInIMEProc, sizeof(LONG), 1);
|
||||||
|
InterlockedIncrement(&pimeui->nCntInIMEProc);
|
||||||
|
}
|
||||||
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
goto Quit;
|
||||||
|
}
|
||||||
|
_SEH2_END;
|
||||||
|
|
||||||
|
// Detach from the process if necessary
|
||||||
|
if (bDifferent)
|
||||||
|
KeDetachProcess();
|
||||||
|
|
||||||
|
UserRefObjectCo(pwndUI, &Ref);
|
||||||
|
ret = co_IntSendMessage(UserHMGetHandle(pwndUI), uMsg, wParam, lParam);
|
||||||
|
UserDerefObjectCo(pwndUI);
|
||||||
|
|
||||||
|
// Attach to the process if necessary
|
||||||
|
if (bDifferent)
|
||||||
|
KeAttachProcess(&(ptiIME->ppi->peProcess->Pcb));
|
||||||
|
|
||||||
|
// Decrement the recursion count of the IME procedure
|
||||||
|
_SEH2_TRY
|
||||||
|
{
|
||||||
|
ProbeForWrite(&pimeui->nCntInIMEProc, sizeof(LONG), 1);
|
||||||
|
InterlockedDecrement(&pimeui->nCntInIMEProc);
|
||||||
|
}
|
||||||
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
goto Quit;
|
||||||
|
}
|
||||||
|
_SEH2_END;
|
||||||
|
|
||||||
|
Quit:
|
||||||
|
// Detach from the process if necessary
|
||||||
|
if (bDifferent)
|
||||||
|
KeDetachProcess();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the open status notification.
|
||||||
|
// Win: xxxSendOpenStatusNotify
|
||||||
|
VOID FASTCALL
|
||||||
|
IntSendOpenStatusNotify(PTHREADINFO ptiIME, PIMEUI pimeui, PWND pWnd, BOOL bOpen)
|
||||||
|
{
|
||||||
|
WPARAM wParam = (bOpen ? IMN_OPENSTATUSWINDOW : IMN_CLOSESTATUSWINDOW);
|
||||||
|
PTHREADINFO ptiWnd = pWnd->head.pti;
|
||||||
|
USER_REFERENCE_ENTRY Ref;
|
||||||
|
|
||||||
|
if (ptiWnd->dwExpWinVer >= WINVER_WINNT4 && pWnd->hImc)
|
||||||
|
{
|
||||||
|
UserRefObjectCo(pWnd, &Ref);
|
||||||
|
co_IntSendMessage(UserHMGetHandle(pWnd), WM_IME_NOTIFY, wParam, 0);
|
||||||
|
UserDerefObjectCo(pWnd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IntSendMessageToUI(ptiIME, pimeui, WM_IME_NOTIFY, wParam, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the IME status and send a notification.
|
||||||
|
// Win: xxxNotifyImeShowStatus
|
||||||
|
VOID FASTCALL IntNotifyImeShowStatus(PWND pImeWnd)
|
||||||
|
{
|
||||||
|
PIMEUI pimeui;
|
||||||
|
PWND pWnd;
|
||||||
|
PTHREADINFO pti, ptiIME;
|
||||||
|
BOOL bShow, bSendNotify = FALSE;
|
||||||
|
IMEUI SafeImeUI;
|
||||||
|
|
||||||
|
if (!IS_IMM_MODE() || (pImeWnd->state2 & WNDS2_INDESTROY))
|
||||||
|
return;
|
||||||
|
|
||||||
|
pti = PsGetCurrentThreadWin32Thread();
|
||||||
|
ptiIME = pImeWnd->head.pti;
|
||||||
|
|
||||||
|
// Attach to the process if necessary
|
||||||
|
if (pti != ptiIME)
|
||||||
|
KeAttachProcess(&(ptiIME->ppi->peProcess->Pcb));
|
||||||
|
|
||||||
|
// Get an IMEUI and check whether hwndIMC is valid and update fShowStatus
|
||||||
|
_SEH2_TRY
|
||||||
|
{
|
||||||
|
ProbeForWrite(pImeWnd, sizeof(IMEWND), 1);
|
||||||
|
pimeui = ((PIMEWND)pImeWnd)->pimeui;
|
||||||
|
SafeImeUI = *pimeui;
|
||||||
|
|
||||||
|
bShow = (gfIMEShowStatus == TRUE) && SafeImeUI.fCtrlShowStatus;
|
||||||
|
|
||||||
|
pWnd = ValidateHwndNoErr(SafeImeUI.hwndIMC);
|
||||||
|
if (!pWnd)
|
||||||
|
pWnd = ptiIME->MessageQueue->spwndFocus;
|
||||||
|
|
||||||
|
if (pWnd)
|
||||||
|
{
|
||||||
|
bSendNotify = TRUE;
|
||||||
|
pimeui->fShowStatus = bShow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
if (pti != ptiIME)
|
||||||
|
KeDetachProcess();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_SEH2_END;
|
||||||
|
|
||||||
|
// Detach from the process if necessary
|
||||||
|
if (pti != ptiIME)
|
||||||
|
KeDetachProcess();
|
||||||
|
|
||||||
|
if (bSendNotify)
|
||||||
|
IntSendOpenStatusNotify(ptiIME, &SafeImeUI, pWnd, bShow);
|
||||||
|
|
||||||
|
if (!(pImeWnd->state2 & WNDS2_INDESTROY))
|
||||||
|
IntCheckImeShowStatus(pImeWnd, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Win: xxxBroadcastImeShowStatusChange
|
||||||
|
BOOL FASTCALL IntBroadcastImeShowStatusChange(PWND pImeWnd, BOOL bShow)
|
||||||
|
{
|
||||||
|
if (gfIMEShowStatus == bShow || !IS_IMM_MODE())
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
gfIMEShowStatus = bShow;
|
||||||
|
IntNotifyImeShowStatus(pImeWnd);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -114,6 +114,10 @@ NtUserCallNoParam(DWORD Routine)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case NOPARAM_ROUTINE_GETIMESHOWSTATUS:
|
||||||
|
Result = !!gfIMEShowStatus;
|
||||||
|
break;
|
||||||
|
|
||||||
/* this is a ReactOS only case and is needed for gui-on-demand */
|
/* this is a ReactOS only case and is needed for gui-on-demand */
|
||||||
case NOPARAM_ROUTINE_ISCONSOLEMODE:
|
case NOPARAM_ROUTINE_ISCONSOLEMODE:
|
||||||
Result = (ScreenDeviceContext == NULL);
|
Result = (ScreenDeviceContext == NULL);
|
||||||
|
@ -895,11 +899,10 @@ NtUserCallHwndParamLock(
|
||||||
|
|
||||||
switch (Routine)
|
switch (Routine)
|
||||||
{
|
{
|
||||||
case X_ROUTINE_IMESHOWSTATUSCHANGE:
|
case TWOPARAM_ROUTINE_IMESHOWSTATUSCHANGE:
|
||||||
{
|
Ret = IntBroadcastImeShowStatusChange(Window, !!Param);
|
||||||
// TODO:
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case TWOPARAM_ROUTINE_VALIDATERGN:
|
case TWOPARAM_ROUTINE_VALIDATERGN:
|
||||||
{
|
{
|
||||||
PREGION Rgn = REGION_LockRgn((HRGN)Param);
|
PREGION Rgn = REGION_LockRgn((HRGN)Param);
|
||||||
|
|
|
@ -112,9 +112,13 @@ VOID FASTCALL IntFreeHwndList(PWINDOWLIST pwlTarget);
|
||||||
(((pWnd)->pcls->style & CS_IME) || \
|
(((pWnd)->pcls->style & CS_IME) || \
|
||||||
((pWnd)->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]))
|
((pWnd)->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]))
|
||||||
|
|
||||||
|
extern BOOL gfIMEShowStatus;
|
||||||
|
|
||||||
BOOL FASTCALL IntWantImeWindow(PWND pwndTarget);
|
BOOL FASTCALL IntWantImeWindow(PWND pwndTarget);
|
||||||
PWND FASTCALL co_IntCreateDefaultImeWindow(PWND pwndTarget, HINSTANCE hInst);
|
PWND FASTCALL co_IntCreateDefaultImeWindow(PWND pwndTarget, HINSTANCE hInst);
|
||||||
BOOL FASTCALL IntImeCanDestroyDefIMEforChild(PWND pImeWnd, PWND pwndTarget);
|
BOOL FASTCALL IntImeCanDestroyDefIMEforChild(PWND pImeWnd, PWND pwndTarget);
|
||||||
BOOL FASTCALL IntImeCanDestroyDefIME(PWND pImeWnd, PWND pwndTarget);
|
BOOL FASTCALL IntImeCanDestroyDefIME(PWND pImeWnd, PWND pwndTarget);
|
||||||
|
BOOL FASTCALL IntBroadcastImeShowStatusChange(PWND pImeWnd, BOOL bShow);
|
||||||
|
VOID FASTCALL IntNotifyImeShowStatus(PWND pImeWnd);
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -23,16 +23,18 @@ BOOL gbImmInitializing = FALSE; // Win: bImmInitializing
|
||||||
|
|
||||||
INT gfConIme = -1; // Win: gfConIme
|
INT gfConIme = -1; // Win: gfConIme
|
||||||
|
|
||||||
// Win: GetTopLevelWindow
|
HWND FASTCALL IntGetTopLevelWindow(HWND hWnd)
|
||||||
PWND FASTCALL User32GetTopLevelWindow(PWND pwnd)
|
|
||||||
{
|
{
|
||||||
if (!pwnd)
|
DWORD style;
|
||||||
return NULL;
|
|
||||||
|
|
||||||
while (pwnd->style & WS_CHILD)
|
for (; hWnd; hWnd = GetParent(hWnd))
|
||||||
pwnd = pwnd->spwndParent;
|
{
|
||||||
|
style = (DWORD)GetWindowLongPtrW(hWnd, GWL_STYLE);
|
||||||
|
if (!(style & WS_CHILD))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return pwnd;
|
return hWnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* define stub functions */
|
/* define stub functions */
|
||||||
|
@ -573,7 +575,7 @@ static LRESULT ImeWnd_OnImeSystem(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
|
||||||
if (User32GetImeShowStatus() == !lParam)
|
if (User32GetImeShowStatus() == !lParam)
|
||||||
{
|
{
|
||||||
hImeWnd = UserHMGetHandle(pimeui->spwnd);
|
hImeWnd = UserHMGetHandle(pimeui->spwnd);
|
||||||
NtUserCallHwndParamLock(hImeWnd, lParam, X_ROUTINE_IMESHOWSTATUSCHANGE);
|
NtUserCallHwndParamLock(hImeWnd, lParam, TWOPARAM_ROUTINE_IMESHOWSTATUSCHANGE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -707,7 +709,7 @@ LRESULT ImeWnd_OnImeSetContext(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
|
||||||
HIMC hIMC;
|
HIMC hIMC;
|
||||||
LPINPUTCONTEXTDX pIC;
|
LPINPUTCONTEXTDX pIC;
|
||||||
HWND hwndFocus, hwndOldImc, hwndNewImc, hImeWnd, hwndActive, hwndOwner;
|
HWND hwndFocus, hwndOldImc, hwndNewImc, hImeWnd, hwndActive, hwndOwner;
|
||||||
PWND pwndFocus, pwndOldImc, pwndNewImc, pImeWnd, pwndOwner;
|
PWND pwndFocus, pImeWnd, pwndOwner;
|
||||||
COMPOSITIONFORM CompForm;
|
COMPOSITIONFORM CompForm;
|
||||||
|
|
||||||
pimeui->fActivate = !!wParam;
|
pimeui->fActivate = !!wParam;
|
||||||
|
@ -813,10 +815,8 @@ LRESULT ImeWnd_OnImeSetContext(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
|
||||||
hwndNewImc = pimeui->hwndIMC;
|
hwndNewImc = pimeui->hwndIMC;
|
||||||
if (pimeui->fShowStatus)
|
if (pimeui->fShowStatus)
|
||||||
{
|
{
|
||||||
pwndNewImc = ValidateHwnd(hwndNewImc);
|
if (hwndOldImc && hwndNewImc && hwndOldImc != hwndNewImc &&
|
||||||
pwndOldImc = ValidateHwnd(hwndOldImc);
|
IntGetTopLevelWindow(hwndOldImc) != IntGetTopLevelWindow(hwndNewImc))
|
||||||
if (pwndNewImc && pwndOldImc && pwndNewImc != pwndOldImc &&
|
|
||||||
User32GetTopLevelWindow(pwndNewImc) != User32GetTopLevelWindow(pwndOldImc))
|
|
||||||
{
|
{
|
||||||
User32NotifyOpenStatus(pimeui, hwndOldImc, FALSE);
|
User32NotifyOpenStatus(pimeui, hwndOldImc, FALSE);
|
||||||
User32NotifyOpenStatus(pimeui, hwndNewImc, TRUE);
|
User32NotifyOpenStatus(pimeui, hwndNewImc, TRUE);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue