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