Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

ntimm.c

Go to the documentation of this file.
00001 /**************************************************************************\ 00002 * Module Name: ntimm.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * This module contains IMM functionality 00007 * 00008 * History: 00009 * 21-Dec-1995 wkwok 00010 \**************************************************************************/ 00011 00012 #include "precomp.h" 00013 #pragma hdrstop 00014 00015 00016 static CONST WCHAR wszDefaultIme[] = L"Default IME"; 00017 00018 #if DBG 00019 BOOL CheckOwnerCirculate(PWND pwnd) 00020 { 00021 PWND pwndT = pwnd->spwndOwner; 00022 00023 while (pwndT) { 00024 UserAssert(pwndT->spwndOwner != pwnd); 00025 pwndT = pwndT->spwndOwner; 00026 } 00027 return TRUE; 00028 } 00029 #endif 00030 00031 /**************************************************************************\ 00032 * CreateInputContext 00033 * 00034 * Create input context object. 00035 * 00036 * History: 00037 * 21-Dec-1995 wkwok Created 00038 \**************************************************************************/ 00039 00040 PIMC CreateInputContext( 00041 ULONG_PTR dwClientImcData) 00042 { 00043 PTHREADINFO ptiCurrent; 00044 PIMC pImc; 00045 PDESKTOP pdesk = NULL; 00046 00047 ptiCurrent = PtiCurrentShared(); 00048 00049 /* 00050 * Only for thread that wants IME processing. 00051 */ 00052 if ((ptiCurrent->TIF_flags & TIF_DISABLEIME) || !IS_IME_ENABLED()) { 00053 RIPMSG1(RIP_VERBOSE, "CreateInputContext: TIF_DISABLEIME or !IME Enabled. pti=%#p", ptiCurrent); 00054 return NULL; 00055 } 00056 00057 /* 00058 * If pti->spDefaultImc is NULL (means this is the first instance) 00059 * but dwClientImcData is not 0, some bogus application like NtCrash 00060 * has tried to trick the kernel. Just bail out. 00061 */ 00062 if (dwClientImcData != 0 && ptiCurrent->spDefaultImc == NULL) { 00063 RIPMSG2(RIP_WARNING, "CreateInputContext: bogus value(0x%08x) is passed. pti=%#p", 00064 dwClientImcData, ptiCurrent); 00065 return NULL; 00066 } 00067 00068 /* 00069 * If the windowstation has been initialized, allocate from 00070 * the current desktop. 00071 */ 00072 pdesk = ptiCurrent->rpdesk; 00073 #ifdef LATER 00074 RETURN_IF_ACCESS_DENIED(ptiCurrent->amdesk, DESKTOP_CREATEINPUTCONTEXT, NULL); 00075 #else 00076 if (ptiCurrent->rpdesk == NULL) { 00077 return NULL; 00078 } 00079 #endif 00080 00081 pImc = HMAllocObject(ptiCurrent, pdesk, TYPE_INPUTCONTEXT, sizeof(IMC)); 00082 00083 if (pImc == NULL) { 00084 RIPMSG0(RIP_WARNING, "CreateInputContext: out of memory"); 00085 return NULL; 00086 } 00087 00088 if (dwClientImcData == 0) { 00089 /* 00090 * We are creating default input context for current thread. 00091 * Initialize the default input context as head of the 00092 * per-thread IMC list. 00093 */ 00094 UserAssert(ptiCurrent->spDefaultImc == NULL); 00095 Lock(&ptiCurrent->spDefaultImc, pImc); 00096 pImc->pImcNext = NULL; 00097 } 00098 else { 00099 /* 00100 * Link it to the per-thread IMC list. 00101 */ 00102 UserAssert(ptiCurrent->spDefaultImc != NULL); 00103 pImc->pImcNext = ptiCurrent->spDefaultImc->pImcNext; 00104 ptiCurrent->spDefaultImc->pImcNext = pImc; 00105 } 00106 00107 pImc->dwClientImcData = dwClientImcData; 00108 00109 return pImc; 00110 } 00111 00112 00113 /**************************************************************************\ 00114 * DestroyInputContext 00115 * 00116 * Destroy the specified input context object. 00117 * 00118 * History: 00119 * 21-Dec-1995 wkwok Created 00120 \**************************************************************************/ 00121 00122 BOOL DestroyInputContext( 00123 IN PIMC pImc) 00124 { 00125 PTHREADINFO ptiImcOwner; 00126 PBWL pbwl; 00127 PWND pwnd; 00128 HWND *phwnd; 00129 PHE phe; 00130 00131 ptiImcOwner = GETPTI(pImc); 00132 00133 /* 00134 * Cannot destroy input context from other thread. 00135 */ 00136 if (ptiImcOwner != PtiCurrent()) { 00137 RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, 00138 "DestroyInputContext: pImc not of current pti"); 00139 return FALSE; 00140 } 00141 00142 /* 00143 * Cannot destroy default input context. 00144 */ 00145 if (pImc == ptiImcOwner->spDefaultImc) { 00146 RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, 00147 "DestroyInputContext: can't destroy default Imc"); 00148 return FALSE; 00149 } 00150 00151 /* 00152 * Cleanup destroyed input context from each associated window. 00153 */ 00154 pbwl = BuildHwndList(ptiImcOwner->rpdesk->pDeskInfo->spwnd->spwndChild, 00155 BWL_ENUMLIST|BWL_ENUMCHILDREN, ptiImcOwner); 00156 00157 if (pbwl != NULL) { 00158 00159 for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) { 00160 /* 00161 * Make sure this hwnd is still around. 00162 */ 00163 if ((pwnd = RevalidateHwnd(*phwnd)) == NULL) 00164 continue; 00165 00166 /* 00167 * Cleanup by associating the default input context. 00168 */ 00169 if (pwnd->hImc == (HIMC)PtoH(pImc)) 00170 AssociateInputContext(pwnd, ptiImcOwner->spDefaultImc); 00171 } 00172 00173 FreeHwndList(pbwl); 00174 } 00175 00176 phe = HMPheFromObject(pImc); 00177 00178 /* 00179 * Make sure this object isn't already marked to be destroyed - we'll 00180 * do no good if we try to destroy it now since it is locked. 00181 */ 00182 if (!(phe->bFlags & HANDLEF_DESTROY)) 00183 HMDestroyUnlockedObject(phe); 00184 00185 return TRUE; 00186 } 00187 00188 00189 /**************************************************************************\ 00190 * FreeInputContext 00191 * 00192 * Free up the specified input context object. 00193 * 00194 * History: 00195 * 21-Dec-1995 wkwok Created 00196 \**************************************************************************/ 00197 00198 VOID FreeInputContext( 00199 IN PIMC pImc) 00200 { 00201 PIMC pImcT; 00202 00203 /* 00204 * Mark it for destruction. If it the object is locked it can't 00205 * be freed right now. 00206 */ 00207 if (!HMMarkObjectDestroy((PVOID)pImc)) 00208 return; 00209 00210 /* 00211 * Unlink it. 00212 */ 00213 pImcT = GETPTI(pImc)->spDefaultImc; 00214 00215 while (pImcT != NULL && pImcT->pImcNext != pImc) 00216 pImcT = pImcT->pImcNext; 00217 00218 if (pImcT != NULL) 00219 pImcT->pImcNext = pImc->pImcNext; 00220 00221 /* 00222 * We're really going to free the input context. 00223 */ 00224 HMFreeObject((PVOID)pImc); 00225 00226 return; 00227 } 00228 00229 00230 /**************************************************************************\ 00231 * UpdateInputContext 00232 * 00233 * Update the specified input context object according to UpdateType. 00234 * 00235 * History: 00236 * 21-Dec-1995 wkwok Created 00237 \**************************************************************************/ 00238 00239 BOOL UpdateInputContext( 00240 IN PIMC pImc, 00241 IN UPDATEINPUTCONTEXTCLASS UpdateType, 00242 IN ULONG_PTR UpdateValue) 00243 { 00244 PTHREADINFO ptiCurrent, ptiImcOwner; 00245 00246 ptiCurrent = PtiCurrent(); 00247 ptiImcOwner = GETPTI(pImc); 00248 00249 /* 00250 * Cannot update input context from other process. 00251 */ 00252 if (ptiImcOwner->ppi != ptiCurrent->ppi) { 00253 RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "UpdateInputContext: pImc not of current ppi"); 00254 return FALSE; 00255 } 00256 00257 00258 switch (UpdateType) { 00259 00260 case UpdateClientInputContext: 00261 if (pImc->dwClientImcData != 0) { 00262 RIPERR0(RIP_WARNING, RIP_WARNING, "UpdateInputContext: pImc->dwClientImcData != 0"); 00263 return FALSE; 00264 } 00265 pImc->dwClientImcData = UpdateValue; 00266 break; 00267 00268 case UpdateInUseImeWindow: 00269 pImc->hImeWnd = (HWND)UpdateValue; 00270 break; 00271 00272 default: 00273 return FALSE; 00274 } 00275 00276 return TRUE; 00277 } 00278 00279 00280 /**************************************************************************\ 00281 * AssociateInputContext 00282 * 00283 * Associate input context object to the specified window. 00284 * 00285 * History: 00286 * 21-Dec-1995 wkwok Created 00287 \**************************************************************************/ 00288 00289 HIMC AssociateInputContext( 00290 IN PWND pWnd, 00291 IN PIMC pImc) 00292 { 00293 HIMC hImcRet = pWnd->hImc; 00294 pWnd->hImc = (HIMC)PtoH(pImc); 00295 00296 return hImcRet; 00297 } 00298 00299 AIC_STATUS AssociateInputContextEx( 00300 IN PWND pWnd, 00301 IN PIMC pImc, 00302 IN DWORD dwFlag) 00303 { 00304 PTHREADINFO ptiWnd = GETPTI(pWnd); 00305 PWND pWndFocus = ptiWnd->pq->spwndFocus; 00306 HIMC hImcFocus = pWndFocus->hImc; 00307 BOOL fIgnoreNoContext = (dwFlag & IACE_IGNORENOCONTEXT) == IACE_IGNORENOCONTEXT; 00308 AIC_STATUS Status = AIC_SUCCESS; 00309 00310 if (dwFlag & IACE_DEFAULT) { 00311 /* 00312 * use default input context. 00313 */ 00314 pImc = ptiWnd->spDefaultImc; 00315 00316 } else if (pImc != NULL && GETPTI(pImc) != ptiWnd) { 00317 /* 00318 * Cannot associate input context to window created 00319 * by other thread. 00320 */ 00321 RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, 00322 "AssociateInputContextEx: pwnd not of Imc pti"); 00323 return AIC_ERROR; 00324 } 00325 00326 /* 00327 * Cannot do association under different process context. 00328 */ 00329 if (GETPTI(pWnd)->ppi != PtiCurrent()->ppi) { 00330 RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, 00331 "AssociateInputContextEx: pwnd not of current ppi"); 00332 return AIC_ERROR; 00333 } 00334 00335 /* 00336 * Finally, make sure they are on the same desktop. 00337 */ 00338 if (pImc != NULL && pImc->head.rpdesk != pWnd->head.rpdesk) { 00339 RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, 00340 "AssociateInputContextEx: no desktop access"); 00341 return AIC_ERROR; 00342 } 00343 00344 /* 00345 * If IACE_CHILDREN is specified, associate the input context 00346 * to the child windows of pWnd as well. 00347 */ 00348 if ((dwFlag & IACE_CHILDREN) && pWnd->spwndChild != NULL) { 00349 PBWL pbwl; 00350 PWND pwndT; 00351 HWND *phwndT; 00352 00353 pbwl = BuildHwndList(pWnd->spwndChild, 00354 BWL_ENUMLIST|BWL_ENUMCHILDREN, ptiWnd); 00355 00356 if (pbwl != NULL) { 00357 00358 for (phwndT = pbwl->rghwnd; *phwndT != (HWND)1; phwndT++) { 00359 /* 00360 * Make sure this hwnd is still around. 00361 */ 00362 if ((pwndT = RevalidateHwnd(*phwndT)) == NULL) 00363 continue; 00364 00365 if (pwndT->hImc == (HIMC)PtoH(pImc)) 00366 continue; 00367 00368 if (pwndT->hImc == NULL_HIMC && fIgnoreNoContext) 00369 continue; 00370 00371 AssociateInputContext(pwndT, pImc); 00372 00373 if (pwndT == pWndFocus) 00374 Status = AIC_FOCUSCONTEXTCHANGED; 00375 } 00376 00377 FreeHwndList(pbwl); 00378 } 00379 } 00380 00381 /* 00382 * Associate the input context to pWnd. 00383 */ 00384 if (pWnd->hImc != NULL_HIMC || !fIgnoreNoContext) { 00385 if (pWnd->hImc != (HIMC)PtoH(pImc)) { 00386 AssociateInputContext(pWnd, pImc); 00387 if (pWnd == pWndFocus) 00388 Status = AIC_FOCUSCONTEXTCHANGED; 00389 } 00390 } 00391 00392 return Status; 00393 } 00394 00395 00396 /**************************************************************************\ 00397 * xxxFocusSetInputContext 00398 * 00399 * Set active input context upon focus change. 00400 * 00401 * History: 00402 * 21-Mar-1996 wkwok Created 00403 \**************************************************************************/ 00404 00405 VOID xxxFocusSetInputContext( 00406 IN PWND pWnd, 00407 IN BOOL fActivate, 00408 IN BOOL fQueueMsg) 00409 { 00410 PTHREADINFO pti; 00411 PWND pwndDefaultIme; 00412 TL tlpwndDefaultIme; 00413 00414 CheckLock(pWnd); 00415 00416 pti = GETPTI(pWnd); 00417 00418 /* 00419 * CS_IME class or "IME" class windows can not be SetActivated to hImc. 00420 * WinWord 6.0 US Help calls ShowWindow with the default IME window. 00421 * HELPMACROS get the default IME window by calling GetNextWindow(). 00422 */ 00423 if (TestCF(pWnd, CFIME) || 00424 (pWnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME])) 00425 return; 00426 00427 /* 00428 * Do nothing if the thread does not have default IME window. 00429 */ 00430 if ((pwndDefaultIme = pti->spwndDefaultIme) == NULL) 00431 return; 00432 00433 /* 00434 * If the thread is going away or the default IME window is being vanished, 00435 * then do nothing. 00436 */ 00437 if (pti->TIF_flags & TIF_INCLEANUP) 00438 return; 00439 00440 UserAssert(!TestWF(pwndDefaultIme, WFDESTROYED)); 00441 00442 ThreadLockAlways(pwndDefaultIme, &tlpwndDefaultIme); 00443 00444 if (fQueueMsg) { 00445 xxxSendMessageCallback(pwndDefaultIme, WM_IME_SYSTEM, 00446 fActivate ? IMS_ACTIVATECONTEXT : IMS_DEACTIVATECONTEXT, 00447 (LPARAM)HWq(pWnd), NULL, 1L, 0); 00448 } else { 00449 xxxSendMessage(pwndDefaultIme, WM_IME_SYSTEM, 00450 fActivate ? IMS_ACTIVATECONTEXT : IMS_DEACTIVATECONTEXT, 00451 (LPARAM)HWq(pWnd)); 00452 } 00453 00454 #if _DBG 00455 if (pti->spwndDefaultIme != pwndDefaultIme) { 00456 RIPMSG1(RIP_WARNING, "pti(%#p)->spwndDefaultIme got freed during the callback.", pti); 00457 } 00458 #endif 00459 00460 ThreadUnlock(&tlpwndDefaultIme); 00461 00462 return; 00463 } 00464 00465 00466 /**************************************************************************\ 00467 * BuildHimcList 00468 * 00469 * Retrieve the list of input context handles created by given thread. 00470 * 00471 * History: 00472 * 21-Feb-1995 wkwok Created 00473 \**************************************************************************/ 00474 00475 UINT BuildHimcList( 00476 PTHREADINFO pti, 00477 UINT cHimcMax, 00478 HIMC *ccxphimcFirst) 00479 { 00480 PIMC pImcT; 00481 UINT i = 0; 00482 00483 if (pti == NULL) { 00484 /* 00485 * Build the list which contains all IMCs created by calling process. 00486 */ 00487 for (pti = PtiCurrent()->ppi->ptiList; pti != NULL; pti = pti->ptiSibling) { 00488 pImcT = pti->spDefaultImc; 00489 while (pImcT != NULL) { 00490 if (i < cHimcMax) { 00491 try { 00492 ccxphimcFirst[i] = (HIMC)PtoH(pImcT); 00493 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 00494 } 00495 } 00496 i++; 00497 pImcT = pImcT->pImcNext; 00498 } 00499 } 00500 } 00501 else { 00502 /* 00503 * Build the list which contains all IMCs created by specified thread. 00504 */ 00505 pImcT = pti->spDefaultImc; 00506 while (pImcT != NULL) { 00507 if (i < cHimcMax) { 00508 try { 00509 ccxphimcFirst[i] = (HIMC)PtoH(pImcT); 00510 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 00511 } 00512 } 00513 i++; 00514 pImcT = pImcT->pImcNext; 00515 } 00516 } 00517 00518 return i; 00519 } 00520 00521 00522 /**************************************************************************\ 00523 * xxxCreateDefaultImeWindow 00524 * 00525 * Create per-thread based default IME window. 00526 * 00527 * History: 00528 * 21-Mar-1996 wkwok Created 00529 \**************************************************************************/ 00530 00531 PWND xxxCreateDefaultImeWindow( 00532 IN PWND pwnd, 00533 IN ATOM atomT, 00534 IN HANDLE hInst) 00535 { 00536 LARGE_STRING strWindowName; 00537 PWND pwndDefaultIme; 00538 TL tlpwnd; 00539 PIMEUI pimeui; 00540 PTHREADINFO ptiCurrent = PtiCurrentShared(); 00541 LPWSTR pwszDefaultIme; 00542 00543 UserAssert(ptiCurrent == GETPTI(pwnd) && ptiCurrent->spwndDefaultIme == NULL); 00544 00545 /* 00546 * Those conditions should have been checked by WantImeWindow() 00547 * before xxxCreateDefaultImeWindow gets called. 00548 */ 00549 UserAssert(!(ptiCurrent->TIF_flags & TIF_DISABLEIME)); 00550 UserAssert(!TestWF(pwnd, WFSERVERSIDEPROC)); 00551 00552 /* 00553 * The first Winlogon thread starts without default input context. 00554 * Create it now. 00555 */ 00556 if (ptiCurrent->spDefaultImc == NULL && 00557 ptiCurrent->pEThread->Cid.UniqueProcess == gpidLogon) 00558 CreateInputContext(0); 00559 00560 /* 00561 * No default IME window for thread that doesn't have 00562 * default input context 00563 */ 00564 if (ptiCurrent->spDefaultImc == NULL) 00565 return (PWND)NULL; 00566 00567 /* 00568 * Avoid recursion 00569 */ 00570 if (atomT == gpsi->atomSysClass[ICLS_IME] || TestCF(pwnd, CFIME)) 00571 return (PWND)NULL; 00572 00573 /* 00574 * B#12165-win95b 00575 * Yet MFC does another nice. We need to avoid to give an IME window 00576 * to the child of desktop window which is in different process. 00577 */ 00578 if (TestwndChild(pwnd) && GETPTI(pwnd->spwndParent)->ppi != ptiCurrent->ppi && 00579 !(pwnd->style & WS_VISIBLE)) 00580 return (PWND)NULL; 00581 00582 if (ptiCurrent->rpdesk->pheapDesktop == NULL) 00583 return (PWND)NULL; 00584 00585 /* 00586 * Allocate storage for L"Default IME" string from desktop heap 00587 * so that it can be referenced from USER32.DLL in user mode. 00588 */ 00589 pwszDefaultIme = (LPWSTR)DesktopAlloc(ptiCurrent->rpdesk, 00590 sizeof(wszDefaultIme), 00591 DTAG_IMETEXT); 00592 if (pwszDefaultIme == NULL) 00593 return (PWND)NULL; 00594 00595 RtlCopyMemory(pwszDefaultIme, wszDefaultIme, sizeof(wszDefaultIme)); 00596 00597 RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)&strWindowName, 00598 pwszDefaultIme, 00599 (UINT)-1); 00600 00601 ThreadLock(pwnd, &tlpwnd); 00602 00603 pwndDefaultIme = xxxCreateWindowEx( (DWORD)0, 00604 (PLARGE_STRING)gpsi->atomSysClass[ICLS_IME], 00605 (PLARGE_STRING)&strWindowName, 00606 WS_POPUP | WS_DISABLED, 00607 0, 0, 0, 0, 00608 pwnd, (PMENU)NULL, 00609 hInst, NULL, VER40); 00610 00611 00612 if (pwndDefaultIme != NULL) { 00613 pimeui = ((PIMEWND)pwndDefaultIme)->pimeui; 00614 UserAssert(pimeui != NULL && (LONG_PTR)pimeui != (LONG_PTR)-1); 00615 try { 00616 ProbeForWrite(pimeui, sizeof *pimeui, sizeof(DWORD)); 00617 pimeui->fDefault = TRUE; 00618 if (TestwndChild(pwnd) && GETPTI(pwnd->spwndParent) != ptiCurrent) { 00619 pimeui->fChildThreadDef = TRUE; 00620 } 00621 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 00622 } 00623 } 00624 00625 ThreadUnlock(&tlpwnd); 00626 00627 DesktopFree(ptiCurrent->rpdesk, pwszDefaultIme); 00628 00629 return pwndDefaultIme; 00630 } 00631 00632 00633 /**************************************************************************\ 00634 * xxxImmActivateThreadsLayout 00635 * 00636 * Activate keyboard layout for multiple threads. 00637 * 00638 * Return: 00639 * TRUE if at least one thread has changed its active keyboard layout. 00640 * FALSE otherwise 00641 * 00642 * History: 00643 * 11-Apr-1996 wkwok Created 00644 \**************************************************************************/ 00645 00646 BOOL xxxImmActivateThreadsLayout( 00647 PTHREADINFO pti, 00648 PTLBLOCK ptlBlockPrev, 00649 PKL pkl) 00650 { 00651 TLBLOCK tlBlock; 00652 PTHREADINFO ptiCurrent, ptiT; 00653 UINT cThreads = 0; 00654 INT i; 00655 00656 CheckLock(pkl); 00657 00658 ptiCurrent = PtiCurrentShared(); 00659 00660 /* 00661 * Build a list of threads that we need to update their active layouts. 00662 * We can't just walk the ptiT list while we're doing the work, because 00663 * for IME based keyboard layout, we will do callback to client side 00664 * and the ptiT could get deleted out while we leave the critical section. 00665 */ 00666 for (ptiT = pti; ptiT != NULL; ptiT = ptiT->ptiSibling) { 00667 /* 00668 * Skip all the *do nothing* cases in xxxImmActivateLayout 00669 * so as to minimize the # of TLBLOCK required. 00670 */ 00671 if (ptiT->spklActive == pkl || (ptiT->TIF_flags & TIF_INCLEANUP)) 00672 continue; 00673 00674 UserAssert(ptiT->pClientInfo != NULL); 00675 UserAssert(ptiT->ppi == PpiCurrent()); // can't access pClientInfo of other process 00676 00677 if (ptiT->spwndDefaultIme == NULL) { 00678 /* 00679 * Keyboard layout is being switched but there's no way to callback 00680 * the client side to activate&initialize input context now. 00681 * Let's do hkl switching only in the kernel side for this thread 00682 * but remember the input context needs to be re-initialized 00683 * when this GUI thread recreates the default IME window later. 00684 */ 00685 ptiT->hklPrev = ptiT->spklActive->hkl; 00686 Lock(&ptiT->spklActive, pkl); 00687 if (ptiT->spDefaultImc) { 00688 ptiT->pClientInfo->CI_flags |= CI_INPUTCONTEXT_REINIT; 00689 RIPMSG1(RIP_VERBOSE, "xxxImmActivateThreadsLayout: ptiT(%08p) will be re-initialized.", ptiT); 00690 } 00691 UserAssert((ptiT->TIF_flags & TIF_INCLEANUP) == 0); 00692 ptiT->pClientInfo->hKL = pkl->hkl; 00693 ptiT->pClientInfo->CodePage = pkl->CodePage; 00694 continue; 00695 } 00696 00697 ThreadLockPti(ptiCurrent, ptiT, &tlBlock.list[cThreads].tlpti); 00698 tlBlock.list[cThreads++].pti = ptiT; 00699 00700 if (cThreads == THREADS_PER_TLBLOCK) 00701 break; 00702 } 00703 00704 /* 00705 * Return FALSE if all the threads already had the pkl active. 00706 */ 00707 if (ptlBlockPrev == NULL && ptiT == NULL && cThreads == 0) 00708 return FALSE; 00709 00710 /* 00711 * If we can't service all the threads in this run, 00712 * call ImmActivateThreadsLayout() again for a new TLBLOCK. 00713 */ 00714 if (ptiT != NULL && ptiT->ptiSibling != NULL) { 00715 tlBlock.ptlBlockPrev = ptlBlockPrev; 00716 return xxxImmActivateThreadsLayout(ptiT->ptiSibling, &tlBlock, pkl); 00717 } 00718 00719 /* 00720 * Finally, we can do the actual keyboard layout activation 00721 * starting from this run. Work on current TLBLOCK first. 00722 * We walk the list backwards so that the pti unlocks will 00723 * be done in the right order. 00724 */ 00725 00726 tlBlock.ptlBlockPrev = ptlBlockPrev; 00727 ptlBlockPrev = &tlBlock; 00728 00729 while (ptlBlockPrev != NULL) { 00730 for (i = cThreads - 1; i >= 0; --i) { 00731 if ((ptlBlockPrev->list[i].pti->TIF_flags & TIF_INCLEANUP) == 0) { 00732 ptiT = ptlBlockPrev->list[i].pti; 00733 UserAssert(ptiT); 00734 xxxImmActivateLayout(ptiT, pkl); 00735 if ((ptiT->TIF_flags & TIF_INCLEANUP) == 0) { 00736 ptiT->pClientInfo->hKL = pkl->hkl; 00737 ptiT->pClientInfo->CodePage = pkl->CodePage; 00738 } 00739 } 00740 ThreadUnlockPti(ptiCurrent, &ptlBlockPrev->list[i].tlpti); 00741 } 00742 ptlBlockPrev = ptlBlockPrev->ptlBlockPrev; 00743 cThreads = THREADS_PER_TLBLOCK; 00744 } 00745 00746 return TRUE; 00747 } 00748 00749 VOID xxxImmActivateAndUnloadThreadsLayout( 00750 IN PTHREADINFO *ptiList, 00751 IN UINT nEntries, 00752 IN PTLBLOCK ptlBlockPrev, 00753 PKL pklCurrent, 00754 DWORD dwHklReplace) 00755 { 00756 TLBLOCK tlBlock; 00757 PTHREADINFO ptiCurrent; 00758 int i, cThreads; 00759 enum { RUN_ACTIVATE = 1, RUN_UNLOAD = 2, RUN_FLAGS_MASK = RUN_ACTIVATE | RUN_UNLOAD, RUN_INVALID = 0xffff0000 }; 00760 00761 CheckLock(pklCurrent); 00762 00763 ptiCurrent = PtiCurrentShared(); 00764 00765 tlBlock.ptlBlockPrev = ptlBlockPrev; 00766 00767 /* 00768 * Build a list of threads that we need to unload their IME DLL(s). 00769 * We can't just walk the ptiList while we're doing the work, because 00770 * for IME based keyboard layout, we will do callback to client side 00771 * and the pti could get deleted out while we leave the critical section. 00772 */ 00773 for (i = 0, cThreads = 0; i < (INT)nEntries; i++) { 00774 DWORD dwFlags = 0; 00775 00776 /* 00777 * Skip all the *do nothing* cases in xxxImmActivateLayout 00778 * so as to minimize the # of TLBLOCKs required. 00779 */ 00780 if (ptiList[i]->TIF_flags & TIF_INCLEANUP) { 00781 dwFlags = RUN_INVALID; 00782 } 00783 else if (ptiList[i]->spklActive != pklCurrent) { 00784 if (ptiList[i]->spwndDefaultIme == NULL) { 00785 BOOLEAN fAttached = FALSE; 00786 00787 Lock(&ptiList[i]->spklActive, pklCurrent); 00788 if (ptiList[i]->pClientInfo != ptiCurrent->pClientInfo && 00789 ptiList[i]->ppi != ptiCurrent->ppi) { 00790 /* 00791 * If the thread is in another process, attach 00792 * to that process so that we can access its ClientInfo. 00793 */ 00794 KeAttachProcess(&ptiList[i]->ppi->Process->Pcb); 00795 fAttached = TRUE; 00796 } 00797 00798 try { 00799 ptiList[i]->pClientInfo->CodePage = pklCurrent->CodePage; 00800 ptiList[i]->pClientInfo->hKL = pklCurrent->hkl; 00801 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 00802 dwFlags = RUN_INVALID; 00803 } 00804 if (fAttached) { 00805 KeDetachProcess(); 00806 } 00807 } else { 00808 dwFlags = RUN_ACTIVATE; 00809 } 00810 } 00811 00812 /* 00813 * Skip all the *do nothing* cases in xxxImmUnloadLayout() 00814 * so as to minimize the # of TLBLOCK required. 00815 * (#99321) 00816 */ 00817 if (ptiList[i]->spwndDefaultIme != NULL && 00818 ptiList[i]->spklActive != NULL && 00819 (dwHklReplace != IFL_DEACTIVATEIME || IS_IME_KBDLAYOUT(ptiList[i]->spklActive->hkl)) && 00820 dwFlags != RUN_INVALID) { 00821 dwFlags |= RUN_UNLOAD; 00822 } 00823 00824 if (dwFlags && dwFlags != RUN_INVALID) { 00825 ThreadLockPti(ptiCurrent, ptiList[i], &tlBlock.list[cThreads].tlpti); 00826 #if DBG 00827 tlBlock.list[cThreads].dwUnlockedCount = 0; 00828 #endif 00829 tlBlock.list[cThreads].pti = ptiList[i]; 00830 tlBlock.list[cThreads++].dwFlags = dwFlags; 00831 00832 if (cThreads == THREADS_PER_TLBLOCK) { 00833 i++; // 1 more before exit the loop. 00834 break; 00835 } 00836 } 00837 } 00838 00839 /* 00840 * If we can't service all the threads in this run, 00841 * call xxxImmActivateAndUnloadThreadsLayout again for a new TLBLOCK. 00842 */ 00843 if (i < (INT)nEntries) { 00844 ptiList += i; 00845 nEntries -= i; 00846 xxxImmActivateAndUnloadThreadsLayout(ptiList, nEntries, &tlBlock, pklCurrent, dwHklReplace); 00847 return; 00848 } 00849 00850 /* 00851 * Finally, we can do the actual keyboard layout activation 00852 * starting from this run. Work on current TLBLOCK first. 00853 * We walk the list backwards so that the pti unlocks will 00854 * be done in the right order. 00855 */ 00856 i = cThreads - 1; 00857 for (ptlBlockPrev = &tlBlock; ptlBlockPrev != NULL; ptlBlockPrev = ptlBlockPrev->ptlBlockPrev) { 00858 for ( ; i >= 0; i--) { 00859 if ((ptlBlockPrev->list[i].dwFlags & RUN_ACTIVATE) && 00860 !(ptlBlockPrev->list[i].pti->TIF_flags & TIF_INCLEANUP)) { 00861 xxxImmActivateLayout(ptlBlockPrev->list[i].pti, pklCurrent); 00862 } 00863 00864 // unlock the thread if the thread is only locked for the first run 00865 if ((ptlBlockPrev->list[i].dwFlags & RUN_FLAGS_MASK) == RUN_ACTIVATE) { 00866 ThreadUnlockPti(ptiCurrent, &ptlBlockPrev->list[i].tlpti); 00867 #if DBG 00868 ptlBlockPrev->list[i].dwUnlockedCount++; 00869 #endif 00870 } 00871 } 00872 i = THREADS_PER_TLBLOCK - 1; 00873 } 00874 00875 i = cThreads - 1; 00876 for (ptlBlockPrev = &tlBlock; ptlBlockPrev != NULL; ptlBlockPrev = ptlBlockPrev->ptlBlockPrev) { 00877 for ( ; i >= 0; --i) { 00878 if (ptlBlockPrev->list[i].dwFlags & RUN_UNLOAD) { 00879 if (!(ptlBlockPrev->list[i].pti->TIF_flags & TIF_INCLEANUP)) { 00880 xxxImmUnloadLayout(ptlBlockPrev->list[i].pti, dwHklReplace); 00881 } 00882 else { 00883 RIPMSG1(RIP_WARNING, "xxxImmActivateAndUnloadThreadsLayout: thread %#p is cleaned up.", 00884 ptlBlockPrev->list[i].pti); 00885 } 00886 // unlock the thread 00887 UserAssert((ptlBlockPrev->list[i].dwFlags & RUN_FLAGS_MASK) != RUN_ACTIVATE); 00888 UserAssert(ptlBlockPrev->list[i].dwUnlockedCount == 0); 00889 ThreadUnlockPti(ptiCurrent, &ptlBlockPrev->list[i].tlpti); 00890 #if DBG 00891 ptlBlockPrev->list[i].dwUnlockedCount++; 00892 #endif 00893 } 00894 } 00895 i = THREADS_PER_TLBLOCK - 1; 00896 } 00897 00898 #if DBG 00899 // Check if all the locked thread is properly unlocked 00900 i = cThreads - 1; 00901 for (ptlBlockPrev = &tlBlock; ptlBlockPrev; ptlBlockPrev = ptlBlockPrev->ptlBlockPrev) { 00902 for ( ; i >= 0; --i) { 00903 UserAssert(ptlBlockPrev->list[i].dwUnlockedCount == 1); 00904 } 00905 i = THREADS_PER_TLBLOCK - 1; 00906 } 00907 #endif 00908 00909 return; 00910 } 00911 00912 /**************************************************************************\ 00913 * xxxImmActivateLayout 00914 * 00915 * Activate IME based keyboard layout. 00916 * 00917 * History: 00918 * 21-Mar-1996 wkwok Created 00919 \**************************************************************************/ 00920 00921 VOID xxxImmActivateLayout( 00922 IN PTHREADINFO pti, 00923 IN PKL pkl) 00924 { 00925 TL tlpwndDefaultIme; 00926 PTHREADINFO ptiCurrent; 00927 00928 CheckLock(pkl); 00929 00930 /* 00931 * Do nothing if it's already been the current active layout. 00932 */ 00933 if (pti->spklActive == pkl) 00934 return; 00935 00936 if (pti->spwndDefaultIme == NULL) { 00937 /* 00938 * Only activate kernel side keyboard layout if this pti 00939 * doesn't have the default IME window. 00940 */ 00941 Lock(&pti->spklActive, pkl); 00942 return; 00943 } 00944 00945 ptiCurrent = PtiCurrentShared(); 00946 00947 /* 00948 * Activate client side IME based keyboard layout. 00949 */ 00950 ThreadLockAlwaysWithPti(ptiCurrent, pti->spwndDefaultIme, &tlpwndDefaultIme); 00951 xxxSendMessage(pti->spwndDefaultIme, WM_IME_SYSTEM, 00952 (WPARAM)IMS_ACTIVATETHREADLAYOUT, (LPARAM)pkl->hkl); 00953 ThreadUnlock(&tlpwndDefaultIme); 00954 00955 Lock(&pti->spklActive, pkl); 00956 00957 return; 00958 } 00959 00960 00961 VOID xxxImmUnloadThreadsLayout( 00962 IN PTHREADINFO *ptiList, 00963 IN UINT nEntries, 00964 IN PTLBLOCK ptlBlockPrev, 00965 IN DWORD dwFlag) 00966 { 00967 TLBLOCK tlBlock; 00968 PTHREADINFO ptiCurrent; 00969 INT i, cThreads; 00970 BOOLEAN fPerformUnlock; 00971 00972 ptiCurrent = PtiCurrentShared(); 00973 tlBlock.ptlBlockPrev = ptlBlockPrev; 00974 00975 /* 00976 * Build a list of threads that we need to unload their IME DLL(s). 00977 * We can't just walk the ptiList while we're doing the work, because 00978 * for IME based keyboard layout, we will do callback to client side 00979 * and the pti could get deleted out while we leave the critical section. 00980 */ 00981 for (i = 0, cThreads = 0; i < (INT)nEntries; i++) { 00982 /* 00983 * Skip all the *do nothing* cases in xxxImmUnloadLayout() 00984 * so as to minimize the # of TLBLOCK required. 00985 */ 00986 if ((ptiList[i]->TIF_flags & TIF_INCLEANUP) || ptiList[i]->spwndDefaultIme == NULL) 00987 continue; 00988 00989 if (ptiList[i]->spklActive == NULL) 00990 continue; 00991 00992 if (dwFlag == IFL_DEACTIVATEIME && 00993 !IS_IME_KBDLAYOUT(ptiList[i]->spklActive->hkl)) // #99321 00994 continue; 00995 00996 #if DBG 00997 tlBlock.list[cThreads].dwUnlockedCount = 0; 00998 #endif 00999 ThreadLockPti(ptiCurrent, ptiList[i], &tlBlock.list[cThreads].tlpti); 01000 tlBlock.list[cThreads++].pti = ptiList[i]; 01001 if (cThreads == THREADS_PER_TLBLOCK) { 01002 i++; // 1 more before exit the loop. 01003 break; 01004 } 01005 } 01006 01007 if (i < (INT)nEntries) { 01008 ptiList += i; 01009 nEntries -= i; 01010 xxxImmUnloadThreadsLayout(ptiList, nEntries, &tlBlock, dwFlag); 01011 return; 01012 } 01013 01014 UserAssert(dwFlag == IFL_UNLOADIME || dwFlag == IFL_DEACTIVATEIME); 01015 if (dwFlag == IFL_UNLOADIME) { 01016 dwFlag = IFL_DEACTIVATEIME; 01017 fPerformUnlock = FALSE; 01018 } else { 01019 fPerformUnlock = TRUE; 01020 } 01021 RepeatForUnload: 01022 /* 01023 * Finally, we can unload the IME based keyboard layout 01024 * starting from this run. Work on current TLBLOCK first. 01025 * We walk the list backwards so that the pti unlocks will 01026 * be done in the right order. 01027 */ 01028 i = cThreads - 1; 01029 for (ptlBlockPrev = &tlBlock; ptlBlockPrev; ptlBlockPrev = ptlBlockPrev->ptlBlockPrev) { 01030 for ( ; i >= 0; --i) { 01031 if (!(ptlBlockPrev->list[i].pti->TIF_flags & TIF_INCLEANUP)) { 01032 xxxImmUnloadLayout(ptlBlockPrev->list[i].pti, dwFlag); 01033 } 01034 else { 01035 RIPMSG2(RIP_WARNING, "Thread %#p is cleaned during the loop for %x!", ptlBlockPrev->list[i].pti, dwFlag); 01036 } 01037 01038 if (fPerformUnlock) { 01039 #if DBG 01040 ptlBlockPrev->list[i].dwUnlockedCount++; 01041 #endif 01042 ThreadUnlockPti(ptiCurrent, &ptlBlockPrev->list[i].tlpti); 01043 } 01044 } 01045 i = THREADS_PER_TLBLOCK - 1; 01046 } 01047 01048 if (!fPerformUnlock) { 01049 fPerformUnlock = TRUE; 01050 dwFlag = IFL_UNLOADIME; 01051 goto RepeatForUnload; 01052 } 01053 01054 #if DBG 01055 // Check if all the locked thread is properly unlocked 01056 i = cThreads - 1; 01057 for (ptlBlockPrev = &tlBlock; ptlBlockPrev; ptlBlockPrev = ptlBlockPrev->ptlBlockPrev) { 01058 for ( ; i >= 0; --i) { 01059 UserAssert(ptlBlockPrev->list[i].dwUnlockedCount == 1); 01060 } 01061 i = THREADS_PER_TLBLOCK - 1; 01062 } 01063 #endif 01064 01065 return; 01066 } 01067 01068 01069 01070 VOID xxxImmUnloadLayout( 01071 IN PTHREADINFO pti, 01072 IN DWORD dwFlag) 01073 { 01074 TL tlpwndDefaultIme; 01075 PTHREADINFO ptiCurrent; 01076 ULONG_PTR dwResult; 01077 LRESULT r; 01078 01079 /* 01080 * Do nothing if the thread does not have default IME window. 01081 */ 01082 if (pti->spwndDefaultIme == NULL) 01083 return; 01084 01085 if (pti->spklActive == NULL) 01086 return; 01087 01088 if (dwFlag == IFL_DEACTIVATEIME && 01089 !IS_IME_KBDLAYOUT(pti->spklActive->hkl)) 01090 return; 01091 01092 ptiCurrent = PtiCurrentShared(); 01093 01094 ThreadLockAlwaysWithPti(ptiCurrent, pti->spwndDefaultIme, &tlpwndDefaultIme); 01095 r = xxxSendMessageTimeout(pti->spwndDefaultIme, WM_IME_SYSTEM, 01096 IMS_UNLOADTHREADLAYOUT, (LONG)dwFlag, 01097 SMTO_NOTIMEOUTIFNOTHUNG, CMSHUNGAPPTIMEOUT, &dwResult); 01098 01099 if (!r) { 01100 RIPMSG1(RIP_WARNING, "Timeout in xxxImmUnloadLayout: perhaps this thread (0x%x) is not pumping messages.", 01101 pti->pEThread->Cid.UniqueThread); 01102 } 01103 01104 ThreadUnlock(&tlpwndDefaultIme); 01105 01106 return; 01107 } 01108 01109 /**************************************************************************\ 01110 * xxxImmLoadLayout 01111 * 01112 * Retrieves extended IMEINFO for the given IME based keyboard layout. 01113 * 01114 * History: 01115 * 21-Mar-1996 wkwok Created 01116 \**************************************************************************/ 01117 01118 PIMEINFOEX xxxImmLoadLayout( 01119 IN HKL hKL) 01120 { 01121 PIMEINFOEX piiex; 01122 PTHREADINFO ptiCurrent; 01123 TL tlPool; 01124 01125 /* 01126 * No IMEINFOEX for non-IME based keyboard layout. 01127 */ 01128 if (!IS_IME_KBDLAYOUT(hKL)) 01129 return (PIMEINFOEX)NULL; 01130 01131 piiex = (PIMEINFOEX)UserAllocPool(sizeof(IMEINFOEX), TAG_IME); 01132 01133 if (piiex == NULL) { 01134 RIPMSG1(RIP_WARNING, 01135 "xxxImmLoadLayout: failed to create piiex for hkl = %lx", hKL); 01136 return (PIMEINFOEX)NULL; 01137 } 01138 01139 ptiCurrent = PtiCurrent(); 01140 01141 /* 01142 * Lock this allocations since we are going to the client side 01143 */ 01144 ThreadLockPool(ptiCurrent, piiex, &tlPool); 01145 01146 if (!ClientImmLoadLayout(hKL, piiex)) { 01147 ThreadUnlockAndFreePool(ptiCurrent, &tlPool); 01148 return (PIMEINFOEX)NULL; 01149 } 01150 01151 ThreadUnlockPool(ptiCurrent, &tlPool); 01152 01153 return piiex; 01154 } 01155 01156 01157 /**************************************************************************\ 01158 * GetImeInfoEx 01159 * 01160 * Query extended IMEINFO. 01161 * 01162 * History: 01163 * 21-Mar-1996 wkwok Created 01164 \**************************************************************************/ 01165 01166 BOOL GetImeInfoEx( 01167 PWINDOWSTATION pwinsta, 01168 PIMEINFOEX piiex, 01169 IMEINFOEXCLASS SearchType) 01170 { 01171 PKL pkl, pklFirst; 01172 01173 /* 01174 * Note: this check was forced to insert due to winmm.dll who indirectly 01175 * loads imm32.dll in CSRSS context. CSRSS is not always bound to 01176 * specific window station, thus pwinsta could be NULL. 01177 * This has been avoided by not loading imm32.dll. 01178 * After winmm.dll gets removed from CSRSS, this if statement should be 01179 * removed, or substituted as an assertion. 01180 */ 01181 if (pwinsta == NULL) { 01182 return FALSE; 01183 } 01184 01185 /* 01186 * Keyboard layer has not been initialized. 01187 */ 01188 if (pwinsta->spklList == NULL) 01189 return FALSE; 01190 01191 pkl = pklFirst = pwinsta->spklList; 01192 01193 switch (SearchType) { 01194 case ImeInfoExKeyboardLayout: 01195 do { 01196 if (pkl->hkl == piiex->hkl) { 01197 01198 if (pkl->piiex == NULL) 01199 break; 01200 01201 RtlCopyMemory(piiex, pkl->piiex, sizeof(IMEINFOEX)); 01202 return TRUE; 01203 } 01204 pkl = pkl->pklNext; 01205 } while (pkl != pklFirst); 01206 break; 01207 01208 case ImeInfoExImeFileName: 01209 do { 01210 if (pkl->piiex != NULL && 01211 !_wcsnicmp(pkl->piiex->wszImeFile, piiex->wszImeFile, IM_FILE_SIZE)) { 01212 01213 RtlCopyMemory(piiex, pkl->piiex, sizeof(IMEINFOEX)); 01214 return TRUE; 01215 } 01216 pkl = pkl->pklNext; 01217 } while (pkl != pklFirst); 01218 break; 01219 01220 default: 01221 break; 01222 } 01223 01224 return FALSE; 01225 } 01226 01227 01228 /**************************************************************************\ 01229 * SetImeInfoEx 01230 * 01231 * Set extended IMEINFO. 01232 * 01233 * History: 01234 * 21-Mar-1996 wkwok Created 01235 \**************************************************************************/ 01236 01237 BOOL SetImeInfoEx( 01238 PWINDOWSTATION pwinsta, 01239 PIMEINFOEX piiex) 01240 { 01241 PKL pkl, pklFirst; 01242 01243 if (pwinsta == NULL) { 01244 return FALSE; 01245 } 01246 01247 UserAssert(pwinsta->spklList != NULL); 01248 01249 pkl = pklFirst = pwinsta->spklList; 01250 01251 do { 01252 if (pkl->hkl == piiex->hkl) { 01253 01254 /* 01255 * Error out for non-IME based keyboard layout. 01256 */ 01257 if (pkl->piiex == NULL) 01258 return FALSE; 01259 01260 /* 01261 * Update kernel side IMEINFOEX for this keyboard layout 01262 * only if this is its first loading. 01263 */ 01264 if (pkl->piiex->fLoadFlag == IMEF_NONLOAD) { 01265 RtlCopyMemory(pkl->piiex, piiex, sizeof(IMEINFOEX)); 01266 } 01267 01268 return TRUE; 01269 } 01270 pkl = pkl->pklNext; 01271 01272 } while (pkl != pklFirst); 01273 01274 return FALSE; 01275 } 01276 01277 01278 /***************************************************************************\ 01279 * xxxImmProcessKey 01280 * 01281 * 01282 * History: 01283 * 03-03-96 TakaoK Created. 01284 \***************************************************************************/ 01285 01286 DWORD xxxImmProcessKey( 01287 IN PQ pq, 01288 IN PWND pwnd, 01289 IN UINT message, 01290 IN WPARAM wParam, 01291 IN LPARAM lParam) 01292 { 01293 UINT uVKey; 01294 PKL pkl; 01295 DWORD dwHotKeyID; 01296 DWORD dwReturn = 0; 01297 PIMC pImc = NULL; 01298 BOOL fDBERoman = FALSE; 01299 PIMEHOTKEYOBJ pImeHotKeyObj; 01300 HKL hklTarget; 01301 01302 CheckLock(pwnd); 01303 01304 // 01305 // we're interested in only keyboard messages. 01306 // 01307 if ( message != WM_KEYDOWN && 01308 message != WM_SYSKEYDOWN && 01309 message != WM_KEYUP && 01310 message != WM_SYSKEYUP ) { 01311 01312 return dwReturn; 01313 } 01314 01315 // 01316 // Check if it's IME hotkey. This must be done before checking 01317 // the keyboard layout because IME hotkey handler should be 01318 // called even if current keyboard layout is non-IME layout. 01319 // 01320 pkl = GETPTI(pwnd)->spklActive; 01321 if ( pkl == NULL ) { 01322 return dwReturn; 01323 } 01324 01325 uVKey = (UINT)wParam & 0xff; 01326 01327 pImeHotKeyObj = CheckImeHotKey(pq, uVKey, lParam); 01328 if (pImeHotKeyObj) { 01329 dwHotKeyID = pImeHotKeyObj->hk.dwHotKeyID; 01330 hklTarget = pImeHotKeyObj->hk.hKL; 01331 } 01332 else { 01333 dwHotKeyID = IME_INVALID_HOTKEY; 01334 hklTarget = (HKL)NULL; 01335 } 01336 01337 // 01338 // Handle Direct KL switching here. 01339 // 01340 if (dwHotKeyID >= IME_HOTKEY_DSWITCH_FIRST && dwHotKeyID <= IME_HOTKEY_DSWITCH_LAST) { 01341 UserAssert(hklTarget != NULL); 01342 if (pkl->hkl != hklTarget) { 01343 // 01344 // Post the message only if the new Keyboard Layout is different from 01345 // the current Keyboard Layout. 01346 // 01347 _PostMessage(pwnd, WM_INPUTLANGCHANGEREQUEST, 01348 (pkl->dwFontSigs & gSystemFS) ? INPUTLANGCHANGE_SYSCHARSET : 0, 01349 (LPARAM)hklTarget); 01350 } 01351 if (GetAppImeCompatFlags(GETPTI(pwnd)) & IMECOMPAT_HYDRACLIENT) { 01352 return 0; 01353 } 01354 return IPHK_HOTKEY; 01355 } 01356 01357 if (!IS_IME_ENABLED()) { 01358 // 01359 // Since IMM is disabled, no need to process further. 01360 // Just bail out. 01361 // 01362 return 0; 01363 } 01364 01365 if ( dwHotKeyID != IME_INVALID_HOTKEY ) { 01366 // 01367 // if it's a valid hotkey, go straight and call back 01368 // the IME in the client side. 01369 // 01370 goto ProcessKeyCallClient; 01371 } 01372 01373 // 01374 // if it's not a hotkey, we may want to check something 01375 // before calling back. 01376 // 01377 if ( pkl->piiex == NULL ) { 01378 return dwReturn; 01379 } 01380 01381 // 01382 // Check input context 01383 // 01384 pImc = HtoP(pwnd->hImc); 01385 if ( pImc == NULL ) { 01386 return dwReturn; 01387 } 01388 01389 #ifdef LATER 01390 // 01391 // If there is an easy way to check the input context open/close status 01392 // from the kernel side, IME_PROP_NO_KEYS_ON_CLOSE checking should be 01393 // done here in kernel side. [ 3/10/96 takaok] 01394 // 01395 01396 // 01397 // Check IME_PROP_NO_KEYS_ON_CLOSE bit 01398 // 01399 // if the current imc is not open and IME doesn't need 01400 // keys when being closed, we don't pass any keyboard 01401 // input to ime except hotkey and keys that change 01402 // the keyboard status. 01403 // 01404 if ( (piix->ImeInfo.fdwProperty & IME_PROP_NO_KEYS_ON_CLOSE) && 01405 (!pimc->fdwState & IMC_OPEN) && 01406 uVKey != VK_SHIFT && // 0x10 01407 uVKey != VK_CONTROL && // 0x11 01408 uVKey != VK_CAPITAL && // 0x14 01409 uVKey != VK_KANA && // 0x15 01410 uVKey != VK_NUMLOCK && // 0x90 01411 uVKey != VK_SCROLL ) // 0x91 01412 { 01413 // Check if Korea Hanja conversion mode 01414 if( !(pimc->fdwConvMode & IME_CMODE_HANJACONVERT) ) { 01415 return dwReturn; 01416 } 01417 } 01418 #endif 01419 01420 // 01421 // if the IME doesn't need key up messages, we don't call ime. 01422 // 01423 if ( lParam & 0x80000000 && // set if key up, clear if key down 01424 pkl->piiex->ImeInfo.fdwProperty & IME_PROP_IGNORE_UPKEYS ) 01425 { 01426 return dwReturn; 01427 } 01428 01429 // 01430 // we don't want to handle sys keys since many functions for 01431 // acceelerators won't work without this 01432 // 01433 fDBERoman = (BOOL)( (uVKey == VK_DBE_ROMAN) || 01434 (uVKey == VK_DBE_NOROMAN) || 01435 (uVKey == VK_DBE_HIRAGANA) || 01436 (uVKey == VK_DBE_KATAKANA) || 01437 (uVKey == VK_DBE_CODEINPUT) || 01438 (uVKey == VK_DBE_NOCODEINPUT) || 01439 (uVKey == VK_DBE_IME_WORDREGISTER) || 01440 (uVKey == VK_DBE_IME_DIALOG) ); 01441 01442 if (message == WM_SYSKEYDOWN || message == WM_SYSKEYUP ) { 01443 // 01444 // IME may be waiting for VK_MENU, VK_F10 or VK_DBE_xxx 01445 // 01446 if ( uVKey != VK_MENU && uVKey != VK_F10 && !fDBERoman ) { 01447 return dwReturn; 01448 } 01449 } 01450 01451 // 01452 // check if the IME doesn't need ALT key 01453 // 01454 if ( !(pkl->piiex->ImeInfo.fdwProperty & IME_PROP_NEED_ALTKEY) ) { 01455 // 01456 // IME doesn't need ALT key 01457 // 01458 // we don't pass the ALT and ALT+xxx except VK_DBE_xxx keys. 01459 // 01460 if ( ! fDBERoman && 01461 (uVKey == VK_MENU || (lParam & 0x20000000)) // KF_ALTDOWN 01462 ) 01463 { 01464 return dwReturn; 01465 } 01466 } 01467 01468 // 01469 // finaly call back the client 01470 // 01471 01472 ProcessKeyCallClient: 01473 01474 if ((uVKey & 0xff) == VK_PACKET) { 01475 // 01476 // need to retrieve UNICODE character from pti 01477 // 01478 uVKey = MAKELONG(wParam, PtiCurrent()->wchInjected); 01479 } 01480 dwReturn = ClientImmProcessKey( PtoH(pwnd), 01481 pkl->hkl, 01482 uVKey, 01483 lParam, 01484 dwHotKeyID); 01485 01486 // 01487 // Hydra server wants to see the IME hotkeys. 01488 // 01489 if (GetAppImeCompatFlags(GETPTI(pwnd)) & IMECOMPAT_HYDRACLIENT) { 01490 dwReturn &= ~IPHK_HOTKEY; 01491 } 01492 return dwReturn; 01493 } 01494 01495 01496 /**************************************************************************\ 01497 * ImeCanDestroyDefIME 01498 * 01499 * History: 01500 * 02-Apr-1996 wkwok Ported from FE Win95 (imeclass.c) 01501 \**************************************************************************/ 01502 01503 BOOL ImeCanDestroyDefIME( 01504 PWND pwndDefaultIme, 01505 PWND pwndDestroy) 01506 { 01507 PWND pwnd; 01508 PIMEUI pimeui; 01509 01510 pimeui = ((PIMEWND)pwndDefaultIme)->pimeui; 01511 01512 if (pimeui == NULL || (LONG_PTR)pimeui == (LONG_PTR)-1) 01513 return FALSE; 01514 01515 try { 01516 if (ProbeAndReadStructure(pimeui, IMEUI).fDestroy) { 01517 return FALSE; 01518 } 01519 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 01520 } 01521 01522 /* 01523 * If the pwndDestroy has no owner/ownee relationship with 01524 * pwndDefaultIme, don't bother to change anything. 01525 * 01526 * If pwndDefaultIme->spwndOwner is NULL, this means we need 01527 * to search for a new good owner window. 01528 */ 01529 if ( pwndDefaultIme->spwndOwner != NULL ) { 01530 for (pwnd = pwndDefaultIme->spwndOwner; 01531 pwnd != pwndDestroy && pwnd != NULL; pwnd = pwnd->spwndOwner) ; 01532 01533 if (pwnd == NULL) 01534 return FALSE; 01535 } 01536 01537 /* 01538 * If the destroying window is IME or UI window, do nothing 01539 */ 01540 pwnd = pwndDestroy; 01541 01542 while (pwnd != NULL) { 01543 if (TestCF(pwnd, CFIME) || 01544 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]) 01545 return FALSE; 01546 01547 pwnd = pwnd->spwndOwner; 01548 } 01549 01550 ImeSetFutureOwner(pwndDefaultIme, pwndDestroy); 01551 01552 /* 01553 * If new owner is lower z-order than IME class window, 01554 * we need to check topmost to change z-order. 01555 */ 01556 pwnd = pwndDefaultIme->spwndOwner; 01557 while (pwnd != NULL && pwnd != pwndDefaultIme) 01558 pwnd = pwnd->spwndNext; 01559 01560 if (pwnd == pwndDefaultIme) 01561 ImeCheckTopmost(pwndDefaultIme); 01562 01563 #if DBG 01564 CheckOwnerCirculate(pwndDefaultIme); 01565 #endif 01566 01567 /* 01568 * If ImeSetFutureOwner can not find the owner window any 01569 * more, this IME window should be destroyed. 01570 */ 01571 if (pwndDefaultIme->spwndOwner == NULL || 01572 pwndDestroy == pwndDefaultIme->spwndOwner) { 01573 01574 // RIPMSG1(RIP_WARNING, "ImeCanDestroyDefIME: TRUE for pwnd=%#p", pwndDestroy); 01575 Unlock(&pwndDefaultIme->spwndOwner); 01576 01577 /* 01578 * Return TRUE! Please destroy me. 01579 */ 01580 return TRUE; 01581 } 01582 01583 return FALSE; 01584 } 01585 01586 01587 /**************************************************************************\ 01588 * IsChildSameThread (IsChildSameQ) 01589 * 01590 * History: 01591 * 02-Apr-1996 wkwok Ported from FE Win95 (imeclass.c) 01592 \**************************************************************************/ 01593 01594 BOOL IsChildSameThread( 01595 PWND pwndParent, 01596 PWND pwndChild) 01597 { 01598 PWND pwnd; 01599 PTHREADINFO ptiChild = GETPTI(pwndChild); 01600 01601 for (pwnd = pwndParent->spwndChild; pwnd; pwnd = pwnd->spwndNext) { 01602 /* 01603 * If pwnd is not child window, we need to skip MENU window and 01604 * IME related window. 01605 */ 01606 if (!TestwndChild(pwnd)) { 01607 PWND pwndOwner = pwnd; 01608 BOOL fFoundOwner = FALSE; 01609 01610 /* 01611 * Skip MENU window. 01612 */ 01613 if (pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_MENU]) 01614 continue; 01615 01616 while (pwndOwner != NULL) { 01617 /* 01618 * CS_IME class or "IME" class windows can not be the owner of 01619 * IME windows. 01620 */ 01621 if (TestCF(pwndOwner, CFIME) || 01622 pwndOwner->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]) { 01623 fFoundOwner = TRUE; 01624 break; 01625 } 01626 01627 pwndOwner = pwndOwner->spwndOwner; 01628 } 01629 01630 if (fFoundOwner) 01631 continue; 01632 } 01633 01634 /* 01635 * We need to skip pwndChild. 01636 */ 01637 if (pwnd == pwndChild) 01638 continue; 01639 01640 /* 01641 * pwnd and pwndChild are on same thread? 01642 */ 01643 if (GETPTI(pwnd) == ptiChild) { 01644 PWND pwndT = pwnd; 01645 BOOL fFoundImeWnd = FALSE; 01646 01647 /* 01648 * Check again. If hwndT is children or ownee of 01649 * IME related window, skip it. 01650 */ 01651 if (TestwndChild(pwndT)) { 01652 01653 for (; TestwndChild(pwndT) && GETPTI(pwndT) == ptiChild; 01654 pwndT = pwndT->spwndParent) { 01655 if (TestCF(pwndT, CFIME) || 01656 pwndT->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]) 01657 fFoundImeWnd = TRUE; 01658 } 01659 } 01660 01661 if (!TestwndChild(pwndT)) { 01662 01663 for (; pwndT != NULL && GETPTI(pwndT) == ptiChild; 01664 pwndT = pwndT->spwndOwner) { 01665 if (TestCF(pwndT, CFIME) || 01666 pwndT->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]) 01667 fFoundImeWnd = TRUE; 01668 } 01669 } 01670 01671 if (!fFoundImeWnd) 01672 return TRUE; 01673 } 01674 } 01675 01676 return FALSE; 01677 } 01678 01679 01680 /**************************************************************************\ 01681 * ImeCanDestroyDefIMEforChild 01682 * 01683 * History: 01684 * 02-Apr-1996 wkwok Ported from FE Win95 (imeclass.c) 01685 \**************************************************************************/ 01686 01687 BOOL ImeCanDestroyDefIMEforChild( 01688 PWND pwndDefaultIme, 01689 PWND pwndDestroy) 01690 { 01691 PWND pwnd; 01692 PIMEUI pimeui; 01693 01694 pimeui = ((PIMEWND)pwndDefaultIme)->pimeui; 01695 01696 /* 01697 * If this window is not for Child Thread..... 01698 */ 01699 if (pimeui == NULL || (LONG_PTR)pimeui == (LONG_PTR)-1) 01700 return FALSE; 01701 01702 try { 01703 if (!ProbeAndReadStructure(pimeui, IMEUI).fChildThreadDef) { 01704 return FALSE; 01705 } 01706 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 01707 } 01708 01709 /* 01710 * If parent belongs to different thread, 01711 * we don't need to check any more... 01712 */ 01713 if (pwndDestroy->spwndParent == NULL || 01714 GETPTI(pwndDestroy) == GETPTI(pwndDestroy->spwndParent)) 01715 return FALSE; 01716 01717 pwnd = pwndDestroy; 01718 01719 while (pwnd != NULL && pwnd != PWNDDESKTOP(pwnd)) { 01720 if (IsChildSameThread(pwnd->spwndParent, pwndDestroy)) 01721 return FALSE; 01722 pwnd = pwnd->spwndParent; 01723 } 01724 01725 /* 01726 * We could not find any other window created by GETPTI(pwndDestroy). 01727 * Let's destroy the default IME window of this Q. 01728 */ 01729 return TRUE; 01730 } 01731 01732 01733 /**************************************************************************\ 01734 * ImeCheckTopmost 01735 * 01736 * History: 01737 * 02-Apr-1996 wkwok Ported from FE Win95 (imeclass.c) 01738 \**************************************************************************/ 01739 01740 VOID ImeCheckTopmost( 01741 PWND pwndIme) 01742 { 01743 if (pwndIme->spwndOwner) { 01744 PWND pwndInsertBeforeThis; 01745 /* 01746 * The ime window have to be same topmost tyle with the owner window. 01747 * If the Q of this window is not foreground Q, we don't need to 01748 * forground the IME window. 01749 * But the topmost attribute of owner was changed, this IME window 01750 * should be re-calced. 01751 */ 01752 if (GETPTI(pwndIme) == gptiForeground) { 01753 pwndInsertBeforeThis = NULL; 01754 } else { 01755 pwndInsertBeforeThis = pwndIme->spwndOwner; 01756 } 01757 01758 ImeSetTopmost(pwndIme, TestWF(pwndIme->spwndOwner, WEFTOPMOST) != 0, pwndInsertBeforeThis); 01759 } 01760 } 01761 01762 01763 /**************************************************************************\ 01764 * ImeSetFutureOwner 01765 * 01766 * History: 01767 * 02-Apr-1996 wkwok Ported from FE Win95 (imeclass.c) 01768 \**************************************************************************/ 01769 01770 VOID ImeSetFutureOwner( 01771 PWND pwndIme, 01772 PWND pwndOrgOwner) 01773 { 01774 PWND pwnd, pwndOwner; 01775 PTHREADINFO ptiImeWnd = GETPTI(pwndIme); 01776 01777 if (pwndOrgOwner == NULL || TestWF(pwndOrgOwner, WFCHILD)) 01778 return; 01779 01780 pwnd = pwndOrgOwner; 01781 01782 /* 01783 * Get top of owner created by the same thread. 01784 */ 01785 while ((pwndOwner = pwnd->spwndOwner) != NULL && 01786 GETPTI(pwndOwner) == ptiImeWnd) 01787 pwnd = pwndOwner; 01788 01789 /* 01790 * Bottom window can not be the owner of IME window easily... 01791 */ 01792 if (TestWF(pwnd, WFBOTTOMMOST) && !TestWF(pwndOrgOwner, WFBOTTOMMOST)) 01793 pwnd = pwndOrgOwner; 01794 01795 /* 01796 * CS_IME class or "IME" class windows can not be the owner of 01797 * IME windows. 01798 */ 01799 if (TestCF(pwnd, CFIME) || 01800 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]) 01801 pwnd = pwndOrgOwner; 01802 01803 /* 01804 * If hwndOrgOwner is a top of owner, we start to search 01805 * another top owner window in same queue. 01806 */ 01807 if (pwndOrgOwner == pwnd && pwnd->spwndParent != NULL) { 01808 PWND pwndT; 01809 01810 for (pwndT = pwnd->spwndParent->spwndChild; 01811 pwndT != NULL; pwndT = pwndT->spwndNext) { 01812 01813 if (GETPTI(pwnd) != GETPTI(pwndT)) 01814 continue; 01815 01816 if (pwndT->pcls->atomClassName == gpsi->atomSysClass[ICLS_MENU]) 01817 continue; 01818 01819 /* 01820 * CS_IME class or "IME" class windows can not be the owner of 01821 * IME windows. 01822 */ 01823 if (TestCF(pwndT, CFIME) || 01824 pwndT->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]) 01825 continue; 01826 01827 // We don't like the window that is being destroyed. 01828 if (TestWF(pwndT, WFINDESTROY)) 01829 continue; 01830 01831 /* 01832 * !!!!WARNING!!!!! 01833 * Is hwndT a good owner of hIMEwnd?? 01834 * 1. Of cource, it should no CHILD window! 01835 * 2. If it is hwnd,.. I know it and find next! 01836 * 3. Does hwndT have owner in the same thread? 01837 */ 01838 if (!TestWF(pwndT, WFCHILD) && pwnd != pwndT && 01839 (pwndT->spwndOwner == NULL || 01840 GETPTI(pwndT) != GETPTI(pwndT->spwndOwner))) { 01841 UserAssert(GETPTI(pwndIme) == GETPTI(pwndT)); 01842 pwnd = pwndT; 01843 break; 01844 } 01845 } 01846 } 01847 01848 UserAssert(!TestCF(pwnd, CFIME)); 01849 Lock(&pwndIme->spwndOwner, pwnd); 01850 01851 return; 01852 } 01853 01854 01855 /**************************************************************************\ 01856 * ImeSetTopmostChild 01857 * 01858 * History: 01859 * 02-Apr-1996 wkwok Ported from FE Win95 (imeclass.c) 01860 \**************************************************************************/ 01861 01862 VOID ImeSetTopmostChild( 01863 PWND pwndParent, 01864 BOOL fMakeTopmost) 01865 { 01866 PWND pwnd = pwndParent->spwndChild; 01867 01868 while (pwnd != NULL) { 01869 if (fMakeTopmost) 01870 SetWF(pwnd, WEFTOPMOST); 01871 else 01872 ClrWF(pwnd, WEFTOPMOST); 01873 01874 ImeSetTopmostChild(pwnd, fMakeTopmost); 01875 01876 pwnd = pwnd->spwndNext; 01877 } 01878 01879 return; 01880 } 01881 01882 01883 /**************************************************************************\ 01884 * 01885 * GetLastTopMostWindowNoIME() - 01886 * 01887 * Get the last topmost window which is not the ownee of pwndRoot (IME window). 01888 * 01889 \**************************************************************************/ 01890 01891 PWND GetLastTopMostWindowNoIME(PWND pwndRoot) 01892 { 01893 PWND pwndT = _GetDesktopWindow(); 01894 PWND pwndRet = NULL; 01895 01896 /* 01897 * pwndRoot should not be NULL, and should be IME window. 01898 */ 01899 UserAssert(pwndRoot && pwndRoot->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]); 01900 01901 if (pwndT == NULL || pwndT->spwndChild == NULL) { 01902 #if _DBG 01903 if (pwndT == NULL) { 01904 RIPMSG0(RIP_WARNING, "GetLastTopMostWindowNoIME: there's no desktop window !!"); 01905 } 01906 else { 01907 RIPMSG0(RIP_WARNING, "GetLastTopMostWindowNoIME: there is no toplevel window !!"); 01908 } 01909 #endif 01910 return NULL; 01911 } 01912 01913 /* 01914 * Get the first child of the desktop window. 01915 */ 01916 pwndT = pwndT->spwndChild; 01917 01918 /* 01919 * Loop through the toplevel windows while they are topmost. 01920 */ 01921 while (TestWF(pwndT, WEFTOPMOST)) { 01922 PWND pwndOwner = pwndT; 01923 BOOL fOwned = FALSE; 01924 01925 /* 01926 * If pwndT is a IME related window, track the owner. If pwndRoot is not 01927 * pwndT's owner, remember pwndT as a candidate. 01928 */ 01929 if (TestCF(pwndT,CFIME) || (pwndT->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME])) { 01930 while (pwndOwner != NULL) { 01931 if (pwndRoot == pwndOwner) { 01932 fOwned = TRUE; 01933 break; 01934 } 01935 pwndOwner = pwndOwner->spwndOwner; 01936 } 01937 } 01938 if (!fOwned) 01939 pwndRet = pwndT; 01940 01941 /* 01942 * Next toplevel window. 01943 */ 01944 pwndT = pwndT->spwndNext; 01945 UserAssert(pwndT->spwndParent == _GetDesktopWindow()); 01946 } 01947 01948 return pwndRet; 01949 } 01950 01951 01952 #if DBG 01953 void ImeCheckSetTopmostLink(PWND pwnd, PWND pwndInsFirst, PWND pwndIns) 01954 { 01955 PWND pwndDebT0 = pwndInsFirst; 01956 BOOL fFound = FALSE; 01957 01958 if (pwndDebT0) { 01959 while (pwndDebT0 && (pwndDebT0 != pwndIns)) { 01960 if (pwndDebT0 == pwnd) 01961 fFound = TRUE; 01962 01963 pwndDebT0 = pwndDebT0->spwndNext; 01964 } 01965 01966 if (pwndDebT0 == NULL) { 01967 RIPMSG3(RIP_ERROR, "pwndIns(%#p) is upper that pwndInsFirst(%#p) pwnd is (%#p)", pwndIns, pwndInsFirst, pwnd); 01968 } else if (fFound) { 01969 RIPMSG3(RIP_ERROR, "pwnd(%#p) is between pwndInsFirst(%#p) and pwndIns(%#p)", pwnd, pwndInsFirst, pwndIns); 01970 } 01971 } else if (pwndIns) { 01972 pwndDebT0 = pwnd->spwndParent->spwndChild; 01973 01974 while (pwndDebT0 && (pwndDebT0 != pwndIns)) { 01975 if (pwndDebT0 == pwnd) 01976 fFound = TRUE; 01977 01978 pwndDebT0 = pwndDebT0->spwndNext; 01979 } 01980 01981 if (fFound) { 01982 RIPMSG3(RIP_ERROR, "pwnd(%#p) is between TOPLEVEL pwndInsFirst(%#p) and pwndIns(%#p)", pwnd, pwndInsFirst, pwndIns); 01983 } 01984 } 01985 } 01986 #endif 01987 01988 /**************************************************************************\ 01989 * ImeSetTopmost 01990 * 01991 * History: 01992 * 02-Apr-1996 wkwok Ported from FE Win95 (imeclass.c) 01993 \**************************************************************************/ 01994 01995 VOID ImeSetTopmost( 01996 PWND pwndRootIme, 01997 BOOL fMakeTopmost, 01998 PWND pwndInsertBefore) 01999 { 02000 PWND pwndParent = pwndRootIme->spwndParent; 02001 PWND pwndInsert = PWND_TOP; // pwnd which should be prior to pwndRootIme. 02002 PWND pwnd, pwndT; 02003 PWND pwndInsertFirst; 02004 BOOLEAN fFound; 02005 02006 if (pwndParent == NULL) 02007 return; 02008 02009 pwnd = pwndParent->spwndChild; 02010 02011 if (!fMakeTopmost) { 02012 /* 02013 * Get the last topmost window. This should be after unlink pwndRootIme 02014 * because pwndRootIme may be the last topmost window. 02015 */ 02016 pwndInsert = GetLastTopMostWindowNoIME(pwndRootIme); 02017 02018 if (pwndInsertBefore) { 02019 02020 fFound = FALSE; 02021 pwndT = pwndInsert; 02022 02023 while (pwndT != NULL && pwndT->spwndNext != pwndInsertBefore) { 02024 if (pwndT == pwndRootIme) 02025 fFound = TRUE; 02026 pwndT = pwndT->spwndNext; 02027 } 02028 02029 if (pwndT == NULL || fFound) 02030 return; 02031 02032 pwndInsert = pwndT; 02033 } 02034 02035 if (TestWF(pwndRootIme->spwndOwner, WFBOTTOMMOST)) { 02036 pwndT = pwndInsert; 02037 02038 while (pwndT != NULL && pwndT != pwndRootIme->spwndOwner) { 02039 if (!TestCF(pwndT, CFIME) && 02040 pwndT->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME]) { 02041 pwndInsert = pwndT; 02042 } 02043 pwndT = pwndT->spwndNext; 02044 } 02045 } 02046 } 02047 02048 pwndInsertFirst = pwndInsert; 02049 02050 /* 02051 * Enum the all toplevel windows and if the owner of the window is same as 02052 * the owner of pwndRootIme, the window should be changed the position of 02053 * window link. 02054 */ 02055 while (pwnd != NULL) { 02056 /* 02057 * Get the next window before calling ImeSetTopmost. 02058 * Because the next window will be changed in LinkWindow. 02059 */ 02060 PWND pwndNext = pwnd->spwndNext; 02061 02062 /* 02063 * the owner relation between IME and UI window is in same thread. 02064 */ 02065 if (GETPTI(pwnd) != GETPTI(pwndRootIme)) 02066 goto ist_next; 02067 02068 /* 02069 * pwnd have to be CS_IME class or "IME" class. 02070 */ 02071 if (!TestCF(pwnd, CFIME) && 02072 pwnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME]) 02073 goto ist_next; 02074 02075 /* 02076 * If pwnd is pwndInsert, we don't need to do anything... 02077 */ 02078 if (pwnd == pwndInsert) 02079 goto ist_next; 02080 02081 pwndT = pwnd; 02082 while (pwndT != NULL) { 02083 if (pwndT == pwndRootIme) { 02084 /* 02085 * Found!! 02086 * pwnd is the ownee of pwndRootIme. 02087 */ 02088 02089 UserAssert(GETPTI(pwnd) == GETPTI(pwndRootIme)); 02090 UserAssert(TestCF(pwnd,CFIME) || 02091 (pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME])); 02092 UserAssert(pwnd != pwndInsert); 02093 02094 UnlinkWindow(pwnd, pwndParent); 02095 02096 if (fMakeTopmost) { 02097 if (pwndInsert != PWND_TOP) 02098 UserAssert(TestWF(pwndInsert, WEFTOPMOST)); 02099 SetWF(pwnd, WEFTOPMOST); 02100 } 02101 else { 02102 if (pwndInsert == PWND_TOP) { 02103 /* 02104 * In rare cases, the first toplevel window could be the one we'll look next, 02105 * who may still have obscure topmost flag. 02106 */ 02107 UserAssert(pwndParent->spwndChild == pwndNext || !TestWF(pwndParent->spwndChild, WEFTOPMOST)); 02108 } 02109 else if (pwndInsert->spwndNext != NULL) { 02110 /* 02111 * In rare cases, pwndInsert->spwndNext could be the one we'll look next, 02112 * who may still have obscure topmost flag. 02113 */ 02114 UserAssert(pwndInsert->spwndNext == pwndNext || !TestWF(pwndInsert->spwndNext, WEFTOPMOST)); 02115 } 02116 ClrWF(pwnd, WEFTOPMOST); 02117 } 02118 02119 LinkWindow(pwnd, pwndInsert, pwndParent); 02120 #if 0 // Let's see what happens if we disable this 02121 ImeSetTopmostChild(pwnd, fMakeTopmost); 02122 #endif 02123 02124 pwndInsert = pwnd; 02125 break; // goto ist_next; 02126 } 02127 pwndT = pwndT->spwndOwner; 02128 } 02129 ist_next: 02130 pwnd = pwndNext; 02131 02132 /* 02133 * Skip the windows that were inserted before. 02134 */ 02135 if (pwnd != NULL && pwnd == pwndInsertFirst) 02136 pwnd = pwndInsert->spwndNext; 02137 02138 #if DBG 02139 if (pwnd) 02140 ImeCheckSetTopmostLink(pwnd, pwndInsertFirst, pwndInsert); 02141 #endif 02142 } 02143 } 02144 02145 02146 /**************************************************************************\ 02147 * ProbeAndCaptureSoftKbdData 02148 * 02149 * Captures SoftKbdData that comes from user mode. 02150 * 02151 * 23-Apr-1996 wkwok created 02152 \**************************************************************************/ 02153 02154 PSOFTKBDDATA ProbeAndCaptureSoftKbdData( 02155 PSOFTKBDDATA Source) 02156 { 02157 PSOFTKBDDATA Destination = NULL; 02158 DWORD cbSize; 02159 UINT uCount; 02160 02161 try { 02162 uCount = ProbeAndReadUlong((PULONG)Source); 02163 02164 #if defined(_X86_) 02165 ProbeForReadBuffer(&Source->wCode, uCount, sizeof(BYTE)); 02166 #else 02167 ProbeForReadBuffer(&Source->wCode, uCount, sizeof(WORD)); 02168 #endif 02169 02170 cbSize = FIELD_OFFSET(SOFTKBDDATA, wCode[0]) 02171 + uCount * sizeof(WORD) * 256; 02172 02173 Destination = (PSOFTKBDDATA)UserAllocPool(cbSize, TAG_IME); 02174 02175 if (Destination != NULL) { 02176 RtlCopyMemory(Destination, Source, cbSize); 02177 } else { 02178 ExRaiseStatus(STATUS_NO_MEMORY); 02179 } 02180 02181 } except (W32ExceptionHandler(TRUE, RIP_WARNING)) { 02182 02183 if (Destination != NULL) { 02184 UserFreePool(Destination); 02185 } 02186 02187 return NULL; 02188 } 02189 02190 return Destination; 02191 } 02192 02193 // 02194 // ported from Win95:ctxtman.c\SetConvMode() 02195 // 02196 VOID SetConvMode( PTHREADINFO pti, DWORD dwConversion ) 02197 { 02198 if ( pti->spklActive == NULL ) 02199 return; 02200 02201 switch ( PRIMARYLANGID(HandleToUlong(pti->spklActive->hkl)) ) { 02202 case LANG_JAPANESE: 02203 02204 ClearKeyStateDown(pti->pq, VK_DBE_ALPHANUMERIC); 02205 ClearKeyStateToggle(pti->pq, VK_DBE_ALPHANUMERIC); 02206 ClearKeyStateDown(pti->pq, VK_DBE_KATAKANA); 02207 ClearKeyStateToggle(pti->pq, VK_DBE_KATAKANA); 02208 ClearKeyStateDown(pti->pq, VK_DBE_HIRAGANA); 02209 ClearKeyStateToggle(pti->pq, VK_DBE_HIRAGANA); 02210 02211 if ( dwConversion & IME_CMODE_NATIVE ) { 02212 if ( dwConversion & IME_CMODE_KATAKANA ) { 02213 SetKeyStateDown( pti->pq, VK_DBE_KATAKANA); 02214 SetKeyStateToggle( pti->pq, VK_DBE_KATAKANA); 02215 } else { 02216 SetKeyStateDown( pti->pq, VK_DBE_HIRAGANA); 02217 SetKeyStateToggle( pti->pq, VK_DBE_HIRAGANA); 02218 } 02219 } else { 02220 SetKeyStateDown( pti->pq, VK_DBE_ALPHANUMERIC); 02221 SetKeyStateToggle( pti->pq, VK_DBE_ALPHANUMERIC); 02222 } 02223 02224 if ( dwConversion & IME_CMODE_FULLSHAPE ) { 02225 SetKeyStateDown( pti->pq, VK_DBE_DBCSCHAR); 02226 SetKeyStateToggle( pti->pq, VK_DBE_DBCSCHAR); 02227 ClearKeyStateDown(pti->pq, VK_DBE_SBCSCHAR); 02228 ClearKeyStateToggle(pti->pq, VK_DBE_SBCSCHAR); 02229 } else { 02230 SetKeyStateDown( pti->pq, VK_DBE_SBCSCHAR); 02231 SetKeyStateToggle( pti->pq, VK_DBE_SBCSCHAR); 02232 ClearKeyStateDown(pti->pq, VK_DBE_DBCSCHAR); 02233 ClearKeyStateToggle(pti->pq, VK_DBE_DBCSCHAR); 02234 } 02235 02236 if ( dwConversion & IME_CMODE_ROMAN ) { 02237 SetKeyStateDown( pti->pq, VK_DBE_ROMAN); 02238 SetKeyStateToggle( pti->pq, VK_DBE_ROMAN); 02239 ClearKeyStateDown(pti->pq, VK_DBE_NOROMAN); 02240 ClearKeyStateToggle(pti->pq, VK_DBE_NOROMAN); 02241 } else { 02242 SetKeyStateDown( pti->pq, VK_DBE_NOROMAN); 02243 SetKeyStateToggle( pti->pq, VK_DBE_NOROMAN); 02244 ClearKeyStateDown(pti->pq, VK_DBE_ROMAN); 02245 ClearKeyStateToggle(pti->pq, VK_DBE_ROMAN); 02246 } 02247 02248 if ( dwConversion & IME_CMODE_CHARCODE ) { 02249 SetKeyStateDown( pti->pq, VK_DBE_CODEINPUT); 02250 SetKeyStateToggle( pti->pq, VK_DBE_CODEINPUT); 02251 ClearKeyStateDown(pti->pq, VK_DBE_NOCODEINPUT); 02252 ClearKeyStateToggle(pti->pq, VK_DBE_NOCODEINPUT); 02253 } else { 02254 SetKeyStateDown( pti->pq, VK_DBE_NOCODEINPUT); 02255 SetKeyStateToggle( pti->pq, VK_DBE_NOCODEINPUT); 02256 ClearKeyStateDown(pti->pq, VK_DBE_CODEINPUT); 02257 ClearKeyStateToggle(pti->pq, VK_DBE_CODEINPUT); 02258 } 02259 break; 02260 02261 case LANG_KOREAN: 02262 if ( dwConversion & IME_CMODE_NATIVE) { 02263 SetKeyStateToggle( pti->pq, VK_HANGUL); 02264 } else { 02265 ClearKeyStateToggle( pti->pq, VK_HANGUL); 02266 } 02267 02268 if ( dwConversion & IME_CMODE_FULLSHAPE ) { 02269 SetKeyStateToggle( pti->pq, VK_JUNJA); 02270 } else { 02271 ClearKeyStateToggle( pti->pq, VK_JUNJA); 02272 } 02273 02274 if ( dwConversion & IME_CMODE_HANJACONVERT ) { 02275 SetKeyStateToggle( pti->pq, VK_HANJA); 02276 } else { 02277 ClearKeyStateToggle( pti->pq, VK_HANJA); 02278 } 02279 break; 02280 02281 default: 02282 break; 02283 } 02284 return; 02285 } 02286 02287 // 02288 // called by IMM32 client when: 02289 // 02290 // input focus is switched 02291 // or IME open status is changed 02292 // or IME conversion status is changed 02293 // 02294 // 02295 VOID xxxNotifyIMEStatus( 02296 IN PWND pwnd, 02297 IN DWORD dwOpen, 02298 IN DWORD dwConversion ) 02299 { 02300 PTHREADINFO pti; 02301 02302 CheckLock(pwnd); 02303 02304 if ( (pti = GETPTI(pwnd)) != NULL && gptiForeground != NULL ) { 02305 if ( pti == gptiForeground || pti->pq == gptiForeground->pq ) { 02306 02307 if ( gHimcFocus != pwnd->hImc || 02308 gdwIMEOpenStatus != dwOpen || 02309 gdwIMEConversionStatus != dwConversion ) { 02310 02311 // 02312 // save the new status 02313 // 02314 gHimcFocus = pwnd->hImc; 02315 if ( gHimcFocus != (HIMC)NULL ) { 02316 02317 RIPMSG2(RIP_VERBOSE, "xxxNotifyIMEStatus: newOpen=%x newConv=%x", 02318 dwOpen, dwConversion); 02319 gdwIMEOpenStatus = dwOpen; 02320 gdwIMEConversionStatus = dwConversion; 02321 02322 // 02323 // set keyboard states that are related to IME conversion status 02324 // 02325 SetConvMode(pti, dwOpen ? dwConversion : 0); 02326 } 02327 02328 // 02329 // notify shell the IME status change 02330 // 02331 // Implementation note: [takaok 9/5/96] 02332 // 02333 // Using HSHELL_LANGUAGE is not the best way to inform shell 02334 // IME status change because we didn't change the keyboard layout. 02335 // ( The spec says HSHELL_LANGUAGE is for keyboard layout change. 02336 // Also passing window handle as WPARAM is not documented ) 02337 // 02338 // This is same as what Win95 does. I won't change this for now 02339 // because in the future shell will be developed by a different 02340 // group in MS. 02341 // 02342 // Currently only Korean Windows is interested in getting 02343 // the conversion status change. 02344 // 02345 if (IsHooked(pti, WHF_SHELL)) { 02346 HKL hkl = NULL; 02347 02348 if (pti->spklActive != NULL) { 02349 hkl = pti->spklActive->hkl; 02350 } 02351 xxxCallHook(HSHELL_LANGUAGE, (WPARAM)HWq(pwnd), (LPARAM)hkl, WH_SHELL); 02352 } 02353 02354 // 02355 // notify keyboard driver 02356 // 02357 NlsKbdSendIMENotification(dwOpen,dwConversion); 02358 } 02359 } 02360 } 02361 } 02362 02363 //--------------------------------------------------------------------------- 02364 // 02365 // xxxCheckImeShowStatus() - 02366 // 02367 // Only one Status Window should be shown in the System. 02368 // This functsion enums all IME window and check the show status of them. 02369 // 02370 // If pti is NULL, check all toplevel windows regardless their owners. 02371 // If pti is not NULL, check only windows belong to the thread. 02372 // 02373 //---------------------------------------------------------------------------- 02374 02375 BOOL xxxCheckImeShowStatus(PWND pwndIme, PTHREADINFO pti) 02376 { 02377 PBWL pbwl; 02378 PHWND phwnd; 02379 BOOL fRet = FALSE; 02380 PTHREADINFO ptiCurrent = PtiCurrent(); 02381 02382 if (TestWF(pwndIme, WFINDESTROY)) { 02383 return FALSE; 02384 } 02385 02386 // Parent window of IME window should be the desktop window 02387 UserAssert(pwndIme); 02388 UserAssert(pwndIme->spwndParent == GETPTI(pwndIme)->pDeskInfo->spwnd); 02389 02390 pbwl = BuildHwndList(pwndIme->spwndParent->spwndChild, BWL_ENUMLIST, NULL); 02391 if (pbwl != NULL) { 02392 fRet = TRUE; 02393 for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) { 02394 PWND pwndT = RevalidateHwnd(*phwnd); 02395 02396 // If pwndT is the current active IME window, we should skip it 02397 // since it's the only one window allowed to show status, and 02398 // we've already taken care of it. 02399 if (pwndT == NULL || (/*pwndIme && */pwndIme == pwndT)) { // Can skip pwndIme != NULL test 02400 continue; 02401 } 02402 02403 // We are going to touch IME windows only 02404 if (pwndT->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME] && 02405 !TestWF(pwndT, WFINDESTROY)) { 02406 02407 PIMEUI pimeui = ((PIMEWND)pwndT)->pimeui; 02408 02409 if (pimeui == NULL || pimeui == (PIMEUI)-1) { 02410 continue; 02411 } 02412 02413 if (pti == NULL || pti == GETPTI(pwndT)) { 02414 BOOLEAN fAttached = FALSE; 02415 PWND pwndIMC; 02416 02417 // If pwndT is not a window of the current process, we have to138163 02418 // attach the process to get access to pimeui. 02419 if (GETPTI(pwndT)->ppi != ptiCurrent->ppi) { 02420 RIPMSG0(RIP_VERBOSE, "Attaching process in xxxCheckImeShowStatus"); 02421 KeAttachProcess(&GETPTI(pwndT)->ppi->Process->Pcb); 02422 fAttached = TRUE; 02423 } 02424 02425 try { 02426 if (ProbeAndReadStructure(pimeui, IMEUI).fShowStatus) { 02427 if (pti == NULL) { 02428 RIPMSG0(RIP_VERBOSE, "xxxCheckImeShowStatus: the status window is shown !!"); 02429 } 02430 if ((pwndIMC = RevalidateHwnd(pimeui->hwndIMC)) != NULL) { 02431 pimeui->fShowStatus = FALSE; 02432 } 02433 } else { 02434 pwndIMC = NULL; 02435 } 02436 02437 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 02438 pwndIMC = NULL; 02439 } 02440 if (fAttached) { 02441 KeDetachProcess(); 02442 } 02443 02444 if (pwndIMC && GETPTI(pwndIMC) && !(GETPTI(pwndIMC)->TIF_flags & TIF_INCLEANUP)) { 02445 TL tl; 02446 02447 ThreadLockAlways(pwndIMC, &tl); 02448 RIPMSG1(RIP_VERBOSE, "Sending WM_IME_NOTIFY to %#p, IMN_CLOSESTATUSWINDOW", pwndIMC); 02449 xxxSendMessage(pwndIMC, WM_IME_NOTIFY, IMN_CLOSESTATUSWINDOW, 0L); 02450 ThreadUnlock(&tl); 02451 } 02452 02453 } 02454 } 02455 } 02456 FreeHwndList(pbwl); 02457 } 02458 return fRet; 02459 } 02460 02461 LRESULT xxxSendMessageToUI( 02462 PTHREADINFO ptiIme, 02463 PIMEUI pimeui, 02464 UINT message, 02465 WPARAM wParam, 02466 LPARAM lParam) 02467 { 02468 PWND pwndUI; 02469 LRESULT lRet = 0L; 02470 TL tl; 02471 BOOL fAttached = FALSE; 02472 02473 CheckCritIn(); 02474 02475 if (ptiIme != PtiCurrent()) { 02476 fAttached = TRUE; 02477 KeAttachProcess(&ptiIme->ppi->Process->Pcb); 02478 } 02479 02480 try { 02481 pwndUI = RevalidateHwnd(ProbeAndReadStructure(pimeui, IMEUI).hwndUI); 02482 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 02483 pwndUI = NULL; 02484 } 02485 02486 if (pwndUI != NULL){ 02487 try { 02488 ProbeAndReadUlong((PULONG)&pimeui->nCntInIMEProc); 02489 InterlockedIncrement(&pimeui->nCntInIMEProc); // Mark to avoid recursion. 02490 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 02491 goto skip_it; 02492 } 02493 if (fAttached) { 02494 KeDetachProcess(); 02495 } 02496 02497 ThreadLockAlways(pwndUI, &tl); 02498 RIPMSG3(RIP_VERBOSE, "Sending message UI pwnd=%#p, msg:%x to wParam=%#p", pwndUI, message, wParam); 02499 lRet = xxxSendMessage(pwndUI, message, wParam, lParam); 02500 ThreadUnlock(&tl); 02501 02502 if (fAttached) { 02503 KeAttachProcess(&ptiIme->ppi->Process->Pcb); 02504 } 02505 try { 02506 InterlockedDecrement(&pimeui->nCntInIMEProc); // Mark to avoid recursion. 02507 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 02508 } 02509 } 02510 skip_it: 02511 if (fAttached) { 02512 KeDetachProcess(); 02513 } 02514 02515 return lRet; 02516 } 02517 02518 VOID xxxSendOpenStatusNotify( 02519 PTHREADINFO ptiIme, 02520 PIMEUI pimeui, 02521 PWND pwndApp, 02522 BOOL fOpen) 02523 { 02524 WPARAM wParam = fOpen ? IMN_OPENSTATUSWINDOW : IMN_CLOSESTATUSWINDOW; 02525 02526 UserAssert(GETPTI(pwndApp)); 02527 02528 if (GETPTI(pwndApp)->dwExpWinVer >= VER40 && pwndApp->hImc != NULL) { 02529 TL tl; 02530 ThreadLockAlways(pwndApp, &tl); 02531 RIPMSG2(RIP_VERBOSE, "Sending %s to pwnd=%#p", 02532 fOpen ? "IMN_OPENSTATUSWINDOW" : "IMN_CLOSESTATUSWINDOW", 02533 pwndApp); 02534 xxxSendMessage(pwndApp, WM_IME_NOTIFY, wParam, 0L); 02535 ThreadUnlock(&tl); 02536 } 02537 else { 02538 xxxSendMessageToUI(ptiIme, pimeui, WM_IME_NOTIFY, wParam, 0L); 02539 } 02540 02541 return; 02542 } 02543 02544 VOID xxxNotifyImeShowStatus(PWND pwndIme) 02545 { 02546 PIMEUI pimeui; 02547 BOOL fShow; 02548 PWND pwnd; 02549 PTHREADINFO ptiIme, ptiCurrent; 02550 BOOL fSendOpenStatusNotify = FALSE; 02551 02552 if (!IS_IME_ENABLED() || TestWF(pwndIme, WFINDESTROY)) { 02553 RIPMSG0(RIP_WARNING, "IME is not enabled or in destroy."); 02554 return; 02555 } 02556 02557 ptiCurrent = PtiCurrent(); 02558 ptiIme = GETPTI(pwndIme); 02559 02560 if (ptiIme != ptiCurrent) { 02561 RIPMSG1(RIP_VERBOSE, "Attaching pti=%#p", ptiIme); 02562 KeAttachProcess(&GETPTI(pwndIme)->ppi->Process->Pcb); 02563 } 02564 02565 try { 02566 pimeui = ((PIMEWND)pwndIme)->pimeui; 02567 fShow = gfIMEShowStatus && ProbeAndReadStructure(pimeui, IMEUI).fCtrlShowStatus; 02568 02569 pwnd = RevalidateHwnd(pimeui->hwndIMC); 02570 02571 if (pwnd != NULL || (pwnd = GETPTI(pwndIme)->pq->spwndFocus) != NULL) { 02572 RIPMSG0(RIP_VERBOSE, "Setting new show status."); 02573 fSendOpenStatusNotify = TRUE; 02574 pimeui->fShowStatus = fShow; 02575 } 02576 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 02577 if (ptiIme != ptiCurrent) { 02578 KeDetachProcess(); 02579 } 02580 return; 02581 } 02582 if (ptiIme != ptiCurrent) { 02583 KeDetachProcess(); 02584 } 02585 02586 if (fSendOpenStatusNotify) { 02587 RIPMSG1(RIP_VERBOSE, "Sending OpenStatus fShow=%d", fShow); 02588 xxxSendOpenStatusNotify(ptiIme, pimeui, pwnd, fShow); 02589 } 02590 02591 // Check the show status of all IME windows in the system. 02592 if (!TestWF(pwndIme, WFINDESTROY)) { 02593 xxxCheckImeShowStatus(pwndIme, NULL); 02594 } 02595 } 02596 02597 02598 /***************************************************************************\ 02599 * xxxSetIMEShowStatus() - 02600 * 02601 * Set IME Status windows' show status. Called from SystemParametersInfo() 02602 * handler. 02603 * 02604 \***************************************************************************/ 02605 02606 BOOL xxxSetIMEShowStatus(IN BOOL fShow) 02607 { 02608 CheckCritIn(); 02609 02610 UserAssert(fShow == FALSE || fShow == TRUE); 02611 02612 if (gfIMEShowStatus == fShow) { 02613 return TRUE; 02614 } 02615 02616 if (gfIMEShowStatus == IMESHOWSTATUS_NOTINITIALIZED) { 02617 /* 02618 * Called for the first time after logon. 02619 * No need to write the value to the registry. 02620 */ 02621 gfIMEShowStatus = fShow; 02622 } 02623 else { 02624 /* 02625 * We need to save the new fShow status to the registry. 02626 */ 02627 TL tlName; 02628 PUNICODE_STRING pProfileUserName; 02629 BOOL fOK = FALSE; 02630 02631 pProfileUserName = CreateProfileUserName(&tlName); 02632 if (pProfileUserName) { 02633 UserAssert(pProfileUserName != NULL); 02634 fOK = UpdateWinIniInt(pProfileUserName, PMAP_INPUTMETHOD, STR_SHOWIMESTATUS, fShow); 02635 FreeProfileUserName(pProfileUserName, &tlName); 02636 } 02637 if (!fOK) { 02638 return FALSE; 02639 } 02640 gfIMEShowStatus = fShow; 02641 } 02642 02643 /* 02644 * If IME is not enabled, further processing is not needed 02645 */ 02646 if (!IS_IME_ENABLED()) { 02647 return TRUE; 02648 } 02649 02650 /* 02651 * Let the current active IME window know the change. 02652 */ 02653 if (gpqForeground && gpqForeground->spwndFocus) { 02654 PTHREADINFO ptiFocus = GETPTI(gpqForeground->spwndFocus); 02655 TL tl; 02656 02657 UserAssert(ptiFocus); 02658 02659 if (ptiFocus->spwndDefaultIme && !(ptiFocus->TIF_flags & TIF_INCLEANUP)) { 02660 ThreadLockAlways(ptiFocus->spwndDefaultIme, &tl); 02661 xxxNotifyImeShowStatus(ptiFocus->spwndDefaultIme); 02662 ThreadUnlock(&tl); 02663 } 02664 } 02665 02666 return TRUE; 02667 } 02668 02669 /***************************************************************************\ 02670 * xxxBroadcastImeShowStatusChange() - 02671 * 02672 * Let all IME windows in the desktop, including myself know about the 02673 * status change. 02674 * This routine does not touch the registry, assuming internat.exe updated 02675 * the registry. 02676 * 02677 \***************************************************************************/ 02678 02679 VOID xxxBroadcastImeShowStatusChange(PWND pwndIme, BOOL fShow) 02680 { 02681 CheckCritIn(); 02682 02683 gfIMEShowStatus = !!fShow; 02684 xxxNotifyImeShowStatus(pwndIme); 02685 } 02686 02687 /***************************************************************************\ 02688 * xxxCheckImeShowStatusInThread() - 02689 * 02690 * Let all IME windows in the same thread know about the status change. 02691 * Called from ImeSetContextHandler(). 02692 * 02693 \***************************************************************************/ 02694 VOID xxxCheckImeShowStatusInThread(PWND pwndIme) 02695 { 02696 if (IS_IME_ENABLED()) { 02697 UserAssert(pwndIme); 02698 02699 if (!TestWF(pwndIme, WFINDESTROY)) { 02700 xxxCheckImeShowStatus(pwndIme, GETPTI(pwndIme)); 02701 } 02702 } 02703 } 02704 02705 BOOL _GetIMEShowStatus(VOID) 02706 { 02707 return gfIMEShowStatus != FALSE; 02708 } 02709

Generated on Sat May 15 19:41:00 2004 for test by doxygen 1.3.7