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

xlate.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: xlate.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * History: 00007 * 12-07-90 GregoryW Created. 00008 \***************************************************************************/ 00009 00010 #include "precomp.h" 00011 #pragma hdrstop 00012 00013 00014 /* 00015 * "The great artist is the simplifier." 00016 * - Henri Frederic Amiel (1821-1881) 00017 * Ibid., November 25, 1861 00018 */ 00019 00020 /* 00021 * Determine the state of all the Modifier Keys (a Modifier Key 00022 * is any key that may modify values produced by other keys: these are 00023 * commonly SHIFT, CTRL and/or ALT) 00024 * Build a bit-mask (wModBits) to encode which modifier keys are depressed. 00025 */ 00026 WORD GetModifierBits( 00027 PMODIFIERS pModifiers, 00028 LPBYTE afKeyState) 00029 { 00030 PVK_TO_BIT pVkToBit = pModifiers->pVkToBit; 00031 WORD wModBits = 0; 00032 00033 CheckCritIn(); 00034 00035 while (pVkToBit->Vk) { 00036 if (TestKeyDownBit(afKeyState, pVkToBit->Vk)) { 00037 wModBits |= pVkToBit->ModBits; 00038 } 00039 pVkToBit++; 00040 } 00041 return wModBits; 00042 } 00043 00044 /* 00045 * Given modifier bits, return the modification number. 00046 */ 00047 WORD GetModificationNumber( 00048 PMODIFIERS pModifiers, 00049 WORD wModBits) 00050 { 00051 CheckCritInShared(); 00052 if (wModBits > pModifiers->wMaxModBits) { 00053 return SHFT_INVALID; 00054 } 00055 00056 return pModifiers->ModNumber[wModBits]; 00057 } 00058 00059 /*****************************************************************************\ 00060 * VKFromVSC 00061 * 00062 * This function is called from KeyEvent() after each call to VSCFromSC. The 00063 * keyboard input data passed in is translated to a virtual key code. 00064 * This translation is dependent upon the currently depressed modifier keys. 00065 * 00066 * For instance, scan codes representing the number pad keys may be 00067 * translated into VK_NUMPAD codes or cursor movement codes depending 00068 * upon the state of NumLock and the modifier keys. 00069 * 00070 * History: 00071 * 00072 \*****************************************************************************/ 00073 BYTE VKFromVSC( 00074 PKE pke, 00075 BYTE bPrefix, 00076 LPBYTE afKeyState 00077 ) 00078 { 00079 USHORT usVKey; 00080 PVSC_VK pVscVk; 00081 PKBDTABLES pKbdTbl; 00082 static BOOL fVkPause; 00083 00084 CheckCritIn(); 00085 DBG_UNREFERENCED_PARAMETER(afKeyState); 00086 00087 /* 00088 * Initialize as an unknown VK (unrecognised scancode) 00089 */ 00090 pke->usFlaggedVk = usVKey = 0xFF; 00091 00092 /* HACK ALERT 00093 * For Korean 103 keyboard: 00094 * Check this is Korean keyboard layout or not. 00095 */ 00096 if (IS_IME_ENABLED() && 00097 KOREAN_KBD_LAYOUT(GetActiveHKL())) { 00098 if ((pke->bScanCode == 0x71) || (pke->bScanCode == 0x72)) { 00099 pke->bScanCode |= 0x80; 00100 bPrefix = 0xE0; 00101 } else { 00102 pke->bScanCode &= 0x7F; 00103 } 00104 } else { 00105 pke->bScanCode &= 0x7F; 00106 } 00107 00108 if (gptiForeground == NULL) { 00109 RIPMSG0(RIP_VERBOSE, "VKFromVSC: NULL gptiForeground\n"); 00110 pKbdTbl = gpKbdTbl; 00111 } else { 00112 if (gptiForeground->spklActive) { 00113 pKbdTbl = gptiForeground->spklActive->spkf->pKbdTbl; 00114 } else { 00115 RIPMSG0(RIP_VERBOSE, "VKFromVSC: NULL spklActive\n"); 00116 pKbdTbl = gpKbdTbl; 00117 } 00118 } 00119 if (bPrefix == 0) { 00120 if (pke->bScanCode < pKbdTbl->bMaxVSCtoVK) { 00121 /* 00122 * direct index into non-prefix table 00123 */ 00124 usVKey = pKbdTbl->pusVSCtoVK[pke->bScanCode]; 00125 if (usVKey == 0) { 00126 return 0xFF; 00127 } 00128 } else { 00129 /* 00130 * unexpected scancode 00131 */ 00132 RIPMSG2(RIP_VERBOSE, "unrecognized scancode 0x%x, prefix %x", 00133 pke->bScanCode, bPrefix); 00134 return 0xFF; 00135 } 00136 } else { 00137 /* 00138 * Scan the E0 or E1 prefix table for a match 00139 */ 00140 if (bPrefix == 0xE0) { 00141 /* 00142 * Set the KBDEXT (extended key) bit in case the scancode is not 00143 * found in the table (eg: FUJITSU POS keyboard #65436) 00144 */ 00145 usVKey |= KBDEXT; 00146 /* 00147 * Ignore the SHIFT keystrokes generated by the hardware 00148 */ 00149 if ((pke->bScanCode == SCANCODE_LSHIFT) || 00150 (pke->bScanCode == SCANCODE_RSHIFT)) { 00151 return 0; 00152 } 00153 pVscVk = pKbdTbl->pVSCtoVK_E0; 00154 } else if (bPrefix == 0xE1) { 00155 pVscVk = pKbdTbl->pVSCtoVK_E1; 00156 } else { 00157 /* 00158 * Unrecognized prefix (from ScancodeMap?) produces an 00159 * unextended and unrecognized VK. 00160 */ 00161 return 0xFF; 00162 } 00163 while (pVscVk->Vk) { 00164 if (pVscVk->Vsc == pke->bScanCode) { 00165 usVKey = pVscVk->Vk; 00166 break; 00167 } 00168 pVscVk++; 00169 } 00170 } 00171 00172 /* 00173 * Scancode set 1 returns PAUSE button as E1 1D 45 (E1 Ctrl NumLock) 00174 * so convert E1 Ctrl to VK_PAUSE, and remember to discard the NumLock 00175 */ 00176 if (fVkPause) { 00177 /* 00178 * This is the "45" part of the Pause scancode sequence. 00179 * Discard this key event: it is a false NumLock 00180 */ 00181 fVkPause = FALSE; 00182 return 0; 00183 } 00184 if (usVKey == VK_PAUSE) { 00185 /* 00186 * This is the "E1 1D" part of the Pause scancode sequence. 00187 * Alter the scancode to the value Windows expects for Pause, 00188 * and remember to discard the "45" scancode that will follow 00189 */ 00190 pke->bScanCode = 0x45; 00191 fVkPause = TRUE; 00192 } 00193 00194 /* 00195 * Convert to a different VK if some modifier keys are depressed. 00196 */ 00197 if (usVKey & KBDMULTIVK) { 00198 WORD nMod; 00199 PULONG pul; 00200 00201 nMod = GetModificationNumber( 00202 gpModifiers_VK, 00203 GetModifierBits(gpModifiers_VK, gafRawKeyState)); 00204 00205 /* 00206 * Scan gapulCvt_VK[nMod] for matching VK. 00207 */ 00208 if ((nMod != SHFT_INVALID) && ((pul = gapulCvt_VK[nMod]) != NULL)) { 00209 while (*pul != 0) { 00210 if (LOBYTE(*pul) == LOBYTE(usVKey)) { 00211 pke->usFlaggedVk = (USHORT)HIWORD(*pul); 00212 return (BYTE)pke->usFlaggedVk; 00213 } 00214 pul++; 00215 } 00216 } 00217 } 00218 00219 pke->usFlaggedVk = usVKey; 00220 return (BYTE)usVKey; 00221 } 00222 00223 /***************************************************************************\ 00224 * UINT InternalMapVirtualKeyEx(UINT wCode, UINT wType, PKBDTABLES pKbdTbl); 00225 * 00226 * History: 00227 * IanJa 5/13/91 from Win3.1 \\pucus\win31ro!drivers\keyboard\getname.asm 00228 * GregoryW 2/21/95 renamed from _MapVirtualKey and added third parameter. 00229 \***************************************************************************/ 00230 00231 UINT InternalMapVirtualKeyEx( 00232 UINT wCode, 00233 UINT wType, 00234 PKBDTABLES pKbdTbl) 00235 { 00236 PVK_TO_WCHARS1 pVK; 00237 PVK_TO_WCHAR_TABLE pVKT; 00238 UINT VkRet = 0; 00239 USHORT usScanCode; 00240 PVSC_VK pVscVk; 00241 PBYTE pVkNumpad; 00242 00243 switch (wType) { 00244 case 0: 00245 00246 /* 00247 * Convert Virtual Key (wCode) to Scan Code 00248 */ 00249 if ((wCode >= VK_SHIFT) && (wCode <= VK_MENU)) { 00250 00251 /* 00252 * Convert ambiguous Shift/Control/Alt keys to left-hand keys 00253 */ 00254 wCode = (UINT)((wCode - VK_SHIFT) * 2 + VK_LSHIFT); 00255 } 00256 00257 /* 00258 * Scan through the table that maps Virtual Scancodes to Virtual Keys 00259 * for non-extended keys. 00260 */ 00261 for (usScanCode = 0; usScanCode < pKbdTbl->bMaxVSCtoVK; usScanCode++) { 00262 if ((UINT)LOBYTE(pKbdTbl->pusVSCtoVK[usScanCode]) == wCode) { 00263 return usScanCode & 0xFF; 00264 } 00265 } 00266 00267 /* 00268 * Scan through the table that maps Virtual Scancodes to Virtual Keys 00269 * for extended keys. 00270 */ 00271 for (pVscVk = pKbdTbl->pVSCtoVK_E0; pVscVk->Vk; pVscVk++) { 00272 if ((UINT)LOBYTE(pVscVk->Vk) == wCode) { 00273 return (UINT)pVscVk->Vsc; 00274 } 00275 } 00276 00277 /* 00278 * There was no match: maybe the Virtual Key can only be generated 00279 * with Numlock on. Scan through aVkNumpad[] to determine scancode. 00280 */ 00281 for (pVkNumpad = aVkNumpad; *pVkNumpad != 0; pVkNumpad++) { 00282 if ((UINT)(*pVkNumpad) == wCode) { 00283 return (UINT)(pVkNumpad - aVkNumpad) + SCANCODE_NUMPAD_FIRST; 00284 } 00285 } 00286 00287 return 0; // No match found! 00288 00289 case 1: 00290 case 3: 00291 00292 /* 00293 * Convert Scan Code (wCode) to Virtual Key, disregarding modifier keys 00294 * and NumLock key etc. Returns 0 for no corresponding Virtual Key 00295 */ 00296 if (wCode < (UINT)(pKbdTbl->bMaxVSCtoVK)) { 00297 VkRet = (UINT)LOBYTE(pKbdTbl->pusVSCtoVK[wCode]); 00298 } else { 00299 /* 00300 * Scan the E0 prefix table for a match 00301 */ 00302 for (pVscVk = pKbdTbl->pVSCtoVK_E0; pVscVk->Vk; pVscVk++) { 00303 if ((UINT)pVscVk->Vsc == wCode) { 00304 VkRet = (UINT)LOBYTE(pVscVk->Vk); 00305 break; 00306 } 00307 } 00308 } 00309 00310 if ((wType == 1) && (VkRet >= VK_LSHIFT) && (VkRet <= VK_RMENU)) { 00311 00312 /* 00313 * Convert left/right Shift/Control/Alt keys to ambiguous keys 00314 * (neither left nor right) 00315 */ 00316 VkRet = (UINT)((VkRet - VK_LSHIFT) / 2 + VK_SHIFT); 00317 } 00318 00319 if (VkRet == 0xFF) { 00320 VkRet = 0; 00321 } 00322 return VkRet; 00323 00324 case 2: 00325 00326 /* 00327 * Bogus Win3.1 functionality: despite SDK documenation, return uppercase for 00328 * VK_A through VK_Z 00329 */ 00330 if ((wCode >= (WORD)'A') && (wCode <= (WORD)'Z')) { 00331 return wCode; 00332 } 00333 00334 // HIWORD is no loner the wchar, due to app compat problems #287134 00335 // We should not return the wchar from pti->wchInjected that cached 00336 // at GetMessage time. 00337 // (delete this commented-out section by end of March 1999 - IanJa) 00338 // 00339 // if (LOWORD(wCode) == VK_PACKET) { 00340 // return HIWORD(wCode); 00341 // } 00342 00343 /* 00344 * Convert Virtual Key (wCode) to ANSI. 00345 * Search each Shift-state table in turn, looking for the Virtual Key. 00346 */ 00347 for (pVKT = pKbdTbl->pVkToWcharTable; pVKT->pVkToWchars != NULL; pVKT++) { 00348 pVK = pVKT->pVkToWchars; 00349 while (pVK->VirtualKey != 0) { 00350 if ((UINT)pVK->VirtualKey == wCode) { 00351 00352 /* 00353 * Match found: return the unshifted character 00354 */ 00355 if (pVK->wch[0] == WCH_DEAD) { 00356 00357 /* 00358 * It is a dead character: the next entry contains its 00359 * value. Set the high bit to indicate dead key 00360 * (undocumented behaviour) 00361 */ 00362 pVK = (PVK_TO_WCHARS1)((PBYTE)pVK + pVKT->cbSize); 00363 return pVK->wch[0] | (UINT)0x80000000; 00364 } else if (pVK->wch[0] == WCH_NONE) { 00365 return 0; // 9013 00366 } 00367 if (pVK->wch[0] == WCH_NONE) { 00368 return 0; 00369 } 00370 return pVK->wch[0]; 00371 } 00372 pVK = (PVK_TO_WCHARS1)((PBYTE)pVK + pVKT->cbSize); 00373 } 00374 } 00375 } 00376 00377 /* 00378 * Can't find translation, or wType was invalid 00379 */ 00380 return 0; 00381 } 00382 00383 /***************************************************************************\ 00384 * _GetKeyNameText (API) 00385 * 00386 * int _GetKeyNameText(DWORD lParam, LPSTR lpStr, UINT size); 00387 * 00388 * lParam: value from WM_KEYDOWN message, etc. 00389 * 00390 * Byte 3 (bits 16..23) of lParam contains a scan code. 00391 * 00392 * Bit 20 of lParam is the Extended bit (distingushes some keys on 00393 * Enhanced keyboard). 00394 * 00395 * Bit 21 of lParam is a don't care bit (don't distingush between 00396 * left and right control, shift, Enter keys, between edit keys 00397 * in edit area and on numeric pad, etc). The app calling this 00398 * function sets this bit in lParam, if it so desires. 00399 * 00400 * lpStr: Pointer to output string. 00401 * 00402 * iSize: Maximum length of output string, not including null byte. 00403 * 00404 * History: 00405 * IanJa 4/11/91 from Win3.1 \\pucus\win31ro!drivers\keyboard\getname.asm 00406 \***************************************************************************/ 00407 00408 int APIENTRY _GetKeyNameText( 00409 LONG lParam, 00410 LPWSTR ccxlpStr, 00411 int cchSize) 00412 { 00413 BYTE Vsc = LOBYTE(HIWORD(lParam)); 00414 PVSC_LPWSTR pKN; 00415 PTHREADINFO ptiT = PtiCurrentShared(); 00416 PKBDTABLES pKbdTbl; 00417 UINT Vk; 00418 UINT Char; 00419 00420 /* 00421 * NOTE -- lpStr can be a client-side address, so access through it 00422 * must be guarded with try blocks. 00423 */ 00424 00425 if (cchSize < 1) 00426 return 0; 00427 00428 /* 00429 * If bit 25 set (don't care about left vs. right) then: 00430 * 1) convert right-Shift into left-Shift 00431 * 2) clear the extended bit for Ctrl and Alt only (effectively converting 00432 * right-Ctrl & right-Alt into left-Ctrl & right-Alt) 00433 * For Windows '95 compatibility, the DONTCARE_BIT doesn't apply to other 00434 * extended keys (eg: NumPad cursor movement keys, NumPad Enter). Some 00435 * applications (Word '95) depend on this. #37796 00436 */ 00437 if (lParam & DONTCARE_BIT) { 00438 if (Vsc == SCANCODE_RSHIFT) { 00439 Vsc = SCANCODE_LSHIFT; 00440 } 00441 if (lParam & EXTENDED_BIT) { 00442 if ((Vsc == SCANCODE_CTRL) || (Vsc == SCANCODE_ALT)) { 00443 lParam &= ~EXTENDED_BIT; 00444 } 00445 } 00446 lParam &= ~DONTCARE_BIT; 00447 } 00448 00449 if (ptiT->spklActive == (PKL)NULL) { 00450 return 0; 00451 } 00452 pKbdTbl = ptiT->spklActive->spkf->pKbdTbl; 00453 00454 /* 00455 * Scan pKbdTbl->pKeyNames[] or pKeyNamesExt[] for matching Virtual Scan Code 00456 */ 00457 if (lParam & EXTENDED_BIT) { 00458 pKN = pKbdTbl->pKeyNamesExt; 00459 } else { 00460 pKN = pKbdTbl->pKeyNames; 00461 } 00462 00463 if (pKN) { 00464 while (pKN->vsc != 0) { 00465 if (Vsc == pKN->vsc) { 00466 00467 try { 00468 cchSize = wcsncpycch(ccxlpStr, pKN->pwsz, cchSize); 00469 cchSize--; 00470 ccxlpStr[cchSize] = L'\0'; 00471 } except(W32ExceptionHandler(TRUE, RIP_ERROR)) { 00472 return 0; 00473 } 00474 return cchSize; 00475 } 00476 pKN++; 00477 } 00478 } 00479 00480 /* 00481 * The name of the key was not found in the table, so we 00482 * now attempt to construct the key name from the character produced by 00483 * the key. Translate Scancode -> Virtual Key -> character. 00484 */ 00485 00486 /* 00487 * Translate Scancode to Virtual Key (ignoring modifier keys etc.) 00488 */ 00489 Vk = InternalMapVirtualKeyEx((UINT)Vsc, 1, pKbdTbl); 00490 if (Vk == 0) { 00491 return 0; 00492 } 00493 00494 /* 00495 * Now translate Virtual Key to character (ignoring modifier keys etc.) 00496 */ 00497 Char = InternalMapVirtualKeyEx((UINT)Vk, 2, pKbdTbl); 00498 if (Char == 0) { 00499 return 0; 00500 } 00501 00502 if (Char & 0x80000000) { 00503 LPWSTR *ppwsz; 00504 00505 ppwsz = pKbdTbl->pKeyNamesDead; 00506 if (ppwsz) { 00507 while (*ppwsz != NULL) { 00508 if (*ppwsz[0] == (WCHAR)Char) { 00509 try { 00510 cchSize = wcsncpycch(ccxlpStr, (*ppwsz)+1, cchSize); 00511 cchSize--; 00512 ccxlpStr[cchSize] = L'\0'; 00513 } except(W32ExceptionHandler(TRUE, RIP_ERROR)) { 00514 return 0; 00515 } 00516 return cchSize; 00517 } 00518 ppwsz++; 00519 } 00520 } 00521 } 00522 00523 /* 00524 * Construct a single character name (adding null-terminator if possible) 00525 */ 00526 try { 00527 ccxlpStr[0] = (WCHAR)Char; 00528 if (cchSize >= 2) { 00529 ccxlpStr[1] = L'\0'; 00530 } 00531 } except(W32ExceptionHandler(TRUE, RIP_ERROR)) { 00532 return 0; 00533 } 00534 return 1; 00535 } 00536 00537 /***************************************************************************\ 00538 * xxxAltGr() - handle special case Right-hand ALT key (Locale dependent) 00539 * 00540 * Note: gbAltGrDown reminds us to send the fake Ctrl key back up if we 00541 * switched to a non-AltGr layout while ALtGr was down: otherwise the Ctrl key 00542 * gets stuck down. (For example: using AltGr with KBDSEL to switch from 00543 * German to US layout). 00544 \***************************************************************************/ 00545 BOOL gbAltGrDown = FALSE; 00546 00547 xxxAltGr( 00548 PKE pKe) 00549 { 00550 UserAssert(pKe != NULL); 00551 00552 if ((pKe->usFlaggedVk & 0xFF) != VK_RMENU) { 00553 return TRUE; 00554 } 00555 00556 if (!(pKe->usFlaggedVk & KBDBREAK)) { 00557 /* 00558 * If neither CTRL key is down, then fake one going down so that 00559 * the right hand ALT key is converted to CTRL + ALT. 00560 */ 00561 if (!TestRawKeyDown(VK_CONTROL)) { 00562 gbAltGrDown = TRUE; 00563 xxxKeyEvent(VK_LCONTROL, 0x1D | SCANCODE_SIMULATED, 00564 pKe->dwTime, 0, FALSE); 00565 } 00566 } else { 00567 /* 00568 * If the physical Left Ctrl key is not really down, fake the 00569 * Left Ctrl key coming back up (undo earlier faked Left Ctrl down) 00570 */ 00571 gbAltGrDown = FALSE; 00572 if (!TestRawKeyDown(VK_LCONTROL)) { 00573 xxxKeyEvent(VK_LCONTROL | KBDBREAK, 0x1D | SCANCODE_SIMULATED, 00574 pKe->dwTime, 0, FALSE); 00575 } 00576 } 00577 return TRUE; 00578 } 00579 00580 /*****************************************************************************\ 00581 * xxxShiftLock() 00582 * handle ShiftLock feature, where only hitting Shift turns CapsLock off 00583 * 00584 \*****************************************************************************/ 00585 00586 xxxShiftLock( 00587 PKE pKe) 00588 { 00589 USHORT Vk; 00590 00591 UserAssert(pKe != NULL); 00592 00593 /* 00594 * We only mess with downstrokes: return TRUE to let it pass unmolested. 00595 */ 00596 if (pKe->usFlaggedVk & KBDBREAK) { 00597 return TRUE; 00598 } 00599 00600 Vk = pKe->usFlaggedVk & 0xFF; 00601 00602 /* 00603 * If CapsLock is pressed when CapsLock is already on, lose the keystroke. 00604 */ 00605 if ((Vk == VK_CAPITAL) && TestAsyncKeyStateToggle(VK_CAPITAL)) { 00606 return FALSE; 00607 } 00608 00609 /* 00610 * If a Shift key goes down when CapsLock is on, turn CapsLock off 00611 * by simulating a click on the CapsLock key. 00612 * Let the Shift down through FIRST, since it might be part of an 00613 * input lang toggle (tough luck that this toggle turns off CapsLock!) 00614 */ 00615 if (((Vk == VK_LSHIFT) || (Vk == VK_RSHIFT) || (Vk == VK_SHIFT)) && 00616 TestAsyncKeyStateToggle(VK_CAPITAL)) { 00617 xxxKeyEvent(pKe->usFlaggedVk, pKe->bScanCode, 00618 pKe->dwTime, 0, FALSE); 00619 xxxKeyEvent(VK_CAPITAL, 0x3A | SCANCODE_SIMULATED, 00620 pKe->dwTime, 0, FALSE); 00621 xxxKeyEvent(VK_CAPITAL | KBDBREAK, 0x3A | SCANCODE_SIMULATED, 00622 pKe->dwTime, 0, FALSE); 00623 return FALSE; 00624 } 00625 00626 return TRUE; 00627 } 00628 00629 /* 00630 * Returning FALSE means the Key Event has been deleted by a special-case 00631 * KeyEvent processor. 00632 * Returning TRUE means the Key Event should be passed on (although it may 00633 * have been altered. 00634 */ 00635 BOOL KEOEMProcs(PKE pKe) 00636 { 00637 int i; 00638 00639 CheckCritIn(); 00640 00641 for (i = 0; aKEProcOEM[i] != NULL; i++) { 00642 if (!aKEProcOEM[i](pKe)) { 00643 /* 00644 * Eat the key event 00645 */ 00646 return FALSE; 00647 } 00648 } 00649 00650 /* 00651 * Pass the (possibly altered) key event on. 00652 */ 00653 return TRUE; 00654 } 00655 00656 /* 00657 * Returning FALSE means the Key Event has been deleted by a special-case 00658 * KeyEvent processor. 00659 * Returning TRUE means the Key Event should be passed on (although it may 00660 * have been altered. 00661 */ 00662 BOOL xxxKELocaleProcs(PKE pKe) 00663 { 00664 CheckCritIn(); 00665 00666 /* 00667 * AltGr is a layout-specific behavior 00668 * Modifier keys are sent up as necessary in xxxInternalActivateKeyboardLayout 00669 * (#139178), so left-Ctrl won't be left stuck down if we switch from an 00670 * AltGr keyboard to a non-AltGr keybord while the AltGr is held down. 00671 */ 00672 if ((gpKbdTbl->fLocaleFlags & KLLF_ALTGR) || gbAltGrDown) { 00673 if (!xxxAltGr(pKe)) { 00674 return FALSE; 00675 } 00676 } 00677 00678 /* 00679 * ShiftLock/CapsLock is per-user (global) behavior as well as (for 00680 * backward compatibility) per-layout behavior. 00681 */ 00682 if ((gdwKeyboardAttributes & KLLF_SHIFTLOCK) || 00683 (gpKbdTbl->fLocaleFlags & KLLF_SHIFTLOCK)) { 00684 if (!xxxShiftLock(pKe)) { 00685 return FALSE; 00686 } 00687 } 00688 00689 /* 00690 * Other special Key Event processors 00691 */ 00692 00693 return TRUE; 00694 }

Generated on Sat May 15 19:42:29 2004 for test by doxygen 1.3.7