123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 2006 by Karoly Balogh
- Keyboard unit for MorphOS and Amiga and AROS
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- unit Keyboard;
- interface
- {$i keybrdh.inc}
- {
- Amiga specific function, waits for a system event to occur on the
- message port of the window. This is mainly used in Free Vision to
- give up the Task's timeslice instead of dos.library/Delay() which
- blocks the event handling and ruins proper window refreshing among
- others
- input: specify a timeout to wait for an event to arrive. this is the
- maximum timeout. the function might return earlier or even
- immediately if there's an event. it's specified in milliseconds
- result: boolean if there is an incoming system event. false otherwise
- }
- function WaitForSystemEvent(millisec: Integer): boolean;
- implementation
- uses
- video, exec, intuition, inputevent, mouse, sysutils, keymap, timer;
- {$i keyboard.inc}
- {$i keyscan.inc}
- var
- LastShiftState : Byte; {set by handler for PollShiftStateEvent}
- OldMouseX : LongInt;
- OldmouseY : LongInt;
- OldButtons: Word;
- procedure SysInitKeyboard;
- begin
- // writeln('sysinitkeyboard');
- {$IFDEF MORPHOS}
- InitKeyMapLibrary;
- {$ENDIF}
- LastShiftState := 0;
- OldMouseX := -1;
- OldmouseY := -1;
- OldButtons := 0;
- end;
- procedure SysDoneKeyboard;
- begin
- end;
- function IsMsgPortEmpty(Port: PMsgPort): Boolean; inline;
- begin
- IsMsgPortEmpty := (Port^.mp_MsgList.lh_TailPred = @(Port^.mp_MsgList));
- end;
- var
- KeyQueue: TKeyEvent;
- type
- RawCodeEntry = record
- rc,n,s,c,a : Word; { raw code, normal, shift, ctrl, alt }
- end;
- const
- RCTABLE_MAXIDX = 24;
- RawCodeTable : array[0..RCTABLE_MAXIDX] of RawCodeEntry =
- (
- (rc: 66; n: $0F09; s: $0F00; c: $9400; a: $A500; ), // TAB
- (rc: 68; n: $1C0D; s: $1C0D; c: $1C0A; a: $1C0D; ), // Enter // shift, alt?
- (rc: 69; n: $011B; s: $011B; c: $011B; a: $0100; ), // ESC // shift?
- (rc: 70; n: $5300; s: $0700; c: $A300; a: $A200; ), // Delete
- (rc: 71; n: $5200; s: $0500; c: $0400; a: $A200; ), // Insert
- (rc: 72; n: $4900; s: $4900; c: $8400; a: $9900; ), // PgUP // shift?
- (rc: 73; n: $5100; s: $5100; c: $7600; a: $A100; ), // PgDOWN // shift?
- (rc: 76; n: $4800; s: $4800; c: $8D00; a: $9800; ), // UP // shift?
- (rc: 77; n: $5000; s: $5000; c: $9100; a: $A000; ), // DOWN // shift?
- (rc: 78; n: $4D00; s: $4D00; c: $7400; a: $9D00; ), // RIGHT // shift?
- (rc: 79; n: $4B00; s: $4B00; c: $7300; a: $9B00; ), // LEFT // shift?
-
- (rc: 80; n: $3B00; s: $5400; c: $5E00; a: $6800; ), // F1
- (rc: 81; n: $3C00; s: $5500; c: $5F00; a: $6900; ), // F2
- (rc: 82; n: $3D00; s: $5600; c: $6000; a: $6A00; ), // F3
- (rc: 83; n: $3E00; s: $5700; c: $6100; a: $6B00; ), // F4
- (rc: 84; n: $3F00; s: $5800; c: $6200; a: $6C00; ), // F5
- (rc: 85; n: $4000; s: $5900; c: $6300; a: $6D00; ), // F6
- (rc: 86; n: $4100; s: $5A00; c: $6400; a: $6E00; ), // F7
- (rc: 87; n: $4200; s: $5B00; c: $6500; a: $6F00; ), // F8
- (rc: 88; n: $4300; s: $5C00; c: $6600; a: $7000; ), // F9
- (rc: 89; n: $4400; s: $5D00; c: $6700; a: $7100; ), // F10
- (rc: 75; n: $8500; s: $8700; c: $8900; a: $8B00; ), // F11
- (rc: 76; n: $8600; s: $8800; c: $8A00; a: $8C00; ), // F12
- (rc: 112; n: $4700; s: $4700; c: $7700; a: $9700; ),// Home // shift?
- (rc: 113; n: $4F00; s: $4F00; c: $7500; a: $9F00; ) // End // shift?
- );
- function rcTableIdx(rc: LongInt): LongInt;
- var
- Counter: LongInt;
- begin
- rcTableIdx := -1;
- Counter := 0;
- while (RawCodeTable[Counter].rc <> rc) and (Counter <= RCTABLE_MAXIDX) do
- Inc(Counter);
- if (Counter <= RCTABLE_MAXIDX) then
- rcTableIdx := Counter;
- end;
- function HasShift(IQual: Word): Boolean; inline;
- begin
- HasShift := ((IQual and IEQUALIFIER_LSHIFT) <> 0) or
- ((IQual and IEQUALIFIER_RSHIFT) <> 0);
- end;
- function HasCtrl(IQual: Word): Boolean; inline;
- begin
- HasCtrl := ((IQual and IEQUALIFIER_CONTROL) <> 0);
- end;
- function HasAlt(IQual: Word): Boolean; inline;
- begin
- HasAlt := ((IQual and IEQUALIFIER_LALT) <> 0) or
- ((IQual and IEQUALIFIER_RALT) <> 0);
- end;
- function rcTableCode(IQual: Word; Idx: LongInt): LongInt;
- begin
- if (Idx < 0) or (Idx > RCTABLE_MAXIDX) then
- begin
- rcTableCode := -1;
- Exit;
- end;
- if HasShift(IQual) then
- rcTableCode:=RawCodeTable[Idx].s
- else
- if HasCtrl(IQual) then
- rcTableCode:=RawCodeTable[Idx].c
- else
- if HasAlt(IQual) then
- rcTableCode:=RawCodeTable[Idx].a
- else
- rcTableCode:=RawCodeTable[Idx].n;
- end;
- procedure setShiftState(IQual: Word);
- begin
- LastShiftState := 0;
- if ((IQual and IEQUALIFIER_LSHIFT) <> 0) then
- LastShiftState := LastShiftState or $01;
- if ((IQual and IEQUALIFIER_RSHIFT) <> 0) then
- LastShiftState := LastShiftState or $02;
- if HasCtrl(IQual) then
- LastShiftState := LastShiftState or $04;
- if HasAlt(IQual) then
- LastShiftState := LastShiftState or $08;
- if ((IQual and IEQUALIFIER_NUMERICPAD) <> 0) then
- LastShiftState := LastShiftState or $20;
- if ((IQual and IEQUALIFIER_CAPSLOCK) <> 0) then
- LastShiftState := LastShiftState or $40;
- end;
- function SysPollKeyEvent: TKeyEvent;
- var
- MouseEvent: Boolean; // got a mouseevent -> do not leave cycle
- SendMouse: Boolean; // we got a (or many) mouse move send the last one
- mes: TMouseEvent; // save mouse message send after cycle -> prevent mouse move stacking
- me: TMouseEvent;
- KeyCode: LongInt;
- OldKeyCode: LongInt;
- KeySet: ^TKeyRecord; // points to result to set fields directly
- Ret: LongInt;
- //
- iMsg: PIntuiMessage;
- ICode: Word; // save items from Message
- IQual: Word;
- IClass: Longword;
- MouseX: LongInt;
- MouseY: LongInt;
- KeyUp: Boolean; // Event is a key up event
- Buff: array[0..19] of Char;
- ie: TInputEvent; // for mapchar
- begin
- KeyCode := 0;
- SysPollKeyEvent := 0;
- KeySet := @SysPollKeyEvent;
- FillChar(me, SizeOf(TMouseEvent), 0);
- if KeyQueue <> 0 then
- begin
- SysPollKeyEvent := KeyQueue;
- Exit;
- end;
- SendMouse := False;
- repeat
- MouseEvent := False;
- if VideoWindow <> nil then
- begin
- if IsMsgPortEmpty(videoWindow^.UserPort) then
- Break;
- end else
- Exit;
- PMessage(iMsg) := GetMsg(VideoWindow^.UserPort);
- if (iMsg <> nil) then
- begin
- ICode := iMsg^.Code;
- IQual := iMsg^.Qualifier;
- IClass := iMsg^.iClass;
- MouseX := iMsg^.MouseX;
- MouseY := iMsg^.MouseY;
- ReplyMsg(PMessage(iMsg)); // fast reply to system
- SetShiftState(IQual); // set Shift state qualifiers. do this for all messages we get.
- // main event case
- case (IClass) of
- IDCMP_ACTIVEWINDOW: begin
- GotActiveWindow;
- end;
- IDCMP_INACTIVEWINDOW: begin
- // force cursor off. we stop getting IntuiTicks when
- // the window is inactive, so the blinking stops.
- ToggleCursor(true);
- GotInactiveWindow;
- end;
- IDCMP_INTUITICKS: begin
- ToggleCursor(false);
- TranslateToCharXY(MouseX - VideoWindow^.BorderLeft, MouseY - VideoWindow^.BorderTop, MouseX, MouseY);
- if (MouseX >= 0) and (MouseY >= 0) and
- (MouseX < Video.ScreenWidth) and (MouseY < Video.ScreenHeight) and
- ((MouseX <> OldMouseX) or (MouseY <> OldmouseY))
- then begin
- // //writeln('mousemove:',Mousex,'/',Mousey,' oldbutt:',OldButtons);
- // Drawing is very slow so when moving window it will drag behind
- // because the mouse events stack in the messageport
- // -> so we override move until messageport is empty or keyevent is fired
- SendMouse := True;
- MouseEvent := True;
- mes.Action := MouseActionMove;
- mes.Buttons := OldButtons;
- mes.X := MouseX;
- mes.Y := MouseY;
- //PutMouseEvent(me);
- end;
- end;
- IDCMP_CLOSEWINDOW: begin
- //writeln('got close');
- GotCloseWindow;
- end;
- IDCMP_CHANGEWINDOW: begin
- GotResizeWindow;
- end;
- IDCMP_REFRESHWINDOW: begin
- GotRefreshWindow;
- end;
- IDCMP_MOUSEBUTTONS: begin
- MouseEvent := True;
- TranslateToCharXY(MouseX - videoWindow^.BorderLeft, MouseY - videoWindow^.BorderTop, MouseX, MouseY);
- me.x := MouseX;
- me.y := MouseY;
- case ICode of
- SELECTDOWN: begin
- //writeln('left down!');
- me.Action := MouseActionDown;
- OldButtons := OldButtons or MouseLeftButton;
- me.Buttons := OldButtons;
- PutMouseEvent(me);
- end;
- SELECTUP: begin
- //writeln('left up!');
- me.Action := MouseActionUp;
- OldButtons := OldButtons and (not MouseLeftButton);
- me.Buttons := OldButtons;
- PutMouseEvent(me);
- end;
- MENUDOWN: begin
- //writeln('right down!');
- me.Action := MouseActionDown;
- OldButtons := OldButtons or MouseRightButton;
- me.Buttons := OldButtons;
- PutMouseEvent(me);
- end;
- MENUUP: begin
- //writeln('right up!');
- me.Action := MouseActionUp;
- OldButtons := OldButtons and (not MouseRightButton);
- me.Buttons := OldButtons;
- PutMouseEvent(me);
- end;
- end;
- //writeln('Buttons: ' , me.Buttons);
- end;
- IDCMP_MOUSEMOVE: begin
- { IDCMP_MOUSEMOVE is disabled now in the video unit,
- according to autodocs INTUITICKS should be enough
- to handle most moves, esp. in a "textmode" app }
- TranslateToCharXY(MouseX - VideoWindow^.BorderLeft, MouseY - VideoWindow^.BorderTop, MouseX, MouseY);
- if (MouseX >= 0) and (MouseY >= 0) and
- (MouseX < Video.ScreenWidth) and (MouseY < Video.ScreenHeight) and
- ((MouseX <> OldMouseX) or (MouseY <> OldmouseY))
- then begin
- // //writeln('mousemove:',Mousex,'/',Mousey,' oldbutt:',OldButtons);
- // Drawing is very slow so when moving window it will drag behind
- // because the mouse events stack in the messageport
- // -> so we override move until messageport is empty or keyevent is fired
- SendMouse := True;
- MouseEvent := True;
- mes.Action := MouseActionMove;
- mes.Buttons := OldButtons;
- mes.X := MouseX;
- mes.Y := MouseY;
- //PutMouseEvent(me);
- end;
- end;
- IDCMP_RAWKEY: begin
- // mouse wheel up or down -> pgup and pgdown
- if ICode = 122 then
- ICode := 72;
- if ICode = 123 then
- ICode := 73;
- // get char from rawkey
- KeyUp := (ICode and IECODE_UP_PREFIX) <> 0; // is key up
- ICode := ICode and not IECODE_UP_PREFIX; // remove key up from ICode
- ie.ie_Class := IECLASS_RAWKEY;
- ie.ie_SubClass := 0;
- ie.ie_Code := ICode;
- ie.ie_Qualifier := IQual;
- ie.ie_NextEvent := nil;
- Buff[0] := #0;
- Ret := MapRawKey(@ie, @Buff[0], 1, nil);
- KeyCode := Ord(Buff[0]);
- KeySet^.KeyCode := Ord(Buff[0]); // if maprawkey does not work it still is 0
- KeySet^.ShiftState := LastShiftState; // shift state set before the case
- KeySet^.Flags := 0;
- if keyup then // we do not need key up events up to now
- begin
- KeySet^.Flags := KeySet^.Flags or kbReleased; // kbReleased does work but make strange effects
- SysPollKeyEvent := 0;
- Exit;
- end;
- // check our hard coed list if there is an entry -> leave it must be right ;)
- // F-keys, cursor, esc, del, ins, del, pgup, pgdown, pos, end, enter, tab
- if rcTableCode(IQual,rcTableIdx(ICode)) >= 0 then
- begin
- KeyCode := rcTableCode(IQual,rcTableIdx(ICode));
- KeySet^.KeyCode := KeyCode;
- KeySet^.Flags := kbPhys;
- end else
- begin
- // left alt or ctrl is pressed -> check for alternative Scancode -> commando
- if ((IQual and IEQUALIFIER_LALT) <> 0) or HasCtrl(IQual) then
- begin
- OldKeyCode := KeyCode; // save keycode if nothing found
- KeyCode := 0;
- ie.ie_Class := IECLASS_RAWKEY; // get keycode without qualifier easier case
- ie.ie_SubClass := 0;
- ie.ie_Code := ICode;
- ie.ie_Qualifier := 0;
- ie.ie_NextEvent := nil;
- Buff[0] := #0;
- Ret := MapRawKey(@ie, @Buff[0], 1, nil);
- if Ret > 0 then
- begin
- if ((IQual and IEQUALIFIER_LALT) <> 0) then // check left alt keycodes
- begin
- case Buff[0] of // Alt - keys already defined
- 'a': KeyCode := kbAltA shl 8;
- 'b': KeyCode := kbAltB shl 8;
- 'c': KeyCode := kbAltC shl 8;
- 'd': KeyCode := kbAltD shl 8;
- 'e': KeyCode := kbAltE shl 8;
- 'f': KeyCode := kbAltF shl 8;
- 'g': KeyCode := kbAltG shl 8;
- 'h': KeyCode := kbAltH shl 8;
- 'i': KeyCode := kbAltI shl 8;
- 'j': KeyCode := kbAltJ shl 8;
- 'k': KeyCode := kbAltK shl 8;
- 'l': KeyCode := kbAltL shl 8;
- 'm': KeyCode := kbAltM shl 8;
- 'n': KeyCode := kbAltN shl 8;
- 'o': KeyCode := kbAltO shl 8;
- 'p': KeyCode := kbAltP shl 8;
- 'q': KeyCode := kbAltQ shl 8;
- 'r': KeyCode := kbAltR shl 8;
- 's': KeyCode := kbAltS shl 8;
- 't': KeyCode := kbAltT shl 8;
- 'u': KeyCode := kbAltU shl 8;
- 'v': KeyCode := kbAltV shl 8;
- 'w': KeyCode := kbAltW shl 8;
- 'x': KeyCode := kbAltX shl 8;
- 'y': KeyCode := kbAltY shl 8;
- 'z': KeyCode := kbAltZ shl 8;
- end;
- end else
- begin
- case Buff[0] of // ctrl - keys defined in FreeVision/drivers.pas -> so here direct numbers
- 'a': KeyCode := $1E01;
- 'b': KeyCode := $3002;
- 'c': KeyCode := $2E03;
- 'd': KeyCode := $2004;
- 'e': KeyCode := $1205;
- 'f': KeyCode := $2106;
- 'g': KeyCode := $2207;
- 'h': KeyCode := $2308;
- 'i': KeyCode := $1709;
- 'j': KeyCode := $240a;
- 'k': KeyCode := $250b;
- 'l': KeyCode := $260c;
- 'm': KeyCode := $320d;
- 'n': KeyCode := $310e;
- 'o': KeyCode := $180f;
- 'p': KeyCode := $1910;
- 'q': KeyCode := $1011;
- 'r': KeyCode := $1312;
- 's': KeyCode := $1F13;
- 't': KeyCode := $1414;
- 'u': KeyCode := $1615;
- 'v': KeyCode := $2F16;
- 'w': KeyCode := $1117;
- 'x': KeyCode := $2D18;
- 'y': KeyCode := $1519;
- 'z': KeyCode := $2C1A;
- end;
- end;
- end;
- if KeyCode <= 0 then // nothing found restore keycode
- KeyCode := OldKeyCode;
- KeySet^.KeyCode := KeyCode;
- KeySet^.Flags := kbPhys;
- end;
- end;
- if keycode <= 0 then
- begin
- KeySet^.KeyCode := 0;
- KeyCode := 0;
- end;
- //writeln('raw keycode: ',iMsg^.code, ' -> $', IntToHex(keycode,4), ' ret: ', ret);
- end;
- else begin
- KeyCode := 0;
- end;
- end;
- end else
- Break;
- until (not MouseEvent);
- //
- if SendMouse then
- begin
- PutMouseEvent(mes);
- OldMouseX:=Mousex;
- OldmouseY:=Mousey;
- end;
- if KeyCode <= 0 then // no keycode found then also delete flags and shiftstate
- SysPollKeyEvent := 0
- else
- KeyQueue:=SysPollKeyEvent;
- end;
- function SysGetKeyEvent: TKeyEvent;
- var
- Res: TKeyEvent;
- me: TMouseEvent;
- begin
- Res := 0;
- if VideoWindow <> nil then
- begin
- if KeyQueue <> 0 then
- begin
- SysGetKeyEvent := KeyQueue;
- KeyQueue := 0;
- Exit;
- end;
- repeat
- WaitPort(VideoWindow^.UserPort);
- Res := SysPollKeyEvent;
- until Res <> 0;
- end else
- begin
- me.Action := MouseActionDown;
- me.Buttons := MouseRightButton;
- PutMouseEvent(me);
- end;
- SysGetKeyEvent := Res;
- end;
- {function SysTranslateKeyEvent(KeyEvent: TKeyEvent): TKeyEvent;
- begin
- end;}
- function SysGetShiftState: Byte;
- begin
- //writeln('SysgetShiftState:',hexstr(LastShiftState,2));
- SysGetShiftState := LastShiftState;
- end;
- var
- waitTPort: PMsgPort;
- waitTimer: PTimeRequest;
- waitTimerFired: boolean;
- function WaitForSystemEvent(millisec: Integer): boolean;
- var
- windowbit: PtrUInt;
- timerbit: PtrUInt;
- recvbits: PtrUInt;
- begin
- WaitForSystemEvent:=false;
- if waitTPort = nil then
- begin
- { this really shouldn't happen, but it's enough to avoid a
- crash if the timer init failed during startup }
- if VideoWindow <> nil then
- WaitPort(VideoWindow^.UserPort);
- exit;
- end;
- windowbit:=0;
- if VideoWindow <> nil then
- begin
- if not IsMsgPortEmpty(VideoWindow^.UserPort) then
- begin
- WaitForSystemEvent:=true;
- exit;
- end;
- windowbit:=1 shl (VideoWindow^.UserPort^.mp_SigBit);
- end;
- timerbit:=0;
- if waitTPort <> nil then
- timerbit:=1 shl (waitTPort^.mp_SigBit);
- if (windowbit or timerbit) = 0 then exit;
- if not waitTimerFired then
- begin
- waitTimer^.tr_node.io_Command:=TR_ADDREQUEST;
- waitTimer^.tr_time.tv_secs:=millisec div 1000;
- waitTimer^.tr_time.tv_micro:=(millisec mod 1000) * 1000;
- SendIO(PIORequest(waitTimer));
- waitTimerFired:=true;
- end;
- recvbits:=Wait(windowbit or timerbit);
- if (recvbits and windowbit) > 0 then
- WaitForSystemEvent:=true;
- if waitTimerFired then
- begin
- AbortIO(PIORequest(waitTimer));
- WaitIO(PIORequest(waitTimer));
- SetSignal(0,timerbit);
- waitTimerFired:=false;
- end;
- end;
- procedure DoneSystemEventWait;
- begin
- if assigned(waitTimer) then
- begin
- if waitTimerFired then
- begin
- AbortIO(PIORequest(waitTimer));
- WaitIO(PIORequest(waitTimer));
- waitTimerFired:=false;
- end;
- CloseDevice(PIORequest(waitTimer));
- DeleteIORequest(PIORequest(waitTimer));
- waitTimer:=nil;
- end;
- if assigned(waitTPort) then
- begin
- DeleteMsgPort(waitTPort);
- waitTPort:=nil;
- end;
- end;
- procedure InitSystemEventWait;
- var
- initOK: boolean;
- begin
- waitTimerFired:=false;
- waitTPort:=CreateMsgPort();
- if assigned(waitTPort) then
- begin
- waitTimer:=PTimeRequest(CreateIORequest(waitTPort,sizeof(TTimeRequest)));
- if assigned(waitTimer) then
- begin
- if OpenDevice(TIMERNAME,UNIT_VBLANK,PIORequest(waitTimer),0) = 0 then
- begin
- initOK:=true;
- waitTimerFired:=false;
- end;
- end;
- end;
- if not initOK then begin
- {* this really shouldn't happen if everything is OK with the system *}
- SysDebugLn('FPC RTL-Console: SystemEventWait Initialization failed!');
- DoneSystemEventWait;
- end;
- end;
- const
- SysKeyboardDriver : TKeyboardDriver = (
- InitDriver : @SysInitKeyBoard;
- DoneDriver : @SysDoneKeyBoard;
- GetKeyevent : @SysGetKeyEvent;
- PollKeyEvent : @SysPollKeyEvent;
- GetShiftState : @SysGetShiftState;
- // TranslateKeyEvent : @SysTranslateKeyEvent;
- TranslateKeyEvent : Nil;
- TranslateKeyEventUnicode : Nil;
- GetEnhancedKeyEvent : Nil;
- PollEnhancedKeyEvent : Nil;
- );
- initialization
- SetKeyBoardDriver(SysKeyBoardDriver);
- InitSystemEventWait;
- finalization
- DoneSystemEventWait;
- end.
|