Pascal Keyboard

Keyboard

Unit KeyBoard;

{ Ž¡ëç­® ª« ¢¨ âãà  ¯®áë« ¥â ᨬ¢®«ë ¢ ª®¬¯ìîâ¥à }
{ á ¬ ªá¨¬ «ì­®© ᪮à®áâìî 4 èâ㪨 ¢ ᥪ㭤ã. }
{ —â®¡ë ¨£àã誠 ­¥ ¯à®áâ ¨¢ «  ¢ ®¦¨¤ ­¨¨ ¢¢®¤  á ª« ¢¨ âãàë }
{ ­ã¦­® ॠ«¨§®¢ âì á«¥¤ãî騩  «£®à¨â¬: }
{ 1) ¢ ­ ç «¥ ¯à®£à ¬¬ë ¤®¯ãáâ¨âì, çâ® ¢á¥ ª« ¢¨è¨ ®â¯ã饭ë }
{    ¢ 横«¥ ¯à®£à ¬¬ë: }
{ 2) áç¨â âì ­ ¦ â묨 ⥠ª« ¢¨è¨, ª®â®àë¥ ­¥ ®â¯ã饭ë }
{ 3) ¯®  ­ «®£¨¨ áç¨â âì ®â¯ã饭­ë¬¨ ­¥ ­ ¦ âë¥ }
{ ‘®¡á⢥­­® íâ®â ¬®¤ã«ì ¨ ¯®¬®£ ¥â ॠ«¨§®¢ âì ᥩ  «£®à¨â¬: }
{ Set_Handler -> 1) }
{ New_Handler -> 2), 3) }

Interface

{ ‡¤¥áì ᪠­ª®¤ë ¯®ç⨠¢á¥å ª« ¢¨è }

Const
  sEsc          =       1;
  s1            =       2;
  s2            =       3;
  s3            =       4;
  s4            =       5;
  s5            =       6;
  s6            =       7;
  s7            =       8;
  s8            =       9;
  s9            =     $0A;
  s0            =     $0B;
  sMinus        =     $0C;              { - _ }
  sEqual        =     $0D;              { = + }
  sBackSpace    =     $0E;
  sTab          =     $0F;
  sQ            =     $10;
  sW            =     $11;
  sE            =     $12;
  sR            =     $13;
  sT            =     $14;
  sY            =     $15;
  sU            =     $16;
  sI            =     $17;
  sO            =     $18;
  sP            =     $19;
  sLBraket      =     $1A;             (* [ { *)
  sRBraket      =     $1B;             (* ] } *)
  sEnter        =     $1C;
  sCtrl         =     $1D;
  sA            =     $1E;
  sS            =     $1F;
  sD            =     $20;
  sF            =     $21;
  sG            =     $22;
  sH            =     $23;
  sJ            =     $24;
  sK            =     $25;
  sL            =     $26;
  sSemicolon    =     $27;              { ; :  }
  sQuote        =     $28;              { ' "  }
  sApostrophe   =     $29;              { ` ~  }
  sLShift       =     $2A;
  sSlash        =     $2B;              { \ |  }
  sZ            =     $2C;
  sX            =     $2D;
  sC            =     $2E;
  sV            =     $2F;
  sB            =     $30;
  sN            =     $31;
  sM            =     $32;
  sComma        =     $33;              { , <  }
  sPoint        =     $34;              { . >  }
  sBackSlash    =     $35;              { / ?  }
  sRShift       =     $36;
  sAsteriks     =     $37;              { *  ­  æ¨ä஢®© ª« ¢¨ âãॠ}
  sAlt          =     $38;
  sSpace        =     $39;              { ¯à®¡¥« }
  sCapsLock     =     $3A;
  sF1           =     $3B;
  sF2           =     $3C;
  sF3           =     $3D;
  sF4           =     $3E;
  sF5           =     $3F;
  sF6           =     $40;
  sF7           =     $41;
  sF8           =     $42;
  sF9           =     $43;
  sF10          =     $44;
  sNumLock      =     $45;
  sScrollLock   =     $46;
  sHome         =     $47;
  sUp           =     $48;
  sPageUp       =     $49;
  sGrayMinus    =     $4A;              { -  ­  æ¨ä஢®© ª« ¢¨ âãॠ}
  sLeft         =     $4B;
  sFive         =     $4C;              { 5  ­  æ¨ä஢®© ª« ¢¨ âãॠ}
  sRight        =     $4D;
  sGrayPlus     =     $4E;              { +  ­  æ¨ä஢®© ª« ¢¨ âãॠ}
  sEnd          =     $4F;
  sDown         =     $50;
  sPageDown     =     $51;
  sInsert       =     $52;
  sDelete       =     $53;
  sF11          =     $57;
  sF12          =     $58;

Var
  KeyMap : Array [0..$7F] of Boolean;   { ‘¬¥é¥­¨¥-᪠­ª®¤ ª« ¢¨è¨, TRUE - }
                                        { ­ ¦ â  ᥩç á, FALSE - ®â¯ã饭  }
  SymMap : Array [0..$7F] of Char;      { ‘¬¥é¥­¨¥-᪠­ª®¤ ª« ¢¨è¨, }
                                        { ᮤ¥à¦¨¬®¥ - ASCII-ᨬ¢®«ë ¤«ï ª« ¢¨è }

Procedure Set_Handler;
{ “áâ ­ ¢«¨¢ ¥â ­®¢ë© ®¡à ¡®â稪 ª« ¢¨ âãà­®£® ¯à¥à뢠­¨ï, }
{ ª®£¤  ­®¢ë© ®¡à ¡®â稪  ªâ¨¢¥­, â® …‚އŒŽ†Ž ¯®«ì§®¢ âìáï }
{ KeyPressed, ReadKey ¨ Read,   â ª¦¥ ®áâ ­ ¢«¨¢ âì ¯à®£à ¬¬ã }
{ ¯® Ctrl+C (Ctrl+Break) ¨«¨ ¥¥ ®â« ¦¨¢ âì. }
{ KeyPressed ¨ ReadKey ¨¬¥îâ  ­ «®£¨ - ᬮâਠ­¨¦¥ }

Procedure Remove_Handler;
{ ‚®§¢à é ¥â áâ àë© ®¡à ¡®â稪 ª« ¢¨ âãà­®£® }
{ ¯à¥à뢠­¨ï ­  ¥£® § ª®­­®¥ ¬¥áâ® }

Procedure WaitForACSReleased;
{ †¤¥â ®â¯ã᪠­¨ï Alt,Ctrl,Shift; ¨á¯®«ì§ã¥âáï ’Ž‹œŠŽ ……„ }
{ ãáâ ­®¢ª®© ­®¢®£® ®¡à ¡®â稪  ª« ¢¨ âãà­®£® ¯à¥à뢠­¨ï }

Function KeyPressedNow : Boolean;
{ ‚®§¢à é ¥â TRUE ¥á«¨ ¢ „€›‰ ¬®¬¥­â ¢à¥¬¥­¨ }
{ ¤¥©á⢨⥫쭮 ­ ¦ â  å®âï¡ë ®¤­  ª« ¢¨è , ¨­ ç¥ ¢®§¢à é ¥â FALSE. }
{ ˆá¯®«ì§ã¥âáï ¢¬¥áâ¥ á ¬ áᨢ ¬¨ KeyMap ¨ SymMap }

Function KeyPressed2 : Boolean;
{ ®«­ë©  ­ «®£ ä-樨 KeyPressed ¨§ ¬®¤ã«ï CRT. }

Function ReadScan : Byte;
{ €­ «®£ ä-樨 ReadKey (¬®¤ã«ì CRT). }
{  §­¨æ  ¢ ⮬, çâ® íâ  ä-æ¨ï ¢®§¢à é ¥â }
{ ­¥ ᨬ¢®« ª« ¢¨è¨,   ¥¥ ᪠­ª®¤, ¯®§¢®«ïï }
{ ¤®¡à âìáï ¤® ª ¦¤®© ª« ¢¨è¨. }
{ ˆá¯®«ì§ã¥âáï ¢¬¥á⥠á KeyPressed2 }

Function ReadChar : Char;
{ €­ «®£ ä-樨 ReadKey (¬®¤ã«ì CRT). }
{  §­¨æ  ¢ ⮬, çâ® íâ  ä-æ¨ï ¢®§¢à é ¥â }
{ ᨬ¢®« ª« ¢¨è¨ ¡¥§ ãç¥â  á®áâ®ï­¨© Alt,Ctrl,Shift ¨ Caps Lock. }
{ …᫨ ­ ¦ â ï ª« ¢¨è  ­¥ ¨¬¥¥â ­  ᥡ¥ ᨬ¢®« , â® ¢®§¢à é ¥âáï }
{ ­ã«¥¢®© ᨬ¢®«, ­¨ ® ª ª¨å à áè¨à¥­­ëå ª®¤ å §¤¥áì à¥ç¨ ¡ëâì ­¥ }
{ ¬®¦¥â. ˆá¯®«ì§ã¥âáï ¢¬¥á⥠á KeyPressed2 }

Procedure ClearKeyboardBuf;
{ Žç¨é ¥â ª®«ì楢®© ¡ãä¥à, ¨á¯®«ì§ã¥¬ë© ä-æ¨ï¬¨ KeyPressedNow, KeyPressed2, }
{ ReadScan ¨ ReadChar }

Implementation

Uses DOS;

Const
  Old_Handler : Pointer = Nil;          { ‘ á®åà ­¨¬  ¤à¥á áâ à®£® ®¡à ¡®â稪  }
  KeyBufSize            = 16;           { Š« ¢¨ âãà­ë© ¡ãä¥à ¡ã¤¥â ᮤ¥à¦ âì }
                                        { ¬ ªá¨¬ã¬ 16 ᪠­ª®¤®¢ }

  Symbs : Array [sEsc..sSpace] of Char =
    #27'1234567890-='#8#9'QWERTYUIOP[]'#13#0'ASDFGHJKL;''`'#0'\'+
    'ZXCVBNM,./'#0'*'#0' ';

Var
  KeyBuf : Array [0..KeyBufSize] of Byte;       { Š®«ì楢®© ª« ¢¨ âãà­ë© ¡ãä¥à }
  BufHead,                                      { ƒ®«®¢  ¡ãä¥à  }
  BufTail : Word;                               { •¢®áâ ¡ãä¥à  }
  KeyCount : Byte;                              { Š®«-¢® ᪠­ª®¤®¢ ª« ¢¨è }
                                                { ¢ ¡ãä¥à¥ }

Procedure New_Handler; Interrupt; Assembler;
{ Using assembler because we need a fast interrupt-handling routine }
Asm
  Push  AX
  Push  BX
  In    AL, 060h
  Mov   AH, AL
  And   AL, 07Fh                                { AL = ‘ª ­ª®¤ }
  LEA   BX, KeyMap
  Add   BL, AL
  AdC   BH, 0
  Test  AH, 080h
  JNZ   @released                               { ‘â à訩 ¡¨â - ä« £ ®â¯ã᪠­¨ï }
  Mov   Byte Ptr [BX], TRUE                     { Š« ¢¨è  ¡ë«  ­ ¦ â  }
  Cmp   KeyCount, KeyBufSize
  JE    @done                                   { ãä¥à ¡¨âª®¬ ­ ¡¨â }
  LEA   BX, KeyBuf
  Add   BX, BufTail
  Mov   [BX], AL                                { ‘®åà ­¨«¨ ᪠­ª®¤ ¢ KeyBuf }
  Inc   KeyCount                                { More keys avaible to read }
  Inc   BufTail                                 { ‘«¥¤ãîé ï ¯®§¨æ¨ï ¤«ï á®åà ­¥­¨ï }
  Cmp   BufTail, KeyBufSize
  JNE   @done
  Mov   BufTail, 0                              { ‘ª®à४â¨à®¢ «¨ ¯®§¨æ¨î }
  Jmp   @done
@released:
  Mov   Byte Ptr [BX], FALSE                    { Š« ¢¨è  ¡ë«  ®â¯ã饭  }
@done:
  Mov   AL, 020h                                { ‘®®¡é¨«¨ ª®­â஫«¥àã }
  Out   020h, AL                                { ¯à¥à뢠­¨©, çâ® ¯à¥à뢠­¨¥ }
                                                { ®¡à ¡®â ­® }
  Pop   BX
  Pop   AX
End;

Procedure Set_Handler;
Begin
  If Old_Handler <> Nil then Exit;
  FillChar (KeyMap, $80, False);        { ˆ§­ ç «ì­® áç¨â ¥¬ ¢á¥ ª« ¢¨è¨ }
  KeyCount := 0;                        { ®â¯ã饭­ë¬¨ }
  BufHead := 0;                         { -//- }
  BufTail := 0;                         { -//- }
  GetIntVec (9, Old_Handler);
  SetIntVec (9, @New_Handler)
End;

Procedure Remove_Handler;
Begin
  If Old_Handler = Nil then Exit;
  SetIntVec (9, Old_Handler);
  Old_Handler := Nil
End;

Procedure WaitForACSReleased;
Begin
  While Mem[$40:$17] and $0F <> 0 do
End;

Function KeyPressedNow : Boolean; Assembler;
{    áᥬ¡«¥à¥ à ¡®â ¥â èãáâ॥, 祬 ­   áª «¥ }
Asm
  Mov   AX, DS
  Mov   ES, AX
  LEA   DI, KeyMap+1                            {  ç¨­ ¥¬ á Escape }
  Mov   CX, 058h                                { ‚ᥠª« ¢¨è¨ ¯«îá F11 ¨ F12 }
  Mov   AL, FALSE                               { à¥¤¯®«®¦¨«¨, çâ® ¯ãáâ® }
  CLD
  RepE  ScaSB                                   { ‘ª ­­¨à㥬 ¬ áᨢ KeyMap }
  JE    @end                                    { ãáâ® }
  Mov   AL, TRUE                                { —â®-â® ­ ¦ â® }
@end:
End;

Function KeyPressed2 : Boolean;
Begin
  KeyPressed2 := KeyCount<>0                    { ãä¥à ­¥ ¯ãáâ }
End;

Function ReadScan : Byte;
Begin
  While KeyCount=0 do;
  ReadScan := KeyBuf[BufHead];
  Inc (BufHead);                                { ‘¬¥é¥­¨¥ á«¥¤ãî饩 ª« ¢¨è¨ }
  If BufHead = KeyBufSize then BufHead := 0;
  Dec (KeyCount)                                { ޤ­ã ª« ¢¨èã ¤®«®© }
End;

Function ReadChar : Char;
Begin
  ReadChar := SymMap[ReadScan]
End;

Procedure ClearKeyboardBuf;
Begin
  Asm PushF; CLI End;
  BufHead := BufTail;
  KeyCount := 0;
  Asm PopF End
End;

Var I : Byte;

Begin
  { ‡ ¯®«­¥­¨¥ ¬ áᨢ  ᨬ¢®«®¢ }
  FillChar (SymMap, $80, 0);
  For I := sEsc to sSpace do
    SymMap[I] := Symbs[I];
  SymMap[sGrayMinus] := '-';
  SymMap[sGrayPlus] := '+'
End.