keyboard.pp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Florian Klaempfl
  4. member of the Free Pascal development team
  5. Keyboard unit for Win32
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit Keyboard;
  13. interface
  14. {$ifdef DEBUG}
  15. uses
  16. windows;
  17. var
  18. last_ir : Input_Record;
  19. {$endif DEBUG}
  20. {$i keybrdh.inc}
  21. implementation
  22. { WARNING: Keyboard-Drivers (i.e. german) will only work under WinNT.
  23. 95 and 98 do not support keyboard-drivers other than us for win32
  24. console-apps. So we always get the keys in us-keyboard layout
  25. from Win9x.
  26. }
  27. uses
  28. {$ifndef DEBUG}
  29. Windows,
  30. {$endif DEBUG}
  31. Dos,
  32. WinEvent;
  33. {$i keyboard.inc}
  34. const MaxQueueSize = 120;
  35. FrenchKeyboard = $040C040C;
  36. var
  37. keyboardeventqueue : array[0..maxqueuesize] of TKeyEventRecord;
  38. nextkeyevent,nextfreekeyevent : longint;
  39. newKeyEvent : THandle; {sinaled if key is available}
  40. lockVar : TCriticalSection; {for queue access}
  41. lastShiftState : byte; {set by handler for PollShiftStateEvent}
  42. altNumActive : boolean; {for alt+0..9}
  43. altNumBuffer : string [3];
  44. { used for keyboard specific stuff }
  45. KeyBoardLayout : HKL;
  46. Inited : Boolean;
  47. HasAltGr : Boolean = false;
  48. procedure incqueueindex(var l : longint);
  49. begin
  50. inc(l);
  51. { wrap around? }
  52. if l>maxqueuesize then
  53. l:=0;
  54. end;
  55. function keyEventsInQueue : boolean;
  56. begin
  57. keyEventsInQueue := (nextkeyevent <> nextfreekeyevent);
  58. end;
  59. function rightistruealt(dw:cardinal):boolean; // inline ?
  60. // used to wrap checks for right alt/altgr.
  61. begin
  62. rightistruealt:=true;
  63. if hasaltgr then
  64. rightistruealt:=(dw and RIGHT_ALT_PRESSED)=0;
  65. end;
  66. { gets or peeks the next key from the queue, does not wait for new keys }
  67. function getKeyEventFromQueue (VAR t : TKeyEventRecord; Peek : boolean) : boolean;
  68. begin
  69. if not Inited then
  70. begin
  71. getKeyEventFromQueue := false;
  72. exit;
  73. end;
  74. EnterCriticalSection (lockVar);
  75. if keyEventsInQueue then
  76. begin
  77. t := keyboardeventqueue[nextkeyevent];
  78. if not peek then incqueueindex (nextkeyevent);
  79. getKeyEventFromQueue := true;
  80. if not keyEventsInQueue then ResetEvent (newKeyEvent);
  81. end else
  82. begin
  83. getKeyEventFromQueue := false;
  84. ResetEvent (newKeyEvent);
  85. end;
  86. LeaveCriticalSection (lockVar);
  87. end;
  88. { gets the next key from the queue, does wait for new keys }
  89. function getKeyEventFromQueueWait (VAR t : TKeyEventRecord) : boolean;
  90. begin
  91. if not Inited then
  92. begin
  93. getKeyEventFromQueueWait := false;
  94. exit;
  95. end;
  96. WaitForSingleObject (newKeyEvent, dword(INFINITE));
  97. getKeyEventFromQueueWait := getKeyEventFromQueue (t, false);
  98. end;
  99. { translate win32 shift-state to keyboard shift state }
  100. function transShiftState (ControlKeyState : dword) : byte;
  101. var b : byte;
  102. begin
  103. b := 0;
  104. if ControlKeyState and SHIFT_PRESSED <> 0 then { win32 makes no difference between left and right shift }
  105. b := b or kbShift;
  106. if (ControlKeyState and LEFT_CTRL_PRESSED <> 0) or
  107. (ControlKeyState and RIGHT_CTRL_PRESSED <> 0) then
  108. b := b or kbCtrl;
  109. if (ControlKeyState and LEFT_ALT_PRESSED <> 0) or
  110. (ControlKeyState and RIGHT_ALT_PRESSED <> 0) then
  111. b := b or kbAlt;
  112. transShiftState := b;
  113. end;
  114. { The event-Handler thread from the unit event will call us if a key-event
  115. is available }
  116. procedure HandleKeyboard(var ir:INPUT_RECORD);
  117. var
  118. i : longint;
  119. c : word;
  120. altc : char;
  121. addThis: boolean;
  122. begin
  123. with ir.Event.KeyEvent do
  124. begin
  125. { key up events are ignored (except alt) }
  126. if bKeyDown then
  127. begin
  128. EnterCriticalSection (lockVar);
  129. for i:=1 to wRepeatCount do
  130. begin
  131. addThis := true;
  132. if (dwControlKeyState and LEFT_ALT_PRESSED <> 0) or
  133. (dwControlKeyState and RIGHT_ALT_PRESSED <> 0) then {alt pressed}
  134. if ((wVirtualKeyCode >= $60) and (wVirtualKeyCode <= $69)) or
  135. ((dwControlKeyState and ENHANCED_KEY = 0) and
  136. (wVirtualKeyCode in [$C{VK_CLEAR generated by keypad 5},
  137. $21 {VK_PRIOR (PgUp) 9},
  138. $22 {VK_NEXT (PgDown) 3},
  139. $23 {VK_END 1},
  140. $24 {VK_HOME 7},
  141. $25 {VK_LEFT 4},
  142. $26 {VK_UP 8},
  143. $27 {VK_RIGHT 6},
  144. $28 {VK_DOWN 2},
  145. $2D {VK_INSERT 0}])) then {0..9 on NumBlock}
  146. begin
  147. if length (altNumBuffer) = 3 then
  148. delete (altNumBuffer,1,1);
  149. case wVirtualKeyCode of
  150. $60..$69 : altc:=char (wVirtualKeyCode-48);
  151. $c : altc:='5';
  152. $21 : altc:='9';
  153. $22 : altc:='3';
  154. $23 : altc:='1';
  155. $24 : altc:='7';
  156. $25 : altc:='4';
  157. $26 : altc:='8';
  158. $27 : altc:='6';
  159. $28 : altc:='2';
  160. $2D : altc:='0';
  161. end;
  162. altNumBuffer := altNumBuffer + altc;
  163. altNumActive := true;
  164. addThis := false;
  165. end else
  166. begin
  167. altNumActive := false;
  168. altNumBuffer := '';
  169. end;
  170. if addThis then
  171. begin
  172. keyboardeventqueue[nextfreekeyevent]:=
  173. ir.Event.KeyEvent;
  174. incqueueindex(nextfreekeyevent);
  175. end;
  176. end;
  177. lastShiftState := transShiftState (dwControlKeyState); {save it for PollShiftStateEvent}
  178. SetEvent (newKeyEvent); {event that a new key is available}
  179. LeaveCriticalSection (lockVar);
  180. end
  181. else
  182. begin
  183. lastShiftState := transShiftState (dwControlKeyState); {save it for PollShiftStateEvent}
  184. {for alt-number we have to look for alt-key release}
  185. if altNumActive then
  186. begin
  187. if (wVirtualKeyCode = $12) then {alt-released}
  188. begin
  189. if altNumBuffer <> '' then {numbers with alt pressed?}
  190. begin
  191. Val (altNumBuffer, c, i);
  192. if (i = 0) and (c <= 255) then {valid number?}
  193. begin {add to queue}
  194. fillchar (ir, sizeof (ir), 0);
  195. bKeyDown := true;
  196. AsciiChar := char (c);
  197. {and add to queue}
  198. EnterCriticalSection (lockVar);
  199. keyboardeventqueue[nextfreekeyevent]:=ir.Event.KeyEvent;
  200. incqueueindex(nextfreekeyevent);
  201. SetEvent (newKeyEvent); {event that a new key is available}
  202. LeaveCriticalSection (lockVar);
  203. end;
  204. end;
  205. altNumActive := false; {clear alt-buffer}
  206. altNumBuffer := '';
  207. end;
  208. end;
  209. end;
  210. end;
  211. end;
  212. procedure CheckAltGr;
  213. var ahkl : HKL;
  214. i : integer;
  215. begin
  216. HasAltGr:=false;
  217. ahkl:=GetKeyboardLayout(0);
  218. i:=$20;
  219. while i<$100 do
  220. begin
  221. // <MSDN>
  222. // For keyboard layouts that use the right-hand ALT key as ashift key
  223. // (for example, the French keyboard layout), the shift state is
  224. // represented by the value 6, because the right-hand ALT key is
  225. // converted internally into CTRL+ALT.
  226. // </MSDN>
  227. if (HIBYTE(VkKeyScanEx(chr(i),ahkl))=6) then
  228. begin
  229. HasAltGr:=true;
  230. break;
  231. end;
  232. inc(i);
  233. end;
  234. end;
  235. procedure SysInitKeyboard;
  236. begin
  237. KeyBoardLayout:=GetKeyboardLayout(0);
  238. lastShiftState := 0;
  239. FlushConsoleInputBuffer(StdInputHandle);
  240. newKeyEvent := CreateEvent (nil, // address of security attributes
  241. true, // flag for manual-reset event
  242. false, // flag for initial state
  243. nil); // address of event-object name
  244. if newKeyEvent = INVALID_HANDLE_VALUE then
  245. begin
  246. // what to do here ????
  247. RunError (217);
  248. end;
  249. InitializeCriticalSection (lockVar);
  250. altNumActive := false;
  251. altNumBuffer := '';
  252. nextkeyevent:=0;
  253. nextfreekeyevent:=0;
  254. checkaltgr;
  255. SetKeyboardEventHandler (@HandleKeyboard);
  256. Inited:=true;
  257. end;
  258. procedure SysDoneKeyboard;
  259. begin
  260. SetKeyboardEventHandler(nil); {hangs???}
  261. DeleteCriticalSection (lockVar);
  262. FlushConsoleInputBuffer(StdInputHandle);
  263. closeHandle (newKeyEvent);
  264. Inited:=false;
  265. end;
  266. {$define USEKEYCODES}
  267. {Translatetable Win32 -> Dos for Special Keys = Function Key, Cursor Keys
  268. and Keys other than numbers on numblock (to make fv happy) }
  269. {combinations under dos: Shift+Ctrl: same as Ctrl
  270. Shift+Alt : same as alt
  271. Ctrl+Alt : nothing (here we get it like alt)}
  272. {$ifdef USEKEYCODES}
  273. { use positive values for ScanCode we want to set
  274. 0 for key where we should leave the scancode
  275. -1 for OEM specifc keys
  276. -2 for unassigned
  277. -3 for Kanji systems ???
  278. }
  279. const
  280. Unassigned = -2;
  281. Kanji = -3;
  282. OEM_specific = -1;
  283. KeyToQwertyScan : array [0..255] of integer =
  284. (
  285. { 00 } 0,
  286. { 01 VK_LBUTTON } 0,
  287. { 02 VK_RBUTTON } 0,
  288. { 03 VK_CANCEL } 0,
  289. { 04 VK_MBUTTON } 0,
  290. { 05 unassigned } -2,
  291. { 06 unassigned } -2,
  292. { 07 unassigned } -2,
  293. { 08 VK_BACK } $E,
  294. { 09 VK_TAB } $F,
  295. { 0A unassigned } -2,
  296. { 0B unassigned } -2,
  297. { 0C VK_CLEAR ?? } 0,
  298. { 0D VK_RETURN } 0,
  299. { 0E unassigned } -2,
  300. { 0F unassigned } -2,
  301. { 10 VK_SHIFT } 0,
  302. { 11 VK_CONTROL } 0,
  303. { 12 VK_MENU (Alt key) } 0,
  304. { 13 VK_PAUSE } 0,
  305. { 14 VK_CAPITAL (Caps Lock) } 0,
  306. { 15 Reserved for Kanji systems} -3,
  307. { 16 Reserved for Kanji systems} -3,
  308. { 17 Reserved for Kanji systems} -3,
  309. { 18 Reserved for Kanji systems} -3,
  310. { 19 Reserved for Kanji systems} -3,
  311. { 1A unassigned } -2,
  312. { 1B VK_ESCAPE } $1,
  313. { 1C Reserved for Kanji systems} -3,
  314. { 1D Reserved for Kanji systems} -3,
  315. { 1E Reserved for Kanji systems} -3,
  316. { 1F Reserved for Kanji systems} -3,
  317. { 20 VK_SPACE} 0,
  318. { 21 VK_PRIOR (PgUp) } 0,
  319. { 22 VK_NEXT (PgDown) } 0,
  320. { 23 VK_END } 0,
  321. { 24 VK_HOME } 0,
  322. { 25 VK_LEFT } 0,
  323. { 26 VK_UP } 0,
  324. { 27 VK_RIGHT } 0,
  325. { 28 VK_DOWN } 0,
  326. { 29 VK_SELECT ??? } 0,
  327. { 2A OEM specific !! } -1,
  328. { 2B VK_EXECUTE } 0,
  329. { 2C VK_SNAPSHOT } 0,
  330. { 2D VK_INSERT } 0,
  331. { 2E VK_DELETE } 0,
  332. { 2F VK_HELP } 0,
  333. { 30 VK_0 '0' } 11,
  334. { 31 VK_1 '1' } 2,
  335. { 32 VK_2 '2' } 3,
  336. { 33 VK_3 '3' } 4,
  337. { 34 VK_4 '4' } 5,
  338. { 35 VK_5 '5' } 6,
  339. { 36 VK_6 '6' } 7,
  340. { 37 VK_7 '7' } 8,
  341. { 38 VK_8 '8' } 9,
  342. { 39 VK_9 '9' } 10,
  343. { 3A unassigned } -2,
  344. { 3B unassigned } -2,
  345. { 3C unassigned } -2,
  346. { 3D unassigned } -2,
  347. { 3E unassigned } -2,
  348. { 3F unassigned } -2,
  349. { 40 unassigned } -2,
  350. { 41 VK_A 'A' } $1E,
  351. { 42 VK_B 'B' } $30,
  352. { 43 VK_C 'C' } $2E,
  353. { 44 VK_D 'D' } $20,
  354. { 45 VK_E 'E' } $12,
  355. { 46 VK_F 'F' } $21,
  356. { 47 VK_G 'G' } $22,
  357. { 48 VK_H 'H' } $23,
  358. { 49 VK_I 'I' } $17,
  359. { 4A VK_J 'J' } $24,
  360. { 4B VK_K 'K' } $25,
  361. { 4C VK_L 'L' } $26,
  362. { 4D VK_M 'M' } $32,
  363. { 4E VK_N 'N' } $31,
  364. { 4F VK_O 'O' } $18,
  365. { 50 VK_P 'P' } $19,
  366. { 51 VK_Q 'Q' } $10,
  367. { 52 VK_R 'R' } $13,
  368. { 53 VK_S 'S' } $1F,
  369. { 54 VK_T 'T' } $14,
  370. { 55 VK_U 'U' } $16,
  371. { 56 VK_V 'V' } $2F,
  372. { 57 VK_W 'W' } $11,
  373. { 58 VK_X 'X' } $2D,
  374. { 59 VK_Y 'Y' } $15,
  375. { 5A VK_Z 'Z' } $2C,
  376. { 5B unassigned } -2,
  377. { 5C unassigned } -2,
  378. { 5D unassigned } -2,
  379. { 5E unassigned } -2,
  380. { 5F unassigned } -2,
  381. { 60 VK_NUMPAD0 NumKeyPad '0' } 11,
  382. { 61 VK_NUMPAD1 NumKeyPad '1' } 2,
  383. { 62 VK_NUMPAD2 NumKeyPad '2' } 3,
  384. { 63 VK_NUMPAD3 NumKeyPad '3' } 4,
  385. { 64 VK_NUMPAD4 NumKeyPad '4' } 5,
  386. { 65 VK_NUMPAD5 NumKeyPad '5' } 6,
  387. { 66 VK_NUMPAD6 NumKeyPad '6' } 7,
  388. { 67 VK_NUMPAD7 NumKeyPad '7' } 8,
  389. { 68 VK_NUMPAD8 NumKeyPad '8' } 9,
  390. { 69 VK_NUMPAD9 NumKeyPad '9' } 10,
  391. { 6A VK_MULTIPLY } 0,
  392. { 6B VK_ADD } 0,
  393. { 6C VK_SEPARATOR } 0,
  394. { 6D VK_SUBSTRACT } 0,
  395. { 6E VK_DECIMAL } 0,
  396. { 6F VK_DIVIDE } 0,
  397. { 70 VK_F1 'F1' } $3B,
  398. { 71 VK_F2 'F2' } $3C,
  399. { 72 VK_F3 'F3' } $3D,
  400. { 73 VK_F4 'F4' } $3E,
  401. { 74 VK_F5 'F5' } $3F,
  402. { 75 VK_F6 'F6' } $40,
  403. { 76 VK_F7 'F7' } $41,
  404. { 77 VK_F8 'F8' } $42,
  405. { 78 VK_F9 'F9' } $43,
  406. { 79 VK_F10 'F10' } $44,
  407. { 7A VK_F11 'F11' } $57,
  408. { 7B VK_F12 'F12' } $58,
  409. { 7C VK_F13 } 0,
  410. { 7D VK_F14 } 0,
  411. { 7E VK_F15 } 0,
  412. { 7F VK_F16 } 0,
  413. { 80 VK_F17 } 0,
  414. { 81 VK_F18 } 0,
  415. { 82 VK_F19 } 0,
  416. { 83 VK_F20 } 0,
  417. { 84 VK_F21 } 0,
  418. { 85 VK_F22 } 0,
  419. { 86 VK_F23 } 0,
  420. { 87 VK_F24 } 0,
  421. { 88 unassigned } -2,
  422. { 89 VK_NUMLOCK } 0,
  423. { 8A VK_SCROLL } 0,
  424. { 8B unassigned } -2,
  425. { 8C unassigned } -2,
  426. { 8D unassigned } -2,
  427. { 8E unassigned } -2,
  428. { 8F unassigned } -2,
  429. { 90 unassigned } -2,
  430. { 91 unassigned } -2,
  431. { 92 unassigned } -2,
  432. { 93 unassigned } -2,
  433. { 94 unassigned } -2,
  434. { 95 unassigned } -2,
  435. { 96 unassigned } -2,
  436. { 97 unassigned } -2,
  437. { 98 unassigned } -2,
  438. { 99 unassigned } -2,
  439. { 9A unassigned } -2,
  440. { 9B unassigned } -2,
  441. { 9C unassigned } -2,
  442. { 9D unassigned } -2,
  443. { 9E unassigned } -2,
  444. { 9F unassigned } -2,
  445. { A0 unassigned } -2,
  446. { A1 unassigned } -2,
  447. { A2 unassigned } -2,
  448. { A3 unassigned } -2,
  449. { A4 unassigned } -2,
  450. { A5 unassigned } -2,
  451. { A6 unassigned } -2,
  452. { A7 unassigned } -2,
  453. { A8 unassigned } -2,
  454. { A9 unassigned } -2,
  455. { AA unassigned } -2,
  456. { AB unassigned } -2,
  457. { AC unassigned } -2,
  458. { AD unassigned } -2,
  459. { AE unassigned } -2,
  460. { AF unassigned } -2,
  461. { B0 unassigned } -2,
  462. { B1 unassigned } -2,
  463. { B2 unassigned } -2,
  464. { B3 unassigned } -2,
  465. { B4 unassigned } -2,
  466. { B5 unassigned } -2,
  467. { B6 unassigned } -2,
  468. { B7 unassigned } -2,
  469. { B8 unassigned } -2,
  470. { B9 unassigned } -2,
  471. { BA OEM specific } 0,
  472. { BB OEM specific } 0,
  473. { BC OEM specific } 0,
  474. { BD OEM specific } 0,
  475. { BE OEM specific } 0,
  476. { BF OEM specific } 0,
  477. { C0 OEM specific } 0,
  478. { C1 unassigned } -2,
  479. { C2 unassigned } -2,
  480. { C3 unassigned } -2,
  481. { C4 unassigned } -2,
  482. { C5 unassigned } -2,
  483. { C6 unassigned } -2,
  484. { C7 unassigned } -2,
  485. { C8 unassigned } -2,
  486. { C9 unassigned } -2,
  487. { CA unassigned } -2,
  488. { CB unassigned } -2,
  489. { CC unassigned } -2,
  490. { CD unassigned } -2,
  491. { CE unassigned } -2,
  492. { CF unassigned } -2,
  493. { D0 unassigned } -2,
  494. { D1 unassigned } -2,
  495. { D2 unassigned } -2,
  496. { D3 unassigned } -2,
  497. { D4 unassigned } -2,
  498. { D5 unassigned } -2,
  499. { D6 unassigned } -2,
  500. { D7 unassigned } -2,
  501. { D8 unassigned } -2,
  502. { D9 unassigned } -2,
  503. { DA unassigned } -2,
  504. { DB OEM specific } 0,
  505. { DC OEM specific } 0,
  506. { DD OEM specific } 0,
  507. { DE OEM specific } 0,
  508. { DF OEM specific } 0,
  509. { E0 OEM specific } 0,
  510. { E1 OEM specific } 0,
  511. { E2 OEM specific } 0,
  512. { E3 OEM specific } 0,
  513. { E4 OEM specific } 0,
  514. { E5 unassigned } -2,
  515. { E6 OEM specific } 0,
  516. { E7 unassigned } -2,
  517. { E8 unassigned } -2,
  518. { E9 OEM specific } 0,
  519. { EA OEM specific } 0,
  520. { EB OEM specific } 0,
  521. { EC OEM specific } 0,
  522. { ED OEM specific } 0,
  523. { EE OEM specific } 0,
  524. { EF OEM specific } 0,
  525. { F0 OEM specific } 0,
  526. { F1 OEM specific } 0,
  527. { F2 OEM specific } 0,
  528. { F3 OEM specific } 0,
  529. { F4 OEM specific } 0,
  530. { F5 OEM specific } 0,
  531. { F6 unassigned } -2,
  532. { F7 unassigned } -2,
  533. { F8 unassigned } -2,
  534. { F9 unassigned } -2,
  535. { FA unassigned } -2,
  536. { FB unassigned } -2,
  537. { FC unassigned } -2,
  538. { FD unassigned } -2,
  539. { FE unassigned } -2,
  540. { FF unassigned } -2
  541. );
  542. {$endif USEKEYCODES}
  543. type TTEntryT = packed record
  544. n,s,c,a : byte; {normal,shift, ctrl, alt, normal only for f11,f12}
  545. end;
  546. CONST
  547. DosTT : ARRAY [$3B..$58] OF TTEntryT =
  548. ((n : $3B; s : $54; c : $5E; a: $68), {3B F1}
  549. (n : $3C; s : $55; c : $5F; a: $69), {3C F2}
  550. (n : $3D; s : $56; c : $60; a: $6A), {3D F3}
  551. (n : $3E; s : $57; c : $61; a: $6B), {3E F4}
  552. (n : $3F; s : $58; c : $62; a: $6C), {3F F5}
  553. (n : $40; s : $59; c : $63; a: $6D), {40 F6}
  554. (n : $41; s : $5A; c : $64; a: $6E), {41 F7}
  555. (n : $42; s : $5B; c : $65; a: $6F), {42 F8}
  556. (n : $43; s : $5C; c : $66; a: $70), {43 F9}
  557. (n : $44; s : $5D; c : $67; a: $71), {44 F10}
  558. (n : $45; s : $00; c : $00; a: $00), {45 ???}
  559. (n : $46; s : $00; c : $00; a: $00), {46 ???}
  560. (n : $47; s : $47; c : $77; a: $97), {47 Home}
  561. (n : $48; s : $00; c : $8D; a: $98), {48 Up}
  562. (n : $49; s : $49; c : $84; a: $99), {49 PgUp}
  563. (n : $4A; s : $00; c : $8E; a: $4A), {4A -}
  564. (n : $4B; s : $4B; c : $73; a: $9B), {4B Left}
  565. (n : $4C; s : $00; c : $00; a: $00), {4C ???}
  566. (n : $4D; s : $4D; c : $74; a: $9D), {4D Right}
  567. (n : $4E; s : $00; c : $90; a: $4E), {4E +}
  568. (n : $4F; s : $4F; c : $75; a: $9F), {4F End}
  569. (n : $50; s : $50; c : $91; a: $A0), {50 Down}
  570. (n : $51; s : $51; c : $76; a: $A1), {51 PgDown}
  571. (n : $52; s : $52; c : $92; a: $A2), {52 Insert}
  572. (n : $53; s : $53; c : $93; a: $A3), {53 Del}
  573. (n : $54; s : $00; c : $00; a: $00), {54 ???}
  574. (n : $55; s : $00; c : $00; a: $00), {55 ???}
  575. (n : $56; s : $00; c : $00; a: $00), {56 ???}
  576. (n : $85; s : $87; c : $89; a: $8B), {57 F11}
  577. (n : $86; s : $88; c : $8A; a: $8C)); {58 F12}
  578. DosTT09 : ARRAY [$02..$0F] OF TTEntryT =
  579. ((n : $00; s : $00; c : $00; a: $78), {02 1 }
  580. (n : $00; s : $00; c : $00; a: $79), {03 2 }
  581. (n : $00; s : $00; c : $00; a: $7A), {04 3 }
  582. (n : $00; s : $00; c : $00; a: $7B), {05 4 }
  583. (n : $00; s : $00; c : $00; a: $7C), {06 5 }
  584. (n : $00; s : $00; c : $00; a: $7D), {07 6 }
  585. (n : $00; s : $00; c : $00; a: $7E), {08 7 }
  586. (n : $00; s : $00; c : $00; a: $7F), {09 8 }
  587. (n : $00; s : $00; c : $00; a: $80), {0A 9 }
  588. (n : $00; s : $00; c : $00; a: $81), {0B 0 }
  589. (n : $00; s : $00; c : $00; a: $82), {0C ß }
  590. (n : $00; s : $00; c : $00; a: $00), {0D}
  591. (n : $00; s : $09; c : $00; a: $00), {0E Backspace}
  592. (n : $00; s : $0F; c : $94; a: $00)); {0F Tab }
  593. function TranslateKey (t : TKeyEventRecord) : TKeyEvent;
  594. var key : TKeyEvent;
  595. ss : byte;
  596. {$ifdef USEKEYCODES}
  597. ScanCode : byte;
  598. {$endif USEKEYCODES}
  599. b : byte;
  600. begin
  601. Key := 0;
  602. if t.bKeyDown then
  603. begin
  604. { ascii-char is <> 0 if not a specal key }
  605. { we return it here otherwise we have to translate more later }
  606. if t.AsciiChar <> #0 then
  607. begin
  608. if (t.dwControlKeyState and ENHANCED_KEY <> 0) and
  609. (t.wVirtualKeyCode = $DF) then
  610. begin
  611. t.dwControlKeyState:=t.dwControlKeyState and not ENHANCED_KEY;
  612. t.wVirtualKeyCode:=VK_DIVIDE;
  613. t.AsciiChar:='/';
  614. end;
  615. {drivers needs scancode, we return it here as under dos and linux
  616. with $03000000 = the lowest two bytes is the physical representation}
  617. {$ifdef USEKEYCODES}
  618. Scancode:=KeyToQwertyScan[t.wVirtualKeyCode AND $00FF];
  619. If ScanCode>0 then
  620. t.wVirtualScanCode:=ScanCode;
  621. Key := byte (t.AsciiChar) + (t.wVirtualScanCode shl 8) + $03000000;
  622. ss := transShiftState (t.dwControlKeyState);
  623. key := key or (ss shl 16);
  624. if (ss and kbAlt <> 0) and rightistruealt(t.dwControlKeyState) then
  625. key := key and $FFFFFF00;
  626. {$else not USEKEYCODES}
  627. Key := byte (t.AsciiChar) + ((t.wVirtualScanCode AND $00FF) shl 8) + $03000000;
  628. {$endif not USEKEYCODES}
  629. end else
  630. begin
  631. {$ifdef USEKEYCODES}
  632. Scancode:=KeyToQwertyScan[t.wVirtualKeyCode AND $00FF];
  633. If ScanCode>0 then
  634. t.wVirtualScanCode:=ScanCode;
  635. {$endif not USEKEYCODES}
  636. translateKey := 0;
  637. { ignore shift,ctrl,alt,numlock,capslock alone }
  638. case t.wVirtualKeyCode of
  639. $0010, {shift}
  640. $0011, {ctrl}
  641. $0012, {alt}
  642. $0014, {capslock}
  643. $0090, {numlock}
  644. $0091, {scrollock}
  645. { This should be handled !! }
  646. { these last two are OEM specific
  647. this is not good !!! }
  648. $00DC, {^ : next key i.e. a is modified }
  649. { Strange on my keyboard this corresponds to double point over i or u PM }
  650. $00DD: exit; {´ and ` : next key i.e. e is modified }
  651. end;
  652. key := $03000000 + (t.wVirtualScanCode shl 8); { make lower 8 bit=0 like under dos }
  653. end;
  654. { Handling of ~ key as AltGr 2 }
  655. { This is also French keyboard specific !! }
  656. { but without this I can not get a ~ !! PM }
  657. { MvdV: not rightruealtised, since it already has frenchkbd guard}
  658. if (t.wVirtualKeyCode=$32) and
  659. (KeyBoardLayout = FrenchKeyboard) and
  660. (t.dwControlKeyState and RIGHT_ALT_PRESSED <> 0) then
  661. key:=(key and $ffffff00) or ord('~');
  662. { ok, now add Shift-State }
  663. ss := transShiftState (t.dwControlKeyState);
  664. key := key or (ss shl 16);
  665. { Reset Ascii-Char if Alt+Key, fv needs that, may be we
  666. need it for other special keys too
  667. 18 Sept 1999 AD: not for right Alt i.e. for AltGr+ß = \ on german keyboard }
  668. if ((ss and kbAlt <> 0) and rightistruealt(t.dwControlKeyState)) or
  669. (*
  670. { yes, we need it for cursor keys, 25=left, 26=up, 27=right,28=down}
  671. {aggg, this will not work because esc is also virtualKeyCode 27!!}
  672. {if (t.wVirtualKeyCode >= 25) and (t.wVirtualKeyCode <= 28) then}
  673. no VK_ESCAPE is $1B !!
  674. there was a mistake :
  675. VK_LEFT is $25 not 25 !! *)
  676. { not $2E VK_DELETE because its only the Keypad point !! PM }
  677. (t.wVirtualKeyCode in [$21..$28,$2C,$2D,$2F]) then
  678. { if t.wVirtualScanCode in [$47..$49,$4b,$4d,$4f,$50..$53] then}
  679. key := key and $FFFFFF00;
  680. {and translate to dos-scancodes to make fv happy, we will convert this
  681. back in translateKeyEvent}
  682. if rightistruealt(t.dwControlKeyState) then {not for alt-gr}
  683. if (t.wVirtualScanCode >= low (DosTT)) and
  684. (t.wVirtualScanCode <= high (dosTT)) then
  685. begin
  686. b := 0;
  687. if (ss and kbAlt) <> 0 then
  688. b := DosTT[t.wVirtualScanCode].a
  689. else
  690. if (ss and kbCtrl) <> 0 then
  691. b := DosTT[t.wVirtualScanCode].c
  692. else
  693. if (ss and kbShift) <> 0 then
  694. b := DosTT[t.wVirtualScanCode].s
  695. else
  696. b := DosTT[t.wVirtualScanCode].n;
  697. if b <> 0 then
  698. key := (key and $FFFF00FF) or (longint (b) shl 8);
  699. end;
  700. {Alt-0 to Alt-9}
  701. if rightistruealt(t.dwControlKeyState) then {not for alt-gr}
  702. if (t.wVirtualScanCode >= low (DosTT09)) and
  703. (t.wVirtualScanCode <= high (dosTT09)) then
  704. begin
  705. b := 0;
  706. if (ss and kbAlt) <> 0 then
  707. b := DosTT09[t.wVirtualScanCode].a
  708. else
  709. if (ss and kbCtrl) <> 0 then
  710. b := DosTT09[t.wVirtualScanCode].c
  711. else
  712. if (ss and kbShift) <> 0 then
  713. b := DosTT09[t.wVirtualScanCode].s
  714. else
  715. b := DosTT09[t.wVirtualScanCode].n;
  716. if b <> 0 then
  717. key := (key and $FFFF0000) or (longint (b) shl 8);
  718. end;
  719. TranslateKey := key;
  720. end;
  721. translateKey := Key;
  722. end;
  723. function SysGetKeyEvent: TKeyEvent;
  724. var t : TKeyEventRecord;
  725. key : TKeyEvent;
  726. begin
  727. key := 0;
  728. repeat
  729. if getKeyEventFromQueueWait (t) then
  730. key := translateKey (t);
  731. until key <> 0;
  732. {$ifdef DEBUG}
  733. last_ir.Event.KeyEvent:=t;
  734. {$endif DEBUG}
  735. SysGetKeyEvent := key;
  736. end;
  737. function SysPollKeyEvent: TKeyEvent;
  738. var t : TKeyEventRecord;
  739. k : TKeyEvent;
  740. begin
  741. SysPollKeyEvent := 0;
  742. if getKeyEventFromQueue (t, true) then
  743. begin
  744. { we get an enty for shift, ctrl, alt... }
  745. k := translateKey (t);
  746. while (k = 0) do
  747. begin
  748. getKeyEventFromQueue (t, false); {remove it}
  749. if not getKeyEventFromQueue (t, true) then exit;
  750. k := translateKey (t)
  751. end;
  752. SysPollKeyEvent := k;
  753. end;
  754. end;
  755. function SysTranslateKeyEvent(KeyEvent: TKeyEvent): TKeyEvent;
  756. begin
  757. if KeyEvent and $03000000 = $03000000 then
  758. begin
  759. if KeyEvent and $000000FF <> 0 then
  760. begin
  761. SysTranslateKeyEvent := KeyEvent and $00FFFFFF;
  762. exit;
  763. end;
  764. {translate function-keys and other specials, ascii-codes are already ok}
  765. case (KeyEvent AND $0000FF00) shr 8 of
  766. {F1..F10}
  767. $3B..$44 : SysTranslateKeyEvent := (KeyEvent AND $FCFF0000) + kbdF1 + ((KeyEvent AND $0000FF00) SHR 8) - $3B + $02000000;
  768. {F11,F12}
  769. $85..$86 : SysTranslateKeyEvent := (KeyEvent AND $FCFF0000) + kbdF11 + ((KeyEvent AND $0000FF00) SHR 8) - $85 + $02000000;
  770. {Shift F1..F10}
  771. $54..$5D : SysTranslateKeyEvent := (KeyEvent AND $FCFF0000) + kbdF1 + ((KeyEvent AND $0000FF00) SHR 8) - $54 + $02000000;
  772. {Shift F11,F12}
  773. $87..$88 : SysTranslateKeyEvent := (KeyEvent AND $FCFF0000) + kbdF11 + ((KeyEvent AND $0000FF00) SHR 8) - $87 + $02000000;
  774. {Alt F1..F10}
  775. $68..$71 : SysTranslateKeyEvent := (KeyEvent AND $FCFF0000) + kbdF1 + ((KeyEvent AND $0000FF00) SHR 8) - $68 + $02000000;
  776. {Alt F11,F12}
  777. $8B..$8C : SysTranslateKeyEvent := (KeyEvent AND $FCFF0000) + kbdF11 + ((KeyEvent AND $0000FF00) SHR 8) - $8B + $02000000;
  778. {Ctrl F1..F10}
  779. $5E..$67 : SysTranslateKeyEvent := (KeyEvent AND $FCFF0000) + kbdF1 + ((KeyEvent AND $0000FF00) SHR 8) - $5E + $02000000;
  780. {Ctrl F11,F12}
  781. $89..$8A : SysTranslateKeyEvent := (KeyEvent AND $FCFF0000) + kbdF11 + ((KeyEvent AND $0000FF00) SHR 8) - $89 + $02000000;
  782. {normal,ctrl,alt}
  783. $47,$77,$97 : SysTranslateKeyEvent := (KeyEvent AND $FCFF0000) + kbdHome + $02000000;
  784. $48,$8D,$98 : SysTranslateKeyEvent := (KeyEvent AND $FCFF0000) + kbdUp + $02000000;
  785. $49,$84,$99 : SysTranslateKeyEvent := (KeyEvent AND $FCFF0000) + kbdPgUp + $02000000;
  786. $4b,$73,$9B : SysTranslateKeyEvent := (KeyEvent AND $FCFF0000) + kbdLeft + $02000000;
  787. $4d,$74,$9D : SysTranslateKeyEvent := (KeyEvent AND $FCFF0000) + kbdRight + $02000000;
  788. $4f,$75,$9F : SysTranslateKeyEvent := (KeyEvent AND $FCFF0000) + kbdEnd + $02000000;
  789. $50,$91,$A0 : SysTranslateKeyEvent := (KeyEvent AND $FCFF0000) + kbdDown + $02000000;
  790. $51,$76,$A1 : SysTranslateKeyEvent := (KeyEvent AND $FCFF0000) + kbdPgDn + $02000000;
  791. $52,$92,$A2 : SysTranslateKeyEvent := (KeyEvent AND $FCFF0000) + kbdInsert + $02000000;
  792. $53,$93,$A3 : SysTranslateKeyEvent := (KeyEvent AND $FCFF0000) + kbdDelete + $02000000;
  793. else
  794. SysTranslateKeyEvent := KeyEvent;
  795. end;
  796. end else
  797. SysTranslateKeyEvent := KeyEvent;
  798. end;
  799. function SysGetShiftState: Byte;
  800. begin
  801. {may be better to save the last state and return that if no key is in buffer???}
  802. SysGetShiftState:= lastShiftState;
  803. end;
  804. Const
  805. SysKeyboardDriver : TKeyboardDriver = (
  806. InitDriver : @SysInitKeyBoard;
  807. DoneDriver : @SysDoneKeyBoard;
  808. GetKeyevent : @SysGetKeyEvent;
  809. PollKeyEvent : @SysPollKeyEvent;
  810. GetShiftState : @SysGetShiftState;
  811. TranslateKeyEvent : @SysTranslateKeyEvent;
  812. TranslateKeyEventUnicode : Nil;
  813. );
  814. begin
  815. SetKeyBoardDriver(SysKeyBoardDriver);
  816. end.