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

kbdlyout.c

Go to the documentation of this file.
00001 /**************************** Module Header ********************************\ 00002 * Module Name: kbdlyout.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * Keyboard Layout API 00007 * 00008 * History: 00009 * 04-14-92 IanJa Created 00010 \***************************************************************************/ 00011 00012 #include "precomp.h" 00013 #pragma hdrstop 00014 00015 /* 00016 * Workers (forward declarations) 00017 */ 00018 BOOL xxxInternalUnloadKeyboardLayout(PWINDOWSTATION, PKL, UINT); 00019 VOID ReorderKeyboardLayouts(PWINDOWSTATION, PKL); 00020 00021 /* 00022 * Note that this only works for sections < 64K 00023 */ 00024 #define FIXUP_PTR(p, pBase) ((p) ? (p) = (PVOID)((PBYTE)pBase + (WORD)(ULONG_PTR)(p)) : 0) 00025 00026 00027 /****************************************************************************\ 00028 * HKLtoPKL 00029 * 00030 * pti - thread to look in 00031 * hkl - HKL_NEXT or HKL_PREV 00032 * Finds the the next/prev LOADED layout, NULL if none. 00033 * (Starts from the pti's active layout, may return pklActive itself) 00034 * - a real HKL (Keyboard Layout handle): 00035 * Finds the kbd layout struct (loaded or not), NULL if no match found. 00036 * 00037 * History: 00038 * 1997-02-05 IanJa added pti parameter 00039 \****************************************************************************/ 00040 PKL HKLtoPKL( 00041 PTHREADINFO pti, 00042 HKL hkl) 00043 { 00044 PKL pklActive; 00045 PKL pkl; 00046 00047 UserAssert(pti != NULL); 00048 if ((pklActive = pti->spklActive) == NULL) { 00049 return NULL; 00050 } 00051 00052 pkl = pklActive; 00053 00054 if (hkl == (HKL)HKL_PREV) { 00055 do { 00056 pkl = pkl->pklPrev; 00057 if (!(pkl->dwKL_Flags & KL_UNLOADED)) { 00058 return pkl; 00059 } 00060 } while (pkl != pklActive); 00061 return NULL; 00062 } else if (hkl == (HKL)HKL_NEXT) { 00063 do { 00064 pkl = pkl->pklNext; 00065 if (!(pkl->dwKL_Flags & KL_UNLOADED)) { 00066 return pkl; 00067 } 00068 } while (pkl != pklActive); 00069 return NULL; 00070 } 00071 00072 /* 00073 * Find the pkl for this hkl. 00074 * If the kbd layout isn't specified (in the HIWORD), ignore it and look 00075 * for a Locale match only. (Mohamed Hamid's fix for Word bug) 00076 */ 00077 if (HandleToUlong(hkl) & 0xffff0000) { 00078 do { 00079 if (pkl->hkl == hkl) { 00080 return pkl; 00081 } 00082 pkl = pkl->pklNext; 00083 } while (pkl != pklActive); 00084 } else { 00085 do { 00086 if (LOWORD(HandleToUlong(pkl->hkl)) == LOWORD(HandleToUlong(hkl))) { 00087 return pkl; 00088 } 00089 pkl = pkl->pklNext; 00090 } while (pkl != pklActive); 00091 } 00092 00093 return NULL; 00094 } 00095 00096 00097 /***************************************************************************\ 00098 * ReadLayoutFile 00099 * 00100 * Maps layout file into memory and initializes layout table. 00101 * 00102 * History: 00103 * 01-10-95 JimA Created. 00104 \***************************************************************************/ 00105 00106 PKBDTABLES ReadLayoutFile( 00107 PKBDFILE pkf, 00108 HANDLE hFile, 00109 UINT offTable, 00110 PKBDNLSTABLES *ppNlsTables) 00111 { 00112 HANDLE hmap; 00113 SIZE_T ulViewSize = 0; 00114 NTSTATUS Status; 00115 PIMAGE_DOS_HEADER DosHdr; 00116 PIMAGE_NT_HEADERS NtHeader; 00117 PIMAGE_SECTION_HEADER SectionTableEntry; 00118 ULONG NumberOfSubsections; 00119 ULONG OffsetToSectionTable; 00120 PBYTE pBaseDst, pBaseVirt; 00121 PKBDTABLES pktNew = NULL; 00122 DWORD dwDataSize; 00123 PKBDNLSTABLES pknlstNew = NULL; 00124 UINT offNlsTable = HIWORD(offTable); 00125 /* 00126 * Mask off hiword. 00127 */ 00128 offTable &= 0x0000FFFF; 00129 00130 /* 00131 * Initialize KbdNlsTables with NULL. 00132 */ 00133 *ppNlsTables = NULL; 00134 00135 /* 00136 * Map the layout file into memory 00137 */ 00138 DosHdr = NULL; 00139 Status = ZwCreateSection(&hmap, SECTION_ALL_ACCESS, NULL, 00140 NULL, PAGE_READONLY, SEC_COMMIT, hFile); 00141 if (!NT_SUCCESS(Status)) 00142 return NULL; 00143 00144 Status = ZwMapViewOfSection(hmap, NtCurrentProcess(), &DosHdr, 0, 0, NULL, 00145 &ulViewSize, ViewShare, 0, PAGE_READONLY); 00146 if (!NT_SUCCESS(Status)) { 00147 goto exitread; 00148 } 00149 00150 /* 00151 * HACK Part 2! We find the .data section in the file header 00152 * and by subtracting the virtual address from offTable find 00153 * the offset in the section of the layout table. 00154 */ 00155 NtHeader = (PIMAGE_NT_HEADERS)((PBYTE)DosHdr + (ULONG)DosHdr->e_lfanew); 00156 00157 /* 00158 * Build the next subsections. 00159 */ 00160 NumberOfSubsections = NtHeader->FileHeader.NumberOfSections; 00161 00162 /* 00163 * At this point the object table is read in (if it was not 00164 * already read in) and may displace the image header. 00165 */ 00166 OffsetToSectionTable = sizeof(ULONG) + 00167 sizeof(IMAGE_FILE_HEADER) + 00168 NtHeader->FileHeader.SizeOfOptionalHeader; 00169 SectionTableEntry = (PIMAGE_SECTION_HEADER)((PBYTE)NtHeader + 00170 OffsetToSectionTable); 00171 00172 while (NumberOfSubsections > 0) { 00173 if (strcmp(SectionTableEntry->Name, ".data") == 0) 00174 break; 00175 00176 SectionTableEntry++; 00177 NumberOfSubsections--; 00178 } 00179 if (NumberOfSubsections == 0) { 00180 goto exitread; 00181 } 00182 00183 /* 00184 * We found the section, now compute starting offset and the table size. 00185 */ 00186 offTable -= SectionTableEntry->VirtualAddress; 00187 dwDataSize = SectionTableEntry->Misc.VirtualSize; 00188 00189 /* 00190 * Allocate layout table and copy from file. 00191 */ 00192 pBaseDst = UserAllocPool(dwDataSize, TAG_KBDTABLE); 00193 if (pBaseDst != NULL) { 00194 VK_TO_WCHAR_TABLE *pVkToWcharTable; 00195 VSC_LPWSTR *pKeyName; 00196 LPWSTR *lpDeadKey; 00197 00198 pkf->hBase = (HANDLE)pBaseDst; 00199 RtlMoveMemory(pBaseDst, (PBYTE)DosHdr + 00200 SectionTableEntry->PointerToRawData, dwDataSize); 00201 00202 if (ISTS()) { 00203 pkf->Size = dwDataSize; // For shadow hotkey processing 00204 } 00205 00206 /* 00207 * Compute table address and fixup pointers in table. 00208 */ 00209 pktNew = (PKBDTABLES)(pBaseDst + offTable); 00210 00211 /* 00212 * The address in the data section has the virtual address 00213 * added in, so we need to adjust the fixup pointer to 00214 * compensate. 00215 */ 00216 pBaseVirt = pBaseDst - SectionTableEntry->VirtualAddress; 00217 00218 FIXUP_PTR(pktNew->pCharModifiers, pBaseVirt); 00219 FIXUP_PTR(pktNew->pCharModifiers->pVkToBit, pBaseVirt); 00220 if (FIXUP_PTR(pktNew->pVkToWcharTable, pBaseVirt)) { 00221 for (pVkToWcharTable = pktNew->pVkToWcharTable; 00222 pVkToWcharTable->pVkToWchars != NULL; pVkToWcharTable++) 00223 FIXUP_PTR(pVkToWcharTable->pVkToWchars, pBaseVirt); 00224 } 00225 FIXUP_PTR(pktNew->pDeadKey, pBaseVirt); 00226 /* 00227 * Version 1 layouts support ligatures. 00228 */ 00229 if (GET_KBD_VERSION(pktNew)) { 00230 FIXUP_PTR(pktNew->pLigature, pBaseVirt); 00231 } 00232 if (FIXUP_PTR(pktNew->pKeyNames, pBaseVirt)) { 00233 for (pKeyName = pktNew->pKeyNames; pKeyName->vsc != 0; pKeyName++) 00234 FIXUP_PTR(pKeyName->pwsz, pBaseVirt); 00235 } 00236 if (FIXUP_PTR(pktNew->pKeyNamesExt, pBaseVirt)) { 00237 for (pKeyName = pktNew->pKeyNamesExt; pKeyName->vsc != 0; pKeyName++) 00238 FIXUP_PTR(pKeyName->pwsz, pBaseVirt); 00239 } 00240 if (FIXUP_PTR(pktNew->pKeyNamesDead, pBaseVirt)) { 00241 for (lpDeadKey = pktNew->pKeyNamesDead; *lpDeadKey != NULL; 00242 lpDeadKey++) 00243 FIXUP_PTR(*lpDeadKey, pBaseVirt); 00244 } 00245 FIXUP_PTR(pktNew->pusVSCtoVK, pBaseVirt); 00246 FIXUP_PTR(pktNew->pVSCtoVK_E0, pBaseVirt); 00247 FIXUP_PTR(pktNew->pVSCtoVK_E1, pBaseVirt); 00248 00249 if (offNlsTable) { 00250 /* 00251 * Compute table address and fixup pointers in table. 00252 */ 00253 offNlsTable -= SectionTableEntry->VirtualAddress; 00254 pknlstNew = (PKBDNLSTABLES)(pBaseDst + offNlsTable); 00255 00256 /* 00257 * Fixup the address. 00258 */ 00259 FIXUP_PTR(pknlstNew->pVkToF, pBaseVirt); 00260 FIXUP_PTR(pknlstNew->pusMouseVKey, pBaseVirt); 00261 00262 /* 00263 * Save the pointer. 00264 */ 00265 *ppNlsTables = pknlstNew; 00266 00267 #if DBG_FE 00268 { 00269 UINT NumOfVkToF = pknlstNew->NumOfVkToF; 00270 00271 DbgPrint("NumOfVkToF - %d\n",NumOfVkToF); 00272 00273 while(NumOfVkToF) { 00274 DbgPrint("VK = %x\n",pknlstNew->pVkToF[NumOfVkToF-1].Vk); 00275 NumOfVkToF--; 00276 } 00277 } 00278 #endif // DBG_FE 00279 } 00280 } 00281 00282 exitread: 00283 00284 /* 00285 * Unmap and release the mapped section. 00286 */ 00287 ZwUnmapViewOfSection(NtCurrentProcess(), DosHdr); 00288 ZwClose(hmap); 00289 00290 return pktNew; 00291 } 00292 00293 PKBDTABLES PrepareFallbackKeyboardFile(PKBDFILE pkf) 00294 { 00295 PBYTE pBaseDst; 00296 00297 pBaseDst = UserAllocPool(sizeof(KBDTABLES), TAG_KBDTABLE); 00298 if (pBaseDst != NULL) { 00299 RtlCopyMemory(pBaseDst, &KbdTablesFallback, sizeof KbdTablesFallback); 00300 // Note: Unlike ReadLayoutFile(), 00301 // we don't need to fix up pointers in struct KBDFILE. 00302 } 00303 pkf->hBase = (HANDLE)pBaseDst; 00304 pkf->pKbdNlsTbl = NULL; 00305 return (PKBDTABLES)pBaseDst; 00306 } 00307 00308 00309 /***************************************************************************\ 00310 * LoadKeyboardLayoutFile 00311 * 00312 * History: 00313 * 10-29-95 GregoryW Created. 00314 \***************************************************************************/ 00315 00316 PKBDFILE LoadKeyboardLayoutFile( 00317 HANDLE hFile, 00318 UINT offTable, 00319 LPCWSTR pwszKLID) 00320 { 00321 PKBDFILE pkf = gpkfList; 00322 00323 if (pkf) { 00324 int iCmp; 00325 00326 do { 00327 iCmp = wcscmp(pkf->awchKF, pwszKLID); 00328 if (iCmp == 0) { 00329 00330 /* 00331 * The layout is already loaded. 00332 */ 00333 return pkf; 00334 } 00335 pkf = pkf->pkfNext; 00336 } while (pkf); 00337 } 00338 00339 /* 00340 * Allocate a new Keyboard File structure. 00341 */ 00342 pkf = (PKBDFILE)HMAllocObject(NULL, NULL, TYPE_KBDFILE, sizeof(KBDFILE)); 00343 if (!pkf) { 00344 RIPMSG0(RIP_WARNING, "Keyboard Layout File: out of memory"); 00345 return (PKBDFILE)NULL; 00346 } 00347 00348 /* 00349 * Load layout table. 00350 */ 00351 if (hFile != NULL) { 00352 /* 00353 * Load NLS layout table also... 00354 */ 00355 pkf->pKbdTbl = ReadLayoutFile(pkf, hFile, offTable, &(pkf->pKbdNlsTbl)); 00356 } else { 00357 /* 00358 * We failed to open the keyboard layout file in client side 00359 * because the dll was missing. 00360 * If this ever happens, we used to fail creating 00361 * a window station, but we should allow a user 00362 * at least to boot the system. 00363 */ 00364 pkf->pKbdTbl = PrepareFallbackKeyboardFile(pkf); 00365 // Note: pkf->pKbdNlsTbl has been NULL'ed in PrepareFallbackKeyboardFile() 00366 } 00367 00368 if (pkf->pKbdTbl == NULL) { 00369 HMFreeObject(pkf); 00370 return (PKBDFILE)NULL; 00371 } 00372 00373 wcsncpycch(pkf->awchKF, pwszKLID, sizeof(pkf->awchKF) / sizeof(WCHAR)); 00374 00375 /* 00376 * Put keyboard layout file at front of list. 00377 */ 00378 pkf->pkfNext = gpkfList; 00379 gpkfList = pkf; 00380 00381 return pkf; 00382 } 00383 00384 /***************************************************************************\ 00385 * RemoveKeyboardLayoutFile 00386 * 00387 * History: 00388 * 10-29-95 GregoryW Created. 00389 \***************************************************************************/ 00390 VOID RemoveKeyboardLayoutFile( 00391 PKBDFILE pkf) 00392 { 00393 PKBDFILE pkfPrev, pkfCur; 00394 00395 // FE: NT4 SP4 #107809 00396 if (gpKbdTbl == pkf->pKbdTbl) { 00397 gpKbdTbl = &KbdTablesFallback; 00398 } 00399 if (gpKbdNlsTbl == pkf->pKbdNlsTbl) { 00400 gpKbdNlsTbl = NULL; 00401 } 00402 00403 /* 00404 * Good old linked list management 101 00405 */ 00406 if (pkf == gpkfList) { 00407 /* 00408 * Head of the list. 00409 */ 00410 gpkfList = pkf->pkfNext; 00411 return; 00412 } 00413 pkfPrev = gpkfList; 00414 pkfCur = gpkfList->pkfNext; 00415 while (pkf != pkfCur) { 00416 pkfPrev = pkfCur; 00417 pkfCur = pkfCur->pkfNext; 00418 } 00419 /* 00420 * Found it! 00421 */ 00422 pkfPrev->pkfNext = pkfCur->pkfNext; 00423 } 00424 00425 /***************************************************************************\ 00426 * DestroyKF 00427 * 00428 * Called when a keyboard layout file is destroyed due to an unlock. 00429 * 00430 * History: 00431 * 24-Feb-1997 adams Created. 00432 \***************************************************************************/ 00433 00434 void 00435 DestroyKF(PKBDFILE pkf) 00436 { 00437 if (!HMMarkObjectDestroy(pkf)) 00438 return; 00439 00440 RemoveKeyboardLayoutFile(pkf); 00441 UserFreePool(pkf->hBase); 00442 HMFreeObject(pkf); 00443 } 00444 00445 INT GetThreadsWithPKL( 00446 PTHREADINFO **ppptiList, 00447 PKL pkl) 00448 { 00449 PTHREADINFO ptiT, *pptiT, *pptiListAllocated; 00450 INT cThreads, cThreadsAllocated; 00451 PWINDOWSTATION pwinsta; 00452 PDESKTOP pdesk; 00453 PLIST_ENTRY pHead, pEntry; 00454 00455 if (ppptiList != NULL) 00456 *ppptiList = NULL; 00457 00458 cThreads = 0; 00459 00460 /* 00461 * allocate a first list for 128 entries 00462 */ 00463 cThreadsAllocated = 128; 00464 pptiListAllocated = UserAllocPool(cThreadsAllocated * sizeof(PTHREADINFO), 00465 TAG_SYSTEM); 00466 00467 if (pptiListAllocated == NULL) { 00468 RIPMSG0(RIP_WARNING, "GetPKLinThreads: out of memory"); 00469 return 0; 00470 } 00471 00472 // for all the winstations 00473 for (pwinsta = grpWinStaList; pwinsta != NULL ; pwinsta = pwinsta->rpwinstaNext) { 00474 00475 // for all the desktops in that winstation 00476 for (pdesk = pwinsta->rpdeskList; pdesk != NULL ; pdesk = pdesk->rpdeskNext) { 00477 00478 pHead = &pdesk->PtiList; 00479 00480 // for all the threads in that desktop 00481 for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) { 00482 00483 ptiT = CONTAINING_RECORD(pEntry, THREADINFO, PtiLink); 00484 00485 if (ptiT == NULL) { 00486 continue; 00487 } 00488 00489 if (pkl && (pkl != ptiT->spklActive)) { // #99321 cmp pkls, not hkls? 00490 continue; 00491 } 00492 00493 if (cThreads == cThreadsAllocated) { 00494 00495 cThreadsAllocated += 128; 00496 00497 pptiT = UserReAllocPool(pptiListAllocated, 00498 cThreads * sizeof(PTHREADINFO), 00499 cThreadsAllocated * sizeof(PTHREADINFO), 00500 TAG_SYSTEM); 00501 00502 if (pptiT == NULL) { 00503 RIPMSG0(RIP_ERROR, "GetPKLinThreads: Out of memory"); 00504 UserFreePool(pptiListAllocated); 00505 return 0; 00506 } 00507 00508 pptiListAllocated = pptiT; 00509 00510 } 00511 00512 pptiListAllocated[cThreads++] = ptiT; 00513 } 00514 } 00515 } 00516 00517 /* 00518 * add CSRSS threads 00519 */ 00520 for (ptiT = PpiFromProcess(gpepCSRSS)->ptiList; ptiT != NULL; ptiT = ptiT->ptiSibling) { 00521 00522 if (pkl && (pkl != ptiT->spklActive)) { // #99321 cmp pkls, not hkls? 00523 continue; 00524 } 00525 00526 if (cThreads == cThreadsAllocated) { 00527 00528 cThreadsAllocated += 128; 00529 00530 pptiT = UserReAllocPool(pptiListAllocated, 00531 cThreads * sizeof(PTHREADINFO), 00532 cThreadsAllocated * sizeof(PTHREADINFO), 00533 TAG_SYSTEM); 00534 00535 if (pptiT == NULL) { 00536 RIPMSG0(RIP_ERROR, "GetPKLinThreads: Out of memory"); 00537 UserFreePool(pptiListAllocated); 00538 return 0; 00539 } 00540 00541 pptiListAllocated = pptiT; 00542 00543 } 00544 00545 pptiListAllocated[cThreads++] = ptiT; 00546 } 00547 00548 if (cThreads == 0) { 00549 UserFreePool(pptiListAllocated); 00550 } else if (ppptiList != NULL) { 00551 *ppptiList = pptiListAllocated; 00552 } else { 00553 UserFreePool(pptiListAllocated); 00554 } 00555 00556 return cThreads; 00557 } 00558 00559 00560 VOID xxxSetPKLinThreads( 00561 PKL pklNew, 00562 PKL pklToBeReplaced) 00563 { 00564 PTHREADINFO *pptiList; 00565 INT cThreads, i; 00566 00567 UserAssert(pklNew != pklToBeReplaced); 00568 00569 CheckLock(pklNew); 00570 CheckLock(pklToBeReplaced); 00571 00572 cThreads = GetThreadsWithPKL(&pptiList, pklToBeReplaced); 00573 00574 /* 00575 * Will the foreground thread's keyboard layout change? 00576 */ 00577 if (pklNew && gptiForeground && gptiForeground->spklActive == pklToBeReplaced) { 00578 ChangeForegroundKeyboardTable(pklToBeReplaced, pklNew); 00579 } 00580 00581 if (pptiList != NULL) { 00582 if (pklToBeReplaced == NULL) { 00583 for (i = 0; i < cThreads; i++) { 00584 Lock(&pptiList[i]->spklActive, pklNew); 00585 } 00586 } else { 00587 /* 00588 * This is a replace. First, deactivate the *replaced* IME by 00589 * activating the pklNew. Second, unload the *replaced* IME. 00590 */ 00591 xxxImmActivateAndUnloadThreadsLayout(pptiList, cThreads, NULL, 00592 pklNew, HandleToUlong(pklToBeReplaced->hkl)); 00593 } 00594 UserFreePool(pptiList); 00595 } 00596 00597 /* 00598 * If this is a replace, link the new layout immediately after the 00599 * layout being replaced. This maintains ordering of layouts when 00600 * the *replaced* layout is unloaded. The input locale panel in the 00601 * regional settings applet depends on this. 00602 */ 00603 if (pklToBeReplaced) { 00604 if (pklToBeReplaced->pklNext == pklNew) { 00605 /* 00606 * Ordering already correct. Nothing to do. 00607 */ 00608 return; 00609 } 00610 /* 00611 * Move new layout immediately after layout being replaced. 00612 * 1. Remove new layout from current position. 00613 * 2. Update links in new layout. 00614 * 3. Link new layout into desired position. 00615 */ 00616 pklNew->pklPrev->pklNext = pklNew->pklNext; 00617 pklNew->pklNext->pklPrev = pklNew->pklPrev; 00618 00619 pklNew->pklNext = pklToBeReplaced->pklNext; 00620 pklNew->pklPrev = pklToBeReplaced; 00621 00622 pklToBeReplaced->pklNext->pklPrev = pklNew; 00623 pklToBeReplaced->pklNext = pklNew; 00624 } 00625 } 00626 00627 VOID xxxFreeImeKeyboardLayouts( 00628 PWINDOWSTATION pwinsta) 00629 { 00630 PTHREADINFO *pptiList; 00631 INT cThreads; 00632 00633 if (pwinsta->dwWSF_Flags & WSF_NOIO) 00634 return; 00635 00636 /* 00637 * should make GetThreadsWithPKL aware of pwinsta? 00638 */ 00639 cThreads = GetThreadsWithPKL(&pptiList, NULL); 00640 if (pptiList != NULL) { 00641 xxxImmUnloadThreadsLayout(pptiList, cThreads, NULL, IFL_UNLOADIME); 00642 UserFreePool(pptiList); 00643 } 00644 00645 return; 00646 } 00647 00648 /***************************************************************************\ 00649 * xxxLoadKeyboardLayoutEx 00650 * 00651 * History: 00652 \***************************************************************************/ 00653 00654 HKL xxxLoadKeyboardLayoutEx( 00655 PWINDOWSTATION pwinsta, 00656 HANDLE hFile, 00657 HKL hklToBeReplaced, 00658 UINT offTable, 00659 LPCWSTR pwszKLID, 00660 UINT KbdInputLocale, 00661 UINT Flags) 00662 { 00663 PKL pkl, pklFirst, pklToBeReplaced; 00664 PKBDFILE pkf; 00665 CHARSETINFO cs; 00666 TL tlpkl; 00667 PTHREADINFO ptiCurrent; 00668 UNICODE_STRING strLcidKF; 00669 LCID lcidKF; 00670 BOOL bCharSet; 00671 PIMEINFOEX piiex; 00672 00673 /* 00674 * If the windowstation does not do I/O, don't load the 00675 * layout. Also check KdbInputLocale for #307132 00676 */ 00677 if ((KbdInputLocale == 0) || (pwinsta->dwWSF_Flags & WSF_NOIO)) { 00678 return NULL; 00679 } 00680 00681 /* 00682 * If hklToBeReplaced is non-NULL make sure it's valid. 00683 * NOTE: may want to verify they're not passing HKL_NEXT or HKL_PREV. 00684 */ 00685 ptiCurrent = PtiCurrent(); 00686 if (hklToBeReplaced && !(pklToBeReplaced = HKLtoPKL(ptiCurrent, hklToBeReplaced))) { 00687 return NULL; 00688 } 00689 if (KbdInputLocale == HandleToUlong(hklToBeReplaced)) { 00690 /* 00691 * Replacing a layout/lang pair with itself. Nothing to do. 00692 */ 00693 return pklToBeReplaced->hkl; 00694 } 00695 00696 if (Flags & KLF_RESET) { 00697 /* 00698 * Only WinLogon can use this flag 00699 */ 00700 if (ptiCurrent->pEThread->Cid.UniqueProcess != gpidLogon) { 00701 RIPERR0(ERROR_INVALID_FLAGS, RIP_WARNING, 00702 "Invalid flag passed to LoadKeyboardLayout" ); 00703 return NULL; 00704 } 00705 xxxFreeImeKeyboardLayouts(pwinsta); 00706 /* 00707 * Make sure we don't lose track of the left-over layouts 00708 * They have been unloaded, but are still in use by some threads). 00709 * The FALSE will prevent xxxFreeKeyboardLayouts from unlocking the 00710 * unloaded layouts. 00711 */ 00712 xxxFreeKeyboardLayouts(pwinsta, FALSE); 00713 } 00714 00715 /* 00716 * Does this hkl already exist? 00717 */ 00718 pkl = pklFirst = pwinsta->spklList; 00719 00720 if (pkl) { 00721 do { 00722 if (pkl->hkl == (HKL)IntToPtr( KbdInputLocale )) { 00723 /* 00724 * The hkl already exists. 00725 */ 00726 00727 /* 00728 * If it is unloaded (but not yet destroyed because it is 00729 * still is use), recover it. 00730 */ 00731 if (pkl->dwKL_Flags & KL_UNLOADED) { 00732 // stop it from being destroyed if not is use. 00733 PHE phe = HMPheFromObject(pkl); 00734 // An unloaded layout must be marked for destroy. 00735 UserAssert(phe->bFlags & HANDLEF_DESTROY); 00736 phe->bFlags &= ~HANDLEF_DESTROY; 00737 #if DBG 00738 phe->bFlags &= ~HANDLEF_MARKED_OK; 00739 #endif 00740 pkl->dwKL_Flags &= ~KL_UNLOADED; 00741 } else if (!(Flags & KLF_RESET)) { 00742 /* 00743 * If it was already loaded and we didn't change all layouts 00744 * with KLF_RESET, there is nothing to tell the shell about 00745 */ 00746 Flags &= ~KLF_NOTELLSHELL; 00747 } 00748 00749 goto AllPresentAndCorrectSir; 00750 } 00751 pkl = pkl->pklNext; 00752 } while (pkl != pklFirst); 00753 } 00754 00755 if (IS_IME_KBDLAYOUT((HKL)IntToPtr( KbdInputLocale ))) { 00756 /* 00757 * This is an IME keyboard layout, do a callback 00758 * to read the extended IME information structure. 00759 * Note: We can't fail the call so easily if 00760 * KLF_RESET is specified. 00761 */ 00762 piiex = xxxImmLoadLayout((HKL)IntToPtr( KbdInputLocale )); 00763 if (piiex == NULL && !(Flags & KLF_RESET)) { 00764 RIPMSG1(RIP_WARNING, 00765 "Keyboard Layout: xxxImmLoadLayout(%lx) failed", KbdInputLocale); 00766 return NULL; 00767 } 00768 } else { 00769 piiex = NULL; 00770 } 00771 00772 /* 00773 * Get the system font's font signature. These are 64-bit FS_xxx values, 00774 * but we are only asking for an ANSI ones, so gSystemFS is just a DWORD. 00775 * gSystemFS is consulted when posting WM_INPUTLANGCHANGEREQUEST (input.c) 00776 */ 00777 if (gSystemFS == 0) { 00778 LCID lcid; 00779 00780 ZwQueryDefaultLocale(FALSE, &lcid); 00781 if (xxxClientGetCharsetInfo(lcid, &cs)) { 00782 gSystemFS = cs.fs.fsCsb[0]; 00783 gSystemCPCharSet = (BYTE)cs.ciCharset; 00784 } else { 00785 gSystemFS = 0xFFFF; 00786 gSystemCPCharSet = ANSI_CHARSET; 00787 } 00788 } 00789 00790 /* 00791 * Use the Keyboard Layout's LCID to calculate the charset, codepage etc, 00792 * so that characters from that layout don't just becomes ?s if the input 00793 * locale doesn't match. This allows "dumb" applications to display the 00794 * text if the user chooses the right font. 00795 * We can't just use the HIWORD of KbdInputLocale because if a variant 00796 * keyboard layout was chosen, this will be something like F008 - have to 00797 * look inside the KF to get the real LCID of the kbdfile: this will be 00798 * something like L"00010419", and we want the last 4 digits. 00799 */ 00800 RtlInitUnicodeString(&strLcidKF, pwszKLID + 4); 00801 RtlUnicodeStringToInteger(&strLcidKF, 16, (PULONG)&lcidKF); 00802 bCharSet = xxxClientGetCharsetInfo(lcidKF, &cs); 00803 00804 /* 00805 * Keyboard Layout Handle object does not exist. Load keyboard layout file, 00806 * if not already loaded. 00807 */ 00808 if (!(pkf = LoadKeyboardLayoutFile(hFile, offTable, pwszKLID))) { 00809 goto freePiiex; 00810 } 00811 /* 00812 * Allocate a new Keyboard Layout structure (hkl) 00813 */ 00814 pkl = (PKL)HMAllocObject(NULL, NULL, TYPE_KBDLAYOUT, sizeof(KL)); 00815 if (!pkl) { 00816 RIPMSG0(RIP_WARNING, "Keyboard Layout: out of memory"); 00817 UserFreePool(pkf->hBase); 00818 HMMarkObjectDestroy(pkf); 00819 HMUnlockObject(pkf); 00820 freePiiex: 00821 if (piiex) { 00822 UserFreePool(piiex); 00823 } 00824 return NULL; 00825 } 00826 00827 /* 00828 * Link to itself in case we have to DestroyKL 00829 */ 00830 pkl->pklNext = pkl; 00831 pkl->pklPrev = pkl; 00832 00833 /* 00834 * Init KL 00835 */ 00836 pkl->dwKL_Flags = 0; 00837 pkl->wchDiacritic = 0; 00838 pkl->hkl = (HKL)IntToPtr( KbdInputLocale ); 00839 Lock(&pkl->spkf, pkf); 00840 00841 pkl->spkf->pKbdTbl->fLocaleFlags |= KLL_LAYOUT_ATTR_FROM_KLF(Flags); 00842 00843 pkl->piiex = piiex; 00844 00845 if (bCharSet) { 00846 pkl->CodePage = (WORD)cs.ciACP; 00847 pkl->dwFontSigs = cs.fs.fsCsb[1]; // font signature mask (FS_xxx values) 00848 pkl->iBaseCharset = cs.ciCharset; // charset value 00849 } else { 00850 pkl->CodePage = CP_ACP; 00851 pkl->dwFontSigs = FS_LATIN1; 00852 pkl->iBaseCharset = ANSI_CHARSET; 00853 } 00854 00855 /* 00856 * Insert KL in the double-linked circular list, at the end. 00857 */ 00858 pklFirst = pwinsta->spklList; 00859 if (pklFirst == NULL) { 00860 Lock(&pwinsta->spklList, pkl); 00861 } else { 00862 pkl->pklNext = pklFirst; 00863 pkl->pklPrev = pklFirst->pklPrev; 00864 pklFirst->pklPrev->pklNext = pkl; 00865 pklFirst->pklPrev = pkl; 00866 } 00867 00868 AllPresentAndCorrectSir: 00869 00870 // FE_IME 00871 ThreadLockAlwaysWithPti(ptiCurrent, pkl, &tlpkl); 00872 00873 if (hklToBeReplaced) { 00874 TL tlPKLToBeReplaced; 00875 ThreadLockAlwaysWithPti(ptiCurrent, pklToBeReplaced, &tlPKLToBeReplaced); 00876 xxxSetPKLinThreads(pkl, pklToBeReplaced); 00877 xxxInternalUnloadKeyboardLayout(pwinsta, pklToBeReplaced, KLF_INITTIME); 00878 ThreadUnlock(&tlPKLToBeReplaced); 00879 } 00880 00881 if (Flags & KLF_REORDER) { 00882 ReorderKeyboardLayouts(pwinsta, pkl); 00883 } 00884 00885 if (!(Flags & KLF_NOTELLSHELL) && IsHooked(PtiCurrent(), WHF_SHELL)) { 00886 xxxCallHook(HSHELL_LANGUAGE, (WPARAM)NULL, (LPARAM)0, WH_SHELL); 00887 gLCIDSentToShell = 0; 00888 } 00889 00890 if (Flags & KLF_ACTIVATE) { 00891 TL tlPKL; 00892 ThreadLockAlwaysWithPti(ptiCurrent, pkl, &tlPKL); 00893 xxxInternalActivateKeyboardLayout(pkl, Flags, NULL); 00894 ThreadUnlock(&tlPKL); 00895 } 00896 00897 if (Flags & KLF_RESET) { 00898 RIPMSG2(RIP_VERBOSE, "Flag & KLF_RESET, locking gspklBaseLayout(%08x) with new kl(%08x)", 00899 gspklBaseLayout ? gspklBaseLayout->hkl : 0, 00900 pkl->hkl); 00901 Lock(&gspklBaseLayout, pkl); 00902 xxxSetPKLinThreads(pkl, NULL); 00903 } 00904 00905 /* 00906 * Use the hkl as the layout handle 00907 * If the KL is freed somehow, return NULL for safety. -- ianja -- 00908 */ 00909 pkl = ThreadUnlock(&tlpkl); 00910 if (pkl == NULL) { 00911 return NULL; 00912 } 00913 return pkl->hkl; 00914 } 00915 00916 HKL xxxActivateKeyboardLayout( 00917 PWINDOWSTATION pwinsta, 00918 HKL hkl, 00919 UINT Flags, 00920 PWND pwnd) 00921 { 00922 PKL pkl; 00923 TL tlPKL; 00924 HKL hklRet; 00925 PTHREADINFO ptiCurrent = PtiCurrent(); 00926 00927 CheckLock(pwnd); 00928 00929 pkl = HKLtoPKL(ptiCurrent, hkl); 00930 if (pkl == NULL) { 00931 return 0; 00932 } 00933 00934 if (Flags & KLF_REORDER) { 00935 ReorderKeyboardLayouts(pwinsta, pkl); 00936 } 00937 00938 ThreadLockAlwaysWithPti(ptiCurrent, pkl, &tlPKL); 00939 hklRet = xxxInternalActivateKeyboardLayout(pkl, Flags, pwnd); 00940 ThreadUnlock(&tlPKL); 00941 return hklRet; 00942 } 00943 00944 VOID ReorderKeyboardLayouts( 00945 PWINDOWSTATION pwinsta, 00946 PKL pkl) 00947 { 00948 PKL pklFirst = pwinsta->spklList; 00949 00950 if (pwinsta->dwWSF_Flags & WSF_NOIO) { 00951 RIPMSG1(RIP_ERROR, "ReorderKeyboardLayouts called for non-interactive windowstation %#p", 00952 pwinsta); 00953 return; 00954 } 00955 00956 UserAssert(pklFirst != NULL); 00957 00958 /* 00959 * If the layout is already at the front of the list there's nothing to do. 00960 */ 00961 if (pkl == pklFirst) { 00962 return; 00963 } 00964 /* 00965 * Cut pkl from circular list: 00966 */ 00967 pkl->pklPrev->pklNext = pkl->pklNext; 00968 pkl->pklNext->pklPrev = pkl->pklPrev; 00969 00970 /* 00971 * Insert pkl at front of list 00972 */ 00973 pkl->pklNext = pklFirst; 00974 pkl->pklPrev = pklFirst->pklPrev; 00975 00976 pklFirst->pklPrev->pklNext = pkl; 00977 pklFirst->pklPrev = pkl; 00978 00979 Lock(&pwinsta->spklList, pkl); 00980 } 00981 00982 VOID ChangeForegroundKeyboardTable(PKL pklOld, PKL pklNew) 00983 { 00984 CheckCritIn(); 00985 UserAssert(pklNew != NULL); 00986 00987 if (pklOld == pklNew || (pklOld != NULL && pklOld->spkf == pklNew->spkf)) { 00988 return; 00989 } 00990 00991 // Manage the VK_KANA toggle key for Japanese KL. 00992 // Since VK_HANGUL and VK_KANA share the same VK value and 00993 // VK_KANA is a toggle key, when keyboard layouts are switched, 00994 // VK_KANA toggle status should be restored. 00995 00996 // 00997 // If: 00998 // 1) Old and New keyboard layouts are both Japanese, do nothing. 00999 // 2) Old and New keyboard layouts are not Japanese, do nothing. 01000 // 3) Old keyboard is Japanese and new one is not, clear the KANA toggle. 01001 // 4) New keyboard is Japanese and old one is not, restore the KANA toggle. 01002 // 01003 01004 if (pklOld && JAPANESE_KBD_LAYOUT(pklOld->hkl)) { 01005 if (!JAPANESE_KBD_LAYOUT(pklNew->hkl)) { 01006 // Old keyboard layout is Japanese and the new one is not Japanese, 01007 // so we save the current KANA toggle status and clear it. 01008 gfKanaToggle = (TestAsyncKeyStateToggle(VK_KANA) != 0); 01009 RIPMSG0(RIP_VERBOSE, "Old kbd is JPN. VK_KANA toggle is being cleared.\n"); 01010 ClearAsyncKeyStateToggle(VK_KANA); 01011 ClearRawKeyToggle(VK_KANA); 01012 UpdateKeyLights(TRUE); 01013 } 01014 } else if (JAPANESE_KBD_LAYOUT(pklNew->hkl)) { 01015 // Previous keyboard layout does not exist or is not Japanese, 01016 // and the new one is Japanese. 01017 // Have to restore the KANA toggle status. 01018 RIPMSG0(RIP_VERBOSE, "New kbd is JPN. "); 01019 if (gfKanaToggle) { 01020 RIPMSG0(RIP_VERBOSE, "VK_KANA is being set.\n"); 01021 SetAsyncKeyStateToggle(VK_KANA); 01022 SetRawKeyToggle(VK_KANA); 01023 if (gptiForeground && gptiForeground->pq) { 01024 SetKeyStateToggle(gptiForeground->pq, VK_KANA); 01025 } 01026 } else { 01027 RIPMSG0(RIP_VERBOSE, "VK_KANA is beging cleared.\n"); 01028 ClearAsyncKeyStateToggle(VK_KANA); 01029 ClearRawKeyToggle(VK_KANA); 01030 if (gptiForeground && gptiForeground->pq) { 01031 ClearKeyStateToggle(gptiForeground->pq, VK_KANA); 01032 } 01033 } 01034 UpdateKeyLights(TRUE); 01035 } 01036 01037 /* 01038 * Set gpKbdTbl so foreground thread processes AltGr appropriately 01039 */ 01040 gpKbdTbl = pklNew->spkf->pKbdTbl; 01041 if (ISTS()) { 01042 ghKbdTblBase = pklNew->spkf->hBase; 01043 guKbdTblSize = pklNew->spkf->Size; 01044 } 01045 01046 UserAssert(pklNew); 01047 TAGMSG2(DBGTAG_IMM, "ChangeForegroundKeyboardTable:Changing KL NLS Table: prev HKL=%x to new HKL=%x\n", pklOld ? pklOld->hkl : 0, pklNew->hkl); 01048 TAGMSG1(DBGTAG_IMM, "ChangeForegroundKeyboardTable: new gpKbdNlsTbl=%x\n", pklNew->spkf->pKbdNlsTbl); 01049 gpKbdNlsTbl = pklNew->spkf->pKbdNlsTbl; 01050 } 01051 01052 01053 // 01054 // Toggle and push state adjusters: 01055 // 01056 // ResetPushState, AdjustPushState, AdjustPushStateForKL 01057 // 01058 01059 void ResetPushState(PTHREADINFO pti, UINT uVk) 01060 { 01061 TAGMSG1(DBGTAG_IMM, "ResetPushState: has to reset the push state of vk=%x\n", uVk); 01062 if (uVk != 0) { 01063 ClearAsyncKeyStateDown(uVk); 01064 ClearAsyncKeyStateDown(uVk); 01065 ClearRawKeyDown(uVk); 01066 ClearRawKeyToggle(uVk); 01067 ClearKeyStateDown(pti->pq, uVk); 01068 ClearKeyStateToggle(pti->pq, uVk); 01069 } 01070 } 01071 01072 // 01073 // AdjustPushState: 01074 // 01075 // Left Right Clear? 01076 // Down Vanish Down Vanish 01077 // (x) (y) (z) (w) (f) 01078 // 0 0 0 0 0 01079 // 0 0 0 1 0 01080 // 0 0 1 0 0 01081 // 0 0 1 1 1* 01082 // 01083 // 0 1 0 0 0 01084 // 0 1 0 1 0 01085 // 0 1 1 0 0 01086 // 0 1 1 1 1* 01087 // 01088 // 1 0 0 0 0 01089 // 1 0 0 1 0 01090 // 1 0 1 0 0 01091 // 1 0 1 1 0 01092 // 01093 // 1 1 0 0 1* 01094 // 1 1 0 1 1* 01095 // 1 1 1 0 0 01096 // 1 1 1 1 1* 01097 // 01098 // f = ~x~yzw + ~xyzw + xy~z~w + xy~zw + xyzw 01099 // = zw~x(y + ~y) + xy~z(~w +w) + xyzw 01100 // = zw~x + xy~z + xyzw 01101 // = xy~z + ~xzw + xyzw. 01102 // = xy(~z + zw) + ~xzw 01103 // 01104 void AdjustPushState(PTHREADINFO ptiCurrent, BYTE bBaseVk, BYTE bVkL, BYTE bVkR, PKL pklPrev, PKL pklNew) 01105 { 01106 BOOLEAN fDownL = FALSE, fDownR = FALSE; 01107 BOOLEAN fVanishL = FALSE, fVanishR = FALSE; 01108 01109 UINT uScanCode1, uScanCode2; 01110 01111 if (bVkL) { 01112 fDownL = TestRawKeyDown(bVkL) || TestAsyncKeyStateDown(bVkL) || TestKeyStateDown(ptiCurrent->pq, bVkL); 01113 uScanCode1 = InternalMapVirtualKeyEx(bVkL, 0, pklPrev->spkf->pKbdTbl); 01114 uScanCode2 = InternalMapVirtualKeyEx(bVkL, 0, pklNew->spkf->pKbdTbl); 01115 fVanishL = (uScanCode1 && uScanCode2 == 0); 01116 if (fVanishL) { 01117 ResetPushState(ptiCurrent, bVkL); 01118 } 01119 } 01120 01121 if (bVkR) { 01122 fDownR = TestRawKeyDown(bVkR) || TestAsyncKeyStateDown(bVkR) || TestKeyStateDown(ptiCurrent->pq, bVkR); 01123 uScanCode1 = InternalMapVirtualKeyEx(bVkR, 0, pklPrev->spkf->pKbdTbl); 01124 uScanCode2 = InternalMapVirtualKeyEx(bVkR, 0, pklNew->spkf->pKbdTbl); 01125 fVanishR = (uScanCode1 && uScanCode2 == 0); 01126 if (fVanishR) { 01127 ResetPushState(ptiCurrent, bVkR); 01128 } 01129 } 01130 01131 if (bBaseVk) { 01132 TAGMSG4(DBGTAG_IMM, "fDL(%d) fVL(%d) fDR(%d) fVR(%d)\n", fDownL, fVanishL, fDownR, fVanishR); 01133 if (((fDownL & fVanishL & ((BOOLEAN)~fDownR | (fDownR & fVanishR))) | ((BOOLEAN)~fDownL & fDownR & fVanishR)) & 1) { 01134 TAGMSG1(DBGTAG_IMM, "AdjustPushState(): Going to reset %x\n", bBaseVk); 01135 ResetPushState(ptiCurrent, bBaseVk); 01136 } 01137 } 01138 } 01139 01140 VOID AdjustPushStateForKL(PTHREADINFO ptiCurrent, PBYTE pbDone, PKL pklTarget, PKL pklPrev, PKL pklNew) 01141 { 01142 CONST VK_TO_BIT* pVkToBits; 01143 01144 UserAssert(pklPrev); 01145 CheckLock(pklPrev); 01146 UserAssert(pklNew); 01147 CheckLock(pklNew); 01148 01149 if (pklTarget->spkf == NULL || pklPrev->spkf == NULL) { 01150 return; 01151 } 01152 01153 pVkToBits = pklTarget->spkf->pKbdTbl->pCharModifiers->pVkToBit; 01154 01155 for (; pVkToBits->Vk; ++pVkToBits) { 01156 BYTE bVkVar1 = 0, bVkVar2 = 0; 01157 01158 // 01159 // Is it already processed ? 01160 // 01161 UserAssert(pVkToBits->Vk < 0x100); 01162 if (pbDone[pVkToBits->Vk >> 3] & (1 << (pVkToBits->Vk & 7))) { 01163 continue; 01164 } 01165 01166 switch (pVkToBits->Vk) { 01167 case VK_SHIFT: 01168 bVkVar1 = VK_LSHIFT; 01169 bVkVar2 = VK_RSHIFT; 01170 break; 01171 case VK_CONTROL: 01172 bVkVar1 = VK_LCONTROL; 01173 bVkVar2 = VK_RCONTROL; 01174 break; 01175 case VK_MENU: 01176 bVkVar1 = VK_LMENU; 01177 bVkVar2 = VK_RMENU; 01178 break; 01179 } 01180 01181 TAGMSG3(DBGTAG_IMM, "Adjusting VK=%x var1=%x var2=%x\n", pVkToBits->Vk, bVkVar1, bVkVar2); 01182 01183 AdjustPushState(ptiCurrent, pVkToBits->Vk, bVkVar1, bVkVar2, pklPrev, pklNew); 01184 01185 pbDone[pVkToBits->Vk >> 3] |= (1 << (pVkToBits->Vk & 7)); 01186 } 01187 } 01188 01189 /*****************************************************************************\ 01190 * xxxInternalActivateKeyboardLayout 01191 * 01192 * pkl - pointer to keyboard layout to switch the current thread to 01193 * Flags - KLF_RESET 01194 * KLF_SETFORPROCESS 01195 * KLLF_SHIFTLOCK (any of KLLF_GLOBAL_ATTRS) 01196 * others are ignored 01197 * pwnd - If the current thread has no focus or active window, send the 01198 * WM_INPUTLANGCHANGE message to this window (unless it is NULL too) 01199 * 01200 * History: 01201 * 1998-10-14 IanJa Added pwnd parameter 01202 \*****************************************************************************/ 01203 HKL xxxInternalActivateKeyboardLayout( 01204 PKL pkl, 01205 UINT Flags, 01206 PWND pwnd) 01207 { 01208 HKL hklPrev; 01209 PKL pklPrev; 01210 TL tlpklPrev; 01211 PTHREADINFO ptiCurrent = PtiCurrent(); 01212 01213 CheckLock(pkl); 01214 CheckLock(pwnd); 01215 01216 /* 01217 * Remember what is about to become the "previously" active hkl 01218 * for the return value. 01219 */ 01220 if (ptiCurrent->spklActive != (PKL)NULL) { 01221 pklPrev = ptiCurrent->spklActive; 01222 hklPrev = ptiCurrent->spklActive->hkl; 01223 } else { 01224 pklPrev = NULL; 01225 hklPrev = (HKL)0; 01226 } 01227 01228 /* 01229 * ShiftLock/CapsLock is a global feature applying to all layouts 01230 * Only Winlogon and the Input Locales cpanel applet set KLF_RESET. 01231 */ 01232 if (Flags & KLF_RESET) { 01233 gdwKeyboardAttributes = KLL_GLOBAL_ATTR_FROM_KLF(Flags); 01234 } 01235 01236 /* 01237 * Early out 01238 */ 01239 if (!(Flags & KLF_SETFORPROCESS) && (pkl == ptiCurrent->spklActive)) { 01240 return hklPrev; 01241 } 01242 01243 /* 01244 * Clear out diacritics when switching kbd layouts #102838 01245 */ 01246 pkl->wchDiacritic = 0; 01247 01248 /* 01249 * Update the active layout in the pti. KLF_SETFORPROCESS will always be set 01250 * when the keyboard layout switch is initiated by the keyboard hotkey. 01251 */ 01252 01253 /* 01254 * Lock the previous keyboard layout for it's used later. 01255 */ 01256 ThreadLockWithPti(ptiCurrent, pklPrev, &tlpklPrev); 01257 01258 /* 01259 * Is this is a console thread, apply this change to any process in it's 01260 * window. This can really help character-mode apps! (#58025) 01261 */ 01262 if (ptiCurrent->TIF_flags & TIF_CSRSSTHREAD) { 01263 Lock(&ptiCurrent->spklActive, pkl); 01264 ptiCurrent->pClientInfo->CodePage = pkl->CodePage; 01265 #if 0 // see Raid #58025 and #78586 01266 ptiCurrent->pClientInfo->hKL = pkl->hkl; 01267 PLIST_ENTRY pHead; 01268 PLIST_ENTRY pEntry; 01269 PQ pqCurrent = ptiCurrent->pq; 01270 PTHREADINFO ptiT; 01271 01272 pHead = &(grpdeskRitInput->PtiList); 01273 for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) { 01274 ptiT = CONTAINING_RECORD(pEntry, THREADINFO, PtiLink); 01275 if (ptiT->pq == pqCurrent) { 01276 Lock(&ptiT->spklActive, pkl); 01277 UserAssert(ptiT->pClientInfo != NULL); 01278 ptiT->pClientInfo->CodePage = pkl->CodePage; 01279 ptiT->pClientInfo->hKL = pkl->hkl; 01280 } 01281 } 01282 #endif 01283 } else if ((Flags & KLF_SETFORPROCESS) && !(ptiCurrent->TIF_flags & TIF_16BIT)) { 01284 /* 01285 * For 16 bit app., only the calling thread will have its active layout updated. 01286 */ 01287 PTHREADINFO ptiT; 01288 01289 if (IS_IME_ENABLED()) { 01290 /* 01291 * Only allow *NOT* CSRSS to make this call 01292 */ 01293 UserAssert(PsGetCurrentProcess() != gpepCSRSS); 01294 // pti->pClientInfo is updated in xxxImmActivateThreadsLayout() 01295 if (!xxxImmActivateThreadsLayout(ptiCurrent->ppi->ptiList, NULL, pkl)) { 01296 RIPMSG1(RIP_WARNING, "no layout change necessary via xxxImmActivateThreadLayout() for process %lx", ptiCurrent->ppi); 01297 goto UnlockAndGo; 01298 } 01299 } else { 01300 BOOL fKLChanged = FALSE; 01301 01302 for (ptiT = ptiCurrent->ppi->ptiList; ptiT != NULL; ptiT = ptiT->ptiSibling) { 01303 if (ptiT->spklActive != pkl && (ptiT->TIF_flags & TIF_INCLEANUP) == 0) { 01304 Lock(&ptiT->spklActive, pkl); 01305 UserAssert(ptiT->pClientInfo != NULL); 01306 ptiT->pClientInfo->CodePage = pkl->CodePage; 01307 ptiT->pClientInfo->hKL = pkl->hkl; 01308 fKLChanged = TRUE; 01309 } 01310 } 01311 if (!fKLChanged) { 01312 RIPMSG1(RIP_WARNING, "no layout change necessary for process %lx ?", ptiCurrent->ppi); 01313 goto UnlockAndGo; 01314 } 01315 } 01316 01317 } else { 01318 if (IS_IME_ENABLED()) { 01319 xxxImmActivateLayout(ptiCurrent, pkl); 01320 } else { 01321 Lock(&ptiCurrent->spklActive, pkl); 01322 } 01323 UserAssert(ptiCurrent->pClientInfo != NULL); 01324 if ((ptiCurrent->TIF_flags & TIF_INCLEANUP) == 0) { 01325 ptiCurrent->pClientInfo->CodePage = pkl->CodePage; 01326 ptiCurrent->pClientInfo->hKL = pkl->hkl; 01327 } 01328 } 01329 01330 /* 01331 * Some keys (pressed to switch layout) may still be down. When these come 01332 * back up, they may have different VK values due to the new layout, so the 01333 * original key will be left stuck down. (eg: an ISV layout from Attachmate 01334 * and the CAN/CSA layout, both of which redefine the right-hand Ctrl key's 01335 * VK so switching to that layout with right Ctrl+Shift will leave the Ctrl 01336 * stuck down). 01337 * The solution is to clear all the keydown bits whenever we switch layouts 01338 * (leaving the toggle bits alone to preserve CapsLock, NumLock etc.). This 01339 * also solves the AltGr problem, where the simulated Ctrl key doesn't come 01340 * back up if we switch to a non-AltGr layout before releasing AltGr - IanJa 01341 * 01342 * Clear down bits only if necessary --- i.e. if the VK value differs between 01343 * old and new keyboard layout. We have to take complex path for some of the 01344 * keys, like Ctrl or Alt, may have left and right equivalents. - HiroYama 01345 */ 01346 if (ptiCurrent->pq) { 01347 if (pklPrev) { 01348 BYTE baDone[256 / 8]; 01349 01350 RtlZeroMemory(baDone, sizeof baDone); 01351 01352 /* 01353 * Clear the toggle state if needed. First check the modifier keys 01354 * of pklPrev. Next check the modifier keys of pklNew. 01355 */ 01356 TAGMSG2(DBGTAG_IMM, "Changing KL from %08lx to %08lx", pklPrev->hkl, pkl->hkl); 01357 AdjustPushStateForKL(ptiCurrent, baDone, pklPrev, pklPrev, pkl); 01358 AdjustPushStateForKL(ptiCurrent, baDone, pkl, pklPrev, pkl); 01359 01360 if (pklPrev->spkf && (pklPrev->spkf->pKbdTbl->fLocaleFlags & KLLF_ALTGR)) { 01361 /* 01362 * If the previous keyboard has AltGr, clear the left control anyway. 01363 * See xxxAltGr(). 01364 */ 01365 TAGMSG0(DBGTAG_IMM, "Clearing VK_LCONTROL for AltGr\n"); 01366 ResetPushState(ptiCurrent, VK_LCONTROL); 01367 } 01368 } 01369 else { 01370 /* 01371 * If the current keyboard is unkown, clear all the push state. 01372 */ 01373 int i; 01374 for (i = 0; i < CBKEYSTATE; i++) { 01375 ptiCurrent->pq->afKeyState[i] &= KEYSTATE_TOGGLE_BYTEMASK; 01376 gafAsyncKeyState[i] &= KEYSTATE_TOGGLE_BYTEMASK; 01377 gafRawKeyState[i] &= KEYSTATE_TOGGLE_BYTEMASK; 01378 } 01379 } 01380 } 01381 01382 /* 01383 * Call the Shell hook with the new language. 01384 */ 01385 if (gptiForeground && (gptiForeground->ppi == ptiCurrent->ppi)) { 01386 ChangeForegroundKeyboardTable(pklPrev, pkl); 01387 01388 /* 01389 * Only call the hook if we are the foreground process, to prevent 01390 * background apps from changing the indicator. (All console apps 01391 * are part of the same process, but I have never seen a cmd window 01392 * app change the layout, let alone in the background) 01393 */ 01394 if (gLCIDSentToShell != pkl->hkl && (ptiCurrent != gptiRit)) { 01395 if (IsHooked(ptiCurrent, WHF_SHELL)) { 01396 gLCIDSentToShell = pkl->hkl; 01397 xxxCallHook(HSHELL_LANGUAGE, (WPARAM)NULL, (LPARAM)pkl->hkl, WH_SHELL); 01398 } 01399 } 01400 } 01401 01402 /* 01403 * Tell the app what happened 01404 */ 01405 if (ptiCurrent->pq) { 01406 PWND pwndT; 01407 TL tlpwndT; 01408 01409 /* 01410 * If we have no Focus window, use the Active window. 01411 * eg: Console full-screen has NULL focus window. 01412 */ 01413 pwndT = ptiCurrent->pq->spwndFocus; 01414 if (pwndT == NULL) { 01415 pwndT = ptiCurrent->pq->spwndActive; 01416 if (pwndT == NULL) { 01417 pwndT = pwnd; 01418 } 01419 } 01420 01421 if (pwndT != NULL) { 01422 ThreadLockAlwaysWithPti( ptiCurrent, pwndT, &tlpwndT); 01423 xxxSendMessage(pwndT, WM_INPUTLANGCHANGE, (WPARAM)pkl->iBaseCharset, (LPARAM)pkl->hkl); 01424 ThreadUnlock(&tlpwndT); 01425 } 01426 } 01427 01428 /* 01429 * Tell IME to send mode update notification 01430 */ 01431 if (ptiCurrent && ptiCurrent->spwndDefaultIme && 01432 (ptiCurrent->TIF_flags & TIF_CSRSSTHREAD) == 0) { 01433 if (IS_IME_KBDLAYOUT(pkl->hkl)) { 01434 BOOL fForProcess = (ptiCurrent->TIF_flags & KLF_SETFORPROCESS) && !(ptiCurrent->TIF_flags & TIF_16BIT); 01435 TL tlpwndIme; 01436 01437 TAGMSG1(DBGTAG_IMM, "Sending IMS_SENDNOTIFICATION to pwnd=%p", ptiCurrent->spwndDefaultIme); 01438 01439 ThreadLockAlwaysWithPti(ptiCurrent, ptiCurrent->spwndDefaultIme, &tlpwndIme); 01440 xxxSendMessage(ptiCurrent->spwndDefaultIme, WM_IME_SYSTEM, IMS_SENDNOTIFICATION, fForProcess); 01441 ThreadUnlock(&tlpwndIme); 01442 } 01443 } 01444 01445 UnlockAndGo: 01446 ThreadUnlock(&tlpklPrev); 01447 01448 return hklPrev; 01449 } 01450 01451 BOOL xxxUnloadKeyboardLayout( 01452 PWINDOWSTATION pwinsta, 01453 HKL hkl) 01454 { 01455 PKL pkl; 01456 01457 /* 01458 * Validate HKL and check to make sure an app isn't attempting to unload a system 01459 * preloaded layout. 01460 */ 01461 pkl = HKLtoPKL(PtiCurrent(), hkl); 01462 if (pkl == NULL) { 01463 return FALSE; 01464 } 01465 01466 return xxxInternalUnloadKeyboardLayout(pwinsta, pkl, 0); 01467 } 01468 01469 HKL _GetKeyboardLayout( 01470 DWORD idThread) 01471 { 01472 PTHREADINFO ptiT; 01473 PLIST_ENTRY pHead, pEntry; 01474 01475 CheckCritIn(); 01476 01477 /* 01478 * If idThread is NULL return hkl of the current thread 01479 */ 01480 if (idThread == 0) { 01481 PKL pklActive = PtiCurrentShared()->spklActive; 01482 01483 if (pklActive == NULL) { 01484 return (HKL)0; 01485 } 01486 return pklActive->hkl; 01487 } 01488 /* 01489 * Look for idThread 01490 */ 01491 pHead = &PtiCurrent()->rpdesk->PtiList; 01492 for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) { 01493 ptiT = CONTAINING_RECORD(pEntry, THREADINFO, PtiLink); 01494 if (ptiT->pEThread->Cid.UniqueThread == (HANDLE)LongToHandle( idThread )) { 01495 if (ptiT->spklActive == NULL) { 01496 return (HKL)0; 01497 } 01498 return ptiT->spklActive->hkl; 01499 } 01500 } 01501 /* 01502 * idThread doesn't exist 01503 */ 01504 return (HKL)0; 01505 } 01506 01507 UINT _GetKeyboardLayoutList( 01508 PWINDOWSTATION pwinsta, 01509 UINT nItems, 01510 HKL *ccxlpBuff) 01511 { 01512 UINT nHKL = 0; 01513 PKL pkl, pklFirst; 01514 01515 if (!pwinsta) { 01516 return 0; 01517 } 01518 01519 pkl = pwinsta->spklList; 01520 01521 /* 01522 * Windowstations that do not take input could have no layouts 01523 */ 01524 if (pkl == NULL) { 01525 // SetLastError() ???? 01526 return 0; 01527 } 01528 01529 /* 01530 * The client/server thunk sets nItems to 0 if ccxlpBuff == NULL 01531 */ 01532 UserAssert(ccxlpBuff || (nItems == 0)); 01533 01534 pklFirst = pkl; 01535 if (nItems) { 01536 try { 01537 do { 01538 if (!(pkl->dwKL_Flags & KL_UNLOADED)) { 01539 if (nItems-- == 0) { 01540 break; 01541 } 01542 nHKL++; 01543 *ccxlpBuff++ = pkl->hkl; 01544 } 01545 pkl = pkl->pklNext; 01546 } while (pkl != pklFirst); 01547 } except (EXCEPTION_EXECUTE_HANDLER) { 01548 RIPERR1(ERROR_INVALID_PARAMETER, RIP_ERROR, 01549 "_GetKeyBoardLayoutList: exception writing ccxlpBuff %lx", ccxlpBuff); 01550 return 0; 01551 } 01552 } else do { 01553 if (!(pkl->dwKL_Flags & KL_UNLOADED)) { 01554 nHKL++; 01555 } 01556 pkl = pkl->pklNext; 01557 } while (pkl != pklFirst); 01558 01559 return nHKL; 01560 } 01561 01562 /* 01563 * Layouts are locked by each thread using them and possibly by: 01564 * - pwinsta->spklList (head of windowstation's list) 01565 * - gspklBaseLayout (default layout for new threads) 01566 * The layout is marked for destruction when gets unloaded, so that it will be 01567 * unlinked and freed as soon as an Unlock causes the lock count to go to 0. 01568 * If it is reloaded before that time, it is unmarked for destruction. This 01569 * ensures that laoded layouts stay around even when they go out of use. 01570 */ 01571 BOOL xxxInternalUnloadKeyboardLayout( 01572 PWINDOWSTATION pwinsta, 01573 PKL pkl, 01574 UINT Flags) 01575 { 01576 PTHREADINFO ptiCurrent = PtiCurrent(); 01577 TL tlpkl; 01578 01579 UserAssert(pkl); 01580 01581 /* 01582 * Never unload the default layout, unless we are destroying the current 01583 * windowstation or replacing one user's layouts with another's. 01584 */ 01585 if ((pkl == gspklBaseLayout) && !(Flags & KLF_INITTIME)) { 01586 return FALSE; 01587 } 01588 01589 /* 01590 * Keeps pkl good, but also allows destruction when unlocked later 01591 */ 01592 ThreadLockAlwaysWithPti(ptiCurrent, pkl, &tlpkl); 01593 01594 /* 01595 * Mark it for destruction so it gets removed when the lock count reaches 0 01596 * Mark it KL_UNLOADED so that it appears to be gone from the toggle list 01597 */ 01598 HMMarkObjectDestroy(pkl); 01599 pkl->dwKL_Flags |= KL_UNLOADED; 01600 01601 /* 01602 * If unloading this thread's active layout, helpfully activate the next one 01603 * (Don't bother if KLF_INITTIME - unloading all previous user's layouts) 01604 */ 01605 if (!(Flags & KLF_INITTIME)) { 01606 UserAssert(ptiCurrent->spklActive != NULL); 01607 if (ptiCurrent->spklActive == pkl) { 01608 PKL pklNext; 01609 pklNext = HKLtoPKL(ptiCurrent, (HKL)HKL_NEXT); 01610 if (pklNext != NULL) { 01611 TL tlPKL; 01612 ThreadLockAlwaysWithPti(ptiCurrent, pklNext, &tlPKL); 01613 xxxInternalActivateKeyboardLayout(pklNext, Flags, NULL); 01614 ThreadUnlock(&tlPKL); 01615 } 01616 } 01617 } 01618 01619 /* 01620 * If this pkl == pwinsta->spklList, give it a chance to be destroyed by 01621 * unlocking it from pwinsta->spklList. 01622 */ 01623 if (pwinsta->spklList == pkl) { 01624 UserAssert(pkl != NULL); 01625 if (pkl != pkl->pklNext) { 01626 pkl = Lock(&pwinsta->spklList, pkl->pklNext); 01627 UserAssert(pkl != NULL); // gspklBaseLayout and ThreadLocked pkl 01628 } 01629 } 01630 01631 /* 01632 * This finally destroys the unloaded layout if it is not in use anywhere 01633 */ 01634 ThreadUnlock(&tlpkl); 01635 01636 /* 01637 * Update keyboard list. 01638 */ 01639 if (IsHooked(ptiCurrent, WHF_SHELL)) { 01640 xxxCallHook(HSHELL_LANGUAGE, (WPARAM)NULL, (LPARAM)0, WH_SHELL); 01641 gLCIDSentToShell = 0; 01642 } 01643 01644 return TRUE; 01645 } 01646 01647 VOID xxxFreeKeyboardLayouts( 01648 PWINDOWSTATION pwinsta, BOOL bUnlock) 01649 { 01650 PKL pkl; 01651 01652 /* 01653 * Unload all of the windowstation's layouts. 01654 * They may still be locked by some threads (eg: console), so this 01655 * may not destroy them all, but it will mark them all KL_UNLOADED. 01656 * Set KLF_INITTIME to ensure that the default layout (gspklBaseLayout) 01657 * gets unloaded too. 01658 * Note: it's much faster to unload non-active layouts, so start with 01659 * the next loaded layout, leaving the active layout till last. 01660 */ 01661 while ((pkl = HKLtoPKL(PtiCurrent(), (HKL)HKL_NEXT)) != NULL) { 01662 xxxInternalUnloadKeyboardLayout(pwinsta, pkl, KLF_INITTIME); 01663 } 01664 01665 /* 01666 * The WindowStation is being destroyed, or one user's layouts are being 01667 * replaced by another user's, so it's OK to Unlock spklList. 01668 * Any layout still in the double-linked circular KL list will still be 01669 * pointed to by gspklBaseLayout: this is important, since we don't want 01670 * to leak any KL or KBDFILE objects by losing pointers to them. 01671 * There are no layouts when we first come here (during bootup). 01672 */ 01673 if (bUnlock) { 01674 Unlock(&pwinsta->spklList); 01675 } 01676 } 01677 01678 /***************************************************************************\ 01679 * DestroyKL 01680 * 01681 * Destroys a keyboard layout. Note that this function does not 01682 * follow normal destroy function semantics. See IanJa. 01683 * 01684 * History: 01685 * 25-Feb-1997 adams Created. 01686 \***************************************************************************/ 01687 01688 VOID DestroyKL( 01689 PKL pkl) 01690 { 01691 PKBDFILE pkf; 01692 01693 /* 01694 * Cut it out of the pwinsta->spklList circular bidirectional list. 01695 * We know pwinsta->spklList != pkl, since pkl is unlocked. 01696 */ 01697 pkl->pklPrev->pklNext = pkl->pklNext; 01698 pkl->pklNext->pklPrev = pkl->pklPrev; 01699 01700 /* 01701 * Unlock its pkf 01702 */ 01703 pkf = Unlock(&pkl->spkf); 01704 if (pkf) { 01705 DestroyKF(pkf); 01706 } 01707 01708 if (pkl->piiex != NULL) { 01709 UserFreePool(pkl->piiex); 01710 } 01711 01712 /* 01713 * Free the pkl itself. 01714 */ 01715 HMFreeObject(pkl); 01716 }

Generated on Sat May 15 19:40:33 2004 for test by doxygen 1.3.7