Code Library
Home Submit Free Hosting Link To Us Contacts

Pascal Keyboard

Pascal Keyboard Pascal Pascal Keyboard Download (.zip)



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.




  • PascalKeyboard


Tatet