Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1439 lines
38 KiB

/**************************************************************************\
* Module Name: ntimm.c
*
* Copyright (c) Microsoft Corp. 1995 All Rights Reserved
*
* This module contains IMM functionality
*
* History:
* 21-Dec-1995 wkwok
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
#ifdef FE_IME
/**************************************************************************\
* xxxCreateInputContext
*
* Create input context object.
*
* History:
* 21-Dec-1995 wkwok Created
\**************************************************************************/
PIMC xxxCreateInputContext(
DWORD dwClientImcData)
{
PTHREADINFO ptiCurrent;
PIMC pImc;
TL tlpimc;
PDESKTOP pdesk = NULL;
ptiCurrent = PtiCurrent();
/*
* Only for thread that wants IME processing.
*/
if (ptiCurrent->TIF_flags & TIF_DISABLEIME)
return NULL;
/*
* If the windowstation has been initialized, allocate from
* the current desktop.
*/
pdesk = ptiCurrent->rpdesk;
#ifdef LATER
RETURN_IF_ACCESS_DENIED(ptiCurrent->amdesk, DESKTOP_CREATEINPUTCONTEXT, NULL);
#else
if (ptiCurrent->rpdesk == NULL) {
return NULL;
}
#endif
pImc = HMAllocObject(ptiCurrent, pdesk, TYPE_INPUTCONTEXT, sizeof(IMC));
if (pImc == NULL) {
RIPMSG0(RIP_WARNING, "xxxCreateInputContext: out of memory");
return NULL;
}
if (dwClientImcData == 0) {
/*
* We are creating default input context for current thread.
* Initialize the default input context as head of the
* per-thread IMC list.
*/
UserAssert(ptiCurrent->spDefaultImc == NULL);
Lock(&ptiCurrent->spDefaultImc, pImc);
pImc->pImcNext = NULL;
/*
* Callback to create client side default input context
* for IME based keyboard layout.
*/
if (ptiCurrent->spklActive != NULL &&
IS_IME_KBDLAYOUT(ptiCurrent->spklActive->hkl)) {
ThreadLockAlwaysWithPti(ptiCurrent, pImc, &tlpimc);
ClientImmCreateDefaultContext((HIMC)PtoH(pImc));
return ThreadUnlock(&tlpimc);
}
}
else {
/*
* Link it to the per-thread IMC list.
*/
UserAssert(ptiCurrent->spDefaultImc != NULL);
pImc->pImcNext = ptiCurrent->spDefaultImc->pImcNext;
ptiCurrent->spDefaultImc->pImcNext = pImc;
pImc->dwClientImcData = dwClientImcData;
}
return pImc;
}
/**************************************************************************\
* DestroyInputContext
*
* Destroy the specified input context object.
*
* History:
* 21-Dec-1995 wkwok Created
\**************************************************************************/
BOOL DestroyInputContext(
IN PIMC pImc)
{
PTHREADINFO ptiImcOwner;
PBWL pbwl;
PWND pwnd;
HWND *phwnd;
PHE phe;
ptiImcOwner = GETPTI(pImc);
/*
* Cannot destroy input context from other thread.
*/
if (ptiImcOwner != PtiCurrent()) {
RIPMSG0(ERROR_ACCESS_DENIED,
"DestroyInputContext: pImc not of current pti");
return FALSE;
}
/*
* Cannot destroy default input context.
*/
if (pImc == ptiImcOwner->spDefaultImc) {
RIPMSG0(ERROR_INVALID_PARAMETER,
"DestroyInputContext: can't destroy default Imc");
return FALSE;
}
/*
* Cleanup destroyed input context from each associated window.
*/
pbwl = BuildHwndList(ptiImcOwner->rpdesk->pDeskInfo->spwnd->spwndChild,
BWL_ENUMLIST|BWL_ENUMCHILDREN, ptiImcOwner);
if (pbwl != NULL) {
for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
/*
* Make sure this hwnd is still around.
*/
if ((pwnd = RevalidateHwnd(*phwnd)) == NULL)
continue;
/*
* Cleanup by associating the default input context.
*/
if (pwnd->hImc == (HIMC)PtoH(pImc))
AssociateInputContext(pwnd, ptiImcOwner->spDefaultImc);
}
FreeHwndList(pbwl);
}
phe = HMPheFromObject(pImc);
/*
* Make sure this object isn't already marked to be destroyed - we'll
* do no good if we try to destroy it now since it is locked.
*/
if (!(phe->bFlags & HANDLEF_DESTROY))
HMDestroyUnlockedObject(phe);
return TRUE;
}
/**************************************************************************\
* FreeInputContext
*
* Free up the specified input context object.
*
* History:
* 21-Dec-1995 wkwok Created
\**************************************************************************/
VOID FreeInputContext(
IN PIMC pImc)
{
PIMC pImcT;
/*
* Mark it for destruction. If it the object is locked it can't
* be freed right now.
*/
if (!HMMarkObjectDestroy((PVOID)pImc))
return;
/*
* Unlink it.
*/
pImcT = GETPTI(pImc)->spDefaultImc;
while (pImcT != NULL && pImcT->pImcNext != pImc)
pImcT = pImcT->pImcNext;
if (pImcT != NULL)
pImcT->pImcNext = pImc->pImcNext;
/*
* We're really going to free the input context.
*/
HMFreeObject((PVOID)pImc);
return;
}
/**************************************************************************\
* UpdateInputContext
*
* Update the specified input context object according to UpdateType.
*
* History:
* 21-Dec-1995 wkwok Created
\**************************************************************************/
BOOL UpdateInputContext(
IN PIMC pImc,
IN UPDATEINPUTCONTEXTCLASS UpdateType,
IN DWORD UpdateValue)
{
PTHREADINFO ptiCurrent, ptiImcOwner;
ptiCurrent = PtiCurrent();
ptiImcOwner = GETPTI(pImc);
/*
* Cannot update input context from other process.
*/
if (ptiImcOwner->ppi != ptiCurrent->ppi) {
RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "UpdateInputContext: pImc not of current ppi");
return FALSE;
}
switch (UpdateType) {
case UpdateClientInputContext:
if (pImc->dwClientImcData != 0) {
RIPERR0(RIP_WARNING, RIP_WARNING, "UpdateInputContext: pImc->dwClientImcData != 0");
return FALSE;
}
pImc->dwClientImcData = UpdateValue;
break;
case UpdateInUseImeWindow:
pImc->hImeWnd = (HWND)UpdateValue;
break;
default:
return FALSE;
}
return TRUE;
}
/**************************************************************************\
* AssociateInputContext
*
* Associate input context object to the specified window.
*
* History:
* 21-Dec-1995 wkwok Created
\**************************************************************************/
HIMC AssociateInputContext(
IN PWND pWnd,
IN PIMC pImc)
{
HIMC hRetImc;
/*
* Cannot associate input context to window created
* by other thread.
*/
if (pImc != NULL && GETPTI(pImc) != GETPTI(pWnd)) {
RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "AssociateInputContext: pwnd not of Imc pti");
return NULL_HIMC;
}
/*
* Cannot do association under different process context.
*/
if (GETPTI(pWnd)->ppi != PtiCurrent()->ppi) {
RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "AssociateInputContext: pwnd not of current ppi");
return NULL_HIMC;
}
/*
* Finally, make sure they are on the same desktop.
*/
if (pImc != NULL && pImc->head.rpdesk != pWnd->head.rpdesk) {
RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "AssociateInputContext: no desktop access");
return NULL_HIMC;
}
hRetImc = pWnd->hImc;
pWnd->hImc = (HIMC)PtoH(pImc);
return hRetImc;
}
/**************************************************************************\
* xxxFocusSetInputContext
*
* Set active input context upon focus change.
*
* History:
* 21-Mar-1996 wkwok Created
\**************************************************************************/
VOID xxxFocusSetInputContext(
IN PWND pWnd,
IN BOOL fActivate)
{
PTHREADINFO pti;
PWND pwndDefaultIme;
TL tlpwndDefaultIme;
CheckLock(pWnd);
pti = GETPTI(pWnd);
/*
* CS_IME class or "IME" class windows can not be SetActivated to hImc.
* WinWord 6.0 US Help calls ShowWindow with the default IME window.
* HELPMACROS get the default IME window by calling GetNextWindow().
*/
if (TestCF(pWnd, CFIME) ||
(pWnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]))
return;
/*
* Do nothing if the thread does not have default IME window.
*/
if ((pwndDefaultIme = pti->spwndDefaultIme) == NULL)
return;
#ifdef LATER
if (pti != PtiCurrent() && pti->pq != gpqForeground) {
RemoveEventMessage(pti->pq, QEVENT_IMEACTIVATECONTEXT, (DWORD)-1);
PostEventMessage(pti, pti->pq,QEVENT_IMEACTIVATECONTEXT,NULL, 0,
(DWORD)HWq(pWnd), (LONG)fActivate);
return;
}
#endif
ThreadLockAlways(pwndDefaultIme, &tlpwndDefaultIme);
xxxSendMessage(pwndDefaultIme, WM_IME_SYSTEM,
fActivate ? IMS_ACTIVATECONTEXT : IMS_DEACTIVATECONTEXT,
(LONG)HWq(pWnd));
ThreadUnlock(&tlpwndDefaultIme);
return;
}
/**************************************************************************\
* BuildHimcList
*
* Retrieve the list of input context handles created by given thread.
*
* History:
* 21-Feb-1995 wkwok Created
\**************************************************************************/
UINT BuildHimcList(
PTHREADINFO pti,
UINT cHimcMax,
HIMC *phimcFirst)
{
PIMC pImcT;
UINT i = 0;
if (pti == NULL) {
/*
* Build the list which contains all IMCs created by calling process.
*/
for (pti = PtiCurrent()->ppi->ptiList; pti != NULL; pti = pti->ptiSibling) {
pImcT = pti->spDefaultImc;
while (pImcT != NULL) {
if (i < cHimcMax)
phimcFirst[i] = (HIMC)PtoH(pImcT);
i++;
pImcT = pImcT->pImcNext;
}
}
}
else {
/*
* Build the list which contains all IMCs created by specified thread.
*/
pImcT = pti->spDefaultImc;
while (pImcT != NULL) {
if (i < cHimcMax)
phimcFirst[i] = (HIMC)PtoH(pImcT);
i++;
pImcT = pImcT->pImcNext;
}
}
return i;
}
/**************************************************************************\
* xxxCreateDefaultImeWindow
*
* Create per-thread based default IME window.
*
* History:
* 21-Mar-1996 wkwok Created
\**************************************************************************/
PWND xxxCreateDefaultImeWindow(
IN PWND pwnd,
IN ATOM atomT,
IN HANDLE hInst)
{
LARGE_STRING strWindowName;
PWND pwndDefaultIme;
TL tlpwnd;
PIMEUI pimeui;
PTHREADINFO ptiCurrent = PtiCurrent();
UserAssert(ptiCurrent == GETPTI(pwnd) && ptiCurrent->spwndDefaultIme == NULL);
/*
* Only for thread that wants IME processing.
*/
if (ptiCurrent->TIF_flags & TIF_DISABLEIME)
return (PWND)NULL;
/*
* Don't need IME window processing for server side window proc.
*/
if (TestWF(pwnd, WFSERVERSIDEPROC))
return (PWND)NULL;
/*
* No default IME window for thread that doesn't have
* default input context
*/
if (ptiCurrent->spDefaultImc == NULL)
return (PWND)NULL;
/*
* Avoid recursion
*/
if (atomT == gpsi->atomSysClass[ICLS_IME] || TestCF(pwnd, CFIME))
return (PWND)NULL;
/*
* B#12165-win95b
* Yet MFC does another nice. We need to avoid to give an IME window
* to the child of desktop window which is in different process.
*/
if (TestwndChild(pwnd) && GETPTI(pwnd->spwndParent) != ptiCurrent &&
!(pwnd->style & WS_VISIBLE))
return (PWND)NULL;
RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)&strWindowName,
L"Default IME",
(UINT)-1);
ThreadLock(pwnd, &tlpwnd);
pwndDefaultIme = xxxCreateWindowEx( (DWORD)0,
(PLARGE_STRING)gpsi->atomSysClass[ICLS_IME],
(PLARGE_STRING)&strWindowName,
WS_POPUP | WS_DISABLED,
0, 0, 0, 0,
pwnd, (PMENU)NULL,
hInst, NULL, VER40);
if (pwndDefaultIme != NULL) {
pimeui = ((PIMEWND)pwndDefaultIme)->pimeui;
UserAssert(pimeui != NULL && (LONG)pimeui != (LONG)-1);
pimeui->fDefault = TRUE;
if (TestwndChild(pwnd) && GETPTI(pwnd->spwndParent) != ptiCurrent)
pimeui->fChildThreadDef = TRUE;
}
ThreadUnlock(&tlpwnd);
return pwndDefaultIme;
}
/**************************************************************************\
* xxxImmActivateThreadsLayout
*
* Activate keyboard layout for multiple threads.
*
* Return:
* TRUE if at least one thread has changed its active keyboard layout.
* FALSE otherwise
*
* History:
* 11-Apr-1996 wkwok Created
\**************************************************************************/
BOOL xxxImmActivateThreadsLayout(
PTHREADINFO pti,
PTLBLOCK ptlBlockPrev,
PKL pkl)
{
TLBLOCK tlBlock;
PTHREADINFO ptiCurrent, ptiT;
UINT cThreads = 0;
INT i;
#ifdef LATER // until IanJa has done the pkl locking.
CheckLock(pkl);
#endif
ptiCurrent = PtiCurrent();
/*
* Build a list of threads that we need to update their active layouts.
* We can't just walk the ptiT list while we're doing the work, because
* for IME based keyboard layout, we will do callback to client side
* and the ptiT could get deleted out while we leave the critical section.
*/
for (ptiT = pti; ptiT != NULL; ptiT = ptiT->ptiSibling) {
if (ptiT->spklActive == pkl)
continue;
ThreadLockPti(ptiCurrent, ptiT, &tlBlock.tlptiList[cThreads]);
tlBlock.ptiList[cThreads++] = ptiT;
if (cThreads == THREADS_PER_TLBLOCK)
break;
}
/*
* Return FALSE if all the threads already had the pkl active.
*/
if (ptlBlockPrev == NULL && ptiT == NULL && cThreads == 0)
return FALSE;
/*
* If we can't service all the threads in this run,
* call ImmActivateThreadsLayout() again for a new TLBLOCK.
*/
if (ptiT != NULL && ptiT->ptiSibling != NULL) {
tlBlock.ptlBlockPrev = ptlBlockPrev;
return xxxImmActivateThreadsLayout(ptiT->ptiSibling, &tlBlock, pkl);
}
/*
* Finally, we can do the actual keyboard layout activation
* starting from this run. Work on current TLBLOCK first.
* We walk the list backwards so that the pti unlocks will
* be done in the right order.
*/
for (i = cThreads - 1; i >= 0; i--) {
if (!(tlBlock.ptiList[i]->TIF_flags & TIF_INCLEANUP))
xxxImmActivateLayout(tlBlock.ptiList[i], pkl);
ThreadUnlockPti(ptiCurrent, &tlBlock.tlptiList[i]);
}
/*
* Now, we work on all previous TLBLOCKs, if any.
*/
while (ptlBlockPrev != NULL) {
for (i = THREADS_PER_TLBLOCK - 1; i >= 0; i--) {
if (!(ptlBlockPrev->ptiList[i]->TIF_flags & TIF_INCLEANUP))
xxxImmActivateLayout(ptlBlockPrev->ptiList[i], pkl);
ThreadUnlockPti(ptiCurrent, &ptlBlockPrev->tlptiList[i]);
}
ptlBlockPrev = ptlBlockPrev->ptlBlockPrev;
}
return TRUE;
}
/**************************************************************************\
* xxxImmActivateLayout
*
* Activate IME based keyboard layout.
*
* History:
* 21-Mar-1996 wkwok Created
\**************************************************************************/
VOID xxxImmActivateLayout(
IN PTHREADINFO pti,
IN PKL pkl)
{
TL tlpwndDefaultIme;
#ifdef LATER // until IanJa has done the pkl locking.
CheckLock(pkl);
#endif
/*
* Do nothing if it's already been the current active layout.
*/
if (pti->spklActive == pkl)
return;
if (pti->spwndDefaultIme == NULL) {
/*
* Only activate kernel side keyboard layout if this pti
* doesn't have the default IME window.
*/
Lock(&pti->spklActive, pkl);
return;
}
/*
* Activate client side IME based keyboard layout.
*/
ThreadLockAlwaysWithPti(pti, pti->spwndDefaultIme, &tlpwndDefaultIme);
xxxSendMessage(pti->spwndDefaultIme, WM_IME_SYSTEM,
(WPARAM)IMS_ACTIVATETHREADLAYOUT, (LPARAM)pkl->hkl);
ThreadUnlock(&tlpwndDefaultIme);
Lock(&pti->spklActive, pkl);
return;
}
/**************************************************************************\
* xxxImmLoadLayout
*
* Retrieves extended IMEINFO for the given IME based keyboard layout.
*
* History:
* 21-Mar-1996 wkwok Created
\**************************************************************************/
PIMEINFOEX xxxImmLoadLayout(
IN HKL hKL)
{
PIMEINFOEX piiex;
/*
* No IMEINFOEX for non-IME based keyboard layout.
*/
if (!IS_IME_KBDLAYOUT(hKL))
return (PIMEINFOEX)NULL;
piiex = (PIMEINFOEX)HMAllocObject(NULL, NULL, TYPE_KBDLAYOUT, sizeof(IMEINFOEX));
if (piiex == NULL) {
RIPMSG1(RIP_WARNING,
"xxxImmLoadLayout: failed to create piiex for hkl = %lx", hKL);
return (PIMEINFOEX)NULL;
}
if (!ClientImmLoadLayout(hKL, piiex)) {
HMFreeObject(piiex);
return (PIMEINFOEX)NULL;
}
return piiex;
}
/**************************************************************************\
* GetImeInfoEx
*
* Query extended IMEINFO.
*
* History:
* 21-Mar-1996 wkwok Created
\**************************************************************************/
BOOL GetImeInfoEx(
PWINDOWSTATION pwinsta,
PIMEINFOEX piiex,
IMEINFOEXCLASS SearchType)
{
PKL pkl, pklFirst;
UserAssert(pwinsta->spklList != NULL);
pkl = pklFirst = pwinsta->spklList;
switch (SearchType) {
case ImeInfoExKeyboardLayout:
do {
if (pkl->hkl == piiex->hkl) {
if (pkl->piiex == NULL)
break;
RtlCopyMemory(piiex, pkl->piiex, sizeof(IMEINFOEX));
return TRUE;
}
pkl = pkl->pklNext;
} while (pkl != pklFirst);
break;
case ImeInfoExImeFileName:
do {
if (pkl->piiex != NULL &&
!_wcsnicmp(pkl->piiex->wszImeFile, piiex->wszImeFile, IM_FILE_SIZE)) {
RtlCopyMemory(piiex, pkl->piiex, sizeof(IMEINFOEX));
return TRUE;
}
pkl = pkl->pklNext;
} while (pkl != pklFirst);
break;
default:
break;
}
return FALSE;
}
/**************************************************************************\
* SetImeInfoEx
*
* Set extended IMEINFO.
*
* History:
* 21-Mar-1996 wkwok Created
\**************************************************************************/
BOOL SetImeInfoEx(
PWINDOWSTATION pwinsta,
PIMEINFOEX piiex)
{
PKL pkl, pklFirst;
UserAssert(pwinsta->spklList != NULL);
pkl = pklFirst = pwinsta->spklList;
do {
if (pkl->hkl == piiex->hkl) {
/*
* Error out for non-IME based keyboard layout.
*/
if (pkl->piiex == NULL)
return FALSE;
/*
* Update kernel side IMEINFOEX for this keyboard layout
* only if this is its first loading.
*/
if (pkl->piiex->fLoadFlag == IMEF_NONLOAD) {
RtlCopyMemory(pkl->piiex, piiex, sizeof(IMEINFOEX));
}
return TRUE;
}
pkl = pkl->pklNext;
} while (pkl != pklFirst);
return FALSE;
}
/***************************************************************************\
* xxxImmProcessKey
*
*
* History:
* 03-03-96 TakaoK Created.
\***************************************************************************/
// ===LATER===
// This value should be set at the system initialization
// time and be moved to globals.c. Some of non-standard
// Japanese OEM keyboards need the mask value other than 0x00ff.
//
UINT guiVKeyMask = 0x00ff;
DWORD xxxImmProcessKey(
IN PQ pq,
IN PWND pwnd,
IN UINT message,
IN UINT wParam,
IN LONG lParam)
{
UINT uVKey;
PKL pkl;
DWORD dwHotKeyID;
DWORD dwReturn = 0;
PIMC pImc = NULL;
BOOL fDBERoman = FALSE;
CheckLock(pwnd);
//
// we're interested in only keyboard messages.
//
if ( message != WM_KEYDOWN &&
message != WM_SYSKEYDOWN &&
message != WM_KEYUP &&
message != WM_SYSKEYUP ) {
return dwReturn;
}
//
// Check if it's IME hotkey. This must be done before checking
// the keyboard layout because IME hotkey handler should be
// called even if current keyboard layout is non-IME layout.
//
pkl = GETPTI(pwnd)->spklActive;
if ( pkl == NULL ) {
return dwReturn;
}
uVKey = wParam & guiVKeyMask;
dwHotKeyID = CheckImeHotKey( pq, uVKey, lParam );
if ( dwHotKeyID != IME_INVALID_HOTKEY ) {
//
// if it's a valid hotkey, go straight and call back
// the IME in the client side.
//
goto ProcessKeyCallClient;
}
//
// if it's not a hotkey, we may want to check something
// before calling back.
//
if ( pkl->piiex == NULL ) {
return dwReturn;
}
//
// Check input context
//
pImc = HtoP(pwnd->hImc);
if ( pImc == NULL ) {
return dwReturn;
}
#ifdef LATER
//
// If there is an easy way to check the input context open/close status
// from the kernel side, IME_PROP_NO_KEYS_ON_CLOSE checking should be
// done here in kernel side. [ 3/10/96 takaok]
//
//
// Check IME_PROP_NO_KEYS_ON_CLOSE bit
//
// if the current imc is not open and IME doesn't need
// keys when being closed, we don't pass any keyboard
// input to ime except hotkey and keys that change
// the keyboard status.
//
if ( (piix->ImeInfo.fdwProperty & IME_PROP_NO_KEYS_ON_CLOSE) &&
(!pimc->fdwState & IMC_OPEN) &&
uVKey != VK_SHIFT && // 0x10
uVKey != VK_CONTROL && // 0x11
uVKey != VK_CAPITAL && // 0x14
uVKey != VK_KANA && // 0x15
uVKey != VK_NUMLOCK && // 0x90
uVKey != VK_SCROLL ) // 0x91
{
// Check if Korea Hanja conversion mode
if( !(pimc->fdwConvMode & IME_CMODE_HANJACONVERT) ) {
return dwReturn;
}
}
#endif
//
// if the IME doesn't need key up messages, we don't call ime.
//
if ( lParam & 0x80000000 && // set if key up, clear if key down
pkl->piiex->ImeInfo.fdwProperty & IME_PROP_IGNORE_UPKEYS )
{
return dwReturn;
}
//
// we don't want to handle sys keys since many functions for
// acceelerators won't work without this
//
#if 1
//
// at the time I'm writing this, I have a feeling that
// 4.0 keyboard layout shouldn't generate any VK_DBE_XXX.
// we will visit here after HideyukN's keyboard layout
// work is done. [takaok] 3/21/96
//
fDBERoman = FALSE;
#else
fDBERoman = (BOOL)( (uVKey == VK_DBE_ROMAN) ||
(uVKey == VK_DBE_NOROMAN) ||
(uVKey == VK_DBE_HIRAGANA) ||
(uVKey == VK_DBE_KATAKANA) ||
(uVKey == VK_DBE_CODEINPUT) ||
(uVKey == VK_DBE_NOCODEINPUT) ||
(uVKey == VK_DBE_IME_WORDREGISTER) ||
(uVKey == VK_DBE_IME_DIALOG) );
#endif
if (message == WM_SYSKEYDOWN || message == WM_SYSKEYUP ) {
//
// IME may be waiting for VK_MENU, VK_F10 or VK_DBE_xxx
//
if ( uVKey != VK_MENU && uVKey != VK_F10 && !fDBERoman ) {
return dwReturn;
}
}
//
// check if the IME doesn't need ALT key
//
if ( !(pkl->piiex->ImeInfo.fdwProperty & IME_PROP_NEED_ALTKEY) ) {
//
// IME doesn't need ALT key
//
// we don't pass the ALT and ALT+xxx except VK_DBE_xxx keys.
//
if ( ! fDBERoman &&
(uVKey == VK_MENU || (lParam & 0x20000000)) // KF_ALTDOWN
)
{
return dwReturn;
}
}
//
// finaly call back the client
//
ProcessKeyCallClient:
dwReturn = ClientImmProcessKey( PtoH(pwnd),
pwnd->hImc,
pkl->hkl,
uVKey,
lParam,
dwHotKeyID );
return dwReturn;
}
/**************************************************************************\
* ImeCanDestroyDefIME
*
* History:
* 02-Apr-1996 wkwok Ported from FE Win95 (imeclass.c)
\**************************************************************************/
BOOL ImeCanDestroyDefIME(
PWND pwndDefaultIme,
PWND pwndDestroy)
{
PWND pwnd;
PIMEUI pimeui;
pimeui = ((PIMEWND)pwndDefaultIme)->pimeui;
if (pimeui == NULL || (LONG)pimeui == (LONG)-1 || pimeui->fDestroy)
return FALSE;
/*
* If the destroying window is IME or UI window, do nothing
*/
pwnd = pwndDestroy;
while (pwnd != NULL) {
if (TestCF(pwnd, CFIME) ||
pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME])
return FALSE;
pwnd = pwnd->spwndOwner;
}
ImeSetFutureOwner(pwndDefaultIme, pwndDestroy);
/*
* If new owner is lower z-order than IME class window,
* we need to check topmost to change z-order.
*/
pwnd = pwndDefaultIme->spwndOwner;
while (pwnd != NULL && pwnd != pwndDefaultIme)
pwnd = pwnd->spwndNext;
if (pwnd == pwndDefaultIme)
ImeCheckTopmost(pwndDefaultIme);
/*
* If ImeSetFutureOwner can not find the owner window any
* more, this IME window should be destroyed.
*/
if (pwndDefaultIme->spwndOwner == NULL ||
pwndDestroy == pwndDefaultIme->spwndOwner) {
Unlock(&pwndDefaultIme->spwndOwner);
/*
* Return TRUE! Please destroy me.
*/
return TRUE;
}
return FALSE;
}
/**************************************************************************\
* IsChildSameThread (IsChildSameQ)
*
* History:
* 02-Apr-1996 wkwok Ported from FE Win95 (imeclass.c)
\**************************************************************************/
BOOL IsChildSameThread(
PWND pwndParent,
PWND pwndChild)
{
PWND pwnd;
PTHREADINFO ptiChild = GETPTI(pwndChild);
for (pwnd = pwndParent->spwndChild; pwnd; pwnd = pwnd->spwndNext) {
/*
* If pwnd is not child window, we need to skip MENU window and
* IME related window.
*/
if (!TestwndChild(pwnd)) {
PWND pwndOwner = pwnd;
BOOL fFoundOwner = FALSE;
/*
* Skip MENU window.
*/
if (pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_MENU])
continue;
while (pwndOwner != NULL) {
/*
* CS_IME class or "IME" class windows can not be the owner of
* IME windows.
*/
if (TestCF(pwndOwner, CFIME) ||
pwndOwner->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]) {
fFoundOwner = TRUE;
break;
}
pwndOwner = pwndOwner->spwndOwner;
}
if (fFoundOwner)
continue;
}
/*
* We need to skip pwndChild.
*/
if (pwnd == pwndChild)
continue;
/*
* pwnd and pwndChild are on same thread?
*/
if (GETPTI(pwnd) == ptiChild) {
PWND pwndT = pwnd;
BOOL fFoundImeWnd = FALSE;
/*
* Check again. If hwndT is children or ownee of
* IME related window, skip it.
*/
if (TestwndChild(pwndT)) {
for (; TestwndChild(pwndT) && GETPTI(pwndT) == ptiChild;
pwndT = pwndT->spwndParent) {
if (TestCF(pwndT, CFIME) ||
pwndT->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME])
fFoundImeWnd = TRUE;
}
}
if (!TestwndChild(pwndT)) {
for (; pwndT != NULL && GETPTI(pwndT) == ptiChild;
pwndT = pwndT->spwndOwner) {
if (TestCF(pwndT, CFIME) ||
pwndT->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME])
fFoundImeWnd = TRUE;
}
}
if (!fFoundImeWnd)
return TRUE;
}
}
return FALSE;
}
/**************************************************************************\
* ImeCanDestroyDefIMEforChild
*
* History:
* 02-Apr-1996 wkwok Ported from FE Win95 (imeclass.c)
\**************************************************************************/
BOOL ImeCanDestroyDefIMEforChild(
PWND pwndDefaultIme,
PWND pwndDestroy)
{
PWND pwnd;
PIMEUI pimeui;
pimeui = ((PIMEWND)pwndDefaultIme)->pimeui;
/*
* If this window is not for Child Thread.....
*/
if (pimeui == NULL || (LONG)pimeui == (LONG)-1 || !pimeui->fChildThreadDef)
return FALSE;
/*
* If parent belongs to different thread,
* we don't need to check any more...
*/
if (pwndDestroy->spwndParent == NULL ||
GETPTI(pwndDestroy) == GETPTI(pwndDestroy->spwndParent))
return FALSE;
pwnd = pwndDestroy;
while (pwnd != NULL && pwnd != PWNDDESKTOP(pwnd)) {
if (IsChildSameThread(pwnd->spwndParent, pwndDestroy))
return FALSE;
pwnd = pwnd->spwndParent;
}
/*
* We could not find any other window created by GETPTI(pwndDestroy).
* Let's destroy the default IME window of this Q.
*/
return TRUE;
}
/**************************************************************************\
* ImeCheckTopmost
*
* History:
* 02-Apr-1996 wkwok Ported from FE Win95 (imeclass.c)
\**************************************************************************/
VOID ImeCheckTopmost(
PWND pwnd)
{
if (pwnd->spwndOwner) {
/*
* The ime window have to be same topmost tyle with the owner window.
* If the Q of this window is not foreground Q, we don't need to
* forground the IME window.
* But the topmost attribute of owner was changed, this IME window
* should be re-calced.
*/
if (GETPTI(pwnd)->pq == gpqForeground) {
if (TestWF(pwnd->spwndOwner, WEFTOPMOST))
ImeSetTopmost(pwnd, TRUE, NULL);
else
ImeSetTopmost(pwnd, FALSE, NULL);
}
else {
if (TestWF(pwnd->spwndOwner, WEFTOPMOST))
ImeSetTopmost(pwnd, TRUE, pwnd->spwndOwner);
if (!TestWF(pwnd->spwndOwner, WEFTOPMOST))
ImeSetTopmost(pwnd, FALSE, pwnd->spwndOwner);
}
}
}
/**************************************************************************\
* ImeSetFutureOwner
*
* History:
* 02-Apr-1996 wkwok Ported from FE Win95 (imeclass.c)
\**************************************************************************/
VOID ImeSetFutureOwner(
PWND pwndIme,
PWND pwndOrgOwner)
{
PWND pwnd, pwndOwner;
PTHREADINFO ptiImeWnd = GETPTI(pwndIme);
if (TestWF(pwndOrgOwner, WFCHILD))
return;
pwnd = pwndOrgOwner;
/*
* Get top of owner created by the same thread.
*/
while ((pwndOwner = pwnd->spwndOwner) != NULL &&
GETPTI(pwndOwner) == ptiImeWnd)
pwnd = pwndOwner;
/*
* Bottom window can not be the owner of IME window easily...
*/
if (TestWF(pwnd, WFBOTTOMMOST) && !TestWF(pwndOrgOwner, WFBOTTOMMOST))
pwnd = pwndOrgOwner;
/*
* CS_IME class or "IME" class windows can not be the owner of
* IME windows.
*/
if (TestCF(pwnd, CFIME) ||
pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME])
pwnd = pwndOrgOwner;
/*
* If hwndOrgOwner is a top of owner, we start to search
* another top owner window in same queue.
*/
if (pwndOrgOwner == pwnd) {
PWND pwndT;
for (pwndT = pwnd->spwndParent->spwndChild;
pwndT != NULL; pwndT = pwndT->spwndNext) {
if (GETPTI(pwnd) != GETPTI(pwndT))
continue;
if (pwndT->pcls->atomClassName == gpsi->atomSysClass[ICLS_MENU])
continue;
/*
* CS_IME class or "IME" class windows can not be the owner of
* IME windows.
*/
if (TestCF(pwndT, CFIME) ||
pwndT->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME])
continue;
/*
* !!!!WARNING!!!!!
* Is hwndT a good owner of hIMEwnd??
* 1. Of cource, it should no CHILD window!
* 2. If it is hwnd,.. I know it and find next!
* 3. Does hwndT have owner in the same thread?
*/
if (!TestWF(pwndT, WFCHILD) && pwnd != pwndT &&
(pwndT->spwndOwner == NULL ||
GETPTI(pwndT) != GETPTI(pwndT->spwndOwner))) {
pwnd = pwndT;
break;
}
}
}
Lock(&pwndIme->spwndOwner, pwnd);
return;
}
/**************************************************************************\
* ImeSetFutureOwner
*
* History:
* 02-Apr-1996 wkwok Ported from FE Win95 (imeclass.c)
\**************************************************************************/
VOID ImeSetTopmostChild(
PWND pwndRoot,
BOOL fFlag)
{
PWND pwnd = pwndRoot->spwndChild;
while (pwnd != NULL) {
if (fFlag)
SetWF(pwnd, WEFTOPMOST);
else
ClrWF(pwnd, WEFTOPMOST);
ImeSetTopmostChild(pwnd, fFlag);
pwnd = pwnd->spwndNext;
}
return;
}
/**************************************************************************\
* ImeSetTopmost
*
* History:
* 02-Apr-1996 wkwok Ported from FE Win95 (imeclass.c)
\**************************************************************************/
VOID ImeSetTopmost(
PWND pwndRoot,
BOOL fFlag,
PWND pwndInsertBefore)
{
PWND pwndParent = pwndRoot->spwndParent;
PWND pwndInsert = PWND_TOP;
PWND pwnd, pwndT;
PWND pwndInsertFirst;
BOOL fFound;
pwnd = pwndRoot->spwndParent->spwndChild;
if (!fFlag) {
/*
* Get the last topmost window. This should be after unlink pwndRoot
* because pwndRoot may be the last topmost window.
*/
pwndInsert = GetLastTopMostWindow();
if (pwndInsertBefore) {
fFound = FALSE;
pwndT = pwndInsert;
while (pwndT != NULL && pwndT->spwndNext != pwndInsertBefore) {
if (pwndT == pwndRoot)
fFound = TRUE;
pwndT = pwndT->spwndNext;
}
if (pwndT == NULL || fFound)
return;
pwndInsert = pwndT;
}
if (TestWF(pwndRoot->spwndOwner, WFBOTTOMMOST)) {
pwndT = pwndInsert;
while (pwndT != NULL && pwndT != pwndRoot->spwndOwner) {
if (!TestCF(pwndT, CFIME) &&
pwndT->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME]) {
pwndInsert = pwndT;
}
pwndT = pwndT->spwndNext;
}
}
}
pwndInsertFirst = pwndInsert;
/*
* Enum the all toplevel windows and if the owner of the window is same as
* the owner of pwndRoot, the window should be changed the position of
* window link.
*/
while (pwnd != NULL) {
/*
* Get the next window before calling ImeSetTopmost.
* Because the next window will changed in LinkWindow.
*/
PWND pwndNext = pwnd->spwndNext;
/*
* the owner relation between IME and UI window is in same thread.
*/
if (GETPTI(pwnd) != GETPTI(pwndRoot))
goto ist_next;
/*
* pwnd have to be CS_IME class or "IME" class.
*/
if (!TestCF(pwnd, CFIME) &&
pwnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
goto ist_next;
/*
* If pwnd is pwndInsert, we don't need to do anything...
*/
if (pwnd == pwndInsert)
goto ist_next;
pwndT = pwnd;
while (pwndT != NULL) {
if (pwndT == pwndRoot) {
/*
* Found!!
* pwnd is the ownee of pwndRoot.
*/
UnlinkWindow(pwnd, &pwndParent->spwndChild);
if (fFlag) {
if (pwndInsert != PWND_TOP)
UserAssert(TestWF(pwndInsert, WEFTOPMOST));
SetWF(pwnd, WEFTOPMOST);
}
else {
if (pwndInsert == PWND_TOP)
UserAssert(!TestWF(pwndParent->spwndChild, WEFTOPMOST));
else if (pwndInsert->spwndNext != NULL)
UserAssert(!TestWF(pwndInsert->spwndNext, WEFTOPMOST));
ClrWF(pwnd, WEFTOPMOST);
}
LinkWindow(pwnd, pwndInsert, &pwndParent->spwndChild);
ImeSetTopmostChild(pwnd, fFlag);
pwndInsert = pwnd;
break; // goto ist_next;
}
pwndT = pwndT->spwndOwner;
}
ist_next:
pwnd = pwndNext;
/*
* Skip the windows that were inserted before.
*/
if (pwnd != NULL && pwnd == pwndInsertFirst)
pwnd = pwndInsert->spwndNext;
}
}
#endif