test: xlate.c File Reference

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

# xlate.c File Reference

`#include "precomp.h"`

Go to the source code of this file.

## Functions

WORD | GetModifierBits (PMODIFIERS pModifiers, LPBYTE afKeyState)
WORD | GetModificationNumber (PMODIFIERS pModifiers, WORD wModBits)
BYTE | VKFromVSC (PKE pke, BYTE bPrefix, LPBYTE afKeyState)
UINT | InternalMapVirtualKeyEx (UINT wCode, UINT wType, PKBDTABLES pKbdTbl)
int APIENTRY | _GetKeyNameText (LONG lParam, LPWSTR ccxlpStr, int cchSize)
| xxxAltGr (PKE pKe)
| xxxShiftLock (PKE pKe)
BOOL | KEOEMProcs (PKE pKe)
BOOL | xxxKELocaleProcs (PKE pKe)

## Variables

BOOL | gbAltGrDown = FALSE

## Function Documentation

int APIENTRY _GetKeyNameText | ( | LONG | lParam,
|  | LPWSTR | ccxlpStr,
|  | int | cchSize
| ) |

Definition at line 408 of file xlate.c.

References APIENTRY, BYTE, InternalMapVirtualKeyEx(), L, LOBYTE, NULL, tagKBDFILE::pKbdTbl, PtiCurrentShared, tagKL::spkf, tagTHREADINFO::spklActive, TRUE, UINT, and wcsncpycch().

Referenced by NtUserGetKeyNameText().

    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 }

WORD GetModificationNumber | ( | PMODIFIERS | pModifiers,
|  | WORD | wModBits
| ) |

Definition at line 47 of file xlate.c.

References CheckCritInShared.

Referenced by InternalVkKeyScanEx(), KbdNlsFuncTypeAlt(), KbdNlsFuncTypeNormal(), VKFromVSC(), and xxxInternalToUnicode().

    00050 {
    00051     CheckCritInShared();
    00052     if (wModBits > pModifiers->wMaxModBits) {
    00053          return SHFT_INVALID;
    00054     }
    00055
    00056     return pModifiers->ModNumber[wModBits];
    00057 }

WORD GetModifierBits | ( | PMODIFIERS | pModifiers,
|  | LPBYTE | afKeyState
| ) |

Definition at line 26 of file xlate.c.

References CheckCritIn, and TestKeyDownBit.

Referenced by KbdNlsFuncTypeAlt(), KbdNlsFuncTypeNormal(), VKFromVSC(), and xxxInternalToUnicode().

    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 }

UINT InternalMapVirtualKeyEx | ( | UINT | wCode,
|  | UINT | wType,
|  | PKBDTABLES | pKbdTbl
| ) |

Definition at line 231 of file xlate.c.

References aVkNumpad, LOBYTE, NULL, PBYTE, UINT, and USHORT.

Referenced by _GetKeyNameText(), AdjustPushState(), and NtUserMapVirtualKeyEx().

    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 }

BOOL KEOEMProcs | ( | PKE | pKe | ) |

Definition at line 635 of file xlate.c.

References aKEProcOEM, BOOL, CheckCritIn, FALSE, NULL, and TRUE.

Referenced by xxxProcessKeyEvent().

    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 }

BYTE VKFromVSC | ( | PKE | pke,
|  | BYTE | bPrefix,
|  | LPBYTE | afKeyState
| ) |

Definition at line 73 of file xlate.c.

References BOOL, BYTE, CheckCritIn, FALSE, gafRawKeyState, gapulCvt_VK, GetActiveHKL(), GetModificationNumber(), GetModifierBits(), gpKbdTbl, gpModifiers_VK, gptiForeground, IS_IME_ENABLED, LOBYTE, NULL, tagKBDFILE::pKbdTbl, tagKL::spkf, tagTHREADINFO::spklActive, TRUE, and USHORT.

Referenced by ProcessKeyboardInput(), and xxxInternalKeyEventDirect().

    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 }

xxxAltGr | ( | PKE | pKe | ) |

Definition at line 547 of file xlate.c.

References FALSE, gbAltGrDown, NULL, TestRawKeyDown, TRUE, and xxxKeyEvent().

Referenced by xxxKELocaleProcs().

    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 }

BOOL xxxKELocaleProcs | ( | PKE | pKe | ) |

Definition at line 662 of file xlate.c.

References BOOL, CheckCritIn, FALSE, gbAltGrDown, gdwKeyboardAttributes, gpKbdTbl, TRUE, xxxAltGr(), and xxxShiftLock().

Referenced by xxxProcessKeyEvent().

    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 }

xxxShiftLock | ( | PKE | pKe | ) |

Definition at line 586 of file xlate.c.

References FALSE, NULL, TestAsyncKeyStateToggle, TRUE, USHORT, and xxxKeyEvent().

Referenced by xxxKELocaleProcs().

    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 }

## Variable Documentation

BOOL gbAltGrDown = FALSE

| Definition at line 545 of file xlate.c. Referenced by xxxAltGr(), and xxxKELocaleProcs().