keyboard.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  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. Function KeyPressed:Boolean;
  191. var
  192. fdsin : fdSet;
  193. Begin
  194. if (KeySend<>KeyPut) or (InCnt>0) then
  195. KeyPressed:=true
  196. else
  197. begin
  198. FD_Zero(fdsin);
  199. fd_Set(StdInputHandle,fdsin);
  200. Keypressed:=(Select(StdInputHandle+1,@fdsin,nil,nil,1)>0);
  201. end;
  202. End;
  203. Function ReadKey:char;
  204. Var
  205. ch : char;
  206. OldState,
  207. State : longint;
  208. fdsin : fdSet;
  209. Begin
  210. {Check Buffer first}
  211. if KeySend<>KeyPut then
  212. begin
  213. ReadKey:=PopKey;
  214. exit;
  215. end;
  216. {Wait for Key}
  217. repeat
  218. until keypressed;
  219. ch:=ttyRecvChar;
  220. {Esc Found ?}
  221. If (ch=#27) then
  222. begin
  223. FD_Zero(fdsin);
  224. fd_Set(StdInputHandle,fdsin);
  225. State:=1;
  226. if InCnt=0 then
  227. Select(StdInputHandle+1,@fdsin,nil,nil,10);
  228. while (State<>0) and (KeyPressed) do
  229. begin
  230. ch:=ttyRecvChar;
  231. OldState:=State;
  232. State:=0;
  233. case OldState of
  234. 1 : begin {Esc}
  235. case ch of
  236. 'a'..'z',
  237. '0'..'9',
  238. '-','=' : PushExt(FAltKey(ch));
  239. #10 : PushKey(#10);
  240. #13 : PushKey(#10);
  241. #127 : PushKey(#8);
  242. '[' : State:=2;
  243. else
  244. begin
  245. PushKey(ch);
  246. PushKey(#27);
  247. end;
  248. end;
  249. end;
  250. 2 : begin {Esc[}
  251. case ch of
  252. '[' : State:=3;
  253. 'A' : PushExt(72);
  254. 'B' : PushExt(80);
  255. 'C' : PushExt(77);
  256. 'D' : PushExt(75);
  257. 'G' : PushKey('5');
  258. 'H' : PushExt(71);
  259. 'K' : PushExt(79);
  260. '1' : State:=4;
  261. '2' : State:=5;
  262. '3' : PushExt(83);
  263. '4' : PushExt(79);
  264. '5' : PushExt(73);
  265. '6' : PushExt(81);
  266. else
  267. begin
  268. PushKey(ch);
  269. PushKey('[');
  270. PushKey(#27);
  271. end;
  272. end;
  273. if ch in ['3'..'6'] then
  274. State:=255;
  275. end;
  276. 3 : begin {Esc[[}
  277. case ch of
  278. 'A' : PushExt(59);
  279. 'B' : PushExt(60);
  280. 'C' : PushExt(61);
  281. 'D' : PushExt(62);
  282. 'E' : PushExt(63);
  283. end;
  284. end;
  285. 4 : begin
  286. case ch of
  287. '~' : PushExt(71);
  288. '7' : PushExt(64);
  289. '8' : PushExt(65);
  290. '9' : PushExt(66);
  291. end;
  292. if (Ch<>'~') then
  293. State:=255;
  294. end;
  295. 5 : begin
  296. case ch of
  297. '~' : PushExt(82);
  298. '0' : pushExt(67);
  299. '1' : PushExt(68);
  300. '3' : PushExt(133);
  301. '4' : PushExt(134);
  302. end;
  303. if (Ch<>'~') then
  304. State:=255;
  305. end;
  306. 255 : ;
  307. end;
  308. if (State<>0) and (InCnt=0) then
  309. Select(StdInputHandle+1,@fdsin,nil,nil,10);
  310. end;
  311. if State=1 then
  312. PushKey(ch);
  313. end
  314. else
  315. Begin
  316. case ch of
  317. #127 : PushKey(#8);
  318. else
  319. PushKey(ch);
  320. end;
  321. End;
  322. ReadKey:=PopKey;
  323. End;
  324. function ShiftState:byte;
  325. var
  326. arg,shift : longint;
  327. begin
  328. arg:=6;
  329. shift:=0;
  330. if IOCtl(StdInputHandle,TIOCLINUX,@arg) then
  331. begin
  332. if (arg and (2 or 8))<>0 then
  333. inc(shift,8);
  334. if (arg and 4)<>0 then
  335. inc(shift,4);
  336. if (arg and 1)<>0 then
  337. inc(shift,3);
  338. end;
  339. ShiftState:=shift;
  340. end;
  341. { Exported functions }
  342. procedure InitKeyboard;
  343. begin
  344. SetRawMode(true);
  345. patchkeyboard;
  346. end;
  347. procedure DoneKeyboard;
  348. begin
  349. unpatchkeyboard;
  350. SetRawMode(false);
  351. end;
  352. function GetKeyEvent: TKeyEvent;
  353. function EvalScan(b:byte):byte;
  354. const
  355. DScan:array[0..31] of byte = (
  356. $39, $02, $28, $04, $05, $06, $08, $28,
  357. $0A, $0B, $09, $0D, $33, $0C, $34, $35,
  358. $0B, $02, $03, $04, $05, $06, $07, $08,
  359. $09, $0A, $27, $27, $33, $0D, $34, $35);
  360. LScan:array[0..31] of byte = (
  361. $29, $1E, $30, $2E, $20, $12, $21, $22,
  362. $23, $17, $24, $25, $26, $32, $31, $18,
  363. $19, $10, $13, $1F, $14, $16, $2F, $11,
  364. $2D, $15, $2C, $1A, $2B, $1B, $29, $0C);
  365. begin
  366. if (b and $E0)=$20 { digits / leters } then
  367. EvalScan:=DScan[b and $1F]
  368. else
  369. case b of
  370. $08:EvalScan:=$0E; { backspace }
  371. $09:EvalScan:=$0F; { TAB }
  372. $0D:EvalScan:=$1C; { CR }
  373. $1B:EvalScan:=$01; { esc }
  374. $40:EvalScan:=$03; { @ }
  375. $5E:EvalScan:=$07; { ^ }
  376. $60:EvalScan:=$29; { ` }
  377. else
  378. EvalScan:=LScan[b and $1F];
  379. end;
  380. end;
  381. function EvalScanZ(b:byte):byte;
  382. begin
  383. EvalScanZ:=b;
  384. if b in [$3B..$44] { F1..F10 -> Alt-F1..Alt-F10} then
  385. EvalScanZ:=b+$2D;
  386. end;
  387. const
  388. CtrlArrow : array [71..81] of byte =
  389. ($77,$8d,$84,$8e,$73,$8f,$74,$90,$75,$91,$76);
  390. var
  391. MyScan,
  392. SState : byte;
  393. MyChar : char;
  394. begin {main}
  395. if PendingKeyEvent<>0 then
  396. begin
  397. GetKeyEvent:=PendingKeyEvent;
  398. PendingKeyEvent:=0;
  399. exit;
  400. end;
  401. MyChar:=Readkey;
  402. MyScan:=ord(MyChar);
  403. SState:=ShiftState;
  404. case MyChar of
  405. #26 : begin { ^Z - replace Alt for Linux OS }
  406. MyChar:=ReadKey;
  407. MyScan:=ord(MyChar);
  408. if MyScan=0 then
  409. MyScan:=EvalScanZ(ord(ReadKey))
  410. else
  411. begin
  412. MyScan:=EvalScan(ord(MyChar));
  413. if MyScan in [$02..$0D] then
  414. inc(MyScan,$76);
  415. MyChar:=chr(0);
  416. end;
  417. end;
  418. #0 : begin
  419. MyScan:=ord(ReadKey);
  420. { Handle Ctrl-<x> }
  421. if (SState and 4)<>0 then
  422. begin
  423. case MyScan of
  424. 71..81 : { cArrow }
  425. MyScan:=CtrlArrow[MyScan];
  426. $3b..$44 : { cF1-cF10 }
  427. MyScan:=MyScan+$23;
  428. end;
  429. end;
  430. { Handle Alt-<x> }
  431. if (SState and 8)<>0 then
  432. begin
  433. case MyScan of
  434. $3b..$44 : { aF1-aF10 }
  435. MyScan:=MyScan+$2d;
  436. end;
  437. end;
  438. end;
  439. else begin
  440. MyScan:=EvalScan(ord(MyChar));
  441. end;
  442. end;
  443. GetKeyEvent:=$3000000 or ord(MyChar) or (MyScan shl 8) or (SState shl 16);
  444. end;
  445. function PollKeyEvent: TKeyEvent;
  446. begin
  447. if PendingKeyEvent<>0 then
  448. exit(PendingKeyEvent);
  449. if keypressed then
  450. begin
  451. { just get the key and place it in the pendingkeyevent }
  452. PendingKeyEvent:=GetKeyEvent;
  453. PollKeyEvent:=PendingKeyEvent;
  454. end
  455. else
  456. PollKeyEvent:=0;
  457. end;
  458. function PollShiftStateEvent: TKeyEvent;
  459. begin
  460. PollShiftStateEvent:=ShiftState shl 16;
  461. end;
  462. { Function key translation }
  463. type
  464. TTranslationEntry = packed record
  465. Min, Max: Byte;
  466. Offset: Word;
  467. end;
  468. const
  469. TranslationTableEntries = 12;
  470. TranslationTable: array [1..TranslationTableEntries] of TTranslationEntry =
  471. ((Min: $3B; Max: $44; Offset: kbdF1), { function keys F1-F10 }
  472. (Min: $54; Max: $5D; Offset: kbdF1), { Shift fn keys F1-F10 }
  473. (Min: $5E; Max: $67; Offset: kbdF1), { Ctrl fn keys F1-F10 }
  474. (Min: $68; Max: $71; Offset: kbdF1), { Alt fn keys F1-F10 }
  475. (Min: $85; Max: $86; Offset: kbdF11), { function keys F11-F12 }
  476. (Min: $87; Max: $88; Offset: kbdF11), { Shift+function keys F11-F12 }
  477. (Min: $89; Max: $8A; Offset: kbdF11), { Ctrl+function keys F11-F12 }
  478. (Min: $8B; Max: $8C; Offset: kbdF11), { Alt+function keys F11-F12 }
  479. (Min: 71; Max: 73; Offset: kbdHome), { Keypad keys kbdHome-kbdPgUp }
  480. (Min: 75; Max: 77; Offset: kbdLeft), { Keypad keys kbdLeft-kbdRight }
  481. (Min: 79; Max: 81; Offset: kbdEnd), { Keypad keys kbdEnd-kbdPgDn }
  482. (Min: $52; Max: $53; Offset: kbdInsert));
  483. function TranslateKeyEvent(KeyEvent: TKeyEvent): TKeyEvent;
  484. var
  485. I: Integer;
  486. ScanCode: Byte;
  487. begin
  488. if KeyEvent and $03000000 = $03000000 then
  489. begin
  490. if KeyEvent and $000000FF <> 0 then
  491. begin
  492. TranslateKeyEvent := KeyEvent and $00FFFFFF;
  493. exit;
  494. end
  495. else
  496. begin
  497. { This is a function key }
  498. ScanCode := (KeyEvent and $0000FF00) shr 8;
  499. for I := 1 to TranslationTableEntries do
  500. begin
  501. if (TranslationTable[I].Min <= ScanCode) and (ScanCode <= TranslationTable[I].Max) then
  502. begin
  503. TranslateKeyEvent := $02000000 + (KeyEvent and $00FF0000) +
  504. (ScanCode - TranslationTable[I].Min) + TranslationTable[I].Offset;
  505. exit;
  506. end;
  507. end;
  508. end;
  509. end;
  510. TranslateKeyEvent := KeyEvent;
  511. end;
  512. function TranslateKeyEventUniCode(KeyEvent: TKeyEvent): TKeyEvent;
  513. begin
  514. TranslateKeyEventUniCode := KeyEvent;
  515. ErrorHandler(errKbdNotImplemented, nil);
  516. end;
  517. {
  518. $Log$
  519. Revision 1.1 2000-01-06 01:20:31 peter
  520. * moved out of packages/ back to topdir
  521. Revision 1.1 1999/11/24 23:36:38 peter
  522. * moved to packages dir
  523. Revision 1.5 1999/02/16 10:44:53 peter
  524. * alt-f<x> support
  525. Revision 1.4 1998/12/15 10:30:34 peter
  526. + ctrl arrows support
  527. * better backspace
  528. Revision 1.3 1998/12/12 19:13:02 peter
  529. * keyboard updates
  530. * make test target, make all only makes units
  531. Revision 1.1 1998/12/04 12:48:30 peter
  532. * moved some dirs
  533. Revision 1.3 1998/10/29 12:49:48 peter
  534. * more fixes
  535. Revision 1.1 1998/10/26 11:31:47 peter
  536. + inital include files
  537. }