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

tounicod.c File Reference

#include "precomp.h"

Go to the source code of this file.

Defines

#define ISCAPSLOCKON(pf)   (TestKeyToggleBit(pf, VK_CAPITAL) != 0)
#define ISNUMLOCKON(pf)   (TestKeyToggleBit(pf, VK_NUMLOCK) != 0)
#define ISSHIFTDOWN(w)   (w & 0x01)
#define ISKANALOCKON(pf)   (TestKeyToggleBit(pf, VK_KANA) != 0)
#define NUMPADSPC_INVALID   (-1)
#define MODIFIER_FOR_ALT_NUMPAD(wModBit)   ((((wModBits) & ~KBDKANA) == KBDALT) || (((wModBits) & ~KBDKANA) == (KBDALT | KBDSHIFT)))

Enumerations

enum  { NUMPADCONV_OEMCP = 0, NUMPADCONV_HKLCP, NUMPADCONV_HEX_HKLCP, NUMPADCONV_HEX_UNICODE }

Functions

WCHAR xxxClientCharToWchar (IN WORD CodePage, IN WORD wch)
int xxxToUnicodeEx (UINT wVirtKey, UINT wScanCode, CONST BYTE *pbKeyState, LPWSTR pwszBuff, int cchBuff, UINT wKeyFlags, HKL hkl)
int ComposeDeadKeys (PKL pkl, PDEADKEY pDeadKey, WCHAR wchTyped, WORD *pUniChar, INT cChar, BOOL bBreak)
int TranslateInjectedVKey (IN UINT uScanCode, OUT PWCHAR awchChars, IN UINT uiTMFlags)
int NumPadScanCodeToHex (UINT uScanCode, UINT uVirKey)
BOOL IsDbcsExemptionForHighAnsi (WORD wCodePage, WORD wNumpadChar)
int xxxInternalToUnicode (IN UINT uVirtKey, IN UINT uScanCode, CONST IN PBYTE pfvk, OUT PWCHAR awchChars, IN INT cChar, IN UINT uiTMFlags, OUT PDWORD pdwKeyFlags, IN HKL hkl)
SHORT InternalVkKeyScanEx (WCHAR wchChar, PKBDTABLES pKbdTbl)


Define Documentation

#define ISCAPSLOCKON pf   )     (TestKeyToggleBit(pf, VK_CAPITAL) != 0)
 

Definition at line 21 of file tounicod.c.

Referenced by xxxInternalToUnicode().

#define ISKANALOCKON pf   )     (TestKeyToggleBit(pf, VK_KANA) != 0)
 

Definition at line 24 of file tounicod.c.

Referenced by xxxInternalToUnicode().

#define ISNUMLOCKON pf   )     (TestKeyToggleBit(pf, VK_NUMLOCK) != 0)
 

Definition at line 22 of file tounicod.c.

#define ISSHIFTDOWN  )     (w & 0x01)
 

Definition at line 23 of file tounicod.c.

#define MODIFIER_FOR_ALT_NUMPAD wModBit   )     ((((wModBits) & ~KBDKANA) == KBDALT) || (((wModBits) & ~KBDKANA) == (KBDALT | KBDSHIFT)))
 

Definition at line 275 of file tounicod.c.

Referenced by xxxInternalToUnicode(), and xxxKeyEvent().

#define NUMPADSPC_INVALID   (-1)
 

Definition at line 207 of file tounicod.c.

Referenced by NumPadScanCodeToHex().


Enumeration Type Documentation

anonymous enum
 

Enumeration values:
NUMPADCONV_OEMCP 
NUMPADCONV_HKLCP 
NUMPADCONV_HEX_HKLCP 
NUMPADCONV_HEX_UNICODE 

Definition at line 200 of file tounicod.c.

00200 { 00201 NUMPADCONV_OEMCP = 0, 00202 NUMPADCONV_HKLCP, 00203 NUMPADCONV_HEX_HKLCP, 00204 NUMPADCONV_HEX_UNICODE, 00205 };


Function Documentation

int ComposeDeadKeys PKL  pkl,
PDEADKEY  pDeadKey,
WCHAR  wchTyped,
WORD *  pUniChar,
INT  cChar,
BOOL  bBreak
 

Definition at line 81 of file tounicod.c.

References DWORD, NULL, and tagKL::wchDiacritic.

Referenced by xxxInternalToUnicode().

00088 { 00089 /* 00090 * Attempt to compose this sequence: 00091 */ 00092 DWORD dwBoth; 00093 00094 TAGMSG4(DBGTAG_ToUnicode | RIP_THERESMORE, 00095 "ComposeDeadKeys dead '%C'(%x)+base '%C'(%x)", 00096 pkl->wchDiacritic, pkl->wchDiacritic, 00097 wchTyped, wchTyped); 00098 TAGMSG2(DBGTAG_ToUnicode | RIP_NONAME | RIP_THERESMORE, 00099 "cChar = %d, bBreak = %d", cChar, bBreak); 00100 UserAssert(pDeadKey); 00101 00102 if (cChar < 1) { 00103 TAGMSG0(DBGTAG_ToUnicode | RIP_NONAME, 00104 "return 0 because cChar < 1"); 00105 return 0; 00106 } 00107 00108 /* 00109 * Use the layout's built-in table for dead char composition 00110 */ 00111 dwBoth = MAKELONG(wchTyped, pkl->wchDiacritic); 00112 00113 if (pDeadKey != NULL) { 00114 /* 00115 * Don't let character upstrokes erase the cached dead char: else 00116 * if this was the dead char key again (being released after the 00117 * AltGr is released) the dead char would be prematurely cleared. 00118 */ 00119 if (!bBreak) { 00120 pkl->wchDiacritic = 0; 00121 } 00122 while (pDeadKey->dwBoth != 0) { 00123 if (pDeadKey->dwBoth == dwBoth) { 00124 /* 00125 * found a composition 00126 */ 00127 if (pDeadKey->uFlags & DKF_DEAD) { 00128 /* 00129 * Dead again! Save the new 'dead' key 00130 */ 00131 if (!bBreak) { 00132 pkl->wchDiacritic = (WORD)pDeadKey->wchComposed; 00133 } 00134 TAGMSG2(DBGTAG_ToUnicode | RIP_NONAME, 00135 "return -1 with dead char '%C'(%x)", 00136 pkl->wchDiacritic, pkl->wchDiacritic); 00137 return -1; 00138 } 00139 *pUniChar = (WORD)pDeadKey->wchComposed; 00140 TAGMSG2(DBGTAG_ToUnicode | RIP_NONAME, 00141 "return 1 with char '%C'(%x)", 00142 *pUniChar, *pUniChar); 00143 return 1; 00144 } 00145 pDeadKey++; 00146 } 00147 } 00148 *pUniChar++ = HIWORD(dwBoth); 00149 if (cChar > 1) { 00150 *pUniChar = LOWORD(dwBoth); 00151 TAGMSG4(DBGTAG_ToUnicode | RIP_NONAME, 00152 "return 2 with uncomposed chars '%C'(%x), '%C'(%x)", 00153 *(pUniChar-1), *(pUniChar-1), *pUniChar, *pUniChar); 00154 return 2; 00155 } 00156 TAGMSG2(DBGTAG_ToUnicode | RIP_NONAME | RIP_THERESMORE, 00157 "return 1 - only one char '%C'(%x) because cChar is 1, '%C'(%x)", 00158 *(pUniChar-1), *(pUniChar-1)); 00159 TAGMSG2(DBGTAG_ToUnicode | RIP_NONAME, 00160 " the second char would have been '%C'(%x)", 00161 LOWORD(dwBoth), LOWORD(dwBoth)); 00162 return 1; 00163 }

SHORT InternalVkKeyScanEx WCHAR  wchChar,
PKBDTABLES  pKbdTbl
 

Definition at line 803 of file tounicod.c.

References BYTE, FALSE, GetModificationNumber(), gspklBaseLayout, NULL, PBYTE, tagKBDFILE::pKbdTbl, SHORT, and tagKL::spkf.

Referenced by NtUserVkKeyScanEx(), and xxxInternalToUnicode().

00806 { 00807 PVK_TO_WCHARS1 pVK; 00808 PVK_TO_WCHAR_TABLE pVKT; 00809 BYTE nShift; 00810 WORD wModBits; 00811 WORD wModNumCtrl, wModNumShiftCtrl; 00812 SHORT shRetvalCtrl = 0; 00813 SHORT shRetvalShiftCtrl = 0; 00814 00815 if (pKbdTbl == NULL) { 00816 pKbdTbl = gspklBaseLayout->spkf->pKbdTbl; 00817 } 00818 00819 /* 00820 * Ctrl and Shift-Control combinations are less favored, so determine 00821 * the values for nShift which we prefer not to use if at all possible. 00822 * This is for compatibility with Windows 95/98, which only returns a 00823 * Ctrl or Shift+Ctrl combo as a last resort. See bugs #78891 & #229141 00824 */ 00825 wModNumCtrl = GetModificationNumber(pKbdTbl->pCharModifiers, KBDCTRL); 00826 wModNumShiftCtrl = GetModificationNumber(pKbdTbl->pCharModifiers, KBDSHIFT | KBDCTRL); 00827 00828 for (pVKT = pKbdTbl->pVkToWcharTable; pVKT->pVkToWchars != NULL; pVKT++) { 00829 for (pVK = pVKT->pVkToWchars; 00830 pVK->VirtualKey != 0; 00831 pVK = (PVK_TO_WCHARS1)((PBYTE)pVK + pVKT->cbSize)) { 00832 for (nShift = 0; nShift < pVKT->nModifications; nShift++) { 00833 if (pVK->wch[nShift] == wchChar) { 00834 /* 00835 * A matching character has been found! 00836 */ 00837 if (pVK->VirtualKey == 0xff) { 00838 /* 00839 * dead char: back up to previous line to get the VK. 00840 */ 00841 pVK = (PVK_TO_WCHARS1)((PBYTE)pVK - pVKT->cbSize); 00842 } 00843 00844 /* 00845 * If this is the first Ctrl or the first Shift+Ctrl match, 00846 * remember in case we don't find any better match. 00847 * In the meantime, keep on looking. 00848 */ 00849 if (nShift == wModNumCtrl) { 00850 if (shRetvalCtrl == 0) { 00851 shRetvalCtrl = (SHORT)MAKEWORD(pVK->VirtualKey, KBDCTRL); 00852 } 00853 } else if (nShift == wModNumShiftCtrl) { 00854 if (shRetvalShiftCtrl == 0) { 00855 shRetvalShiftCtrl = (SHORT)MAKEWORD(pVK->VirtualKey, KBDCTRL | KBDSHIFT); 00856 } 00857 } else { 00858 /* 00859 * this seems like a very good match! 00860 */ 00861 goto GoodMatchFound; 00862 } 00863 } 00864 } 00865 } 00866 } 00867 00868 /* 00869 * Didn't find a good match: use whatever Ctrl/Shift+Ctrl match was found 00870 */ 00871 if (shRetvalCtrl) { 00872 return shRetvalCtrl; 00873 } 00874 if (shRetvalShiftCtrl) { 00875 return shRetvalShiftCtrl; 00876 } 00877 00878 /* 00879 * May be a control character not explicitly in the layout tables 00880 */ 00881 if (wchChar < 0x0020) { 00882 /* 00883 * Ctrl+char -> char - 0x40 00884 */ 00885 return (SHORT)MAKEWORD((wchChar + 0x40), KBDCTRL); 00886 } 00887 return -1; 00888 00889 GoodMatchFound: 00890 /* 00891 * Scan aModification[] to find nShift: the index will be a bitmask 00892 * representing the Shifter Keys that need to be pressed to produce 00893 * this Shift State. 00894 */ 00895 for (wModBits = 0; 00896 wModBits <= pKbdTbl->pCharModifiers->wMaxModBits; 00897 wModBits++) 00898 { 00899 if (pKbdTbl->pCharModifiers->ModNumber[wModBits] == nShift) { 00900 if (pVK->VirtualKey == 0xff) { 00901 /* 00902 * The previous entry contains the actual virtual key in this case. 00903 */ 00904 pVK = (PVK_TO_WCHARS1)((PBYTE)pVK - pVKT->cbSize); 00905 } 00906 return (SHORT)MAKEWORD(pVK->VirtualKey, wModBits); 00907 } 00908 } 00909 00910 /* 00911 * huh? should never reach here! (IanJa) 00912 */ 00913 UserAssertMsg1(FALSE, "InternalVkKeyScanEx error: wchChar = 0x%x", wchChar); 00914 return -1; 00915 }

BOOL IsDbcsExemptionForHighAnsi WORD  wCodePage,
WORD  wNumpadChar
 

Definition at line 244 of file tounicod.c.

References BOOL, CP_JAPANESE, FALSE, HIBYTE, IS_JPN_1BYTE_KATAKANA, and TRUE.

Referenced by GetChar(), and xxxInternalToUnicode().

00247 { 00248 UserAssert(HIBYTE(wNumpadChar) == 0); 00249 00250 if (wCodePage == CP_JAPANESE && IS_JPN_1BYTE_KATAKANA(wNumpadChar)) { 00251 /* 00252 * If hkl is JAPANESE and NumpadChar is in KANA range, 00253 * NumpadChar should be handled by the input locale. 00254 */ 00255 return FALSE; 00256 } 00257 else if (wNumpadChar >= 0x80 && wNumpadChar <= 0xff) { 00258 /* 00259 * Otherwise if NumpadChar is in High ANSI range, 00260 * use 1252 for conversion. 00261 */ 00262 return TRUE; 00263 } 00264 00265 /* 00266 * None of the above. 00267 * This case includes the compound Leading Byte and Trailing Byte, 00268 * which is larger than 0xff. 00269 */ 00270 return FALSE; 00271 }

int NumPadScanCodeToHex UINT  uScanCode,
UINT  uVirKey
 

Definition at line 209 of file tounicod.c.

References aVkNumpad, gfInNumpadHexInput, L, NUMPAD_HEXMODE_HL, and NUMPADSPC_INVALID.

Referenced by xxxInternalToUnicode().

00210 { 00211 if (uScanCode >= SCANCODE_NUMPAD_FIRST && uScanCode <= SCANCODE_NUMPAD_LAST) { 00212 int digit = aVkNumpad[uScanCode - SCANCODE_NUMPAD_FIRST]; 00213 00214 if (digit != 0xff) { 00215 return digit - VK_NUMPAD0; 00216 } 00217 return NUMPADSPC_INVALID; 00218 } 00219 00220 if (gfInNumpadHexInput & NUMPAD_HEXMODE_HL) { 00221 // 00222 // Full keyboard 00223 // 00224 if (uVirKey >= L'A' && uVirKey <= L'F') { 00225 return uVirKey - L'A' + 0xa; 00226 } 00227 if (uVirKey >= L'0' && uVirKey <= L'9') { 00228 return uVirKey - L'0'; 00229 } 00230 } 00231 00232 return NUMPADSPC_INVALID; 00233 }

int TranslateInjectedVKey IN UINT  uScanCode,
OUT PWCHAR  awchChars,
IN UINT  uiTMFlags
 

Definition at line 185 of file tounicod.c.

References LOBYTE, and PtiCurrent.

Referenced by xxxInternalToUnicode().

00189 { 00190 UserAssert(LOBYTE(uScanCode) == 0); 00191 if (!(uScanCode & KBDBREAK) || (uiTMFlags & TM_POSTCHARBREAKS)) { 00192 awchChars[0] = PtiCurrent()->wchInjected; 00193 return 1; 00194 } 00195 return 0; 00196 }

WCHAR xxxClientCharToWchar IN WORD  CodePage,
IN WORD  wch
 

Referenced by xxxInternalToUnicode().

int xxxInternalToUnicode IN UINT  uVirtKey,
IN UINT  uScanCode,
CONST IN PBYTE  pfvk,
OUT PWCHAR  awchChars,
IN INT  cChar,
IN UINT  uiTMFlags,
OUT PDWORD  pdwKeyFlags,
IN HKL  hkl
 

Definition at line 279 of file tounicod.c.

References __declspec(), BYTE, tagKL::CodePage, ComposeDeadKeys(), GetAppCompatFlags2(), GetModificationNumber(), GetModifierBits(), gfEnableHexNumpad, gfInNumpadHexInput, HIBYTE, HKLtoPKL(), InternalVkKeyScanEx(), IS_DBCS_CODEPAGE, ISCAPSLOCKON, IsDbcsExemptionForHighAnsi(), ISKANALOCKON, LOBYTE, MODIFIER_FOR_ALT_NUMPAD, NlsOemCodePage, NULL, NUMPAD_HEXMODE_HL, NUMPADCONV_HEX_HKLCP, NUMPADCONV_HEX_UNICODE, NUMPADCONV_HKLCP, NUMPADCONV_OEMCP, NumPadScanCodeToHex(), PBYTE, tagKBDFILE::pKbdTbl, PtiCurrentShared, SCANCODE_NUMPAD_DOT, SCANCODE_NUMPAD_PLUS, tagKL::spkf, tagTHREADINFO::spklActive, TestKeyDownBit, TIF_CSRSSTHREAD, tagTHREADINFO::TIF_flags, TranslateInjectedVKey(), USHORT, VER40, tagKL::wchDiacritic, xxxClientCharToWchar(), and xxxMessageBeep().

00288 { 00289 WORD wModBits; 00290 WORD nShift; 00291 WCHAR *pUniChar; 00292 PVK_TO_WCHARS1 pVK; 00293 PVK_TO_WCHAR_TABLE pVKT; 00294 static WORD NumpadChar; 00295 static WORD VKLastDown; 00296 static BYTE ConvMode; // 0 == NUMPADCONV_OEMCP 00297 PTHREADINFO ptiCurrent = PtiCurrentShared(); 00298 PKL pkl; 00299 PKBDTABLES pKbdTbl; 00300 PLIGATURE1 pLigature; 00301 00302 *pdwKeyFlags = (uScanCode & KBDBREAK); 00303 00304 if ((hkl == NULL) && ptiCurrent->spklActive) { 00305 pkl = ptiCurrent->spklActive; 00306 pKbdTbl = pkl->spkf->pKbdTbl; 00307 } else { 00308 pkl = HKLtoPKL(ptiCurrent, hkl); 00309 if (!pkl) { 00310 return 0; 00311 } 00312 pKbdTbl = pkl->spkf->pKbdTbl; 00313 } 00314 UserAssert(pkl != NULL); 00315 UserAssert(pKbdTbl != NULL); 00316 00317 pUniChar = awchChars; 00318 00319 uScanCode &= (0xFF | KBDEXT); 00320 00321 if (*pdwKeyFlags & KBDBREAK) { // break code processing 00322 /* 00323 * Finalize number pad processing 00324 * 00325 */ 00326 if (uVirtKey == VK_MENU) { 00327 if (NumpadChar) { 00328 if (ConvMode == NUMPADCONV_HEX_UNICODE) { 00329 *pUniChar = NumpadChar; 00330 } else if (ConvMode == NUMPADCONV_OEMCP && 00331 (ptiCurrent->TIF_flags & TIF_CSRSSTHREAD)) { 00332 /* 00333 * Pass the OEM char to Console to be converted to Unicode 00334 * there, since we don't know the OEM codepage it is using. 00335 * Set ALTNUMPAD_BIT for console so it knows! 00336 */ 00337 *pdwKeyFlags |= ALTNUMPAD_BIT; 00338 *pUniChar = NumpadChar; 00339 } else { 00340 /* 00341 * Conversion based on OEMCP or current input language. 00342 */ 00343 WORD wCodePage; 00344 00345 if (ConvMode == NUMPADCONV_OEMCP) { 00346 // NlsOemCodePage is exported from ntoskrnl.exe. 00347 extern __declspec(dllimport) USHORT NlsOemCodePage; 00348 00349 wCodePage = (WORD)NlsOemCodePage; 00350 } else { 00351 wCodePage = pkl->CodePage; 00352 } 00353 if (IS_DBCS_CODEPAGE(wCodePage)) { 00354 if (NumpadChar & (WORD)~0xff) { 00355 /* 00356 * Might be a double byte character. 00357 * Let's swab it so that NumpadChar has LB in LOBYTE, 00358 * TB in HIBYTE. 00359 */ 00360 NumpadChar = MAKEWORD(HIBYTE(NumpadChar), LOBYTE(NumpadChar)); 00361 } else if (IsDbcsExemptionForHighAnsi(wCodePage, NumpadChar)) { 00362 /* 00363 * FarEast hack: 00364 * treat characters in High ANSI area as if they are 00365 * the ones of Codepage 1252. 00366 */ 00367 wCodePage = 1252; 00368 } 00369 } else { 00370 /* 00371 * Backward compatibility: 00372 * Simulate the legacy modulo behavior for non-FarEast keyboard layouts. 00373 */ 00374 NumpadChar &= 0xff; 00375 } 00376 00377 *pUniChar = xxxClientCharToWchar(wCodePage, NumpadChar); 00378 } 00379 00380 /* 00381 * Clear Alt-Numpad state, the ALT key-release generates 1 character. 00382 */ 00383 VKLastDown = 0; 00384 ConvMode = NUMPADCONV_OEMCP; 00385 NumpadChar = 0; 00386 gfInNumpadHexInput &= ~NUMPAD_HEXMODE_HL; 00387 00388 return 1; 00389 } else if (ConvMode != NUMPADCONV_OEMCP) { 00390 ConvMode = NUMPADCONV_OEMCP; 00391 } 00392 } else if (uVirtKey == VKLastDown) { 00393 /* 00394 * The most recently depressed key has now come up: we are now 00395 * ready to accept a new NumPad key for Alt-Numpad processing. 00396 */ 00397 VKLastDown = 0; 00398 } 00399 } 00400 00401 if (!(*pdwKeyFlags & KBDBREAK) || (uiTMFlags & TM_POSTCHARBREAKS)) { 00402 /* 00403 * Get the character modification bits. 00404 * The bit-mask (wModBits) encodes depressed modifier keys: 00405 * these bits are commonly KBDSHIFT, KBDALT and/or KBDCTRL 00406 * (representing Shift, Alt and Ctrl keys respectively) 00407 */ 00408 wModBits = GetModifierBits(pKbdTbl->pCharModifiers, pfvk); 00409 00410 /* 00411 * If the current shift state is either Alt or Alt-Shift: 00412 * 00413 * 1. If a menu is currently displayed then clear the 00414 * alt bit from wModBits and proceed with normal 00415 * translation. 00416 * 00417 * 2. If this is a number pad key then do alt-<numpad> 00418 * calculations. 00419 * 00420 * 3. Otherwise, clear alt bit and proceed with normal 00421 * translation. 00422 */ 00423 00424 /* 00425 * Equivalent code is in xxxKeyEvent() to check the 00426 * low level mode. If you change this code, you may 00427 * need to change xxxKeyEvent() as well. 00428 */ 00429 if (!(*pdwKeyFlags & KBDBREAK) && MODIFIER_FOR_ALT_NUMPAD(wModBits)) { 00430 /* 00431 * If this is a numeric numpad key 00432 */ 00433 if ((uiTMFlags & TM_INMENUMODE) == 0) { 00434 if (gfEnableHexNumpad && uScanCode == SCANCODE_NUMPAD_DOT) { 00435 if ((gfInNumpadHexInput & NUMPAD_HEXMODE_HL) == 0) { 00436 /* 00437 * If the first key is '.', then we're 00438 * entering hex input lang input mode. 00439 */ 00440 ConvMode = NUMPADCONV_HEX_HKLCP; 00441 /* 00442 * Inidicate to the rest of the system 00443 * we're in Hex Alt+Numpad mode. 00444 */ 00445 gfInNumpadHexInput |= NUMPAD_HEXMODE_HL; 00446 TAGMSG0(DBGTAG_ToUnicode, "NUMPADCONV_HEX_HKLCP"); 00447 } else { 00448 goto ExitNumpadMode; 00449 } 00450 } else if (gfEnableHexNumpad && uScanCode == SCANCODE_NUMPAD_PLUS) { 00451 if ((gfInNumpadHexInput & NUMPAD_HEXMODE_HL) == 0) { 00452 /* 00453 * If the first key is '+', then we're 00454 * entering hex UNICODE input mode. 00455 */ 00456 ConvMode = NUMPADCONV_HEX_UNICODE; 00457 /* 00458 * Inidicate to the rest of the system 00459 * we're in Hex Alt+Numpad mode. 00460 */ 00461 gfInNumpadHexInput |= NUMPAD_HEXMODE_HL; 00462 TAGMSG0(DBGTAG_ToUnicode, "NUMPADCONV_HEX_UNICODE"); 00463 } else { 00464 goto ExitNumpadMode; 00465 } 00466 } else { 00467 int digit = NumPadScanCodeToHex(uScanCode, uVirtKey); 00468 00469 if (digit < 0) { 00470 goto ExitNumpadMode; 00471 } 00472 00473 /* 00474 * Ignore repeats 00475 */ 00476 if (VKLastDown == uVirtKey) { 00477 return 0; 00478 } 00479 00480 switch (ConvMode) { 00481 case NUMPADCONV_HEX_HKLCP: 00482 case NUMPADCONV_HEX_UNICODE: 00483 /* 00484 * Input is treated as hex number. 00485 */ 00486 TAGMSG1(DBGTAG_ToUnicode, "->NUMPADCONV_HEX_*: old NumpadChar=%02x\n", NumpadChar); 00487 NumpadChar = NumpadChar * 0x10 + digit; 00488 TAGMSG1(DBGTAG_ToUnicode, "<-NUMPADCONV_HEX_*: new NumpadChar=%02x\n", NumpadChar); 00489 break; 00490 default: 00491 /* 00492 * Input is treated as decimal number. 00493 */ 00494 NumpadChar = NumpadChar * 10 + digit; 00495 00496 /* 00497 * Do Alt-Numpad0 processing 00498 */ 00499 if (NumpadChar == 0 && digit == 0) { 00500 ConvMode = NUMPADCONV_HKLCP; 00501 } 00502 break; 00503 } 00504 } 00505 VKLastDown = (WORD)uVirtKey; 00506 } else { 00507 ExitNumpadMode: 00508 /* 00509 * Clear Alt-Numpad state and the ALT shift state. 00510 */ 00511 VKLastDown = 0; 00512 ConvMode = NUMPADCONV_OEMCP; 00513 NumpadChar = 0; 00514 wModBits &= ~KBDALT; 00515 gfInNumpadHexInput &= ~NUMPAD_HEXMODE_HL; 00516 } 00517 } 00518 00519 /* 00520 * LShift/RSHift+Backspace -> Left-to-Right and Right-to-Left marker 00521 */ 00522 if ((uVirtKey == VK_BACK) && (pKbdTbl->fLocaleFlags & KLLF_LRM_RLM)) { 00523 if (TestKeyDownBit(pfvk, VK_LSHIFT)) { 00524 *pUniChar = 0x200E; // LRM 00525 return 1; 00526 } else if (TestKeyDownBit(pfvk, VK_RSHIFT)) { 00527 *pUniChar = 0x200F; // RLM 00528 return 1; 00529 } 00530 } else if (((WORD)uVirtKey == VK_PACKET) && (LOBYTE(uScanCode) == 0)) { 00531 return TranslateInjectedVKey(uScanCode, awchChars, uiTMFlags); 00532 } 00533 00534 /* 00535 * Scan through all the shift-state tables until a matching Virtual 00536 * Key is found. 00537 */ 00538 for (pVKT = pKbdTbl->pVkToWcharTable; pVKT->pVkToWchars != NULL; pVKT++) { 00539 pVK = pVKT->pVkToWchars; 00540 while (pVK->VirtualKey != 0) { 00541 if (pVK->VirtualKey == (BYTE)uVirtKey) { 00542 goto VK_Found; 00543 } 00544 pVK = (PVK_TO_WCHARS1)((PBYTE)pVK + pVKT->cbSize); 00545 } 00546 } 00547 00548 /* 00549 * Not found: virtual key is not a character. 00550 */ 00551 goto ReturnBadCharacter; 00552 00553 VK_Found: 00554 /* 00555 * The virtual key has been found in table pVKT, at entry pVK 00556 */ 00557 00558 /* 00559 * If KanaLock affects this key and it is on: toggle KANA state 00560 * only if no other state is on. "KANALOK" attributes only exist 00561 * in Japanese keyboard layout, and only Japanese keyboard hardware 00562 * can be "KANA" lock on state. 00563 */ 00564 if ((pVK->Attributes & KANALOK) && (ISKANALOCKON(pfvk))) { 00565 wModBits |= KBDKANA; 00566 } else 00567 /* 00568 * If CapsLock affects this key and it is on: toggle SHIFT state 00569 * only if no other state is on. 00570 * (CapsLock doesn't affect SHIFT state if Ctrl or Alt are down). 00571 * OR 00572 * If CapsLockAltGr affects this key and it is on: toggle SHIFT 00573 * state only if both Alt & Control are down. 00574 * (CapsLockAltGr only affects SHIFT if AltGr is being used). 00575 */ 00576 if ((pVK->Attributes & CAPLOK) && ((wModBits & ~KBDSHIFT) == 0) && 00577 ISCAPSLOCKON(pfvk)) { 00578 wModBits ^= KBDSHIFT; 00579 } else if ((pVK->Attributes & CAPLOKALTGR) && 00580 ((wModBits & (KBDALT | KBDCTRL)) == (KBDALT | KBDCTRL)) && 00581 ISCAPSLOCKON(pfvk)) { 00582 wModBits ^= KBDSHIFT; 00583 } 00584 00585 /* 00586 * If SGCAPS affects this key and CapsLock is on: use the next entry 00587 * in the table, but not is Ctrl or Alt are down. 00588 * (SGCAPS is used in Swiss-German, Czech and Czech 101 layouts) 00589 */ 00590 if ((pVK->Attributes & SGCAPS) && ((wModBits & ~KBDSHIFT) == 0) && 00591 ISCAPSLOCKON(pfvk)) { 00592 pVK = (PVK_TO_WCHARS1)((PBYTE)pVK + pVKT->cbSize); 00593 } 00594 00595 /* 00596 * Convert the shift-state bitmask into one of the enumerated 00597 * logical shift states. 00598 */ 00599 nShift = GetModificationNumber(pKbdTbl->pCharModifiers, wModBits); 00600 00601 if (nShift == SHFT_INVALID) { 00602 /* 00603 * An invalid combination of Shifter Keys 00604 */ 00605 goto ReturnBadCharacter; 00606 00607 } else if ((nShift < pVKT->nModifications) && 00608 (pVK->wch[nShift] != WCH_NONE)) { 00609 /* 00610 * There is an entry in the table for this combination of 00611 * Shift State (nShift) and Virtual Key (uVirtKey). 00612 */ 00613 if (pVK->wch[nShift] == WCH_DEAD) { 00614 /* 00615 * It is a dead character: the next entry contains 00616 * its value. 00617 */ 00618 pVK = (PVK_TO_WCHARS1)((PBYTE)pVK + pVKT->cbSize); 00619 00620 /* 00621 * If the previous char was not dead return a dead character. 00622 */ 00623 if (pkl->wchDiacritic == 0) { 00624 TAGMSG2(DBGTAG_ToUnicode, 00625 "xxxInternalToUnicode: new dead char '%C'(%x), goto ReturnDeadCharacter", 00626 pVK->wch[nShift], pVK->wch[nShift]); 00627 goto ReturnDeadCharacter; 00628 } 00629 /* 00630 * Else go to ReturnGoodCharacter which will attempt to 00631 * compose this dead character with the previous dead char. 00632 */ 00633 /* 00634 * N.B. NTBUG 6141 00635 * If dead key is hit twice in sequence, Win95/98 gives 00636 * two composed characters from dead chars... 00637 */ 00638 TAGMSG4(DBGTAG_ToUnicode, 00639 "xxxInternalToUnicode: 2 dead chars '%C'(%x)+'%C'(%x)", 00640 pkl->wchDiacritic, pkl->wchDiacritic, 00641 pVK->wch[nShift], pVK->wch[nShift]); 00642 if (GetAppCompatFlags2(VER40) & GACF2_NOCHAR_DEADKEY) { 00643 /* 00644 * AppCompat 377217: Publisher calls TranslateMessage and ToUnicode for 00645 * the same dead key when it's not expecting real characters. 00646 * On NT4, this resulted like "pushing the dead key in the stack and 00647 * no character is compossed", but on NT5 with fix to 6141, 00648 * two dead keys compose real characters clearing the internal 00649 * dead key cache. The app shouldn't call both TranslateMessage and ToUnicode 00650 * for the same key stroke in the first place -- in a way the app was working on 00651 * NT4 by just a thin luck. 00652 * In any case, since the app has been shipped broadly and hard to fix, 00653 * let's simulate the NT4 behavior here, but with just one level cache (not the 00654 * stack). 00655 */ 00656 goto ReturnDeadCharacter; 00657 } 00658 00659 goto ReturnGoodCharacter; 00660 00661 } else if (pVK->wch[nShift] == WCH_LGTR) { 00662 /* 00663 * It is a ligature. Look in ligature table for a match. 00664 */ 00665 if ((GET_KBD_VERSION(pKbdTbl) == 0) || ((pLigature = pKbdTbl->pLigature) == NULL)) { 00666 /* 00667 * Hey, where's the table? 00668 */ 00669 xxxMessageBeep(0); 00670 goto ReturnBadCharacter; 00671 } 00672 00673 while (pLigature->VirtualKey != 0) { 00674 int iLig = 0; 00675 int cwchT = 0; 00676 00677 if ((pLigature->VirtualKey == pVK->VirtualKey) && 00678 (pLigature->ModificationNumber == nShift)) { 00679 /* 00680 * Found the ligature! 00681 */ 00682 while ((iLig < pKbdTbl->nLgMax) && (cwchT < cChar)) { 00683 if (pLigature->wch[iLig] == WCH_NONE) { 00684 /* 00685 * End of ligature. 00686 */ 00687 return cwchT; 00688 } 00689 if (pkl->wchDiacritic != 0) { 00690 int cComposed; 00691 /* 00692 * Attempt to compose the previous deadkey with current 00693 * ligature character. If this generates yet another 00694 * dead key, go round again without adding to pUniChar 00695 * or cwchT. 00696 */ 00697 cComposed = ComposeDeadKeys( 00698 pkl, 00699 pKbdTbl->pDeadKey, 00700 pLigature->wch[iLig], 00701 pUniChar + cwchT, 00702 cChar - cwchT, 00703 *pdwKeyFlags & KBDBREAK 00704 ); 00705 if (cComposed > 0) { 00706 cwchT += cComposed; 00707 } else { 00708 RIPMSG2(RIP_ERROR, // we really don't expect this 00709 "InternalToUnicode: dead+lig(%x)->dead(%x)", 00710 pLigature->wch[0], pkl->wchDiacritic); 00711 } 00712 } else { 00713 pUniChar[cwchT++] = pLigature->wch[iLig]; 00714 } 00715 iLig++; 00716 } 00717 return cwchT; 00718 } 00719 /* 00720 * Not a match, try the next entry. 00721 */ 00722 pLigature = (PLIGATURE1)((PBYTE)pLigature + pKbdTbl->cbLgEntry); 00723 } 00724 /* 00725 * No match found! 00726 */ 00727 xxxMessageBeep(0); 00728 goto ReturnBadCharacter; 00729 } 00730 00731 /* 00732 * Match found: return the unshifted character 00733 */ 00734 TAGMSG2(DBGTAG_ToUnicode, 00735 "xxxInternalToUnicode: Match found '%C'(%x), goto ReturnGoodChar", 00736 pVK->wch[nShift], pVK->wch[nShift]); 00737 goto ReturnGoodCharacter; 00738 00739 } else if ((wModBits == KBDCTRL) || (wModBits == (KBDCTRL|KBDSHIFT)) || 00740 (wModBits == (KBDKANA|KBDCTRL)) || (wModBits == (KBDKANA|KBDCTRL|KBDSHIFT))) { 00741 /* 00742 * There was no entry for this combination of Modification (nShift) 00743 * and Virtual Key (uVirtKey). It may still be an ASCII control 00744 * character though: 00745 */ 00746 if ((uVirtKey >= 'A') && (uVirtKey <= 'Z')) { 00747 /* 00748 * If the virtual key is in the range A-Z we can convert 00749 * it directly to a control character. Otherwise, we 00750 * need to search the control key conversion table for 00751 * a match to the virtual key. 00752 */ 00753 *pUniChar = (WORD)(uVirtKey & 0x1f); 00754 return 1; 00755 } else if ((uVirtKey >= 0xFF61) && (uVirtKey <= 0xFF91)) { 00756 /* 00757 * If the virtual key is in range FF61-FF91 (halfwidth 00758 * katakana), we convert it to Virtual scan code with 00759 * KANA modifier. 00760 */ 00761 *pUniChar = (WORD)(InternalVkKeyScanEx((WCHAR)uVirtKey,pKbdTbl) & 0x1f); 00762 return 1; 00763 } 00764 } 00765 } 00766 00767 ReturnBadCharacter: 00768 // pkl->wchDiacritic = 0; 00769 return 0; 00770 00771 ReturnDeadCharacter: 00772 *pUniChar = pVK->wch[nShift]; 00773 00774 /* 00775 * Save 'dead' key: overwrite an existing one. 00776 */ 00777 if (!(*pdwKeyFlags & KBDBREAK)) { 00778 pkl->wchDiacritic = *pUniChar; 00779 } 00780 00781 UserAssert(pKbdTbl->pDeadKey); 00782 00783 /* 00784 * return negative count for dead characters 00785 */ 00786 return -1; 00787 00788 ReturnGoodCharacter: 00789 if ((pKbdTbl->pDeadKey != NULL) && (pkl->wchDiacritic != 0)) { 00790 return ComposeDeadKeys( 00791 pkl, 00792 pKbdTbl->pDeadKey, 00793 pVK->wch[nShift], 00794 pUniChar, 00795 cChar, 00796 *pdwKeyFlags & KBDBREAK 00797 ); 00798 } 00799 *pUniChar = (WORD)pVK->wch[nShift]; 00800 return 1; 00801 }

int xxxToUnicodeEx UINT  wVirtKey,
UINT  wScanCode,
CONST BYTE pbKeyState,
LPWSTR  pwszBuff,
int  cchBuff,
UINT  wKeyFlags,
HKL  hkl
 

Definition at line 40 of file tounicod.c.

References BYTE, CBKEYSTATE, ClearKeyDownBit, ClearKeyToggleBit, DWORD, SetKeyDownBit, SetKeyToggleBit, and xxxInternalToUnicode().

Referenced by NtUserToUnicodeEx().

00048 { 00049 int i; 00050 BYTE afKeyState[CBKEYSTATE]; 00051 DWORD dwDummy; 00052 00053 /* 00054 * pKeyState is an array of 256 bytes, each byte representing the 00055 * following virtual key state: 0x80 means down, 0x01 means toggled. 00056 * InternalToUnicode() takes an array of bits, so pKeyState needs to 00057 * be translated. _ToAscii only a public api and rarely gets called, 00058 * so this is no big deal. 00059 */ 00060 for (i = 0; i < 256; i++, pbKeyState++) { 00061 if (*pbKeyState & 0x80) { 00062 SetKeyDownBit(afKeyState, i); 00063 } else { 00064 ClearKeyDownBit(afKeyState, i); 00065 } 00066 00067 if (*pbKeyState & 0x01) { 00068 SetKeyToggleBit(afKeyState, i); 00069 } else { 00070 ClearKeyToggleBit(afKeyState, i); 00071 } 00072 } 00073 00074 i = xxxInternalToUnicode(wVirtKey, wScanCode, afKeyState, pwszBuff, cchBuff, 00075 wKeyFlags, &dwDummy, hkl); 00076 00077 00078 return i; 00079 }


Generated on Sat May 15 19:45:48 2004 for test by doxygen 1.3.7