Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

535 lines
17 KiB

/****************************** Module Header ******************************\
* Module Name: tounicod.c
*
* Copyright (c) 1985-91, Microsoft Corporation
*
* History:
* 02-08-92 GregoryW Created.
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/*
* "To a new truth there is nothing more hurtful than an old error."
* - Johann Wolfgang von Goethe (1749-1832)
*/
/*
* macros used locally to make life easier
*/
#define ISCAPSLOCKON(pf) (TestKeyToggleBit(pf, VK_CAPITAL) != 0)
#define ISNUMLOCKON(pf) (TestKeyToggleBit(pf, VK_NUMLOCK) != 0)
#define ISSHIFTDOWN(w) (w & 0x01)
#define N_ELEM(a) (sizeof(a)/sizeof(a[0]))
#define LAST_ELEM(a) ( (a) [ N_ELEM(a) - 1 ] )
#define PLAST_ELEM(a) (&LAST_ELEM(a))
WCHAR xxxClientOemToChar(
char IN chOem);
int xxxClientFoldString(
DWORD IN dwMapFlags,
PUNICODE_STRING IN pstrSrc,
PUNICODE_STRING OUT pstrDest);
/***************************************************************************\
* _ToUnicodeEx (API)
*
* This routine provides Unicode translation for the virtual key code
* passed in.
*
* History:
* 02-10-92 GregoryW Created.
* 01-23-95 GregoryW Expanded from _ToUnicode to _ToUnicodeEx
\***************************************************************************/
int _ToUnicodeEx(
UINT wVirtKey,
UINT wScanCode,
LPBYTE pbKeyState,
LPWSTR pwszBuff,
int cchBuff,
UINT wKeyFlags,
HKL hkl)
{
int i;
BYTE afKeyState[CBKEYSTATE];
BOOL bDummy;
/*
* pKeyState is an array of 256 bytes, each byte representing the
* following virtual key state: 0x80 means down, 0x01 means toggled.
* InternalToUnicode() takes an array of bits, so pKeyState needs to
* be translated. _ToAscii only a public api and rarely gets called,
* so this is no big deal.
*/
for (i = 0; i < 256; i++, pbKeyState++) {
if (*pbKeyState & 0x80) {
SetKeyDownBit(afKeyState, i);
} else {
ClearKeyDownBit(afKeyState, i);
}
if (*pbKeyState & 0x01) {
SetKeyToggleBit(afKeyState, i);
} else {
ClearKeyToggleBit(afKeyState, i);
}
}
i = InternalToUnicodeEx(wVirtKey, wScanCode, afKeyState, pwszBuff, cchBuff,
wKeyFlags, &bDummy, hkl);
return i;
}
int InternalToUnicodeEx(
UINT wVirtKey,
UINT wScanCode,
PBYTE pfvk,
LPVOID pChar,
INT cChar,
UINT wKeyFlags,
PBOOL pbBreak,
HKL hkl)
{
WORD wModBits;
WORD nShift;
WORD *pUniChar;
PVK_TO_WCHARS1 pVK;
PVK_TO_WCHAR_TABLE pVKT;
static BYTE NumpadChar = '\0';
static BOOL fLeading0 = FALSE;
static UINT VKLastDown;
PWINDOWSTATION pwinsta;
PTHREADINFO pti = PtiCurrentShared();
int cwchT;
PKL pkl;
PKBDTABLES pKbdTbl;
pwinsta = pti->rpdesk->rpwinstaParent;
if (hkl == NULL) {
UserAssert(pti->spklActive);
pKbdTbl = pti->spklActive->spkf->pKbdTbl;
} else {
pkl = HKLtoPKL(hkl);
if (!pkl) {
return 0;
}
pKbdTbl = pkl->spkf->pKbdTbl;
}
UserAssert(pKbdTbl != NULL);
pUniChar = (WORD *)pChar;
*pbBreak = ((wScanCode & KBDBREAK) != 0);
wScanCode &= (0xFF | KBDEXT);
if (*pbBreak) { // break code processing
/*
* do number pad processing
*
* NOTE: moving this to an IME would be really cool. Alt-numpad
* processing will need to support OEM codes, ANSI codes,
* and UNICODE codes! IMEs need to be chainable for this
* to work. For now, all number pad processing will be
* for OEM and ANSI chars. Unicode input is not supported
* via the numpad...
*/
if (wVirtKey == VK_MENU) {
if (NumpadChar) {
if (fLeading0) {
/*
* A leading 0 means we have entered an ANSI char.
* However, we store everything internally as
* Unicode.
*/
RtlMultiByteToUnicodeN(
(LPWSTR)pUniChar,
sizeof(WCHAR),
NULL,
(LPSTR)&NumpadChar,
(ULONG)sizeof(CHAR)
);
} else {
*pUniChar = xxxClientOemToChar(NumpadChar);
}
/*
* Clear Alt-Numpad state, the ALT key-release generates 1 character.
*/
VKLastDown = 0;
fLeading0 = FALSE;
NumpadChar = '\0';
return 1;
}
} else if (wVirtKey == VKLastDown) {
/*
* The most recently depressed key has now come up: we are now
* ready to accept a new NumPad key for Alt-Numpad processing.
*/
VKLastDown = 0;
}
}
if (!(*pbBreak) || (wKeyFlags & TM_POSTCHARBREAKS)) {
/*
* Get the character modification bits.
* The bit-mask (wModBits) encodes depressed modifier keys:
* these bits are commonly KBDSHIFT, KBDALT and/or KBDCTRL
* (representing Shift, Alt and Ctrl keys respectively)
*/
wModBits = GetModifierBits(pKbdTbl->pCharModifiers, pfvk);
/*
* If the current shift state is either Alt or Alt-Shift:
*
* 1. If a menu is currently displayed then clear the
* alt bit from wModBits and proceed with normal
* translation.
*
* 2. If this is a number pad key then do alt-<numpad>
* calculations.
*
* 3. Otherwise, clear alt bit and proceed with normal
* translation.
*/
if (!(*pbBreak) &&
((wModBits == KBDALT) || (wModBits == (KBDALT|KBDSHIFT)))) {
/*
* If this is a numeric numpad key
*/
if (((wKeyFlags & 0x1) == 0) &&
(wScanCode >= SCANCODE_NUMPAD_FIRST) &&
(wScanCode <= SCANCODE_NUMPAD_LAST) &&
(aVkNumpad[wScanCode - SCANCODE_NUMPAD_FIRST] != 0xFF)) {
int digit = aVkNumpad[wScanCode - SCANCODE_NUMPAD_FIRST] -
VK_NUMPAD0;
/*
* Ignore repeats
*/
if (VKLastDown == wVirtKey) {
return 0;
}
/*
* Do Alt-Numpad processing
*/
if ((NumpadChar == '\0') && (digit == 0)) {
fLeading0 = TRUE;
}
NumpadChar = NumpadChar * 10 + digit;
VKLastDown = wVirtKey;
} else {
/*
* Clear Alt-Numpad state and the ALT shift state.
*/
VKLastDown = 0;
fLeading0 = FALSE;
NumpadChar = '\0';
wModBits &= ~KBDALT;
}
}
/*
* Scan through all the shift-state tables until a matching Virtual
* Key is found.
*/
for (pVKT = pKbdTbl->pVkToWcharTable; pVKT->pVkToWchars != NULL; pVKT++) {
pVK = pVKT->pVkToWchars;
while (pVK->VirtualKey != 0) {
if (pVK->VirtualKey == (BYTE)wVirtKey) {
goto VK_Found;
}
pVK = (PVK_TO_WCHARS1)((PBYTE)pVK + pVKT->cbSize);
}
}
/*
* Not found: virtual key is not a character.
*/
goto ReturnBadCharacter;
VK_Found:
/*
* The virtual key has been found in table pVKT, at entry pVK
*/
/*
* If CapsLock affects this key and it is on: toggle SHIFT state
* only if no other state is on.
* (CapsLock doesn't affect SHIFT state if Ctrl or Alt are down).
* OR
* If CapsLockAltGr affects this key and it is on: toggle SHIFT
* state only if both Alt & Control are down.
* (CapsLockAltGr only affects SHIFT if AltGr is being used).
*/
if ((pVK->Attributes & CAPLOK) && ((wModBits & ~KBDSHIFT) == 0) &&
ISCAPSLOCKON(pfvk)) {
wModBits ^= KBDSHIFT;
} else if ((pVK->Attributes & CAPLOKALTGR) &&
((wModBits & (KBDALT | KBDCTRL)) == (KBDALT | KBDCTRL)) &&
ISCAPSLOCKON(pfvk)) {
wModBits ^= KBDSHIFT;
}
/*
* If SGCAPS affects this key and CapsLock is on: use the next entry
* in the table, but not is Ctrl or Alt are down.
* (SGCAPS is used in Swiss-German, Czech and Czech 101 layouts)
*/
if ((pVK->Attributes & SGCAPS) && ((wModBits & ~KBDSHIFT) == 0) &&
ISCAPSLOCKON(pfvk)) {
pVK = (PVK_TO_WCHARS1)((PBYTE)pVK + pVKT->cbSize);
}
/*
* Convert the shift-state bitmask into one of the enumerated
* logical shift states.
*/
nShift = GetModificationNumber(pKbdTbl->pCharModifiers, wModBits);
if (nShift == SHFT_INVALID) {
/*
* An invalid combination of Shifter Keys
*/
goto ReturnBadCharacter;
} else if ((nShift < pVKT->nModifications) &&
(pVK->wch[nShift] != WCH_NONE)) {
/*
* There is an entry in the table for this combination of
* Shift State (nShift) and Virtual Key (wVirtKey).
*/
if (pVK->wch[nShift] == WCH_DEAD) {
/*
* It is a dead character: the next entry contains
* its value.
*/
pVK = (PVK_TO_WCHARS1)((PBYTE)pVK + pVKT->cbSize);
/*
* If the previous char was also dead and the layout contains
* it's own dead-key composition table, attempt composition by
* dropping through to ReturnGoodCharacter
*/
if ((pwinsta->pwchDiacritic == PLAST_ELEM(pwinsta->awchDiacritic)) || (pKbdTbl->pDeadKey != NULL)) {
goto ReturnDeadCharacter;
}
}
/*
* Match found: return the unshifted character
*/
goto ReturnGoodCharacter;
} else if ((wModBits == KBDCTRL) || (wModBits == KBDCTRL+KBDSHIFT)) {
/*
* There was no entry for this combination of Modification (nShift)
* and Virtual Key (wVirtKey). It may still be an ASCII control
* character though:
*/
if ((wVirtKey >= 'A') && (wVirtKey <= 'Z')) {
/*
* If the virtual key is in the range A-Z we can convert
* it directly to a control character. Otherwise, we
* need to search the control key conversion table for
* a match to the virtual key.
*/
*pUniChar = (WORD)(wVirtKey & 0x1f);
return 1;
}
}
}
ReturnBadCharacter:
// pwinsta->pwchDiacritic = PLAST_ELEM(pwinsta->awchDiacritic);
return 0;
ReturnDeadCharacter:
*pUniChar = pVK->wch[nShift];
/*
* Save 'dead' key: if cache is full, just lose the oldest dead chars.
*/
if (!*pbBreak) {
if (pwinsta->pwchDiacritic <= pwinsta->awchDiacritic) {
RtlMoveMemory(&(pwinsta->awchDiacritic[1]),
&(pwinsta->awchDiacritic[0]),
sizeof(pwinsta->awchDiacritic) - sizeof(WCHAR));
pwinsta->pwchDiacritic++;
xxxMessageBeep(0);
}
*(pwinsta->pwchDiacritic--) = *pUniChar;
}
if (pKbdTbl->pDeadKey == NULL) {
UNICODE_STRING ustrSrc, ustrDest;
*(pwinsta->pwchDiacritic) = 0x00A0;
/*
* Attempt to compose dead key with NBSP for WM_DEADCHAR value.
*/
RtlInitUnicodeString(&ustrSrc, pwinsta->pwchDiacritic);
ustrDest.Length = ustrDest.MaximumLength = 2;
ustrDest.Buffer = (LPWSTR)pUniChar;
cwchT = xxxClientFoldString(MAP_PRECOMPOSED, &ustrSrc, &ustrDest);
if (cwchT == 2) {
*pUniChar = pwinsta->pwchDiacritic[1];
}
}
/*
* return negative count for dead characters
*/
return -1;
ReturnGoodCharacter:
if (pwinsta->pwchDiacritic < PLAST_ELEM(pwinsta->awchDiacritic)) {
/*
* Attempt to compose this sequence:
*/
PDEADKEY pDeadKey;
WCHAR wchTyped = pVK->wch[nShift];
if ((pDeadKey = pKbdTbl->pDeadKey) != NULL) {
/*
* Use the layout's built-in table for dead char composition
*/
DWORD dwBoth;
dwBoth = MAKELONG(wchTyped, pwinsta->pwchDiacritic[1]);
/*
* Don't let character upstrokes erase the cached dead char: else
* if this was the dead char key again (being released after the
* AltGr is released) the dead char would be prematurely cleared.
*/
if (!*pbBreak) {
pwinsta->pwchDiacritic = PLAST_ELEM(pwinsta->awchDiacritic);
}
while (pDeadKey->dwBoth != 0) {
if (pDeadKey->dwBoth == dwBoth) {
/*
* found a composition
*/
*pUniChar = (WORD)pDeadKey->wchComposed;
return 1;
}
pDeadKey++;
}
pUniChar[0] = HIWORD(dwBoth);
pUniChar[1] = LOWORD(dwBoth);
return 2;
} else {
UNICODE_STRING ustrSrc, ustrDest;
/*
* Use the NLS API to compose characters.
*/
if (wchTyped == L' ') {
/*
* Convert SPACE to NBSP, for dead char composition
*/
*(pwinsta->pwchDiacritic) = 0x00A0;
} else {
*(pwinsta->pwchDiacritic) = wchTyped;
}
cwchT = PLAST_ELEM(pwinsta->awchDiacritic) - pwinsta->pwchDiacritic + 1;
RtlInitUnicodeString(&ustrSrc, pwinsta->pwchDiacritic);
ustrDest.Length = ustrDest.MaximumLength = cChar;
ustrDest.Buffer = (LPWSTR)pUniChar;
cChar = xxxClientFoldString(MAP_PRECOMPOSED, &ustrSrc, &ustrDest);
if (cChar == cwchT) {
/*
* No composition so restore 1st character (most recently typed)
* (a SPACE was previously converted to NBSP)
*/
pUniChar[0] = wchTyped;
}
pwinsta->pwchDiacritic = PLAST_ELEM(pwinsta->awchDiacritic);
return cChar;
}
}
*pUniChar = (WORD)pVK->wch[nShift];
return 1;
}
SHORT InternalVkKeyScanEx(
WCHAR cChar,
PKBDTABLES pKbdTbl)
{
PVK_TO_WCHARS1 pVK;
PVK_TO_WCHAR_TABLE pVKT;
BYTE nShift;
WORD wModBits;
if (pKbdTbl == NULL) {
pKbdTbl = gspklBaseLayout->spkf->pKbdTbl;
}
for (pVKT = pKbdTbl->pVkToWcharTable; pVKT->pVkToWchars != NULL; pVKT++) {
pVK = pVKT->pVkToWchars;
while (pVK->VirtualKey != 0) {
for (nShift = 0; nShift < pVKT->nModifications; nShift++) {
if (pVK->wch[nShift] == cChar) {
if (pVK->VirtualKey == 0xff) {
/*
* dead char: back up to previous line to get the VK.
*/
pVK = (PVK_TO_WCHARS1)((PBYTE)pVK - pVKT->cbSize);
}
goto CharFound;
}
}
pVK = (PVK_TO_WCHARS1)((PBYTE)pVK + pVKT->cbSize);
}
}
/*
* May be a control character not explicitly in the layout tables
*/
if (cChar < 0x0020) {
/*
* Ctrl+char -> char - 0x40
*/
return (SHORT)MAKEWORD((cChar + 0x40), KBDCTRL);
}
return -1;
CharFound:
/*
* Scan aModification[] to find nShift: the index will be a bitmask
* representing the Shifter Keys that need to be pressed to produce
* this Shift State.
*/
for (wModBits = 0;
wModBits <= pKbdTbl->pCharModifiers->wMaxModBits;
wModBits++)
{
if (pKbdTbl->pCharModifiers->ModNumber[wModBits] == nShift) {
if (pVK->VirtualKey == 0xff) {
/*
* The previous entry contains the actual virtual key in this case.
*/
pVK = (PVK_TO_WCHARS1)((PBYTE)pVK - pVKT->cbSize);
}
return (SHORT)MAKEWORD(pVK->VirtualKey, wModBits);
;
}
}
/*
* huh? should never reach here!
*/
return -1;
}