Source code of Windows XP (NT5)
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.

1169 lines
23 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. spkbd.c
  5. Abstract:
  6. Text setup keyboard support routines.
  7. Author:
  8. Ted Miller (tedm) 30-July-1993
  9. Revision History:
  10. --*/
  11. #include "spprecmp.h"
  12. #pragma hdrstop
  13. #include <kbd.h>
  14. #include <ntddkbd.h>
  15. PKBDTABLES KeyboardTable;
  16. HANDLE hKeyboard;
  17. BOOLEAN KeyboardInitialized = FALSE;
  18. BOOLEAN KbdLayoutInitialized = FALSE;
  19. USHORT CurrentLEDs;
  20. //
  21. // Globals for async I/O calls
  22. //
  23. KEYBOARD_INDICATOR_PARAMETERS asyncKbdParams;
  24. IO_STATUS_BLOCK asyncIoStatusBlock;
  25. #define MAX_KEYBOARD_ITEMS 10
  26. VOID
  27. spkbdApcProcedure(
  28. IN PVOID ApcContext,
  29. IN PIO_STATUS_BLOCK IoStatusBlock,
  30. IN ULONG Reserved
  31. );
  32. VOID
  33. spkbdSetLEDs(
  34. VOID
  35. );
  36. VOID
  37. SpkbdInitialize(
  38. VOID
  39. );
  40. VOID
  41. SpkbdTerminate(
  42. VOID
  43. );
  44. VOID
  45. SpkbdLoadLayoutDll(
  46. IN PVOID SifHandle,
  47. IN PWSTR Directory
  48. );
  49. ULONG
  50. SpkbdGetKeypress(
  51. VOID
  52. );
  53. BOOLEAN
  54. SpkbdIsKeyWaiting(
  55. VOID
  56. );
  57. VOID
  58. SpkbdDrain(
  59. VOID
  60. );
  61. //
  62. // Buffer for one character.
  63. //
  64. volatile ULONG KbdNextChar;
  65. //
  66. // The following are used in async calls to NtReadFile and so
  67. // cannot be on the stack.
  68. //
  69. IO_STATUS_BLOCK IoStatusKeyboard;
  70. KEYBOARD_INPUT_DATA KeyboardInputData[MAX_KEYBOARD_ITEMS];
  71. LARGE_INTEGER DontCareLargeInteger;
  72. //
  73. // Current state of shift, control, alt keys.
  74. //
  75. USHORT ModifierBits = 0;
  76. #define START_KEYBOARD_READ() \
  77. \
  78. ZwReadFile( \
  79. hKeyboard, \
  80. NULL, \
  81. spkbdApcProcedure, \
  82. NULL, \
  83. &IoStatusKeyboard, \
  84. KeyboardInputData, \
  85. sizeof(KeyboardInputData), \
  86. &DontCareLargeInteger, \
  87. NULL \
  88. )
  89. VOID
  90. SpInputInitialize(
  91. VOID
  92. )
  93. /*++
  94. Routine Description:
  95. Initialize all input support. This includes
  96. - opening the serial port and checking for a terminal.
  97. - opening the keyboard device.
  98. Arguments:
  99. None.
  100. Return Value:
  101. None. Does not return if not successful.
  102. --*/
  103. {
  104. SpkbdInitialize();
  105. SpTermInitialize();
  106. }
  107. VOID
  108. SpInputTerminate(
  109. VOID
  110. )
  111. /*++
  112. Routine Description:
  113. Terminate all input support. This includes
  114. - closing the serial port.
  115. - closing the keyboard device.
  116. Arguments:
  117. None.
  118. Return Value:
  119. None.
  120. --*/
  121. {
  122. SpkbdTerminate();
  123. SpTermTerminate();
  124. }
  125. VOID
  126. SpInputLoadLayoutDll(
  127. IN PVOID SifHandle,
  128. IN PWSTR Directory
  129. )
  130. {
  131. SpkbdLoadLayoutDll(SifHandle, Directory);
  132. }
  133. ULONG
  134. SpInputGetKeypress(
  135. VOID
  136. )
  137. /*++
  138. Routine Description:
  139. Wait for a keypress and return it to the caller.
  140. The return value will be an ASCII value (ie, not a scan code).
  141. Arguments:
  142. None.
  143. Return Value:
  144. ASCII value.
  145. --*/
  146. {
  147. ULONG Tmp;
  148. //
  149. // If we are in upgrade graphics mode then
  150. // switch to textmode
  151. //
  152. SpvidSwitchToTextmode();
  153. while (TRUE) {
  154. if (SpTermIsKeyWaiting()) {
  155. Tmp = SpTermGetKeypress();
  156. if (Tmp != 0) {
  157. return Tmp;
  158. }
  159. }
  160. if (SpkbdIsKeyWaiting()) {
  161. return SpkbdGetKeypress();
  162. }
  163. }
  164. }
  165. BOOLEAN
  166. SpInputIsKeyWaiting(
  167. VOID
  168. )
  169. /*++
  170. Routine Description:
  171. Tell the caller if a keypress is waiting to be fetched by
  172. a call to SpInputGetKeypress().
  173. Arguments:
  174. None.
  175. Return Value:
  176. TRUE is key waiting; FALSE otherwise.
  177. --*/
  178. {
  179. return (SpTermIsKeyWaiting() || SpkbdIsKeyWaiting());
  180. }
  181. VOID
  182. SpInputDrain(
  183. VOID
  184. )
  185. {
  186. SpTermDrain();
  187. SpkbdDrain();
  188. }
  189. //
  190. //
  191. // Below here are all the functions for keyboard operations...
  192. //
  193. //
  194. VOID
  195. SpkbdInitialize(
  196. VOID
  197. )
  198. /*++
  199. Routine Description:
  200. Initialize keyboard support. This includes
  201. - opening the keyboard device.
  202. Arguments:
  203. None.
  204. Return Value:
  205. None. Does not return if not successful.
  206. --*/
  207. {
  208. NTSTATUS Status;
  209. OBJECT_ATTRIBUTES Attributes;
  210. IO_STATUS_BLOCK IoStatusBlock;
  211. UNICODE_STRING UnicodeString;
  212. ASSERT(!KeyboardInitialized);
  213. if(KeyboardInitialized) {
  214. return;
  215. }
  216. //
  217. // Open the keyboard.
  218. //
  219. RtlInitUnicodeString(&UnicodeString,DD_KEYBOARD_DEVICE_NAME_U L"0");
  220. InitializeObjectAttributes(
  221. &Attributes,
  222. &UnicodeString,
  223. OBJ_CASE_INSENSITIVE,
  224. NULL,
  225. NULL
  226. );
  227. Status = ZwCreateFile(
  228. &hKeyboard,
  229. GENERIC_READ | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  230. &Attributes,
  231. &IoStatusBlock,
  232. NULL, // allocation size
  233. FILE_ATTRIBUTE_NORMAL,
  234. 0, // no sharing
  235. FILE_OPEN,
  236. 0,
  237. NULL, // no EAs
  238. 0
  239. );
  240. if(!NT_SUCCESS(Status)) {
  241. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: NtOpenFile of " DD_KEYBOARD_DEVICE_NAME "0 returns %lx\n",Status));
  242. SpFatalKbdError(SP_SCRN_KBD_OPEN_FAILED);
  243. }
  244. //
  245. // Initialize LEDs.
  246. //
  247. //
  248. // No NEC98 has NumLock and NumLock LED.
  249. // Num keys must be act as Numlock alternated keys.
  250. //
  251. CurrentLEDs = (!IsNEC_98 ? 0 : KEYBOARD_NUM_LOCK_ON);
  252. spkbdSetLEDs();
  253. KeyboardInitialized = TRUE;
  254. //
  255. // Do not initialize keyboard input yet because we don't have a layout.
  256. //
  257. }
  258. VOID
  259. SpkbdTerminate(
  260. VOID
  261. )
  262. /*++
  263. Routine Description:
  264. Terminate keyboard support. This includes
  265. - closing the keyboard device.
  266. Arguments:
  267. None.
  268. Return Value:
  269. None.
  270. --*/
  271. {
  272. NTSTATUS Status;
  273. ASSERT(KeyboardInitialized);
  274. if(KeyboardInitialized) {
  275. Status = ZwClose(hKeyboard);
  276. if(!NT_SUCCESS(Status)) {
  277. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to close " DD_KEYBOARD_DEVICE_NAME "0 (status = %lx)\n",Status));
  278. }
  279. KeyboardInitialized = FALSE;
  280. }
  281. }
  282. VOID
  283. SpkbdLoadLayoutDll(
  284. IN PVOID SifHandle,
  285. IN PWSTR Directory
  286. )
  287. {
  288. PWSTR p,LayoutDll;
  289. NTSTATUS Status;
  290. //
  291. // Determine layout name.
  292. //
  293. if(p = SpGetSectionKeyIndex(SifHandle,SIF_NLS,SIF_DEFAULTLAYOUT,1)) {
  294. LayoutDll = p;
  295. } else {
  296. p = SpGetSectionKeyIndex(SifHandle,SIF_NLS,SIF_DEFAULTLAYOUT,0);
  297. if(!p) {
  298. SpFatalSifError(SifHandle,SIF_NLS,SIF_DEFAULTLAYOUT,0,0);
  299. }
  300. LayoutDll = SpGetSectionKeyIndex(SifHandle,SIF_KEYBOARDLAYOUTFILES,p,0);
  301. if(!LayoutDll) {
  302. SpFatalSifError(SifHandle,SIF_KEYBOARDLAYOUTFILES,p,0,0);
  303. }
  304. }
  305. SpDisplayStatusText(SP_STAT_LOADING_KBD_LAYOUT,DEFAULT_STATUS_ATTRIBUTE,LayoutDll);
  306. //
  307. // Bugcheck if we can't load the layout dll, because we won't be able
  308. // to put up a screen and ask the user to hit f3, etc.
  309. //
  310. Status = SpLoadKbdLayoutDll(Directory,LayoutDll,&KeyboardTable);
  311. if(!NT_SUCCESS(Status)) {
  312. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to load layout dll %ws (%lx)\n",LayoutDll,Status));
  313. SpFatalKbdError(SP_SCRN_KBD_LAYOUT_FAILED, LayoutDll);
  314. }
  315. //
  316. // Erase status text line.
  317. //
  318. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,0);
  319. //
  320. // Now that we've loaded the layout, we can start accepting keyboard input.
  321. //
  322. START_KEYBOARD_READ();
  323. KbdLayoutInitialized = TRUE;
  324. }
  325. ULONG
  326. SpkbdGetKeypress(
  327. VOID
  328. )
  329. /*++
  330. Routine Description:
  331. Wait for a keypress and return it to the caller.
  332. The return value will be an ASCII value (ie, not a scan code).
  333. Arguments:
  334. None.
  335. Return Value:
  336. ASCII value.
  337. --*/
  338. {
  339. ULONG k;
  340. //
  341. // Shouldn't be calling this until we have loaded a keyboard layout.
  342. //
  343. ASSERT(KeyboardTable);
  344. //
  345. // Wait for the user to press a key.
  346. //
  347. while(!KbdNextChar) {
  348. ;
  349. }
  350. k = KbdNextChar;
  351. KbdNextChar = 0;
  352. return(k);
  353. }
  354. BOOLEAN
  355. SpkbdIsKeyWaiting(
  356. VOID
  357. )
  358. /*++
  359. Routine Description:
  360. Tell the caller if a keypress is waiting to be fetched by
  361. a call to SpkbdGetKeypress().
  362. Arguments:
  363. None.
  364. Return Value:
  365. TRUE is key waiting; FALSE otherwise.
  366. --*/
  367. {
  368. //
  369. // Shouldn't be calling this until we have loaded a keyboard layout.
  370. //
  371. ASSERT(KeyboardTable);
  372. return((BOOLEAN)(KbdNextChar != 0));
  373. }
  374. VOID
  375. SpkbdDrain(
  376. VOID
  377. )
  378. /*++
  379. Routine Description:
  380. Drain the keyboard buffer, throwing away any keystrokes
  381. in the buffer waiting to be fetched.
  382. Arguments:
  383. None.
  384. Return Value:
  385. TRUE is key waiting; FALSE otherwise.
  386. --*/
  387. {
  388. ASSERT(KeyboardTable);
  389. KbdNextChar = 0;
  390. }
  391. ULONG
  392. spkbdScanCodeToChar(
  393. IN UCHAR Prefix,
  394. IN USHORT ScanCode,
  395. IN BOOLEAN Break
  396. );
  397. VOID
  398. spkbdApcProcedure(
  399. IN PVOID ApcContext,
  400. IN PIO_STATUS_BLOCK IoStatusBlock,
  401. IN ULONG Reserved
  402. )
  403. /*++
  404. Routine Description:
  405. Async Procedure Call routine for keyboard reads. The I/O
  406. system will call this routine when the keyboard class driver
  407. wants to return some data to us.
  408. Arguments:
  409. Return Value:
  410. None.
  411. --*/
  412. {
  413. UCHAR bPrefix;
  414. PKEYBOARD_INPUT_DATA pkei;
  415. ULONG k;
  416. UNREFERENCED_PARAMETER(ApcContext);
  417. UNREFERENCED_PARAMETER(Reserved);
  418. for(pkei = KeyboardInputData;
  419. (PUCHAR)pkei < (PUCHAR)KeyboardInputData + IoStatusBlock->Information;
  420. pkei++)
  421. {
  422. if(pkei->Flags & KEY_E0) {
  423. bPrefix = 0xE0;
  424. } else if (pkei->Flags & KEY_E1) {
  425. bPrefix = 0xE1;
  426. } else {
  427. bPrefix = 0;
  428. }
  429. k = spkbdScanCodeToChar(
  430. bPrefix,
  431. pkei->MakeCode,
  432. (BOOLEAN)((pkei->Flags & KEY_BREAK) != 0)
  433. );
  434. if(k) {
  435. KbdNextChar = k;
  436. }
  437. }
  438. //
  439. // Keyboard might have been terminated.
  440. //
  441. if(KeyboardInitialized) {
  442. START_KEYBOARD_READ();
  443. }
  444. }
  445. WCHAR SavedDeadChar = 0;
  446. UCHAR AltNumpadAccum = 0;
  447. struct {
  448. BYTE CursorKey;
  449. BYTE NumberKey;
  450. BYTE Value;
  451. } NumpadCursorToNumber[] = { { VK_INSERT, VK_NUMPAD0, 0 },
  452. { VK_END , VK_NUMPAD1, 1 },
  453. { VK_DOWN , VK_NUMPAD2, 2 },
  454. { VK_NEXT , VK_NUMPAD3, 3 },
  455. { VK_LEFT , VK_NUMPAD4, 4 },
  456. { VK_CLEAR , VK_NUMPAD5, 5 },
  457. { VK_RIGHT , VK_NUMPAD6, 6 },
  458. { VK_HOME , VK_NUMPAD7, 7 },
  459. { VK_UP , VK_NUMPAD8, 8 },
  460. { VK_PRIOR , VK_NUMPAD9, 9 },
  461. { VK_DELETE, VK_DECIMAL, 10 }, // no value.
  462. { 0 , 0 , 0 }
  463. };
  464. ULONG
  465. spkbdScanCodeToChar(
  466. IN UCHAR Prefix,
  467. IN USHORT ScanCode,
  468. IN BOOLEAN Break
  469. )
  470. {
  471. USHORT VKey = 0;
  472. PVSC_VK VscVk;
  473. PVK_TO_WCHAR_TABLE pVKT;
  474. PVK_TO_WCHARS1 pVK;
  475. USHORT Modifier;
  476. USHORT ModBits,ModNum;
  477. WCHAR deadChar;
  478. ScanCode &= 0x7f;
  479. if(Prefix == 0) {
  480. if(ScanCode < KeyboardTable->bMaxVSCtoVK) {
  481. //
  482. // Index directly into non-prefix scan code table.
  483. //
  484. VKey = KeyboardTable->pusVSCtoVK[ScanCode];
  485. if(VKey == 0) {
  486. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unknown scan code 0x%x\n",ScanCode));
  487. return (0);
  488. }
  489. } else {
  490. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unknown scan code 0x%x\n",ScanCode));
  491. return(0);
  492. }
  493. } else {
  494. if(Prefix == 0xe0) {
  495. //
  496. // Ignore the SHIFT keystrokes generated by the hardware
  497. //
  498. if((ScanCode == SCANCODE_LSHIFT) || (ScanCode == SCANCODE_RSHIFT)) {
  499. return(0);
  500. }
  501. VscVk = KeyboardTable->pVSCtoVK_E0;
  502. } else if(Prefix == 0xe1) {
  503. VscVk = KeyboardTable->pVSCtoVK_E1;
  504. } else {
  505. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unknown keyboard scan prefix 0x%x\n",Prefix));
  506. return(0);
  507. }
  508. while(VscVk->Vk) {
  509. if(VscVk->Vsc == ScanCode) {
  510. VKey = VscVk->Vk;
  511. break;
  512. }
  513. VscVk++;
  514. }
  515. if(VKey == 0) {
  516. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unknown keyboard scan prefix/code 0x%x/0x%x\n",Prefix,ScanCode));
  517. return(0);
  518. }
  519. }
  520. //
  521. // VirtualKey --> modifier bits. This translation is also
  522. // mapped out in the pCharModifiers field in the keyboard layout
  523. // table but that seems redundant.
  524. //
  525. Modifier = 0;
  526. switch(VKey & 0xff) {
  527. case VK_LSHIFT:
  528. case VK_RSHIFT:
  529. Modifier = KBDSHIFT;
  530. break;
  531. case VK_LCONTROL:
  532. case VK_RCONTROL:
  533. Modifier = KBDCTRL;
  534. break;
  535. case VK_RMENU:
  536. //
  537. // AltGr ==> control+alt modifier.
  538. //
  539. if(KeyboardTable->fLocaleFlags & KLLF_ALTGR) {
  540. Modifier = KBDCTRL;
  541. }
  542. // fall through
  543. case VK_LMENU:
  544. Modifier |= KBDALT;
  545. break;
  546. }
  547. if(Break) {
  548. //
  549. // Key is being released.
  550. // If it's not a modifer, ignore it.
  551. //
  552. if(!Modifier) {
  553. return(0);
  554. }
  555. //
  556. // Key being released is a modifier.
  557. //
  558. ModifierBits &= ~Modifier;
  559. //
  560. // If it's ALT going up and we have a numpad key being entered,
  561. // return it.
  562. //
  563. if((Modifier & KBDALT) && AltNumpadAccum) {
  564. WCHAR UnicodeChar;
  565. RtlOemToUnicodeN(
  566. &UnicodeChar,
  567. sizeof(UnicodeChar),
  568. NULL,
  569. &AltNumpadAccum,
  570. 1
  571. );
  572. AltNumpadAccum = 0;
  573. return(UnicodeChar);
  574. }
  575. return(0);
  576. } else {
  577. if(Modifier) {
  578. //
  579. // Key is being pressed and is a modifier.
  580. //
  581. ModifierBits |= Modifier;
  582. //
  583. // If ALT is going down, reset alt+numpad value.
  584. //
  585. if(Modifier & KBDALT) {
  586. AltNumpadAccum = 0;
  587. }
  588. return(0);
  589. }
  590. }
  591. //
  592. // If we get here, we've got a non-modifier key being made (pressed).
  593. // If the previous key was a dead key, the user gets only
  594. // one try to get a valid second half.
  595. //
  596. deadChar = SavedDeadChar;
  597. SavedDeadChar = 0;
  598. //
  599. // Special processing if the key is a numeric keypad key.
  600. //
  601. if(VKey & KBDNUMPAD) {
  602. int i;
  603. for(i=0; NumpadCursorToNumber[i].CursorKey; i++) {
  604. if(NumpadCursorToNumber[i].CursorKey == (BYTE)VKey) {
  605. //
  606. // Key is a numeric keypad key. If ALT (and only alt) is down,
  607. // then we have an alt+numpad code being entered.
  608. //
  609. if(((ModifierBits & ~KBDALT) == 0) && (NumpadCursorToNumber[i].Value < 10)) {
  610. AltNumpadAccum = (AltNumpadAccum * 10) + NumpadCursorToNumber[i].Value;
  611. }
  612. //
  613. // If numlock is on, translate the key from cursor movement
  614. // to a number key.
  615. //
  616. if(CurrentLEDs & KEYBOARD_NUM_LOCK_ON) {
  617. VKey = NumpadCursorToNumber[i].NumberKey;
  618. }
  619. break;
  620. }
  621. }
  622. }
  623. //
  624. // We need to filter out keystrokes that we know are not part of any
  625. // character set here.
  626. //
  627. if((!deadChar)) {
  628. switch(VKey & 0xff) {
  629. case VK_CAPITAL:
  630. if(CurrentLEDs & KEYBOARD_CAPS_LOCK_ON) {
  631. CurrentLEDs &= ~KEYBOARD_CAPS_LOCK_ON;
  632. } else {
  633. CurrentLEDs |= KEYBOARD_CAPS_LOCK_ON;
  634. }
  635. spkbdSetLEDs();
  636. return(0);
  637. case VK_NUMLOCK:
  638. if(CurrentLEDs & KEYBOARD_NUM_LOCK_ON) {
  639. CurrentLEDs &= ~KEYBOARD_NUM_LOCK_ON;
  640. } else {
  641. CurrentLEDs |= KEYBOARD_NUM_LOCK_ON;
  642. }
  643. spkbdSetLEDs();
  644. return(0);
  645. case VK_PRIOR:
  646. return(KEY_PAGEUP);
  647. case VK_NEXT:
  648. return(KEY_PAGEDOWN);
  649. case VK_UP:
  650. return(KEY_UP);
  651. case VK_DOWN:
  652. return(KEY_DOWN);
  653. case VK_LEFT:
  654. return(KEY_LEFT);
  655. case VK_RIGHT:
  656. return(KEY_RIGHT);
  657. case VK_HOME:
  658. return(KEY_HOME);
  659. case VK_END:
  660. return(KEY_END);
  661. case VK_INSERT:
  662. return(KEY_INSERT);
  663. case VK_DELETE:
  664. return(KEY_DELETE);
  665. case VK_F1:
  666. return(KEY_F1);
  667. case VK_F2:
  668. return(KEY_F2);
  669. case VK_F3:
  670. return(KEY_F3);
  671. case VK_F4:
  672. return(KEY_F4);
  673. case VK_F5:
  674. return(KEY_F5);
  675. case VK_F6:
  676. return(KEY_F6);
  677. case VK_F7:
  678. return(KEY_F7);
  679. case VK_F8:
  680. return(KEY_F8);
  681. case VK_F9:
  682. return(KEY_F9);
  683. case VK_F10:
  684. return(KEY_F10);
  685. case VK_F11:
  686. return(KEY_F11);
  687. case VK_F12:
  688. return(KEY_F12);
  689. }
  690. }
  691. //
  692. // We think the character is probably a 'real' character.
  693. // Scan through all the shift-state tables until a matching Virtual
  694. // Key is found.
  695. //
  696. for(pVKT = KeyboardTable->pVkToWcharTable; pVKT->pVkToWchars; pVKT++) {
  697. pVK = pVKT->pVkToWchars;
  698. while(pVK->VirtualKey) {
  699. if(pVK->VirtualKey == (BYTE)VKey) {
  700. goto VK_Found;
  701. }
  702. pVK = (PVK_TO_WCHARS1)((PBYTE)pVK + pVKT->cbSize);
  703. }
  704. }
  705. //
  706. // Key is not valid with requested modifiers.
  707. //
  708. return(0);
  709. VK_Found:
  710. ModBits = ModifierBits;
  711. //
  712. // If CapsLock affects this key and it is on: toggle SHIFT state
  713. // only if no other state is on.
  714. // (CapsLock doesn't affect SHIFT state if Ctrl or Alt are down).
  715. //
  716. if((pVK->Attributes & CAPLOK) && ((ModBits & ~KBDSHIFT) == 0)
  717. && (CurrentLEDs & KEYBOARD_CAPS_LOCK_ON))
  718. {
  719. ModBits ^= KBDSHIFT;
  720. }
  721. //
  722. // Get the modification number.
  723. //
  724. if(ModBits > KeyboardTable->pCharModifiers->wMaxModBits) {
  725. return(0); // invalid keystroke
  726. }
  727. ModNum = KeyboardTable->pCharModifiers->ModNumber[ModBits];
  728. if(ModNum == SHFT_INVALID) {
  729. return(0); // invalid keystroke
  730. }
  731. if(ModNum >= pVKT->nModifications) {
  732. //
  733. // Key is not valid with current modifiers.
  734. // Could still be a control char that we can convert directly.
  735. //
  736. if((ModBits == KBDCTRL) || (ModBits == (KBDCTRL | KBDSHIFT))) {
  737. if(((UCHAR)VKey >= 'A') && ((UCHAR)VKey <= 'Z')) {
  738. return((ULONG)VKey & 0x1f);
  739. }
  740. }
  741. return(0); // invalid keystroke
  742. }
  743. if(pVK->wch[ModNum] == WCH_NONE) {
  744. return(0);
  745. }
  746. if((pVK->wch[ModNum] == WCH_DEAD)) {
  747. if(!deadChar) {
  748. //
  749. // Remember the current dead character, whose value follows
  750. // the current entry in the modifier mapping table.
  751. //
  752. SavedDeadChar = ((PVK_TO_WCHARS1)((PUCHAR)pVK + pVKT->cbSize))->wch[ModNum];
  753. }
  754. return(0);
  755. }
  756. //
  757. // The keyboard layout table contains some dead key mappings.
  758. // If previous key was a dead key, attempt to compose it with the
  759. // current character by scanning the keyboard layout table for a match.
  760. //
  761. if(deadChar) {
  762. ULONG chr;
  763. PDEADKEY DeadKeyEntry;
  764. chr = MAKELONG(pVK->wch[ModNum],deadChar);
  765. if(DeadKeyEntry = KeyboardTable->pDeadKey) {
  766. while(DeadKeyEntry->dwBoth) {
  767. if(DeadKeyEntry->dwBoth == chr) {
  768. //
  769. // Got a match. Return the composed character.
  770. //
  771. return((ULONG)DeadKeyEntry->wchComposed);
  772. }
  773. DeadKeyEntry++;
  774. }
  775. }
  776. //
  777. // If we get here, then the previous key was a dead char,
  778. // but the current key could not be composed with it.
  779. // So return nothing. Note that the dead key has been forgotten.
  780. //
  781. return(0);
  782. }
  783. return((ULONG)pVK->wch[ModNum]);
  784. }
  785. VOID
  786. spkbdSetLEDs(
  787. VOID
  788. )
  789. {
  790. asyncKbdParams.UnitId = 0;
  791. asyncKbdParams.LedFlags = CurrentLEDs;
  792. ZwDeviceIoControlFile(
  793. hKeyboard,
  794. NULL,
  795. NULL,
  796. NULL,
  797. &asyncIoStatusBlock,
  798. IOCTL_KEYBOARD_SET_INDICATORS,
  799. &asyncKbdParams,
  800. sizeof(asyncKbdParams),
  801. NULL,
  802. 0
  803. );
  804. }
  805. VOID
  806. SpSelectAndLoadLayoutDll(
  807. IN PWSTR Directory,
  808. IN PVOID SifHandle,
  809. IN BOOLEAN ShowStatus
  810. )
  811. /*++
  812. Routine Description:
  813. Allows the user to select a keyboard layout DLL and loads it.
  814. Arguments:
  815. Directory - The setup startup directory
  816. SifHandle - Handle to txtsetup.sif
  817. ShowStatus - Whether status should be displayed or not
  818. Return Value:
  819. None
  820. --*/
  821. {
  822. ULONG SelectedLayout;
  823. ULONG DefLayout = -1;
  824. PWSTR TempPtr = 0;
  825. PWSTR LayoutDll = 0;
  826. NTSTATUS Status;
  827. //
  828. // Get the default layout (index)
  829. //
  830. TempPtr = SpGetSectionKeyIndex(SifHandle, SIF_NLS, SIF_DEFAULTLAYOUT, 0);
  831. if(!TempPtr) {
  832. SpFatalSifError(SifHandle, SIF_NLS, SIF_DEFAULTLAYOUT, 0, 0);
  833. }
  834. DefLayout = SpGetKeyIndex(SifHandle, SIF_KEYBOARDLAYOUTDESC, TempPtr);
  835. if(DefLayout == -1) {
  836. SpFatalSifError(SifHandle, SIF_NLS, SIF_DEFAULTLAYOUT, 0, 0);
  837. }
  838. SelectedLayout = -1;
  839. //
  840. // Let the user select the layout which he wants
  841. //
  842. if (SpSelectSectionItem(SifHandle, SIF_KEYBOARDLAYOUTDESC,
  843. SP_SELECT_KBDLAYOUT, DefLayout, &SelectedLayout)) {
  844. //
  845. // Load the layout if its not already loaded
  846. //
  847. if (DefLayout != SelectedLayout) {
  848. //
  849. // get the key
  850. //
  851. TempPtr = SpGetKeyName(SifHandle, SIF_KEYBOARDLAYOUTDESC, SelectedLayout);
  852. if (TempPtr) {
  853. //
  854. // get the KDB layout dll name
  855. //
  856. LayoutDll = SpGetSectionKeyIndex(SifHandle, SIF_KEYBOARDLAYOUTFILES,
  857. TempPtr, 0);
  858. if (LayoutDll) {
  859. if (ShowStatus) {
  860. SpDisplayStatusText(SP_STAT_LOADING_KBD_LAYOUT,
  861. DEFAULT_STATUS_ATTRIBUTE, LayoutDll);
  862. }
  863. //
  864. // Load the new KDB layout dll
  865. //
  866. Status = SpLoadKbdLayoutDll(Directory, LayoutDll, &KeyboardTable);
  867. }
  868. else
  869. Status = STATUS_INVALID_PARAMETER;
  870. if (!NT_SUCCESS(Status)) {
  871. CLEAR_ENTIRE_SCREEN();
  872. SpFatalKbdError(SP_SCRN_KBD_LAYOUT_FAILED, LayoutDll);
  873. } else {
  874. if (ShowStatus) {
  875. //
  876. // Erase status text line.
  877. //
  878. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE, 0);
  879. }
  880. //
  881. // Now that we've loaded the layout,
  882. // we can start accepting keyboard input.
  883. //
  884. START_KEYBOARD_READ();
  885. KbdLayoutInitialized = TRUE;
  886. }
  887. } else {
  888. CLEAR_ENTIRE_SCREEN();
  889. SpFatalSifError(SifHandle, SIF_KEYBOARDLAYOUTDESC, 0, 0, 0);
  890. }
  891. }
  892. }
  893. }