Leaked source code of windows server 2003
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.

653 lines
20 KiB

  1. /****************************************************************************/
  2. /* hotkey.c */
  3. /* */
  4. /* RDP Shadow hotkey handling functions. */
  5. /* */
  6. /* Copyright(C) Microsoft Corporation 1997-2000 */
  7. /****************************************************************************/
  8. #ifdef __cplusplus
  9. extern "C" {
  10. #endif /* __cplusplus */
  11. #define TRC_FILE "hotkey"
  12. #include <precomp.h>
  13. #pragma hdrstop
  14. #define pTRCWd pWd
  15. #include <adcg.h>
  16. #include <nwdwapi.h>
  17. #include <nwdwint.h>
  18. #include "kbd.h" //TODO: Good Grief!
  19. typedef struct {
  20. DWORD dwVersion;
  21. DWORD dwFlags;
  22. DWORD dwMapCount;
  23. DWORD dwMap[0];
  24. } SCANCODEMAP, *PSCANCODEMAP;
  25. /***************************************************************************\
  26. * How some Virtual Key values change when a SHIFT key is held down.
  27. \***************************************************************************/
  28. #define VK_MULTIPLY 0x6A
  29. #define VK_SNAPSHOT 0x2C
  30. const ULONG aulShiftCvt_VK[] = {
  31. MAKELONG(VK_MULTIPLY, VK_SNAPSHOT),
  32. MAKELONG(0,0)
  33. };
  34. /***************************************************************************\
  35. * How some Virtual Key values change when a CONTROL key is held down.
  36. \***************************************************************************/
  37. #define VK_LSHIFT 0xA0
  38. #define VK_RSHIFT 0xA1
  39. #define VK_LCONTROL 0xA2
  40. #define VK_RCONTROL 0xA3
  41. #define VK_LMENU 0xA4
  42. #define VK_RMENU 0xA5
  43. #define VK_NUMLOCK 0x90
  44. #define VK_SCROLL 0x91
  45. #define VK_PAUSE 0x13
  46. #define VK_CANCEL 0x03
  47. //#define KBDEXT (USHORT)0x0100
  48. const ULONG aulControlCvt_VK[] = {
  49. MAKELONG(VK_NUMLOCK, VK_PAUSE | KBDEXT),
  50. MAKELONG(VK_SCROLL, VK_CANCEL),
  51. MAKELONG(0,0)
  52. };
  53. /***************************************************************************\
  54. * How some Virtual Key values change when an ALT key is held down.
  55. * The SHIFT and ALT keys both alter VK values the same way!!
  56. \***************************************************************************/
  57. #define aulAltCvt_VK aulShiftCvt_VK
  58. /***************************************************************************\
  59. * This table list keys that may affect Virtual Key values when held down.
  60. *
  61. * See kbd.h for a full description.
  62. *
  63. * 101/102key keyboard (type 4):
  64. * Virtual Key values vary only if CTRL is held down.
  65. * 84-86 key keyboards (type 3):
  66. * Virtual Key values vary if one of SHIFT, CTRL or ALT is held down.
  67. \***************************************************************************/
  68. #define VK_SHIFT 0x10
  69. #define VK_CONTROL 0x11
  70. #define VK_MENU 0x12
  71. //#define KBDSHIFT 1
  72. //#define KBDCTRL 2
  73. //#define KBDALT 4
  74. const VK_TO_BIT aVkToBits_VK[] = {
  75. { VK_SHIFT, KBDSHIFT }, // 0x01
  76. { VK_CONTROL, KBDCTRL }, // 0x02
  77. { VK_MENU, KBDALT }, // 0x04
  78. { 0, 0 }
  79. };
  80. /***************************************************************************\
  81. * Tables defining how some Virtual Key values are modified when other keys
  82. * are held down.
  83. * Translates key combinations into indices for gapulCvt_VK_101[] or for
  84. * gapulCvt_VK_84[] or for
  85. *
  86. * See kbd.h for a full description.
  87. *
  88. \***************************************************************************/
  89. //#define SHFT_INVALID 0x0F
  90. const MODIFIERS Modifiers_VK = {
  91. (PVK_TO_BIT)&aVkToBits_VK[0],
  92. 4, // Maximum modifier bitmask/index
  93. {
  94. SHFT_INVALID, // no keys held down (no VKs are modified)
  95. 0, // SHIFT held down 84-86 key kbd
  96. 1, // CTRL held down 101/102 key kbd
  97. SHFT_INVALID, // CTRL-SHIFT held down (no VKs are modified)
  98. 2 // ALT held down 84-86 key kbd
  99. }
  100. };
  101. /***************************************************************************\
  102. * A tables of pointers indexed by the number obtained from Modify_VK.
  103. * If a pointer is non-NULL then the table it points to is searched for
  104. * Virtual Key that should have their values changed.
  105. * There are two versions: one for 84-86 key kbds, one for 101/102 key kbds.
  106. * gapulCvt_VK is initialized with the default (101/102 key kbd).
  107. \***************************************************************************/
  108. const ULONG *const gapulCvt_VK_101[] = {
  109. NULL, // No VKs are changed by SHIFT being held down
  110. aulControlCvt_VK, // Some VKs are changed by CTRL being held down
  111. NULL // No VKs are changed by ALT being held down
  112. };
  113. const ULONG *const gapulCvt_VK_84[] = {
  114. aulShiftCvt_VK, // Some VKs are changed by SHIFT being held down
  115. aulControlCvt_VK, // Some VKs are changed by CTRL being held down
  116. aulAltCvt_VK // Some VKs are changed by ALT being held down
  117. };
  118. /*
  119. * Determine the state of all the Modifier Keys (a Modifier Key
  120. * is any key that may modify values produced by other keys: these are
  121. * commonly SHIFT, CTRL and/or ALT)
  122. * Build a bit-mask (wModBits) to encode which modifier keys are depressed.
  123. */
  124. #define KEY_BYTE(pb, vk) pb[((BYTE)(vk)) >> 2]
  125. #define KEY_DOWN_BIT(vk) (1 << ((((BYTE)(vk)) & 3) << 1))
  126. #define KEY_TOGGLE_BIT(vk) (1 << (((((BYTE)(vk)) & 3) << 1) + 1))
  127. #define TestKeyDownBit(pb, vk) (KEY_BYTE(pb,vk) & KEY_DOWN_BIT(vk))
  128. #define SetKeyDownBit(pb, vk) (KEY_BYTE(pb,vk) |= KEY_DOWN_BIT(vk))
  129. #define ClearKeyDownBit(pb, vk) (KEY_BYTE(pb,vk) &= ~KEY_DOWN_BIT(vk))
  130. #define TestKeyToggleBit(pb, vk) (KEY_BYTE(pb,vk) & KEY_TOGGLE_BIT(vk))
  131. #define SetKeyToggleBit(pb, vk) (KEY_BYTE(pb,vk) |= KEY_TOGGLE_BIT(vk))
  132. #define ClearKeyToggleBit(pb, vk) (KEY_BYTE(pb,vk) &= ~KEY_TOGGLE_BIT(vk))
  133. #define ToggleKeyToggleBit(pb, vk) (KEY_BYTE(pb,vk) ^= KEY_TOGGLE_BIT(vk))
  134. WORD GetModifierBits(
  135. PMODIFIERS pModifiers,
  136. LPBYTE afKeyState)
  137. {
  138. PVK_TO_BIT pVkToBit = pModifiers->pVkToBit;
  139. WORD wModBits = 0;
  140. while (pVkToBit->Vk) {
  141. if (TestKeyDownBit(afKeyState, pVkToBit->Vk)) {
  142. wModBits |= pVkToBit->ModBits;
  143. }
  144. pVkToBit++;
  145. }
  146. return wModBits;
  147. }
  148. /***************************************************************************\
  149. * MapScancode
  150. *
  151. * Converts a scancode (and it's prefix, if any) to a different scancode
  152. * and prefix.
  153. *
  154. * Parameters:
  155. * pbScanCode = address of Scancode byte, the scancode may be changed
  156. * pbPrefix = address of Prefix byte, The prefix may be changed
  157. *
  158. * Return value:
  159. * TRUE - mapping was found, scancode was altered.
  160. * FALSE - no mapping fouind, scancode was not altered.
  161. *
  162. * Note on scancode map table format:
  163. * A table entry DWORD of 0xE0450075 means scancode 0x45, prefix 0xE0
  164. * gets mapped to scancode 0x75, no prefix
  165. *
  166. * History:
  167. * 96-04-18 IanJa Created.
  168. \***************************************************************************/
  169. BOOL
  170. MapScancode(
  171. PSCANCODEMAP gpScancodeMap,
  172. PBYTE pbScanCode,
  173. PBYTE pbPrefix
  174. )
  175. {
  176. DWORD *pdw;
  177. WORD wT = MAKEWORD(*pbScanCode, *pbPrefix);
  178. ASSERT(gpScancodeMap != NULL);
  179. for (pdw = &(gpScancodeMap->dwMap[0]); *pdw; pdw++) {
  180. if (HIWORD(*pdw) == wT) {
  181. wT = LOWORD(*pdw);
  182. *pbScanCode = LOBYTE(wT);
  183. *pbPrefix = HIBYTE(wT);
  184. return TRUE;
  185. }
  186. }
  187. return FALSE;
  188. }
  189. /*
  190. * Given modifier bits, return the modification number.
  191. */
  192. WORD GetModificationNumber(
  193. PMODIFIERS pModifiers,
  194. WORD wModBits)
  195. {
  196. if (wModBits > pModifiers->wMaxModBits) {
  197. return SHFT_INVALID;
  198. }
  199. return pModifiers->ModNumber[wModBits];
  200. }
  201. /***************************************************************************\
  202. * UpdatePhysKeyState
  203. *
  204. * A helper routine for KeyboardApcProcedure.
  205. * Based on a VK and a make/break flag, this function will update the physical
  206. * keystate table.
  207. *
  208. * History:
  209. * 10-13-91 IanJa Created.
  210. \***************************************************************************/
  211. void UpdatePhysKeyState(
  212. BYTE Vk,
  213. BOOL fBreak,
  214. LPBYTE gafPhysKeyState )
  215. {
  216. if (fBreak) {
  217. ClearKeyDownBit(gafPhysKeyState, Vk);
  218. } else {
  219. /*
  220. * This is a key make. If the key was not already down, update the
  221. * physical toggle bit.
  222. */
  223. if (!TestKeyDownBit(gafPhysKeyState, Vk)) {
  224. if (TestKeyToggleBit(gafPhysKeyState, Vk)) {
  225. ClearKeyToggleBit(gafPhysKeyState, Vk);
  226. } else {
  227. SetKeyToggleBit(gafPhysKeyState, Vk);
  228. }
  229. }
  230. /*
  231. * This is a make, so turn on the physical key down bit.
  232. */
  233. SetKeyDownBit(gafPhysKeyState, Vk);
  234. }
  235. }
  236. /*****************************************************************************\
  237. * VKFromVSC
  238. *
  239. * This function is called from KeyEvent() after each call to VSCFromSC. The
  240. * keyboard input data passed in is translated to a virtual key code.
  241. * This translation is dependent upon the currently depressed modifier keys.
  242. *
  243. * For instance, scan codes representing the number pad keys may be
  244. * translated into VK_NUMPAD codes or cursor movement codes depending
  245. * upon the state of NumLock and the modifier keys.
  246. *
  247. * History:
  248. *
  249. \*****************************************************************************/
  250. BYTE WD_VKFromVSC(
  251. PKBDTABLES pKbdTbl,
  252. PKE pke,
  253. BYTE bPrefix,
  254. LPBYTE gafPhysKeyState,
  255. BOOLEAN KeyboardType101 )
  256. {
  257. USHORT usVKey = 0xFF;
  258. PVSC_VK pVscVk = NULL;
  259. static BOOL fVkPause;
  260. PULONG *gapulCvt_VK;
  261. // DBG_UNREFERENCED_PARAMETER(afKeyState);
  262. if (pke->bScanCode == 0xFF) {
  263. /*
  264. * Kbd overrun (kbd hardware and/or keyboard driver) : Beep!
  265. * (some DELL keyboards send 0xFF if keys are hit hard enough,
  266. * presumably due to keybounce)
  267. */
  268. // xxxMessageBeep(0);
  269. return 0;
  270. }
  271. pke->bScanCode &= 0x7F;
  272. // if (gptiForeground == NULL) {
  273. // RIPMSG0(RIP_VERBOSE, "VKFromVSC: NULL gptiForeground\n");
  274. // pKbdTbl = gpKbdTbl;
  275. // } else {
  276. // if (gptiForeground->spklActive) {
  277. // pKbdTbl = gptiForeground->spklActive->spkf->pKbdTbl;
  278. // } else {
  279. // RIPMSG0(RIP_VERBOSE, "VKFromVSC: NULL spklActive\n");
  280. // pKbdTbl = gpKbdTbl;
  281. // }
  282. // }
  283. if (bPrefix == 0) {
  284. if (pke->bScanCode < pKbdTbl->bMaxVSCtoVK) {
  285. /*
  286. * direct index into non-prefix table
  287. */
  288. usVKey = pKbdTbl->pusVSCtoVK[pke->bScanCode];
  289. if (usVKey == 0) {
  290. return 0xFF;
  291. }
  292. } else {
  293. /*
  294. * unexpected scancode
  295. */
  296. // RIPMSG2(RIP_VERBOSE, "unrecognized scancode 0x%x, prefix %x",
  297. // pke->bScanCode, bPrefix);
  298. return 0xFF;
  299. }
  300. } else {
  301. /*
  302. * Scan the E0 or E1 prefix table for a match
  303. */
  304. if (bPrefix == 0xE0) {
  305. /*
  306. * Ignore the SHIFT keystrokes generated by the hardware
  307. */
  308. if ((pke->bScanCode == SCANCODE_LSHIFT) ||
  309. (pke->bScanCode == SCANCODE_RSHIFT)) {
  310. return 0;
  311. }
  312. pVscVk = pKbdTbl->pVSCtoVK_E0;
  313. } else if (bPrefix == 0xE1) {
  314. pVscVk = pKbdTbl->pVSCtoVK_E1;
  315. }
  316. while (pVscVk != NULL && pVscVk->Vk) {
  317. if (pVscVk->Vsc == pke->bScanCode) {
  318. usVKey = pVscVk->Vk;
  319. break;
  320. }
  321. pVscVk++;
  322. }
  323. }
  324. /*
  325. * Scancode set 1 returns PAUSE button as E1 1D 45 (E1 Ctrl NumLock)
  326. * so convert E1 Ctrl to VK_PAUSE, and remember to discard the NumLock
  327. */
  328. if (fVkPause) {
  329. /*
  330. * This is the "45" part of the Pause scancode sequence.
  331. * Discard this key event: it is a false NumLock
  332. */
  333. fVkPause = FALSE;
  334. return 0;
  335. }
  336. if (usVKey == VK_PAUSE) {
  337. /*
  338. * This is the "E1 1D" part of the Pause scancode sequence.
  339. * Alter the scancode to the value Windows expects for Pause,
  340. * and remember to discard the "45" scancode that will follow
  341. */
  342. pke->bScanCode = 0x45;
  343. fVkPause = TRUE;
  344. }
  345. /*
  346. * Convert to a different VK if some modifier keys are depressed.
  347. */
  348. if (usVKey & KBDMULTIVK) {
  349. WORD nMod;
  350. PULONG pul;
  351. nMod = GetModificationNumber(
  352. (MODIFIERS *)&Modifiers_VK,
  353. GetModifierBits((MODIFIERS *)&Modifiers_VK,
  354. gafPhysKeyState));
  355. /*
  356. * Scan gapulCvt_VK[nMod] for matching VK.
  357. */
  358. if ( KeyboardType101 )
  359. gapulCvt_VK = (PULONG *)gapulCvt_VK_101;
  360. else
  361. gapulCvt_VK = (PULONG *)gapulCvt_VK_84;
  362. if ((nMod != SHFT_INVALID) && ((pul = gapulCvt_VK[nMod]) != NULL)) {
  363. while (*pul != 0) {
  364. if (LOBYTE(*pul) == LOBYTE(usVKey)) {
  365. pke->usFlaggedVk = (USHORT)HIWORD(*pul);
  366. return (BYTE)pke->usFlaggedVk;
  367. }
  368. pul++;
  369. }
  370. }
  371. }
  372. pke->usFlaggedVk = usVKey;
  373. return (BYTE)usVKey;
  374. }
  375. /***************************************************************************\
  376. * KeyboardHotKeyProcedure
  377. *
  378. * return TRUE if the hotkey is detected, false otherwise
  379. *
  380. * HotkeyVk (input)
  381. * - hotkey to look for
  382. * HotkeyModifiers (input)
  383. * - hotkey to look for
  384. * pkei (input)
  385. * - scan code
  386. * gpScancodeMap (input)
  387. * - scan code map from WIN32K
  388. * pKbdTbl (input)
  389. * - keyboard layout from WIN32K
  390. * KeyboardType101 (input)
  391. * - keyboard type from WIN32K
  392. * gafPhysKeyState (input/output)
  393. * - key states
  394. *
  395. \***************************************************************************/
  396. BOOLEAN KeyboardHotKeyProcedure(
  397. BYTE HotkeyVk,
  398. USHORT HotkeyModifiers,
  399. PKEYBOARD_INPUT_DATA pkei,
  400. PVOID gpScancodeMap,
  401. PVOID pKbdTbl,
  402. BOOLEAN KeyboardType101,
  403. PVOID gafPhysKeyState )
  404. {
  405. BYTE Vk;
  406. BYTE bPrefix;
  407. KE ke;
  408. WORD ModBits;
  409. if ( !pKbdTbl || !gafPhysKeyState ) {
  410. return FALSE;
  411. }
  412. if (pkei->Flags & KEY_E0) {
  413. bPrefix = 0xE0;
  414. } else if (pkei->Flags & KEY_E1) {
  415. bPrefix = 0xE1;
  416. } else {
  417. bPrefix = 0;
  418. }
  419. ke.bScanCode = (BYTE)(pkei->MakeCode & 0x7F);
  420. if (gpScancodeMap) {
  421. MapScancode(gpScancodeMap, &ke.bScanCode, &bPrefix);
  422. }
  423. Vk = WD_VKFromVSC(pKbdTbl, &ke, bPrefix, gafPhysKeyState, KeyboardType101);
  424. if ((Vk == 0) || (Vk == VK__none_)) {
  425. return FALSE;
  426. }
  427. if (pkei->Flags & KEY_BREAK) {
  428. ke.usFlaggedVk |= KBDBREAK;
  429. }
  430. // Vk = (BYTE)ke.usFlaggedVk;
  431. UpdatePhysKeyState(Vk, ke.usFlaggedVk & KBDBREAK, gafPhysKeyState);
  432. /*
  433. * Convert Left/Right Ctrl/Shift/Alt key to "unhanded" key.
  434. * ie: if VK_LCONTROL or VK_RCONTROL, convert to VK_CONTROL etc.
  435. */
  436. if ((Vk >= VK_LSHIFT) && (Vk <= VK_RMENU)) {
  437. Vk = (BYTE)((Vk - VK_LSHIFT) / 2 + VK_SHIFT);
  438. UpdatePhysKeyState(Vk, ke.usFlaggedVk & KBDBREAK, gafPhysKeyState);
  439. }
  440. /*
  441. * Now check if the shadow hotkey has been hit
  442. */
  443. if ( Vk == HotkeyVk && !(ke.usFlaggedVk & KBDBREAK) ) {
  444. ModBits = GetModifierBits( (MODIFIERS *)&Modifiers_VK, gafPhysKeyState );
  445. if ( ModBits == HotkeyModifiers )
  446. return( TRUE );
  447. }
  448. return( FALSE );
  449. }
  450. /*******************************************************************************
  451. *
  452. * KeyboardSetKeyState
  453. *
  454. * Initialize keyboard state
  455. *
  456. * ENTRY:
  457. * pgafPhysKeyState (input/output)
  458. * - buffer to allocate or clear
  459. *
  460. *
  461. * EXIT:
  462. * STATUS_SUCCESS - no error
  463. *
  464. ******************************************************************************/
  465. #define CVKKEYSTATE 256
  466. #define CBKEYSTATE (CVKKEYSTATE >> 2)
  467. NTSTATUS
  468. KeyboardSetKeyState( PTSHARE_WD pWd, PVOID *pgafPhysKeyState )
  469. {
  470. NTSTATUS Status = STATUS_SUCCESS;
  471. if ( *pgafPhysKeyState == NULL ) {
  472. *pgafPhysKeyState = COM_Malloc(CBKEYSTATE);
  473. if ( *pgafPhysKeyState == NULL )
  474. return STATUS_NO_MEMORY;
  475. }
  476. RtlZeroMemory( *pgafPhysKeyState, CBKEYSTATE );
  477. return Status;
  478. }
  479. /*******************************************************************************
  480. *
  481. * KeyboardFixupLayout
  482. *
  483. * Fixup the pointers inside the keyboard layout
  484. *
  485. * ENTRY:
  486. * pLayout (input/output)
  487. * - buffer to fixup
  488. * pOriginal (input)
  489. * - pointer to original layout buffer
  490. * Length (input)
  491. * - length of layout buffer
  492. * pKbdTblOriginal (input)
  493. * - pointer to original KbdTbl table
  494. * ppKbdTbl (output)
  495. * - pointer to location to save ptr to new KbdTbl table
  496. *
  497. *
  498. * EXIT:
  499. * STATUS_SUCCESS - no error
  500. *
  501. ******************************************************************************/
  502. #define FIXUP_PTR(p, pBase, pOldBase) ((p) ? (p) = (PVOID) ( (PBYTE)pBase + (ULONG) ( (PBYTE)p - (PBYTE)pOldBase ) ) : 0)
  503. //#define CHECK_PTR( p, Limit) { if ( (PVOID)p > Limit ) { ASSERT(FALSE); return STATUS_BUFFER_TOO_SMALL; } }
  504. #define CHECK_PTR( ptr, Limit) \
  505. { if ( (PBYTE) (ptr) > (PBYTE) (Limit) ) { \
  506. KdPrint(("Bad Ptr, Line %ld: %p > %p \n", __LINE__, ptr, Limit)); \
  507. /* ASSERT(FALSE); */ \
  508. /* return STATUS_BUFFER_TOO_SMALL; */ } }
  509. NTSTATUS
  510. KeyboardFixupLayout( PVOID pKbdLayout, PVOID pOriginal, ULONG Length,
  511. PVOID pKbdTblOrig, PVOID *ppKbdTbl )
  512. {
  513. NTSTATUS Status = STATUS_SUCCESS;
  514. VK_TO_WCHAR_TABLE *pVkToWcharTable;
  515. VSC_LPWSTR *pKeyName;
  516. LPWSTR *lpDeadKey;
  517. PKBDTABLES pKbdTbl;
  518. PVOID pLimit;
  519. if ( Length < sizeof(KBDTABLES) ) {
  520. Status = STATUS_BUFFER_TOO_SMALL;
  521. goto error;
  522. }
  523. pLimit = (PBYTE)pKbdLayout + Length;
  524. pKbdTbl = pKbdTblOrig;
  525. FIXUP_PTR(pKbdTbl, pKbdLayout, pOriginal);
  526. FIXUP_PTR(pKbdTbl->pCharModifiers, pKbdLayout, pOriginal);
  527. CHECK_PTR(pKbdTbl->pCharModifiers, pLimit);
  528. FIXUP_PTR(pKbdTbl->pCharModifiers->pVkToBit, pKbdLayout, pOriginal);
  529. CHECK_PTR(pKbdTbl->pCharModifiers->pVkToBit, pLimit);
  530. if (FIXUP_PTR(pKbdTbl->pVkToWcharTable, pKbdLayout, pOriginal)) {
  531. CHECK_PTR(pKbdTbl->pVkToWcharTable, pLimit);
  532. for (pVkToWcharTable = pKbdTbl->pVkToWcharTable;
  533. pVkToWcharTable->pVkToWchars != NULL; pVkToWcharTable++) {
  534. FIXUP_PTR(pVkToWcharTable->pVkToWchars, pKbdLayout, pOriginal);
  535. CHECK_PTR(pVkToWcharTable->pVkToWchars, pLimit);
  536. }
  537. }
  538. FIXUP_PTR(pKbdTbl->pDeadKey, pKbdLayout, pOriginal);
  539. CHECK_PTR(pKbdTbl->pDeadKey, pLimit);
  540. if (FIXUP_PTR(pKbdTbl->pKeyNames, pKbdLayout, pOriginal)) {
  541. CHECK_PTR(pKbdTbl->pKeyNames, pLimit);
  542. for (pKeyName = pKbdTbl->pKeyNames; pKeyName->vsc != 0; pKeyName++) {
  543. FIXUP_PTR(pKeyName->pwsz, pKbdLayout, pOriginal);
  544. CHECK_PTR(pKeyName->pwsz, pLimit);
  545. }
  546. }
  547. if (FIXUP_PTR(pKbdTbl->pKeyNamesExt, pKbdLayout, pOriginal)) {
  548. CHECK_PTR(pKbdTbl->pKeyNamesExt, pLimit);
  549. for (pKeyName = pKbdTbl->pKeyNamesExt; pKeyName->vsc != 0; pKeyName++) {
  550. FIXUP_PTR(pKeyName->pwsz, pKbdLayout, pOriginal);
  551. CHECK_PTR(pKeyName->pwsz, pLimit);
  552. }
  553. }
  554. if (FIXUP_PTR(pKbdTbl->pKeyNamesDead, pKbdLayout, pOriginal)) {
  555. CHECK_PTR(pKbdTbl->pKeyNamesDead, pLimit);
  556. for (lpDeadKey = pKbdTbl->pKeyNamesDead; *lpDeadKey != NULL;
  557. lpDeadKey++) {
  558. FIXUP_PTR(*lpDeadKey, pKbdLayout, pOriginal);
  559. CHECK_PTR(*lpDeadKey, pLimit);
  560. }
  561. }
  562. FIXUP_PTR(pKbdTbl->pusVSCtoVK, pKbdLayout, pOriginal);
  563. CHECK_PTR(pKbdTbl->pusVSCtoVK, pLimit);
  564. FIXUP_PTR(pKbdTbl->pVSCtoVK_E0, pKbdLayout, pOriginal);
  565. CHECK_PTR(pKbdTbl->pVSCtoVK_E0, pLimit);
  566. FIXUP_PTR(pKbdTbl->pVSCtoVK_E1, pKbdLayout, pOriginal);
  567. CHECK_PTR(pKbdTbl->pVSCtoVK_E1, pLimit);
  568. *ppKbdTbl = pKbdTbl;
  569. error:
  570. return( Status );
  571. }
  572. #ifdef __cplusplus
  573. }
  574. #endif /* __cplusplus */