mirror of
https://github.com/reactos/reactos.git
synced 2024-06-29 01:12:06 +00:00
[NTUSER] Implement NtUserSetImeOwnerWindow (#4460)
- Add IntImeSetFutureOwner, IntGetLastTopMostWindowNoIME, IntImeSetTopMost, and IntImeCheckTopmost helper functions. - Implement NtUserSetImeOwnerWindow function. CORE-11700
This commit is contained in:
parent
11d9c88c35
commit
291a94cd6f
|
@ -1344,7 +1344,6 @@ PWND FASTCALL co_GetDesktopWindow(PWND pWnd)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Win: _GetDesktopWindow
|
|
||||||
HWND FASTCALL IntGetDesktopWindow(VOID)
|
HWND FASTCALL IntGetDesktopWindow(VOID)
|
||||||
{
|
{
|
||||||
PDESKTOP pdo = IntGetActiveDesktop();
|
PDESKTOP pdo = IntGetActiveDesktop();
|
||||||
|
@ -1356,6 +1355,7 @@ HWND FASTCALL IntGetDesktopWindow(VOID)
|
||||||
return pdo->DesktopWindow;
|
return pdo->DesktopWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Win: _GetDesktopWindow
|
||||||
PWND FASTCALL UserGetDesktopWindow(VOID)
|
PWND FASTCALL UserGetDesktopWindow(VOID)
|
||||||
{
|
{
|
||||||
PDESKTOP pdo = IntGetActiveDesktop();
|
PDESKTOP pdo = IntGetActiveDesktop();
|
||||||
|
@ -1369,7 +1369,6 @@ PWND FASTCALL UserGetDesktopWindow(VOID)
|
||||||
return UserGetWindowObject(pdo->DesktopWindow);
|
return UserGetWindowObject(pdo->DesktopWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Win: _GetMessageWindow
|
|
||||||
HWND FASTCALL IntGetMessageWindow(VOID)
|
HWND FASTCALL IntGetMessageWindow(VOID)
|
||||||
{
|
{
|
||||||
PDESKTOP pdo = IntGetActiveDesktop();
|
PDESKTOP pdo = IntGetActiveDesktop();
|
||||||
|
@ -1382,6 +1381,7 @@ HWND FASTCALL IntGetMessageWindow(VOID)
|
||||||
return pdo->spwndMessage->head.h;
|
return pdo->spwndMessage->head.h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Win: _GetMessageWindow
|
||||||
PWND FASTCALL UserGetMessageWindow(VOID)
|
PWND FASTCALL UserGetMessageWindow(VOID)
|
||||||
{
|
{
|
||||||
PDESKTOP pdo = IntGetActiveDesktop();
|
PDESKTOP pdo = IntGetActiveDesktop();
|
||||||
|
|
|
@ -21,9 +21,14 @@ DBG_DEFAULT_CHANNEL(UserMisc);
|
||||||
#define LANGID_CHINESE_TRADITIONAL MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)
|
#define LANGID_CHINESE_TRADITIONAL MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)
|
||||||
#define LANGID_NEUTRAL MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)
|
#define LANGID_NEUTRAL MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)
|
||||||
|
|
||||||
|
// The IME-like windows are the IME windows and the IME UI windows.
|
||||||
|
// The IME window's class name is "IME".
|
||||||
|
// The IME UI window behaves the User Interface of IME for the user.
|
||||||
#define IS_WND_IMELIKE(pwnd) \
|
#define IS_WND_IMELIKE(pwnd) \
|
||||||
(((pwnd)->pcls->style & CS_IME) || \
|
(((pwnd)->pcls->style & CS_IME) || \
|
||||||
((pwnd)->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]))
|
((pwnd)->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]))
|
||||||
|
#define IS_WND_MENU(pWnd) \
|
||||||
|
((pWnd)->pcls->atomClassName == gpsi->atomSysClass[ICLS_MENU])
|
||||||
|
|
||||||
// The special virtual keys for Japanese: Used for key states.
|
// The special virtual keys for Japanese: Used for key states.
|
||||||
// https://www.kthree.co.jp/kihelp/index.html?page=app/vkey&type=html
|
// https://www.kthree.co.jp/kihelp/index.html?page=app/vkey&type=html
|
||||||
|
@ -1142,11 +1147,212 @@ Quit:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Choose the preferred owner of the IME window.
|
||||||
|
// Win: ImeSetFutureOwner
|
||||||
|
VOID FASTCALL IntImeSetFutureOwner(PWND pImeWnd, PWND pwndOwner)
|
||||||
|
{
|
||||||
|
PWND pwndNode, pwndNextOwner, pwndParent, pwndSibling;
|
||||||
|
PTHREADINFO pti = pImeWnd->head.pti;
|
||||||
|
|
||||||
|
if (!pwndOwner || (pwndOwner->style & WS_CHILD)) // invalid owner
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get the top-level owner of the same thread
|
||||||
|
for (pwndNode = pwndOwner; ; pwndNode = pwndNextOwner)
|
||||||
|
{
|
||||||
|
pwndNextOwner = pwndNode->spwndOwner;
|
||||||
|
if (!pwndNextOwner || pwndNextOwner->head.pti != pti)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't choose the IME-like windows and the bottom-most windows unless necessary.
|
||||||
|
if (IS_WND_IMELIKE(pwndNode) ||
|
||||||
|
((pwndNode->state2 & WNDS2_BOTTOMMOST) && !(pwndOwner->state2 & WNDS2_BOTTOMMOST)))
|
||||||
|
{
|
||||||
|
pwndNode = pwndOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
pwndParent = pwndNode->spwndParent;
|
||||||
|
if (!pwndParent || pwndOwner != pwndNode)
|
||||||
|
{
|
||||||
|
pImeWnd->spwndOwner = pwndNode;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (pwndSibling = pwndParent->spwndChild; pwndSibling; pwndSibling = pwndSibling->spwndNext)
|
||||||
|
{
|
||||||
|
if (pwndNode->head.pti != pwndSibling->head.pti)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (IS_WND_MENU(pwndSibling) || IS_WND_IMELIKE(pwndSibling))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pwndSibling->state2 & WNDS2_INDESTROY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pwndNode == pwndSibling || (pwndSibling->style & WS_CHILD))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pwndSibling->spwndOwner == NULL ||
|
||||||
|
pwndSibling->head.pti != pwndSibling->spwndOwner->head.pti)
|
||||||
|
{
|
||||||
|
pwndNode = pwndSibling;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pImeWnd->spwndOwner = pwndNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the last non-IME-like top-most window on the desktop.
|
||||||
|
// Win: GetLastTopMostWindowNoIME
|
||||||
|
PWND FASTCALL IntGetLastTopMostWindowNoIME(PWND pImeWnd)
|
||||||
|
{
|
||||||
|
PWND pwndNode, pwndOwner, pwndLastTopMost = NULL;
|
||||||
|
BOOL bFound;
|
||||||
|
|
||||||
|
pwndNode = UserGetDesktopWindow();
|
||||||
|
if (!pwndNode || pwndNode->spwndChild == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (pwndNode = pwndNode->spwndChild;
|
||||||
|
pwndNode && (pwndNode->ExStyle & WS_EX_TOPMOST);
|
||||||
|
pwndNode = pwndNode->spwndNext)
|
||||||
|
{
|
||||||
|
bFound = FALSE;
|
||||||
|
|
||||||
|
if (IS_WND_IMELIKE(pwndNode)) // An IME-like window
|
||||||
|
{
|
||||||
|
// Search the IME window from owners
|
||||||
|
for (pwndOwner = pwndNode; pwndOwner; pwndOwner = pwndOwner->spwndOwner)
|
||||||
|
{
|
||||||
|
if (pImeWnd == pwndOwner)
|
||||||
|
{
|
||||||
|
bFound = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bFound)
|
||||||
|
pwndLastTopMost = pwndNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pwndLastTopMost;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust the ordering of the windows around the IME window.
|
||||||
|
// Win: ImeSetTopMost
|
||||||
|
VOID FASTCALL IntImeSetTopMost(PWND pImeWnd, BOOL bTopMost, PWND pwndInsertBefore)
|
||||||
|
{
|
||||||
|
PWND pwndParent, pwndChild, pwndNode, pwndNext, pwndInsertAfter = NULL;
|
||||||
|
PWND pwndInsertAfterSave;
|
||||||
|
|
||||||
|
pwndParent = pImeWnd->spwndParent;
|
||||||
|
if (!pwndParent)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pwndChild = pwndParent->spwndChild;
|
||||||
|
|
||||||
|
if (!bTopMost)
|
||||||
|
{
|
||||||
|
// Calculate pwndInsertAfter
|
||||||
|
pwndInsertAfter = IntGetLastTopMostWindowNoIME(pImeWnd);
|
||||||
|
if (pwndInsertBefore)
|
||||||
|
{
|
||||||
|
for (pwndNode = pwndInsertAfter; pwndNode; pwndNode = pwndNode->spwndNext)
|
||||||
|
{
|
||||||
|
if (pwndNode->spwndNext == pwndInsertBefore)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (pwndNode == pImeWnd)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pwndNode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pwndInsertAfter = pwndNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust pwndInsertAfter if the owner is bottom-most
|
||||||
|
if (pImeWnd->spwndOwner->state2 & WNDS2_BOTTOMMOST)
|
||||||
|
{
|
||||||
|
for (pwndNode = pwndInsertAfter; pwndNode; pwndNode = pwndNode->spwndNext)
|
||||||
|
{
|
||||||
|
if (pwndNode == pImeWnd->spwndOwner)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!IS_WND_IMELIKE(pwndNode))
|
||||||
|
pwndInsertAfter = pwndNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pwndInsertAfterSave = pwndInsertAfter;
|
||||||
|
|
||||||
|
while (pwndChild)
|
||||||
|
{
|
||||||
|
pwndNext = pwndChild->spwndNext;
|
||||||
|
|
||||||
|
// If pwndChild is a good IME-like window, ...
|
||||||
|
if (IS_WND_IMELIKE(pwndChild) && pwndChild != pwndInsertAfter &&
|
||||||
|
pwndChild->head.pti == pImeWnd->head.pti)
|
||||||
|
{
|
||||||
|
// Find pImeWnd from the owners
|
||||||
|
for (pwndNode = pwndChild; pwndNode; pwndNode = pwndNode->spwndOwner)
|
||||||
|
{
|
||||||
|
if (pwndNode != pImeWnd)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Adjust the ordering and the linking
|
||||||
|
IntUnlinkWindow(pwndChild);
|
||||||
|
|
||||||
|
if (bTopMost)
|
||||||
|
pwndChild->ExStyle |= WS_EX_TOPMOST;
|
||||||
|
else
|
||||||
|
pwndChild->ExStyle &= ~WS_EX_TOPMOST;
|
||||||
|
|
||||||
|
if (!pwndInsertAfter)
|
||||||
|
IntLinkHwnd(pwndChild, HWND_TOP);
|
||||||
|
else
|
||||||
|
IntLinkHwnd(pwndChild, UserHMGetHandle(pwndInsertAfter));
|
||||||
|
|
||||||
|
// Update the preferred position
|
||||||
|
pwndInsertAfter = pwndChild;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the next child, with ignoring pwndInsertAfterSave
|
||||||
|
pwndChild = pwndNext;
|
||||||
|
if (pwndChild && pwndChild == pwndInsertAfterSave && pwndInsertAfter)
|
||||||
|
pwndChild = pwndInsertAfter->spwndNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the IME window top-most if necessary.
|
||||||
|
// Win: ImeCheckTopmost
|
||||||
|
VOID FASTCALL IntImeCheckTopmost(PWND pImeWnd)
|
||||||
|
{
|
||||||
|
BOOL bTopMost;
|
||||||
|
PWND pwndOwner = pImeWnd->spwndOwner, pwndInsertBefore = NULL;
|
||||||
|
|
||||||
|
if (!pwndOwner)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (pImeWnd->head.pti != gptiForeground)
|
||||||
|
pwndInsertBefore = pwndOwner;
|
||||||
|
|
||||||
|
bTopMost = !!(pwndOwner->ExStyle & WS_EX_TOPMOST);
|
||||||
|
IntImeSetTopMost(pImeWnd, bTopMost, pwndInsertBefore);
|
||||||
|
}
|
||||||
|
|
||||||
BOOL NTAPI
|
BOOL NTAPI
|
||||||
NtUserSetImeOwnerWindow(HWND hImeWnd, HWND hwndFocus)
|
NtUserSetImeOwnerWindow(HWND hImeWnd, HWND hwndFocus)
|
||||||
{
|
{
|
||||||
BOOL ret = FALSE;
|
BOOL ret = FALSE;
|
||||||
PWND pImeWnd, pwndFocus, pwndTopLevel, pwnd, pwndActive;
|
PWND pImeWnd, pwndFocus, pwndTopLevel, pwndNode, pwndActive;
|
||||||
PTHREADINFO ptiIme;
|
PTHREADINFO ptiIme;
|
||||||
|
|
||||||
UserEnterExclusive();
|
UserEnterExclusive();
|
||||||
|
@ -1169,9 +1375,9 @@ NtUserSetImeOwnerWindow(HWND hImeWnd, HWND hwndFocus)
|
||||||
|
|
||||||
pwndTopLevel = IntGetTopLevelWindow(pwndFocus);
|
pwndTopLevel = IntGetTopLevelWindow(pwndFocus);
|
||||||
|
|
||||||
for (pwnd = pwndTopLevel; pwnd; pwnd = pwnd->spwndOwner)
|
for (pwndNode = pwndTopLevel; pwndNode; pwndNode = pwndNode->spwndOwner)
|
||||||
{
|
{
|
||||||
if (pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME])
|
if (pwndNode->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME])
|
||||||
{
|
{
|
||||||
pwndTopLevel = NULL;
|
pwndTopLevel = NULL;
|
||||||
break;
|
break;
|
||||||
|
@ -1179,7 +1385,7 @@ NtUserSetImeOwnerWindow(HWND hImeWnd, HWND hwndFocus)
|
||||||
}
|
}
|
||||||
|
|
||||||
pImeWnd->spwndOwner = pwndTopLevel;
|
pImeWnd->spwndOwner = pwndTopLevel;
|
||||||
// TODO:
|
IntImeCheckTopmost(pImeWnd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1194,10 +1400,10 @@ NtUserSetImeOwnerWindow(HWND hImeWnd, HWND hwndFocus)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO:
|
IntImeSetFutureOwner(pImeWnd, pImeWnd->spwndOwner);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:
|
IntImeCheckTopmost(pImeWnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue