mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 09:34: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_UPDATECKIENTRECT,
|
||||
HWNDLOCK_ROUTINE_UPDATEWINDOW,
|
||||
X_ROUTINE_IMESHOWSTATUSCHANGE,
|
||||
TWOPARAM_ROUTINE_IMESHOWSTATUSCHANGE,
|
||||
TWOPARAM_ROUTINE_ENABLEWINDOW,
|
||||
TWOPARAM_ROUTINE_REDRAWTITLE,
|
||||
TWOPARAM_ROUTINE_SHOWOWNEDPOPUPS,
|
||||
|
|
|
@ -41,6 +41,7 @@ DBG_DEFAULT_CHANNEL(UserMisc);
|
|||
HIMC ghIMC = NULL;
|
||||
BOOL gfImeOpen = (BOOL)-1;
|
||||
DWORD gdwImeConversion = (DWORD)-1;
|
||||
BOOL gfIMEShowStatus = (BOOL)-1;
|
||||
|
||||
typedef struct tagIMEHOTKEY
|
||||
{
|
||||
|
@ -2105,4 +2106,268 @@ BOOL FASTCALL IntImeCanDestroyDefIME(PWND pImeWnd, PWND pwndTarget)
|
|||
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 */
|
||||
|
|
|
@ -114,6 +114,10 @@ NtUserCallNoParam(DWORD Routine)
|
|||
break;
|
||||
}
|
||||
|
||||
case NOPARAM_ROUTINE_GETIMESHOWSTATUS:
|
||||
Result = !!gfIMEShowStatus;
|
||||
break;
|
||||
|
||||
/* this is a ReactOS only case and is needed for gui-on-demand */
|
||||
case NOPARAM_ROUTINE_ISCONSOLEMODE:
|
||||
Result = (ScreenDeviceContext == NULL);
|
||||
|
@ -895,11 +899,10 @@ NtUserCallHwndParamLock(
|
|||
|
||||
switch (Routine)
|
||||
{
|
||||
case X_ROUTINE_IMESHOWSTATUSCHANGE:
|
||||
{
|
||||
// TODO:
|
||||
case TWOPARAM_ROUTINE_IMESHOWSTATUSCHANGE:
|
||||
Ret = IntBroadcastImeShowStatusChange(Window, !!Param);
|
||||
break;
|
||||
}
|
||||
|
||||
case TWOPARAM_ROUTINE_VALIDATERGN:
|
||||
{
|
||||
PREGION Rgn = REGION_LockRgn((HRGN)Param);
|
||||
|
|
|
@ -112,9 +112,13 @@ VOID FASTCALL IntFreeHwndList(PWINDOWLIST pwlTarget);
|
|||
(((pWnd)->pcls->style & CS_IME) || \
|
||||
((pWnd)->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]))
|
||||
|
||||
extern BOOL gfIMEShowStatus;
|
||||
|
||||
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);
|
||||
BOOL FASTCALL IntBroadcastImeShowStatusChange(PWND pImeWnd, BOOL bShow);
|
||||
VOID FASTCALL IntNotifyImeShowStatus(PWND pImeWnd);
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -23,16 +23,18 @@ BOOL gbImmInitializing = FALSE; // Win: bImmInitializing
|
|||
|
||||
INT gfConIme = -1; // Win: gfConIme
|
||||
|
||||
// Win: GetTopLevelWindow
|
||||
PWND FASTCALL User32GetTopLevelWindow(PWND pwnd)
|
||||
HWND FASTCALL IntGetTopLevelWindow(HWND hWnd)
|
||||
{
|
||||
if (!pwnd)
|
||||
return NULL;
|
||||
DWORD style;
|
||||
|
||||
while (pwnd->style & WS_CHILD)
|
||||
pwnd = pwnd->spwndParent;
|
||||
for (; hWnd; hWnd = GetParent(hWnd))
|
||||
{
|
||||
style = (DWORD)GetWindowLongPtrW(hWnd, GWL_STYLE);
|
||||
if (!(style & WS_CHILD))
|
||||
break;
|
||||
}
|
||||
|
||||
return pwnd;
|
||||
return hWnd;
|
||||
}
|
||||
|
||||
/* define stub functions */
|
||||
|
@ -573,7 +575,7 @@ static LRESULT ImeWnd_OnImeSystem(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
|
|||
if (User32GetImeShowStatus() == !lParam)
|
||||
{
|
||||
hImeWnd = UserHMGetHandle(pimeui->spwnd);
|
||||
NtUserCallHwndParamLock(hImeWnd, lParam, X_ROUTINE_IMESHOWSTATUSCHANGE);
|
||||
NtUserCallHwndParamLock(hImeWnd, lParam, TWOPARAM_ROUTINE_IMESHOWSTATUSCHANGE);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -707,7 +709,7 @@ LRESULT ImeWnd_OnImeSetContext(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
|
|||
HIMC hIMC;
|
||||
LPINPUTCONTEXTDX pIC;
|
||||
HWND hwndFocus, hwndOldImc, hwndNewImc, hImeWnd, hwndActive, hwndOwner;
|
||||
PWND pwndFocus, pwndOldImc, pwndNewImc, pImeWnd, pwndOwner;
|
||||
PWND pwndFocus, pImeWnd, pwndOwner;
|
||||
COMPOSITIONFORM CompForm;
|
||||
|
||||
pimeui->fActivate = !!wParam;
|
||||
|
@ -813,10 +815,8 @@ LRESULT ImeWnd_OnImeSetContext(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
|
|||
hwndNewImc = pimeui->hwndIMC;
|
||||
if (pimeui->fShowStatus)
|
||||
{
|
||||
pwndNewImc = ValidateHwnd(hwndNewImc);
|
||||
pwndOldImc = ValidateHwnd(hwndOldImc);
|
||||
if (pwndNewImc && pwndOldImc && pwndNewImc != pwndOldImc &&
|
||||
User32GetTopLevelWindow(pwndNewImc) != User32GetTopLevelWindow(pwndOldImc))
|
||||
if (hwndOldImc && hwndNewImc && hwndOldImc != hwndNewImc &&
|
||||
IntGetTopLevelWindow(hwndOldImc) != IntGetTopLevelWindow(hwndNewImc))
|
||||
{
|
||||
User32NotifyOpenStatus(pimeui, hwndOldImc, FALSE);
|
||||
User32NotifyOpenStatus(pimeui, hwndNewImc, TRUE);
|
||||
|
|
Loading…
Reference in a new issue