keyboard.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. {
  2. System independent keyboard interface for linux
  3. $Id$
  4. }
  5. uses
  6. Linux;
  7. var
  8. OldIO : TermIos;
  9. Procedure SetRawMode(b:boolean);
  10. Var
  11. Tio : Termios;
  12. Begin
  13. TCGetAttr(1,Tio);
  14. if b then
  15. begin
  16. OldIO:=Tio;
  17. Tio.c_iflag:=Tio.c_iflag and (not (IGNBRK or BRKINT or PARMRK or ISTRIP or
  18. INLCR or IGNCR or ICRNL or IXON));
  19. Tio.c_lflag:=Tio.c_lflag and (not (ECHO or ECHONL or ICANON or ISIG or IEXTEN));
  20. end
  21. else
  22. Tio := OldIO;
  23. TCSetAttr(1,TCSANOW,Tio);
  24. End;
  25. type
  26. chgentry=packed record
  27. tab,
  28. idx,
  29. oldtab,
  30. oldidx : byte;
  31. oldval,
  32. newval : word;
  33. end;
  34. kbentry=packed record
  35. kb_table,
  36. kb_index : byte;
  37. kb_value : word;
  38. end;
  39. const
  40. kbdchanges=10;
  41. kbdchange:array[1..kbdchanges] of chgentry=(
  42. (tab:8; idx:$3b; oldtab:0; oldidx:$3b; oldval:0; newval:0),
  43. (tab:8; idx:$3c; oldtab:0; oldidx:$3c; oldval:0; newval:0),
  44. (tab:8; idx:$3d; oldtab:0; oldidx:$3d; oldval:0; newval:0),
  45. (tab:8; idx:$3e; oldtab:0; oldidx:$3e; oldval:0; newval:0),
  46. (tab:8; idx:$3f; oldtab:0; oldidx:$3f; oldval:0; newval:0),
  47. (tab:8; idx:$40; oldtab:0; oldidx:$40; oldval:0; newval:0),
  48. (tab:8; idx:$41; oldtab:0; oldidx:$41; oldval:0; newval:0),
  49. (tab:8; idx:$42; oldtab:0; oldidx:$42; oldval:0; newval:0),
  50. (tab:8; idx:$43; oldtab:0; oldidx:$43; oldval:0; newval:0),
  51. (tab:8; idx:$44; oldtab:0; oldidx:$44; oldval:0; newval:0)
  52. );
  53. KDGKBENT=$4B46;
  54. KDSKBENT=$4B47;
  55. procedure PatchKeyboard;
  56. var
  57. e : ^chgentry;
  58. entry : kbentry;
  59. i : longint;
  60. begin
  61. for i:=1to kbdchanges do
  62. begin
  63. e:=@kbdchange[i];
  64. entry.kb_table:=e^.tab;
  65. entry.kb_index:=e^.idx;
  66. Ioctl(stdinputhandle,KDGKBENT,@entry);
  67. e^.oldval:=entry.kb_value;
  68. entry.kb_table:=e^.oldtab;
  69. entry.kb_index:=e^.oldidx;
  70. ioctl(stdinputhandle,KDGKBENT,@entry);
  71. e^.newval:=entry.kb_value;
  72. end;
  73. for i:=1to kbdchanges do
  74. begin
  75. e:=@kbdchange[i];
  76. entry.kb_table:=e^.tab;
  77. entry.kb_index:=e^.idx;
  78. entry.kb_value:=e^.newval;
  79. Ioctl(stdinputhandle,KDSKBENT,@entry);
  80. end;
  81. end;
  82. procedure UnpatchKeyboard;
  83. var
  84. e : ^chgentry;
  85. entry : kbentry;
  86. i : longint;
  87. begin
  88. for i:=1to kbdchanges do
  89. begin
  90. e:=@kbdchange[i];
  91. entry.kb_table:=e^.tab;
  92. entry.kb_index:=e^.idx;
  93. entry.kb_value:=e^.oldval;
  94. Ioctl(stdinputhandle,KDSKBENT,@entry);
  95. end;
  96. end;
  97. { Buffered Input routines }
  98. const
  99. InSize=256;
  100. var
  101. InBuf : array[0..InSize-1] of char;
  102. InCnt,
  103. InHead,
  104. InTail : longint;
  105. function ttyRecvChar:char;
  106. var
  107. Readed,i : longint;
  108. begin
  109. {Buffer Empty? Yes, Input from StdIn}
  110. if (InHead=InTail) then
  111. begin
  112. {Calc Amount of Chars to Read}
  113. i:=InSize-InHead;
  114. if InTail>InHead then
  115. i:=InTail-InHead;
  116. {Read}
  117. Readed:=fdRead(StdInputHandle,InBuf[InHead],i);
  118. {Increase Counters}
  119. inc(InCnt,Readed);
  120. inc(InHead,Readed);
  121. {Wrap if End has Reached}
  122. if InHead>=InSize then
  123. InHead:=0;
  124. end;
  125. {Check Buffer}
  126. if (InCnt=0) then
  127. ttyRecvChar:=#0
  128. else
  129. begin
  130. ttyRecvChar:=InBuf[InTail];
  131. dec(InCnt);
  132. inc(InTail);
  133. if InTail>=InSize then
  134. InTail:=0;
  135. end;
  136. end;
  137. Const
  138. KeyBufferSize = 20;
  139. var
  140. KeyBuffer : Array[0..KeyBufferSize-1] of Char;
  141. KeyPut,
  142. KeySend : longint;
  143. Procedure PushKey(Ch:char);
  144. Var
  145. Tmp : Longint;
  146. Begin
  147. Tmp:=KeyPut;
  148. Inc(KeyPut);
  149. If KeyPut>=KeyBufferSize Then
  150. KeyPut:=0;
  151. If KeyPut<>KeySend Then
  152. KeyBuffer[Tmp]:=Ch
  153. Else
  154. KeyPut:=Tmp;
  155. End;
  156. Function PopKey:char;
  157. Begin
  158. If KeyPut<>KeySend Then
  159. Begin
  160. PopKey:=KeyBuffer[KeySend];
  161. Inc(KeySend);
  162. If KeySend>=KeyBufferSize Then
  163. KeySend:=0;
  164. End
  165. Else
  166. PopKey:=#0;
  167. End;
  168. Procedure PushExt(b:byte);
  169. begin
  170. PushKey(#0);
  171. PushKey(chr(b));
  172. end;
  173. const
  174. AltKeyStr : string[38]='qwertyuiopasdfghjklzxcvbnm1234567890-=';
  175. AltCodeStr : string[38]=#016#017#018#019#020#021#022#023#024#025#030#031#032#033#034#035#036#037#038+
  176. #044#045#046#047#048#049#050#120#121#122#123#124#125#126#127#128#129#130#131;
  177. Function FAltKey(ch:char):byte;
  178. var
  179. Idx : longint;
  180. Begin
  181. Idx:=Pos(ch,AltKeyStr);
  182. if Idx>0 then
  183. FAltKey:=byte(AltCodeStr[Idx])
  184. else
  185. FAltKey:=0;
  186. End;
  187. { This one doesn't care about keypresses already processed by readkey }
  188. { and waiting in the KeyBuffer, only about waiting keypresses at the }
  189. { TTYLevel (including ones that are waiting in the TTYRecvChar buffer) }
  190. function sysKeyPressed: boolean;
  191. var
  192. fdsin : fdSet;
  193. begin
  194. if (InCnt>0) then
  195. sysKeyPressed:=true
  196. else
  197. begin
  198. FD_Zero(fdsin);
  199. fd_Set(StdInputHandle,fdsin);
  200. sysKeypressed:=(Select(StdInputHandle+1,@fdsin,nil,nil,0)>0);
  201. end;
  202. end;
  203. Function KeyPressed:Boolean;
  204. Begin
  205. Keypressed := (KeySend<>KeyPut) or sysKeyPressed;
  206. End;
  207. Function ReadKey:char;
  208. Var
  209. ch : char;
  210. OldState,
  211. State : longint;
  212. fdsin : fdSet;
  213. Begin
  214. {Check Buffer first}
  215. if KeySend<>KeyPut then
  216. begin
  217. ReadKey:=PopKey;
  218. exit;
  219. end;
  220. {Wait for Key}
  221. if not sysKeyPressed then
  222. begin
  223. FD_Zero (fdsin);
  224. FD_Set (StdInputHandle,fdsin);
  225. Select (StdInputHandle+1,@fdsin,nil,nil,nil);
  226. end;
  227. ch:=ttyRecvChar;
  228. {Esc Found ?}
  229. If (ch=#27) then
  230. begin
  231. FD_Zero(fdsin);
  232. fd_Set(StdInputHandle,fdsin);
  233. State:=1;
  234. if InCnt=0 then
  235. Select(StdInputHandle+1,@fdsin,nil,nil,10);
  236. while (State<>0) and (sysKeyPressed) do
  237. begin
  238. ch:=ttyRecvChar;
  239. OldState:=State;
  240. State:=0;
  241. case OldState of
  242. 1 : begin {Esc}
  243. case ch of
  244. 'a'..'z',
  245. '0'..'9',
  246. '-','=' : PushExt(FAltKey(ch));
  247. #10 : PushKey(#10);
  248. #13 : PushKey(#10);
  249. #127 : PushKey(#8);
  250. '[' : State:=2;
  251. else
  252. begin
  253. PushKey(ch);
  254. PushKey(#27);
  255. end;
  256. end;
  257. end;
  258. 2 : begin {Esc[}
  259. case ch of
  260. '[' : State:=3;
  261. 'A' : PushExt(72);
  262. 'B' : PushExt(80);
  263. 'C' : PushExt(77);
  264. 'D' : PushExt(75);
  265. 'G' : PushKey('5');
  266. 'H' : PushExt(71);
  267. 'K' : PushExt(79);
  268. '1' : State:=4;
  269. '2' : State:=5;
  270. '3' : PushExt(83);
  271. '4' : PushExt(79);
  272. '5' : PushExt(73);
  273. '6' : PushExt(81);
  274. else
  275. begin
  276. PushKey(ch);
  277. PushKey('[');
  278. PushKey(#27);
  279. end;
  280. end;
  281. if ch in ['3'..'6'] then
  282. State:=255;
  283. end;
  284. 3 : begin {Esc[[}
  285. case ch of
  286. 'A' : PushExt(59);
  287. 'B' : PushExt(60);
  288. 'C' : PushExt(61);
  289. 'D' : PushExt(62);
  290. 'E' : PushExt(63);
  291. end;
  292. end;
  293. 4 : begin
  294. case ch of
  295. '~' : PushExt(71);
  296. '7' : PushExt(64);
  297. '8' : PushExt(65);
  298. '9' : PushExt(66);
  299. end;
  300. if (Ch<>'~') then
  301. State:=255;
  302. end;
  303. 5 : begin
  304. case ch of
  305. '~' : PushExt(82);
  306. '0' : pushExt(67);
  307. '1' : PushExt(68);
  308. '3' : PushExt(133);
  309. '4' : PushExt(134);
  310. end;
  311. if (Ch<>'~') then
  312. State:=255;
  313. end;
  314. 255 : ;
  315. end;
  316. if (State<>0) and (InCnt=0) then
  317. Select(StdInputHandle+1,@fdsin,nil,nil,10);
  318. end;
  319. if State=1 then
  320. PushKey(ch);
  321. end
  322. else
  323. Begin
  324. case ch of
  325. #127 : PushKey(#8);
  326. else
  327. PushKey(ch);
  328. end;
  329. End;
  330. ReadKey:=PopKey;
  331. End;
  332. function ShiftState:byte;
  333. var
  334. arg,shift : longint;
  335. begin
  336. arg:=6;
  337. shift:=0;
  338. if IOCtl(StdInputHandle,TIOCLINUX,@arg) then
  339. begin
  340. if (arg and (2 or 8))<>0 then
  341. inc(shift,8);
  342. if (arg and 4)<>0 then
  343. inc(shift,4);
  344. if (arg and 1)<>0 then
  345. inc(shift,3);
  346. end;
  347. ShiftState:=shift;
  348. end;
  349. { Exported functions }
  350. procedure InitKeyboard;
  351. begin
  352. SetRawMode(true);
  353. patchkeyboard;
  354. end;
  355. procedure DoneKeyboard;
  356. begin
  357. unpatchkeyboard;
  358. SetRawMode(false);
  359. end;
  360. function GetKeyEvent: TKeyEvent;
  361. function EvalScan(b:byte):byte;
  362. const
  363. DScan:array[0..31] of byte = (
  364. $39, $02, $28, $04, $05, $06, $08, $28,
  365. $0A, $0B, $09, $0D, $33, $0C, $34, $35,
  366. $0B, $02, $03, $04, $05, $06, $07, $08,
  367. $09, $0A, $27, $27, $33, $0D, $34, $35);
  368. LScan:array[0..31] of byte = (
  369. $29, $1E, $30, $2E, $20, $12, $21, $22,
  370. $23, $17, $24, $25, $26, $32, $31, $18,
  371. $19, $10, $13, $1F, $14, $16, $2F, $11,
  372. $2D, $15, $2C, $1A, $2B, $1B, $29, $0C);
  373. begin
  374. if (b and $E0)=$20 { digits / leters } then
  375. EvalScan:=DScan[b and $1F]
  376. else
  377. case b of
  378. $08:EvalScan:=$0E; { backspace }
  379. $09:EvalScan:=$0F; { TAB }
  380. $0D:EvalScan:=$1C; { CR }
  381. $1B:EvalScan:=$01; { esc }
  382. $40:EvalScan:=$03; { @ }
  383. $5E:EvalScan:=$07; { ^ }
  384. $60:EvalScan:=$29; { ` }
  385. else
  386. EvalScan:=LScan[b and $1F];
  387. end;
  388. end;
  389. function EvalScanZ(b:byte):byte;
  390. begin
  391. EvalScanZ:=b;
  392. if b in [$3B..$44] { F1..F10 -> Alt-F1..Alt-F10} then
  393. EvalScanZ:=b+$2D;
  394. end;
  395. const
  396. CtrlArrow : array [71..81] of byte =
  397. ($77,$8d,$84,$8e,$73,$8f,$74,$90,$75,$91,$76);
  398. var
  399. MyScan,
  400. SState : byte;
  401. MyChar : char;
  402. begin {main}
  403. if PendingKeyEvent<>0 then
  404. begin
  405. GetKeyEvent:=PendingKeyEvent;
  406. PendingKeyEvent:=0;
  407. exit;
  408. end;
  409. MyChar:=Readkey;
  410. MyScan:=ord(MyChar);
  411. SState:=ShiftState;
  412. case MyChar of
  413. #26 : begin { ^Z - replace Alt for Linux OS }
  414. MyChar:=ReadKey;
  415. MyScan:=ord(MyChar);
  416. if MyScan=0 then
  417. MyScan:=EvalScanZ(ord(ReadKey))
  418. else
  419. begin
  420. MyScan:=EvalScan(ord(MyChar));
  421. if MyScan in [$02..$0D] then
  422. inc(MyScan,$76);
  423. MyChar:=chr(0);
  424. end;
  425. end;
  426. #0 : begin
  427. MyScan:=ord(ReadKey);
  428. { Handle Ctrl-<x> }
  429. if (SState and 4)<>0 then
  430. begin
  431. case MyScan of
  432. 71..81 : { cArrow }
  433. MyScan:=CtrlArrow[MyScan];
  434. $3b..$44 : { cF1-cF10 }
  435. MyScan:=MyScan+$23;
  436. end;
  437. end;
  438. { Handle Alt-<x> }
  439. if (SState and 8)<>0 then
  440. begin
  441. case MyScan of
  442. $3b..$44 : { aF1-aF10 }
  443. MyScan:=MyScan+$2d;
  444. end;
  445. end;
  446. end;
  447. else begin
  448. MyScan:=EvalScan(ord(MyChar));
  449. end;
  450. end;
  451. GetKeyEvent:=$3000000 or ord(MyChar) or (MyScan shl 8) or (SState shl 16);
  452. end;
  453. function PollKeyEvent: TKeyEvent;
  454. begin
  455. if PendingKeyEvent<>0 then
  456. exit(PendingKeyEvent);
  457. if keypressed then
  458. begin
  459. { just get the key and place it in the pendingkeyevent }
  460. PendingKeyEvent:=GetKeyEvent;
  461. PollKeyEvent:=PendingKeyEvent;
  462. end
  463. else
  464. PollKeyEvent:=0;
  465. end;
  466. function PollShiftStateEvent: TKeyEvent;
  467. begin
  468. PollShiftStateEvent:=ShiftState shl 16;
  469. end;
  470. { Function key translation }
  471. type
  472. TTranslationEntry = packed record
  473. Min, Max: Byte;
  474. Offset: Word;
  475. end;
  476. const
  477. TranslationTableEntries = 12;
  478. TranslationTable: array [1..TranslationTableEntries] of TTranslationEntry =
  479. ((Min: $3B; Max: $44; Offset: kbdF1), { function keys F1-F10 }
  480. (Min: $54; Max: $5D; Offset: kbdF1), { Shift fn keys F1-F10 }
  481. (Min: $5E; Max: $67; Offset: kbdF1), { Ctrl fn keys F1-F10 }
  482. (Min: $68; Max: $71; Offset: kbdF1), { Alt fn keys F1-F10 }
  483. (Min: $85; Max: $86; Offset: kbdF11), { function keys F11-F12 }
  484. (Min: $87; Max: $88; Offset: kbdF11), { Shift+function keys F11-F12 }
  485. (Min: $89; Max: $8A; Offset: kbdF11), { Ctrl+function keys F11-F12 }
  486. (Min: $8B; Max: $8C; Offset: kbdF11), { Alt+function keys F11-F12 }
  487. (Min: 71; Max: 73; Offset: kbdHome), { Keypad keys kbdHome-kbdPgUp }
  488. (Min: 75; Max: 77; Offset: kbdLeft), { Keypad keys kbdLeft-kbdRight }
  489. (Min: 79; Max: 81; Offset: kbdEnd), { Keypad keys kbdEnd-kbdPgDn }
  490. (Min: $52; Max: $53; Offset: kbdInsert));
  491. function TranslateKeyEvent(KeyEvent: TKeyEvent): TKeyEvent;
  492. var
  493. I: Integer;
  494. ScanCode: Byte;
  495. begin
  496. if KeyEvent and $03000000 = $03000000 then
  497. begin
  498. if KeyEvent and $000000FF <> 0 then
  499. begin
  500. TranslateKeyEvent := KeyEvent and $00FFFFFF;
  501. exit;
  502. end
  503. else
  504. begin
  505. { This is a function key }
  506. ScanCode := (KeyEvent and $0000FF00) shr 8;
  507. for I := 1 to TranslationTableEntries do
  508. begin
  509. if (TranslationTable[I].Min <= ScanCode) and (ScanCode <= TranslationTable[I].Max) then
  510. begin
  511. TranslateKeyEvent := $02000000 + (KeyEvent and $00FF0000) +
  512. (ScanCode - TranslationTable[I].Min) + TranslationTable[I].Offset;
  513. exit;
  514. end;
  515. end;
  516. end;
  517. end;
  518. TranslateKeyEvent := KeyEvent;
  519. end;
  520. function TranslateKeyEventUniCode(KeyEvent: TKeyEvent): TKeyEvent;
  521. begin
  522. TranslateKeyEventUniCode := KeyEvent;
  523. ErrorHandler(errKbdNotImplemented, nil);
  524. end;
  525. {
  526. $Log$
  527. Revision 1.3 2000-10-04 11:53:31 pierre
  528. Add TargetEntry and TargetExit (merged)
  529. Revision 1.2 2000/07/13 11:32:25 michael
  530. + removed logs
  531. }