keyboard.pp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2006 by Karoly Balogh
  4. Keyboard unit for MorphOS and Amiga and AROS
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit Keyboard;
  12. interface
  13. {$i keybrdh.inc}
  14. {
  15. Amiga specific function, waits for a system event to occur on the
  16. message port of the window. This is mainly used in Free Vision to
  17. give up the Task's timeslice instead of dos.library/Delay() which
  18. blocks the event handling and ruins proper window refreshing among
  19. others
  20. input: specify a timeout to wait for an event to arrive. this is the
  21. maximum timeout. the function might return earlier or even
  22. immediately if there's an event. it's specified in milliseconds
  23. result: boolean if there is an incoming system event. false otherwise
  24. }
  25. function WaitForSystemEvent(millisec: Integer): boolean;
  26. implementation
  27. uses
  28. video, exec, intuition, inputevent, mouse, sysutils, keymap, timer;
  29. {$i keyboard.inc}
  30. {$i keyscan.inc}
  31. var
  32. LastShiftState : Byte; {set by handler for PollShiftStateEvent}
  33. OldMouseX : LongInt;
  34. OldmouseY : LongInt;
  35. OldButtons: Word;
  36. procedure SysInitKeyboard;
  37. begin
  38. // writeln('sysinitkeyboard');
  39. {$IFDEF MORPHOS}
  40. InitKeyMapLibrary;
  41. {$ENDIF}
  42. LastShiftState := 0;
  43. OldMouseX := -1;
  44. OldmouseY := -1;
  45. OldButtons := 0;
  46. end;
  47. procedure SysDoneKeyboard;
  48. begin
  49. end;
  50. function IsMsgPortEmpty(Port: PMsgPort): Boolean; inline;
  51. begin
  52. IsMsgPortEmpty := (Port^.mp_MsgList.lh_TailPred = @(Port^.mp_MsgList));
  53. end;
  54. var
  55. KeyQueue: TKeyEvent;
  56. type
  57. RawCodeEntry = record
  58. rc,n,s,c,a : Word; { raw code, normal, shift, ctrl, alt }
  59. end;
  60. const
  61. RCTABLE_MAXIDX = 24;
  62. RawCodeTable : array[0..RCTABLE_MAXIDX] of RawCodeEntry =
  63. (
  64. (rc: 66; n: $0F09; s: $0F00; c: $9400; a: $A500; ), // TAB
  65. (rc: 68; n: $1C0D; s: $1C0D; c: $1C0A; a: $1C0D; ), // Enter // shift, alt?
  66. (rc: 69; n: $011B; s: $011B; c: $011B; a: $0100; ), // ESC // shift?
  67. (rc: 70; n: $5300; s: $0700; c: $A300; a: $A200; ), // Delete
  68. (rc: 71; n: $5200; s: $0500; c: $0400; a: $A200; ), // Insert
  69. (rc: 72; n: $4900; s: $4900; c: $8400; a: $9900; ), // PgUP // shift?
  70. (rc: 73; n: $5100; s: $5100; c: $7600; a: $A100; ), // PgDOWN // shift?
  71. (rc: 76; n: $4800; s: $4800; c: $8D00; a: $9800; ), // UP // shift?
  72. (rc: 77; n: $5000; s: $5000; c: $9100; a: $A000; ), // DOWN // shift?
  73. (rc: 78; n: $4D00; s: $4D00; c: $7400; a: $9D00; ), // RIGHT // shift?
  74. (rc: 79; n: $4B00; s: $4B00; c: $7300; a: $9B00; ), // LEFT // shift?
  75. (rc: 80; n: $3B00; s: $5400; c: $5E00; a: $6800; ), // F1
  76. (rc: 81; n: $3C00; s: $5500; c: $5F00; a: $6900; ), // F2
  77. (rc: 82; n: $3D00; s: $5600; c: $6000; a: $6A00; ), // F3
  78. (rc: 83; n: $3E00; s: $5700; c: $6100; a: $6B00; ), // F4
  79. (rc: 84; n: $3F00; s: $5800; c: $6200; a: $6C00; ), // F5
  80. (rc: 85; n: $4000; s: $5900; c: $6300; a: $6D00; ), // F6
  81. (rc: 86; n: $4100; s: $5A00; c: $6400; a: $6E00; ), // F7
  82. (rc: 87; n: $4200; s: $5B00; c: $6500; a: $6F00; ), // F8
  83. (rc: 88; n: $4300; s: $5C00; c: $6600; a: $7000; ), // F9
  84. (rc: 89; n: $4400; s: $5D00; c: $6700; a: $7100; ), // F10
  85. (rc: 75; n: $8500; s: $8700; c: $8900; a: $8B00; ), // F11
  86. (rc: 76; n: $8600; s: $8800; c: $8A00; a: $8C00; ), // F12
  87. (rc: 112; n: $4700; s: $4700; c: $7700; a: $9700; ),// Home // shift?
  88. (rc: 113; n: $4F00; s: $4F00; c: $7500; a: $9F00; ) // End // shift?
  89. );
  90. function rcTableIdx(rc: LongInt): LongInt;
  91. var
  92. Counter: LongInt;
  93. begin
  94. rcTableIdx := -1;
  95. Counter := 0;
  96. while (RawCodeTable[Counter].rc <> rc) and (Counter <= RCTABLE_MAXIDX) do
  97. Inc(Counter);
  98. if (Counter <= RCTABLE_MAXIDX) then
  99. rcTableIdx := Counter;
  100. end;
  101. function HasShift(IQual: Word): Boolean; inline;
  102. begin
  103. HasShift := ((IQual and IEQUALIFIER_LSHIFT) <> 0) or
  104. ((IQual and IEQUALIFIER_RSHIFT) <> 0);
  105. end;
  106. function HasCtrl(IQual: Word): Boolean; inline;
  107. begin
  108. HasCtrl := ((IQual and IEQUALIFIER_CONTROL) <> 0);
  109. end;
  110. function HasAlt(IQual: Word): Boolean; inline;
  111. begin
  112. HasAlt := ((IQual and IEQUALIFIER_LALT) <> 0) or
  113. ((IQual and IEQUALIFIER_RALT) <> 0);
  114. end;
  115. function rcTableCode(IQual: Word; Idx: LongInt): LongInt;
  116. begin
  117. if (Idx < 0) or (Idx > RCTABLE_MAXIDX) then
  118. begin
  119. rcTableCode := -1;
  120. Exit;
  121. end;
  122. if HasShift(IQual) then
  123. rcTableCode:=RawCodeTable[Idx].s
  124. else
  125. if HasCtrl(IQual) then
  126. rcTableCode:=RawCodeTable[Idx].c
  127. else
  128. if HasAlt(IQual) then
  129. rcTableCode:=RawCodeTable[Idx].a
  130. else
  131. rcTableCode:=RawCodeTable[Idx].n;
  132. end;
  133. procedure setShiftState(IQual: Word);
  134. begin
  135. LastShiftState := 0;
  136. if ((IQual and IEQUALIFIER_LSHIFT) <> 0) then
  137. LastShiftState := LastShiftState or $01;
  138. if ((IQual and IEQUALIFIER_RSHIFT) <> 0) then
  139. LastShiftState := LastShiftState or $02;
  140. if HasCtrl(IQual) then
  141. LastShiftState := LastShiftState or $04;
  142. if HasAlt(IQual) then
  143. LastShiftState := LastShiftState or $08;
  144. if ((IQual and IEQUALIFIER_NUMERICPAD) <> 0) then
  145. LastShiftState := LastShiftState or $20;
  146. if ((IQual and IEQUALIFIER_CAPSLOCK) <> 0) then
  147. LastShiftState := LastShiftState or $40;
  148. end;
  149. function SysPollKeyEvent: TKeyEvent;
  150. var
  151. MouseEvent: Boolean; // got a mouseevent -> do not leave cycle
  152. SendMouse: Boolean; // we got a (or many) mouse move send the last one
  153. mes: TMouseEvent; // save mouse message send after cycle -> prevent mouse move stacking
  154. me: TMouseEvent;
  155. KeyCode: LongInt;
  156. OldKeyCode: LongInt;
  157. KeySet: ^TKeyRecord; // points to result to set fields directly
  158. Ret: LongInt;
  159. //
  160. iMsg: PIntuiMessage;
  161. ICode: Word; // save items from Message
  162. IQual: Word;
  163. IClass: Longword;
  164. MouseX: LongInt;
  165. MouseY: LongInt;
  166. KeyUp: Boolean; // Event is a key up event
  167. Buff: array[0..19] of Char;
  168. ie: TInputEvent; // for mapchar
  169. begin
  170. KeyCode := 0;
  171. SysPollKeyEvent := 0;
  172. KeySet := @SysPollKeyEvent;
  173. FillChar(me, SizeOf(TMouseEvent), 0);
  174. if KeyQueue <> 0 then
  175. begin
  176. SysPollKeyEvent := KeyQueue;
  177. Exit;
  178. end;
  179. SendMouse := False;
  180. repeat
  181. MouseEvent := False;
  182. if VideoWindow <> nil then
  183. begin
  184. if IsMsgPortEmpty(videoWindow^.UserPort) then
  185. Break;
  186. end else
  187. Exit;
  188. PMessage(iMsg) := GetMsg(VideoWindow^.UserPort);
  189. if (iMsg <> nil) then
  190. begin
  191. ICode := iMsg^.Code;
  192. IQual := iMsg^.Qualifier;
  193. IClass := iMsg^.iClass;
  194. MouseX := iMsg^.MouseX;
  195. MouseY := iMsg^.MouseY;
  196. ReplyMsg(PMessage(iMsg)); // fast reply to system
  197. SetShiftState(IQual); // set Shift state qualifiers. do this for all messages we get.
  198. // main event case
  199. case (IClass) of
  200. IDCMP_ACTIVEWINDOW: begin
  201. GotActiveWindow;
  202. end;
  203. IDCMP_INACTIVEWINDOW: begin
  204. // force cursor off. we stop getting IntuiTicks when
  205. // the window is inactive, so the blinking stops.
  206. ToggleCursor(true);
  207. GotInactiveWindow;
  208. end;
  209. IDCMP_INTUITICKS: begin
  210. ToggleCursor(false);
  211. TranslateToCharXY(MouseX - VideoWindow^.BorderLeft, MouseY - VideoWindow^.BorderTop, MouseX, MouseY);
  212. if (MouseX >= 0) and (MouseY >= 0) and
  213. (MouseX < Video.ScreenWidth) and (MouseY < Video.ScreenHeight) and
  214. ((MouseX <> OldMouseX) or (MouseY <> OldmouseY))
  215. then begin
  216. // //writeln('mousemove:',Mousex,'/',Mousey,' oldbutt:',OldButtons);
  217. // Drawing is very slow so when moving window it will drag behind
  218. // because the mouse events stack in the messageport
  219. // -> so we override move until messageport is empty or keyevent is fired
  220. SendMouse := True;
  221. MouseEvent := True;
  222. mes.Action := MouseActionMove;
  223. mes.Buttons := OldButtons;
  224. mes.X := MouseX;
  225. mes.Y := MouseY;
  226. //PutMouseEvent(me);
  227. end;
  228. end;
  229. IDCMP_CLOSEWINDOW: begin
  230. //writeln('got close');
  231. GotCloseWindow;
  232. end;
  233. IDCMP_CHANGEWINDOW: begin
  234. GotResizeWindow;
  235. end;
  236. IDCMP_REFRESHWINDOW: begin
  237. GotRefreshWindow;
  238. end;
  239. IDCMP_MOUSEBUTTONS: begin
  240. MouseEvent := True;
  241. TranslateToCharXY(MouseX - videoWindow^.BorderLeft, MouseY - videoWindow^.BorderTop, MouseX, MouseY);
  242. me.x := MouseX;
  243. me.y := MouseY;
  244. case ICode of
  245. SELECTDOWN: begin
  246. //writeln('left down!');
  247. me.Action := MouseActionDown;
  248. OldButtons := OldButtons or MouseLeftButton;
  249. me.Buttons := OldButtons;
  250. PutMouseEvent(me);
  251. end;
  252. SELECTUP: begin
  253. //writeln('left up!');
  254. me.Action := MouseActionUp;
  255. OldButtons := OldButtons and (not MouseLeftButton);
  256. me.Buttons := OldButtons;
  257. PutMouseEvent(me);
  258. end;
  259. MENUDOWN: begin
  260. //writeln('right down!');
  261. me.Action := MouseActionDown;
  262. OldButtons := OldButtons or MouseRightButton;
  263. me.Buttons := OldButtons;
  264. PutMouseEvent(me);
  265. end;
  266. MENUUP: begin
  267. //writeln('right up!');
  268. me.Action := MouseActionUp;
  269. OldButtons := OldButtons and (not MouseRightButton);
  270. me.Buttons := OldButtons;
  271. PutMouseEvent(me);
  272. end;
  273. end;
  274. //writeln('Buttons: ' , me.Buttons);
  275. end;
  276. IDCMP_MOUSEMOVE: begin
  277. { IDCMP_MOUSEMOVE is disabled now in the video unit,
  278. according to autodocs INTUITICKS should be enough
  279. to handle most moves, esp. in a "textmode" app }
  280. TranslateToCharXY(MouseX - VideoWindow^.BorderLeft, MouseY - VideoWindow^.BorderTop, MouseX, MouseY);
  281. if (MouseX >= 0) and (MouseY >= 0) and
  282. (MouseX < Video.ScreenWidth) and (MouseY < Video.ScreenHeight) and
  283. ((MouseX <> OldMouseX) or (MouseY <> OldmouseY))
  284. then begin
  285. // //writeln('mousemove:',Mousex,'/',Mousey,' oldbutt:',OldButtons);
  286. // Drawing is very slow so when moving window it will drag behind
  287. // because the mouse events stack in the messageport
  288. // -> so we override move until messageport is empty or keyevent is fired
  289. SendMouse := True;
  290. MouseEvent := True;
  291. mes.Action := MouseActionMove;
  292. mes.Buttons := OldButtons;
  293. mes.X := MouseX;
  294. mes.Y := MouseY;
  295. //PutMouseEvent(me);
  296. end;
  297. end;
  298. IDCMP_RAWKEY: begin
  299. // mouse wheel up or down -> pgup and pgdown
  300. if ICode = 122 then
  301. ICode := 72;
  302. if ICode = 123 then
  303. ICode := 73;
  304. // get char from rawkey
  305. KeyUp := (ICode and IECODE_UP_PREFIX) <> 0; // is key up
  306. ICode := ICode and not IECODE_UP_PREFIX; // remove key up from ICode
  307. ie.ie_Class := IECLASS_RAWKEY;
  308. ie.ie_SubClass := 0;
  309. ie.ie_Code := ICode;
  310. ie.ie_Qualifier := IQual;
  311. ie.ie_NextEvent := nil;
  312. Buff[0] := #0;
  313. Ret := MapRawKey(@ie, @Buff[0], 1, nil);
  314. KeyCode := Ord(Buff[0]);
  315. KeySet^.KeyCode := Ord(Buff[0]); // if maprawkey does not work it still is 0
  316. KeySet^.ShiftState := LastShiftState; // shift state set before the case
  317. KeySet^.Flags := 0;
  318. if keyup then // we do not need key up events up to now
  319. begin
  320. KeySet^.Flags := KeySet^.Flags or kbReleased; // kbReleased does work but make strange effects
  321. SysPollKeyEvent := 0;
  322. Exit;
  323. end;
  324. // check our hard coed list if there is an entry -> leave it must be right ;)
  325. // F-keys, cursor, esc, del, ins, del, pgup, pgdown, pos, end, enter, tab
  326. if rcTableCode(IQual,rcTableIdx(ICode)) >= 0 then
  327. begin
  328. KeyCode := rcTableCode(IQual,rcTableIdx(ICode));
  329. KeySet^.KeyCode := KeyCode;
  330. KeySet^.Flags := kbPhys;
  331. end else
  332. begin
  333. // left alt or ctrl is pressed -> check for alternative Scancode -> commando
  334. if ((IQual and IEQUALIFIER_LALT) <> 0) or HasCtrl(IQual) then
  335. begin
  336. OldKeyCode := KeyCode; // save keycode if nothing found
  337. KeyCode := 0;
  338. ie.ie_Class := IECLASS_RAWKEY; // get keycode without qualifier easier case
  339. ie.ie_SubClass := 0;
  340. ie.ie_Code := ICode;
  341. ie.ie_Qualifier := 0;
  342. ie.ie_NextEvent := nil;
  343. Buff[0] := #0;
  344. Ret := MapRawKey(@ie, @Buff[0], 1, nil);
  345. if Ret > 0 then
  346. begin
  347. if ((IQual and IEQUALIFIER_LALT) <> 0) then // check left alt keycodes
  348. begin
  349. case Buff[0] of // Alt - keys already defined
  350. 'a': KeyCode := kbAltA shl 8;
  351. 'b': KeyCode := kbAltB shl 8;
  352. 'c': KeyCode := kbAltC shl 8;
  353. 'd': KeyCode := kbAltD shl 8;
  354. 'e': KeyCode := kbAltE shl 8;
  355. 'f': KeyCode := kbAltF shl 8;
  356. 'g': KeyCode := kbAltG shl 8;
  357. 'h': KeyCode := kbAltH shl 8;
  358. 'i': KeyCode := kbAltI shl 8;
  359. 'j': KeyCode := kbAltJ shl 8;
  360. 'k': KeyCode := kbAltK shl 8;
  361. 'l': KeyCode := kbAltL shl 8;
  362. 'm': KeyCode := kbAltM shl 8;
  363. 'n': KeyCode := kbAltN shl 8;
  364. 'o': KeyCode := kbAltO shl 8;
  365. 'p': KeyCode := kbAltP shl 8;
  366. 'q': KeyCode := kbAltQ shl 8;
  367. 'r': KeyCode := kbAltR shl 8;
  368. 's': KeyCode := kbAltS shl 8;
  369. 't': KeyCode := kbAltT shl 8;
  370. 'u': KeyCode := kbAltU shl 8;
  371. 'v': KeyCode := kbAltV shl 8;
  372. 'w': KeyCode := kbAltW shl 8;
  373. 'x': KeyCode := kbAltX shl 8;
  374. 'y': KeyCode := kbAltY shl 8;
  375. 'z': KeyCode := kbAltZ shl 8;
  376. end;
  377. end else
  378. begin
  379. case Buff[0] of // ctrl - keys defined in FreeVision/drivers.pas -> so here direct numbers
  380. 'a': KeyCode := $1E01;
  381. 'b': KeyCode := $3002;
  382. 'c': KeyCode := $2E03;
  383. 'd': KeyCode := $2004;
  384. 'e': KeyCode := $1205;
  385. 'f': KeyCode := $2106;
  386. 'g': KeyCode := $2207;
  387. 'h': KeyCode := $2308;
  388. 'i': KeyCode := $1709;
  389. 'j': KeyCode := $240a;
  390. 'k': KeyCode := $250b;
  391. 'l': KeyCode := $260c;
  392. 'm': KeyCode := $320d;
  393. 'n': KeyCode := $310e;
  394. 'o': KeyCode := $180f;
  395. 'p': KeyCode := $1910;
  396. 'q': KeyCode := $1011;
  397. 'r': KeyCode := $1312;
  398. 's': KeyCode := $1F13;
  399. 't': KeyCode := $1414;
  400. 'u': KeyCode := $1615;
  401. 'v': KeyCode := $2F16;
  402. 'w': KeyCode := $1117;
  403. 'x': KeyCode := $2D18;
  404. 'y': KeyCode := $1519;
  405. 'z': KeyCode := $2C1A;
  406. end;
  407. end;
  408. end;
  409. if KeyCode <= 0 then // nothing found restore keycode
  410. KeyCode := OldKeyCode;
  411. KeySet^.KeyCode := KeyCode;
  412. KeySet^.Flags := kbPhys;
  413. end;
  414. end;
  415. if keycode <= 0 then
  416. begin
  417. KeySet^.KeyCode := 0;
  418. KeyCode := 0;
  419. end;
  420. //writeln('raw keycode: ',iMsg^.code, ' -> $', IntToHex(keycode,4), ' ret: ', ret);
  421. end;
  422. else begin
  423. KeyCode := 0;
  424. end;
  425. end;
  426. end else
  427. Break;
  428. until (not MouseEvent);
  429. //
  430. if SendMouse then
  431. begin
  432. PutMouseEvent(mes);
  433. OldMouseX:=Mousex;
  434. OldmouseY:=Mousey;
  435. end;
  436. if KeyCode <= 0 then // no keycode found then also delete flags and shiftstate
  437. SysPollKeyEvent := 0
  438. else
  439. KeyQueue:=SysPollKeyEvent;
  440. end;
  441. function SysGetKeyEvent: TKeyEvent;
  442. var
  443. Res: TKeyEvent;
  444. me: TMouseEvent;
  445. begin
  446. Res := 0;
  447. if VideoWindow <> nil then
  448. begin
  449. if KeyQueue <> 0 then
  450. begin
  451. SysGetKeyEvent := KeyQueue;
  452. KeyQueue := 0;
  453. Exit;
  454. end;
  455. repeat
  456. WaitPort(VideoWindow^.UserPort);
  457. Res := SysPollKeyEvent;
  458. until Res <> 0;
  459. end else
  460. begin
  461. me.Action := MouseActionDown;
  462. me.Buttons := MouseRightButton;
  463. PutMouseEvent(me);
  464. end;
  465. SysGetKeyEvent := Res;
  466. end;
  467. {function SysTranslateKeyEvent(KeyEvent: TKeyEvent): TKeyEvent;
  468. begin
  469. end;}
  470. function SysGetShiftState: Byte;
  471. begin
  472. //writeln('SysgetShiftState:',hexstr(LastShiftState,2));
  473. SysGetShiftState := LastShiftState;
  474. end;
  475. var
  476. waitTPort: PMsgPort;
  477. waitTimer: PTimeRequest;
  478. waitTimerFired: boolean;
  479. function WaitForSystemEvent(millisec: Integer): boolean;
  480. var
  481. windowbit: PtrUInt;
  482. timerbit: PtrUInt;
  483. recvbits: PtrUInt;
  484. begin
  485. WaitForSystemEvent:=false;
  486. if waitTPort = nil then
  487. begin
  488. { this really shouldn't happen, but it's enough to avoid a
  489. crash if the timer init failed during startup }
  490. if VideoWindow <> nil then
  491. WaitPort(VideoWindow^.UserPort);
  492. exit;
  493. end;
  494. windowbit:=0;
  495. if VideoWindow <> nil then
  496. begin
  497. if not IsMsgPortEmpty(VideoWindow^.UserPort) then
  498. begin
  499. WaitForSystemEvent:=true;
  500. exit;
  501. end;
  502. windowbit:=1 shl (VideoWindow^.UserPort^.mp_SigBit);
  503. end;
  504. timerbit:=0;
  505. if waitTPort <> nil then
  506. timerbit:=1 shl (waitTPort^.mp_SigBit);
  507. if (windowbit or timerbit) = 0 then exit;
  508. if not waitTimerFired then
  509. begin
  510. waitTimer^.tr_node.io_Command:=TR_ADDREQUEST;
  511. waitTimer^.tr_time.tv_secs:=millisec div 1000;
  512. waitTimer^.tr_time.tv_micro:=(millisec mod 1000) * 1000;
  513. SendIO(PIORequest(waitTimer));
  514. waitTimerFired:=true;
  515. end;
  516. recvbits:=Wait(windowbit or timerbit);
  517. if (recvbits and windowbit) > 0 then
  518. WaitForSystemEvent:=true;
  519. if waitTimerFired then
  520. begin
  521. AbortIO(PIORequest(waitTimer));
  522. WaitIO(PIORequest(waitTimer));
  523. SetSignal(0,timerbit);
  524. waitTimerFired:=false;
  525. end;
  526. end;
  527. procedure DoneSystemEventWait;
  528. begin
  529. if assigned(waitTimer) then
  530. begin
  531. if waitTimerFired then
  532. begin
  533. AbortIO(PIORequest(waitTimer));
  534. WaitIO(PIORequest(waitTimer));
  535. waitTimerFired:=false;
  536. end;
  537. CloseDevice(PIORequest(waitTimer));
  538. DeleteIORequest(PIORequest(waitTimer));
  539. waitTimer:=nil;
  540. end;
  541. if assigned(waitTPort) then
  542. begin
  543. DeleteMsgPort(waitTPort);
  544. waitTPort:=nil;
  545. end;
  546. end;
  547. procedure InitSystemEventWait;
  548. var
  549. initOK: boolean;
  550. begin
  551. waitTimerFired:=false;
  552. waitTPort:=CreateMsgPort();
  553. if assigned(waitTPort) then
  554. begin
  555. waitTimer:=PTimeRequest(CreateIORequest(waitTPort,sizeof(TTimeRequest)));
  556. if assigned(waitTimer) then
  557. begin
  558. if OpenDevice(TIMERNAME,UNIT_VBLANK,PIORequest(waitTimer),0) = 0 then
  559. begin
  560. initOK:=true;
  561. waitTimerFired:=false;
  562. end;
  563. end;
  564. end;
  565. if not initOK then begin
  566. {* this really shouldn't happen if everything is OK with the system *}
  567. SysDebugLn('FPC RTL-Console: SystemEventWait Initialization failed!');
  568. DoneSystemEventWait;
  569. end;
  570. end;
  571. const
  572. SysKeyboardDriver : TKeyboardDriver = (
  573. InitDriver : @SysInitKeyBoard;
  574. DoneDriver : @SysDoneKeyBoard;
  575. GetKeyevent : @SysGetKeyEvent;
  576. PollKeyEvent : @SysPollKeyEvent;
  577. GetShiftState : @SysGetShiftState;
  578. // TranslateKeyEvent : @SysTranslateKeyEvent;
  579. TranslateKeyEvent : Nil;
  580. TranslateKeyEventUnicode : Nil;
  581. GetEnhancedKeyEvent : Nil;
  582. PollEnhancedKeyEvent : Nil;
  583. );
  584. initialization
  585. SetKeyBoardDriver(SysKeyBoardDriver);
  586. InitSystemEventWait;
  587. finalization
  588. DoneSystemEventWait;
  589. end.