Mahlzeit
da ich jetzt mal endlich Zeit habe wieder was mit Pascal zu programmieren, brauche ich doch noch ein wenig Nachhilfe...
Es geht um das Auslesen des Tastaturpuffers. Wenn ich eine Taste gedrueckt habe, kann ich ja entweder am Port $60 oder im AX Register den Scancode der Taste auslesen. An den Adressen $0417 und $0418 sehe ich die Statusbits der Strg, Alt usw. Tasten.
Wie mach ich das aber in (sauberem) Assembler, den Tastaturpuffer nach Auslesen wieder zu leeren? Sonst funktioniert das Polling bei immer nur bis die erste Taste gedrueckt wurde
Ein kleines Beispiel wuerde mir da auf die Spruenge helfen
Den bisherigen Quellcode haenge ich gleich mal an oder versuche ihn hier einzubetten.
Beispiel 1: damit habe erstmal angefangen, die Funktion der Tastaturabfrage zu verstehen und zu sehen, was an den Adressen 417h und 418h passiert
Program KEYBTEST; {* This Program will output the keyboard
{* scan codes. Use the Function "ScanCode"
{* in your Program once you know the codes
{* For each keypress *}
Uses
CRT, Dos;
VAR
wKeyCode: WORD;
bKey417 : BYTE;
bKey418 : BYTE;
liCount : LONGINT;
Function Byte2Hex(numb : Byte): String; { Converts Byte to hex String }
Const
HexChars : Array[0..15] of Char = '0123456789ABCDEF';
begin
Byte2Hex[0] := #2;
Byte2Hex[1] := HexChars[numb shr 4];
Byte2Hex[2] := HexChars[numb and 15];
end; { Byte2Hex }
FUNCTION Byte2Dual(numb: BYTE): STRING;
VAR
DualByte: STRING;
cHilf : STRING;
bHilf : BYTE;
bTeiler : BYTE;
BEGIN
DualByte:=''; bTeiler:=128;
FOR bHilf:=1 TO 8 DO BEGIN
{ WRITELN(bTeiler); }
cHilf:='';
STR(numb DIV bTeiler,cHilf);
DualByte:=DualByte+cHilf;
numb:=numb MOD bTeiler;
bTeiler:=bTeiler DIV 2;
END;
Byte2Dual:=DualByte;
END;
Function Numb2Hex(numb : Word): String; { Converts Word to hex String.}
begin
Numb2Hex := Byte2Hex(hi(numb)) + Byte2Hex(lo(numb));
end; { Numb2Hex }
FUNCTION IsKeyPressed: BOOLEAN;
BEGIN
{ Aus Beispiel xyz... scheint aber falsch zu sein }
IsKeyPressed := ((MEM[$40:$17] AND $0F) > 0) OR (MEM[$40:$18] > 0);
END;
FUNCTION GetScanCode: WORD;
VAR
wCode: WORD;
BEGIN
ASM
MOV AH,$10
INT $16
MOV wCode,AX
END;
GetScanCode:=wCode;
end;
{ VORSICHT!!! Funktioniert noch nicht richtig... }
FUNCTION PollScanCode: WORD;
VAR
wCode: WORD;
BEGIN
ASM
MOV AH,$11
INT $16
MOV wCode,AX
END;
PollScanCode:=wCode;
end;
FUNCTION Key_Shift_Right(bScanCode :BYTE): BOOLEAN;
BEGIN
(* Byte $0417 Bit 0 *)
Key_Shift_Right:=NOT((bScanCode AND $01)=0);
END;
FUNCTION Key_Shift_Left(bScanCode :BYTE): BOOLEAN;
BEGIN
(* Byte $0417 Bit 1 *)
Key_Shift_Left:=NOT((bScanCode AND $02)=0);
END;
FUNCTION Key_Crtl(bScanCode :BYTE): BOOLEAN;
BEGIN
(* Byte $0417 Bit 2 *)
Key_Crtl:=NOT((bScanCode AND $04)=0);
END;
FUNCTION Key_Alt(bScanCode :BYTE): BOOLEAN;
BEGIN
(* Byte $0417 Bit 3 *)
Key_Alt:=NOT((bScanCode AND $08)=0);
END;
FUNCTION Key_Scroll_Lock(bScanCode :BYTE): BOOLEAN;
BEGIN
(* Byte $0417 Bit 4 *)
Key_Scroll_Lock:=NOT((bScanCode AND $10)=0);
END;
FUNCTION Key_Num_Lock(bScanCode :BYTE): BOOLEAN;
BEGIN
(* Byte $0417 Bit 5 *)
Key_Num_Lock:=NOT((bScanCode AND $20)=0);
END;
FUNCTION Key_Caps_Lock(bScanCode :BYTE): BOOLEAN;
BEGIN
(* Byte $0417 Bit 6 *)
Key_Caps_Lock:=NOT((bScanCode AND $40)=0);
END;
FUNCTION Key_Insert(bScanCode :BYTE): BOOLEAN;
BEGIN
(* Byte $0417 Bit 7 *)
Key_Insert:=NOT((bScanCode AND $80)=0);
END;
BEGIN
liCount:=0;
CLRSCR;
WRITELN('<Esc> oder <Crtl> + <Break> zum Beenden...');
REPEAT
DELAY(10); INC(liCount,1); GOTOXY(72,1); WRITELN(liCount:8);
wKeyCode:=GetScanCode;
{ wKeyCode:=PollScanCode; }
bKey417:=MEM[$40:$17];
bKey418:=MEM[$40:$18];
{ IF (IsKeyPressed) THEN BEGIN }
WRITELN('ÚÄ Register AH ÂÄ Register AL ¿');
WRITELN('³ ',Byte2Dual(HI(wKeyCode)):12,' ³ ',Byte2Dual(LO(wKeyCode)):12,' ³');
WRITELN('³ ',Byte2Hex(HI(wKeyCode)):12,' ³ ',Byte2Hex(LO(wKeyCode)):12,' ³ ');
WRITELN('ÃÄÄ Byte $0417 ÅÄÄ Byte $0418 ´');
WRITELN('³ ',Byte2Dual(MEM[$40:$17]):12,' ³ ',Byte2Dual(MEM[$40:$18]):12,' ³');
WRITELN('ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ');
WRITELN('Umschalt Rechts: ',Key_Shift_Right(bKey417):8);
WRITELN('Umschalt Links : ',Key_Shift_Left(bKey417):8);
WRITELN('Strg-Taste : ',Key_Crtl(bKey417):8);
WRITELN('Alt-Taste : ',Key_Alt(bKey417):8);
WRITELN('Scroll Lock : ',Key_Scroll_Lock(bKey417):8);
WRITELN('Num Lock : ',Key_Num_Lock(bKey417):8);
WRITELN('Caps Lock : ',Key_Caps_Lock(bKey417):8);
WRITELN('Insert Mode : ',Key_Insert(bKey417):8);
WRITELN('Scancode im Register AX: ',wKeyCode:8);
WRITELN('Taste gedrueckt?',IsKeyPressed:8);
{ !! Tastaturpuffer leeren fehlt noch !! }
{ END; (* IF (IsKeyPressed) *) }
UNTIL (wKeyCode=283);
END.
Alles anzeigen
Beispiel 2 mit Port $60 und einer EmptyKeyBuffer Funktion. Ich moechte aber diese haesslichen Inline-Anweisungen loswerden. Pascal Programme mit diesem Inline-Code laufen nicht auf Windows NT Systemen. Sauberes Assembler hingegen geht ohne Probleme auch auf NT/2000/XP...
PROGRAM KEYTEST2;
USES
CRT;
VAR
progende: BOOLEAN;
flag : BYTE;
anschlag: WORD;
liCount : LONGINT;
PROCEDURE KeyPortON;
{ Abfrage auf Port[$60] an}
ASSEMBLER;
ASM
MOV AX,19
INT 9H
END;
PROCEDURE KeyPortOFF;
ASSEMBLER;
ASM
MOV AX,3
INT 16H
END;
PROCEDURE EmptyKeyBuffer;
BEGIN
INLINE($FA);
MEMW[$40:$1A]:=MEMW[$40:$1C];
INLINE($FB);
END;
BEGIN
TEXTMODE(3);
liCount:=0;
progende:=FALSE;
flag:=0;
anschlag:=0;
GOTOXY(30,13); WRITE('...Testausgabe...');
KeyPortON;
REPEAT
INC(liCount,1); GOTOXY(70,1); WRITE(liCount:8);
EmptyKeyBuffer;
GOTOXY(1,1); WRITE(PORT[$60]:8);
GOTOXY(1,2); WRITE(MEM[$40:$17]:8,':',MEM[$40:$18]:8);
GOTOXY(1,3); WRITE(MEMW[$40:$1A]:8,':',MEMW[$40:$1C]:8);
GOTOXY(1,5);
CASE PORT[$60] OF 28: IF (flag=0) THEN BEGIN
WRITE('Enter'); CLREOL;
INC(anschlag,1);
WRITE(' Anschlaege: ',anschlag);
flag:=1;
END; (* IF *)
15: WRITE('Tabulator');
87: WRITE('F11');
88: WRITE('F12');
1: BEGIN
WRITE('Esc');
progende:=TRUE;
END;
END;
DELAY(10); flag:=0;
UNTIL (progende=TRUE); { PORT[$60]=1; } (* ESC *)
KeyPortOFF;
{ READLN; }
END.
Alles anzeigen
Die Port $60 Geschichte laeuft ab PC AT und aufwaerts, aber (laut Aussage meines Pascal Kompendiums) nicht mehr auf PC XT. Ich habe zwar "nur" 486er hier stehen, moechte aber die XTs ungern von meinem Programmen ausschliessen.