unit keybrd;


interface

type
  TKeyMap = array [0..127] of Char;
  string10 = string[10];
  TKeyState = Record
      Normal, Shift, Ctrl, Alt : word; //hence why arrow keys trip 3-4 interrupts.
     end;

{Unix uses 64K for line length, for some ungodly reason, well, thats C for you.
anyway, we don't need this AND good programmers don't use lines that exceed length that anyway.
there is such a thing as word wrapping in pascal.

shell programming is generally a bad idea, anyhow.scripts should only run
a subset of the programming language and are intended as shortcuts. A better programmer would 
offer those shortcuts and reduce some overhead.
}

var
  ScrollDisabled,NumKeys:boolean; //turns off screen scrolling.NOTE: must use gotoxy now.
  // Also activates magica numkeys on keypad.NOTE: might change the middle key chunk too.
  
  
{Some internal only scancodes}
const KbShiftUp    = $f0;
      KbShiftLeft  = $f1;
      KbShiftRight = $f2;
      KbShiftDown  = $f3;
      KbShiftHome  = $f4;
      KbShiftEnd   = $f5;

{ list of all dos scancode for key giving 0 as char }

   kbNoKey       = $00;
   kbAltEsc      = $01;  {Alt+Esc = scancode 01, ascii code 0.}
   kbEsc         = $01;  {Esc     = scancode 01, ascii code 27.}
   kbAltSpace    = $02;
   kbCtrlIns     = $04;
   kbShiftIns    = $05;
   kbCtrlDel     = $06;
   kbShiftDel    = $07;
   kbAltBack     = $08;
   kbAltShiftBack= $09;
   kbShiftTab    = $0F;
   kbAltQ        = $10;
   kbAltW        = $11;
   kbAltE        = $12;
   kbAltR        = $13;
   kbAltT        = $14;
   kbAltY        = $15;
   kbAltU        = $16;
   kbAltI        = $17;
   kbAltO        = $18;
   kbAltP        = $19;
   kbAltLftBrack = $1A;
   kbAltRgtBrack = $1B;
   kbAltA        = $1E;
   kbAltS        = $1F;
   kbAltD        = $20;
   kbAltF        = $21;
   kbAltG        = $22;
   kbAltH        = $23;
   kbAltJ        = $24;
   kbAltK        = $25;
   kbAltL        = $26;
   kbAltSemiCol  = $27;
   kbAltQuote    = $28;
   kbAltOpQuote  = $29;
   kbAltBkSlash  = $2B;
   kbAltZ        = $2C;
   kbAltX        = $2D;
   kbAltC        = $2E;
   kbAltV        = $2F;
   kbAltB        = $30;
   kbAltN        = $31;
   kbAltM        = $32;
   kbAltComma    = $33;
   kbAltPeriod   = $34;
   kbAltSlash    = $35;
   kbAltGreyAst  = $37;
   kbF1          = $3B;
   kbF2          = $3C;
   kbF3          = $3D;
   kbF4          = $3E;
   kbF5          = $3F;
   kbF6          = $40;
   kbF7          = $41;
   kbF8          = $42;
   kbF9          = $43;
   kbF10         = $44;
   kbHome        = $47;
   kbUp          = $48;
   kbPgUp        = $49;
   kbLeft        = $4B;
   kbCenter      = $4C;
   kbRight       = $4D;
   kbAltGrayPlus = $4E;
   kbend         = $4F;
   kbDown        = $50;
   kbPgDn        = $51;
   kbIns         = $52;
   kbDel         = $53;
   kbShiftF1     = $54;
   kbShiftF2     = $55;
   kbShiftF3     = $56;
   kbShiftF4     = $57;
   kbShiftF5     = $58;
   kbShiftF6     = $59;
   kbShiftF7     = $5A;
   kbShiftF8     = $5B;
   kbShiftF9     = $5C;
   kbShiftF10    = $5D;
   kbCtrlF1      = $5E;
   kbCtrlF2      = $5F;
   kbCtrlF3      = $60;
   kbCtrlF4      = $61;
   kbCtrlF5      = $62;
   kbCtrlF6      = $63;
   kbCtrlF7      = $64;
   kbCtrlF8      = $65;
   kbCtrlF9      = $66;
   kbCtrlF10     = $67;
   kbAltF1       = $68;
   kbAltF2       = $69;
   kbAltF3       = $6A;
   kbAltF4       = $6B;
   kbAltF5       = $6C;
   kbAltF6       = $6D;
   kbAltF7       = $6E;
   kbAltF8       = $6F;
   kbAltF9       = $70;
   kbAltF10      = $71;
   kbCtrlPrtSc   = $72;
   kbCtrlLeft    = $73;
   kbCtrlRight   = $74;
   kbCtrlend     = $75;
   kbCtrlPgDn    = $76;
   kbCtrlHome    = $77;
   kbAlt1        = $78;
   kbAlt2        = $79;
   kbAlt3        = $7A;
   kbAlt4        = $7B;
   kbAlt5        = $7C;
   kbAlt6        = $7D;
   kbAlt7        = $7E;
   kbAlt8        = $7F;
   kbAlt9        = $80;
   kbAlt0        = $81;
   kbAltMinus    = $82;
   kbAltEqual    = $83;
   kbCtrlPgUp    = $84;
   kbF11         = $85;
   kbF12         = $86;
   kbShiftF11    = $87;
   kbShiftF12    = $88;
   kbCtrlF11     = $89;
   kbCtrlF12     = $8A;
   kbAltF11      = $8B;
   kbAltF12      = $8C;
   kbCtrlUp      = $8D;
   kbCtrlMinus   = $8E;
   kbCtrlCenter  = $8F;
   kbCtrlGreyPlus= $90;
   kbCtrlDown    = $91;
   kbCtrlTab     = $94;
   kbAltHome     = $97;
   kbAltUp       = $98;
   kbAltPgUp     = $99;
   kbAltLeft     = $9B;
   kbAltRight    = $9D;
   kbAltend      = $9F;
   kbAltDown     = $A0;
   kbAltPgDn     = $A1;
   kbAltIns      = $A2;
   kbAltDel      = $A3;
   kbAltTab      = $A5;

   {kbHome, kbUp, kbPgUp,Missing, kbLeft,
    kbCenter, kbRight, kbAltGrayPlus, kbend,
    kbDown, kbPgDn, kbIns, kbDel }
  CtrlArrow : array [kbHome..kbDel] of byte =
   {($77,$8d,$84,$8e,$73,$8f,$74,$90,$75,$91,$76);}
   (kbCtrlHome,kbCtrlUp,kbCtrlPgUp,kbNoKey,kbCtrlLeft,
    kbCtrlCenter,kbCtrlRight,kbAltGrayPlus,kbCtrlEnd,
    kbCtrlDown,kbCtrlPgDn,kbCtrlIns,kbCtrlDel);
  AltArrow : array [kbHome..kbDel] of byte =
   (kbAltHome,kbAltUp,kbAltPgUp,kbNoKey,kbAltLeft,
    kbCenter,kbAltRight,kbAltGrayPlus,kbAltEnd,
    kbAltDown,kbAltPgDn,kbAltIns,kbAltDel);
  ShiftArrow : array [kbShiftUp..kbShiftEnd] of byte =
   (kbUp,kbLeft,kbRight,kbDown,kbHome,kbEnd);
var
  CommandBuffer: String = '';
  KeyChange : boolean;
  LastKey : byte;
  KeyData1 : array [1..$5F] of boolean;
  KeyData2 : array [1..$5F] of boolean;
  active : boolean;
  OldExit : pointer;
  CursorPosX: Word = 0;  //not a permanent setting.
  CursorPosY: Word = 0;
  Pause     : boolean;

const

KeyName1 : array [1..$5F] of string10 =
      ('Esc',      '1','2','3','4','5','6','7','8','9','0','-','=','Back',
       'Tab',      'Q','W','E','R','T','Y','U','I','O','P','[',']','Enter',
       'CtrlLeft', 'A','S','D','F','G','H','J','K','L',';','"','\',
       'ShiftLeft','\','Z','X','C','V','B','N','M',',','.','/','ShiftRight',
       'Pad*','AltLeft','Space','Caps',
       'F1','F2','F3','F4','F5','F6','F7','F8','F9','F10',
       'Num','Scroll',
       'Pad7','Pad8','Pad9','Pad-',
       'Pad4','Pad5','Pad6','Pad+',
       'Pad1','Pad2','Pad3','Pad0','Pad.',
        '','',
        '\','F11','F12','','','','','','','');
 KeyName2 : array [1..$5F] of string10 =
       ('','','','','','','','','','','','','','',
        '','','','','','','','','','','','','','PadEnter',
        'CtrlRight','','','','','','','','','','','','',
        '','','','','','','','','','','','Pad/',
        '','Print','AltRight','','',
        '','','','','','','','','','',
        'Pause','',
        'Home','Up','PgUp','',
        'Left','','Right','',
        'End','Down','PgDn',
        'Ins','Del',
        '','','','','','','',
        'WinLeft','WinRight','WinMenu','','');

//key scancode, not ch=#XX or 'r'...

KeyCodeEsc  = 1; KeyCodeTab    =15; KeyCodeCtrlLeft  =29; KeyCodeShiftLeft =42;
 KeyCode1    = 2; KeyCodeQ      =16; KeyCodeA         =30; KeyCodeBackSlashL=43;
 KeyCode2    = 3; KeyCodeW      =17; KeyCodeS         =31; KeyCodeZ         =44;
 KeyCode3    = 4; KeyCodeE      =18; KeyCodeD         =32; KeyCodeX         =45;
 KeyCode4    = 5; KeyCodeR      =19; KeyCodeF         =33; KeyCodeC         =46;
 KeyCode5    = 6; KeyCodeT      =20; KeyCodeG         =34; KeyCodeV         =47;
 KeyCode6    = 7; KeyCodeY      =21; KeyCodeH         =35; KeyCodeB         =48;
 KeyCode7    = 8; KeyCodeU      =22; KeyCodeJ         =36; KeyCodeN         =49;
 KeyCode8    = 9; KeyCodeI      =23; KeyCodeK         =37; KeyCodeM         =50;
 KeyCode9    =10; KeyCodeO      =24; KeyCodeL         =38; KeyCodeComma     =51;
 KeyCode0    =11; KeyCodeP      =25; KeyCodeColon     =39; KeyCodeDot       =52;
 KeyCodeMinus=12; KeyCodeOpenBr =26; KeyCodeDQuote    =40; KeyCodeSlash     =53;
 KeyCodeEqual=13; KeyCodeCloseBr=27; KeyCodeBackSlashR=41; KeyCodeShiftRight=54;
 KeyCodeBack =14; KeyCodeEnter  =28;

 KeyCodePadTimes = 55;
 KeyCodeAltLeft  = 56;
 KeyCodeSpace    = 57;
 KeyCodeCaps     = 58;

 KeyCodeF1       = 59;
 KeyCodeF2       = 60;
 KeyCodeF3       = 61;
 KeyCodeF4       = 62;
 KeyCodeF5       = 63;
 KeyCodeF6       = 64;
 KeyCodeF7       = 65;
 KeyCodeF8       = 66;
 KeyCodeF9       = 67;
 KeyCodeF10      = 68;

 KeyCodeNum      = 69;
 KeyCodeScroll   = 70;

 KeyCodePad7     = 71;   KeyCodePad4   = 75;  KeyCodePad1   = 79;
 KeyCodePad8     = 72;   KeyCodePad5   = 76;  KeyCodePad2   = 80;
 KeyCodePad9     = 73;   KeyCodePad6   = 77;  KeyCodePad3   = 81;
 KeyCodePadMinus = 74;   KeyCodePadPlus= 78;  KeyCodePad0   = 82;
                                              KeyCodePadDot = 83;

 KeyCodePadSlash = 86;
 KeyCodeF11      = 87;
 KeyCodeF12      = 88;

 KeyCode2PadEnter = 28;
 KeyCode2CtrlRight= 29;
 KeyCode2PadSlash = 53;
 KeyCode2Print    = 55;
 KeyCode2AltRight = 56;
 KeyCode2Pause    = 69;
 KeyCode2Home     = 71;
 KeyCode2Up       = 72;
 KeyCode2PgUp     = 73;
 KeyCode2Left     = 75;
 KeyCode2Right    = 77;
 KeyCode2End      = 79;
 KeyCode2Down     = 80;
 KeyCode2PgDown   = 81;
 KeyCode2Insert   = 82;
 KeyCode2Delete   = 83;
 KeyCode2WinLeft  = 91;
 KeyCode2WinRight = 92;
 KeyCode2WinMenu  = 93;


{Foreground and background color constants }
  Black         = 0;
  Blue          = 1;
  Green         = 2;
  Cyan          = 3;
  Red           = 4;
  Magenta       = 5;
  Brown         = 6;
  LightGrey     = 7;

{ Foreground color constants }
  DarkGray      = 8;
  LightBlue     = 9;
  LightGreen    = 10;
  LightCyan     = 11;
  LightRed      = 12;
  LightMagenta  = 13;
  Yellow        = 14;
  White         = 15;

 {Add-in for blinking} 
  Blink         = 128;


type
  TKeyEvent = Cardinal;
  TKeyRecord = packed record
    KeyCode : Word;
    ShiftState, Flags : Byte;
  end;

{ The structure of a TKeyEvent follows in LSB-MSB order:
  2 bytes: depending on flags either the physical representation of a key
           (under DOS scancode, ascii code pair), or the translated
           ASCII/unicode character
  1 byte:  shift-state when this key was pressed (or shortly after)
  1 byte:  flags, the following flags are defined:
           bit0-1
                   0: the lowest two bytes is the translated ASCII value
                   1: the lowest two bytes is the translated Unicode value
                      (wide-char)
                   2: the lowest two bytes is a function key, and the lowest
                      two bytes contains its platform independent code
                   3: the lowest two bytes is the physical representation
           bit2
                   0: the key is pressed
                   1: the key is released (This event is not guaranteed to occur on all platforms)
           bit3-7  undefined, should be 0


  If there are two keys returning the same char-code, there's no way to find
  out which one was pressed (Gray+ and Simple+). If you need to know which
  was pressed, you'll need to use the untranslated keycodes, which is system
  dependent. System dependent constants may be defined to cover those, with
  possibily having the same name (but different value). }

{ System independent function key codes }
const
  kbdF1        = $FF01;
  kbdF2        = $FF02;
  kbdF3        = $FF03;
  kbdF4        = $FF04;
  kbdF5        = $FF05;
  kbdF6        = $FF06;
  kbdF7        = $FF07;
  kbdF8        = $FF08;
  kbdF9        = $FF09;
  kbdF10       = $FF0A;
  kbdF11       = $FF0B;
  kbdF12       = $FF0C;
  kbdF13       = $FF0D;
  kbdF14       = $FF0E;
  kbdF15       = $FF0F;
  kbdF16       = $FF10;
  kbdF17       = $FF11;
  kbdF18       = $FF12;
  kbdF19       = $FF13;
  kbdF20       = $FF14;

  kbdLWin      = $FF15;
  kbdRWin      = $FF16;
  kbdApps      = $FF17;

  { $15 - $1F reserved for future Fxx keys }
  kbdHome      = $FF20;
  kbdUp        = $FF21;
  kbdPgUp      = $FF22;
  kbdLeft      = $FF23;
  kbdMiddle    = $FF24;
  kbdRight     = $FF25;
  kbdEnd       = $FF26;
  kbdDown      = $FF27;
  kbdPgDn      = $FF28;

  kbdInsert    = $FF29;
  kbdDelete    = $FF2A;
  { $2B - $2F reserved for future keypad keys }

  { possible flag values }
  kbASCII       = $00;
  kbUniCode     = $01;
  kbFnKey       = $02;
  kbPhys        = $03;

  kbReleased    = $04;

  { shiftstate flags }
  kbLeftShift   = 1;
  kbRightShift  = 2;
  kbShift       = kbLeftShift or kbRightShift;
  kbCtrl        = 4;
  kbAlt         = 8;

{ ---------------------------------------------------------------------
    Key names. Can be localized if needed.
  ---------------------------------------------------------------------}
  SShift       : Array [1..3] of string[5] = ('SHIFT','CTRL','ALT');
  SLeftRight   : Array [1..2] of string[5] = ('LEFT','RIGHT');
  SUnicodeChar : String = 'Unicode character ';
  SScanCode    : String = 'Key with scancode ';
  SUnknownFunctionKey : String = 'Unknown function key : ';
  SAnd         : String = 'AND';
  SKeyPad      : Array [0..($FF2F-kbdHome)] of string[6] =
                 ('Home','Up','PgUp','Left',
                  'Middle','Right','End','Down',
                  'PgDn','Insert','Delete','',
                  '','','','');

Type
  TKeyboardDriver = Record
    InitDriver : Procedure;
    DoneDriver : Procedure;
    GetKeyEvent : Function : TKeyEvent;
    PollKeyEvent : Function : TKeyEvent;
    GetShiftState : Function : Byte;
    TranslateKeyEvent : Function (KeyEvent: TKeyEvent): TKeyEvent;
    TranslateKeyEventUniCode : Function (KeyEvent: TKeyEvent): TKeyEvent;
  end;

procedure LoadKeyMap(const KeyMap,ShiftedKeyMap: TKeyMap);
procedure InstallKeyboard;

implementation

uses
  x86,irq,video,timer,commands; 

type
  TKeyStatus = (ksCtrl,ksAlt,ksShift,ksCapsLock,ksNumLock,ksScrollLock);
  TKeyStatusSet = set of TKeyStatus;

const
  USKeyMap: TKeyMap = (
    #00,{ 0 }
    #27,{ 1 - Esc }
    '1','2','3','4','5','6','7','8','9','0','-','=',{ 13 }
    #08,{ 14 - Backspace }
    #09,{ 15 - Tab }
    'q','w','e','r','t','y','u','i','o','p','[',']',{ 27 }
    #10,{ 28 - Enter }
    #00,{ 29 - Ctrl }
    'a','s','d','f','g','h','j','k','l',';',{ 39 }
    '''',{ 40 - ' }
    '`',{ 41 }
    #00,{ 42 - Left Shift }
    '\','z','x','c','v','b','n','m',',','.','/',{ 53 }
    #00,{ 54 - Right Shift }
    '*',{ 55 }
    #00,{ 56 - Alt }
    ' ',{ 57 - Space bar }
    #0,{ 58 - Caps lock }
    #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,{ 59 - F1 up to 68 - F10 }
    #0,{ 69 - Num lock}
    #0,{ Scroll Lock }
    #0,{ Home key }
    #0,{ Up Arrow }
    #0,{ Page Up }
    '-',
    #0,{ Left Arrow }
    #0,
    #0,{ Right Arrow }
    '+',
    #0,{ 79 - End key}
    #0,{ Down Arrow }
    #0,{ Page Down }
    #0,{ Insert Key }
    #0,{ Delete Key }
    #0,#0,#0,{ 86 }
    #0,{ F11 Key }
    #0,{ F12 Key }
    #0,{ All other keys are undefined }
    #0,{ 90 }
    #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,{ 100 }
    #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,{ 110 }
    #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,{ 120 }
    #0,#0,#0,#0,#0,#0,#0{ 127 }
  );

  ShiftedUSKeyMap: TKeyMap = (
    #00,{ 0 }
    #27,{ 1 - Esc }
    '!','@','#','$','%','^','&','*','(',')','_','+',{ 13 }
    #08,{ 14 - Backspace }
    #09,{ 15 - Tab }
    'Q','W','E','R','T','Y','U','I','O','P','{','}',{ 27 }
    #10,{ 28 - Enter }
    #00,{ 29 - Ctrl }
    'A','S','D','F','G','H','J','K','L',':',{ 39 }
    '"',{ 40 - ' }
    '~',{ 41 }
    #00,{ 42 - Left Shift }
    '|','Z','X','C','V','B','N','M','<','>','?',{ 53 }
    #00,{ 54 - Right Shift }
    '*',{ 55 - Numpad * }
    #00,{ 56 - Alt }
    ' ',{ 57 - Space bar }
    #0,{ 58 - Caps lock }
    #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,{ 59 - F1 up to 68 - F10 }
    #0,{ 69 - Num lock }
    #0,{ Scroll Lock }
    { 71 - 83 are numpad keys }
    #0,{ Home key (7) }
    #0,{ Up Arrow (8) }
    #0,{ Page Up (9) }
    '-',
    #0,{ Left Arrow (4) }
    #0,{ (5) }
    #0,{ Right Arrow (6) }
    '+',
    #0,{ End key (1) }
    #0,{ Down Arrow (2) }
    #0,{ Page Down (3) }
    #0,{ Insert Key (0) }
    #0,{ Delete Key (.) }
    { end of numpad keys }
    #0,#0,#0,{ 86 }
    #0,{ F11 Key }
    #0,{ F12 Key }
    { All other keys are undefined }
    #0,#0,{ 90 }
    #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,{ 100 }
    #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,{ 110 }
    #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,{ 120 }
    #0,#0,#0,#0,#0,#0,#0{ 127 }
  );

NumUSKeyMap: TKeyMap = (
    #00,{ 0 }
    #27,{ 1 - Esc }
    '1','2','3','4','5','6','7','8','9','0','-','=',{ 13 }
    #08,{ 14 - Backspace }
    #09,{ 15 - Tab }
    'q','w','e','r','t','y','u','i','o','p','[',']',{ 27 }
    #10,{ 28 - Enter }
    #00,{ 29 - Ctrl }
    'a','s','d','f','g','h','j','k','l',';',{ 39 }
    '''',{ 40 - ' }
    '`',{ 41 }
    #00,{ 42 - Left Shift }
    '\','z','x','c','v','b','n','m',',','.','/',{ 53 }
    #00,{ 54 - Right Shift }
    '*',{ 55 }
    #00,{ 56 - Alt }
    ' ',{ 57 - Space bar }
    #0,{ 58 - Caps lock }
    #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,{ 59 - F1 up to 68 - F10 }
    #0,{ 69 - Num lock}
    #0,{ Scroll Lock }
    // the magical num keys button happened.....
    '7',{ Home key }
    '8',{ Up Arrow }
    '9',{ Page Up }
    '-',
    '4',{ Left Arrow }
    #0,
    '6',{ Right Arrow }
    '+',
    '1',{ 79 - End key}
    '2',{ Down Arrow }
    '3',{ Page Down }
    '0',{ Insert Key }
    '.',{ Delete Key }
    #0,#0,#0,{ 86 }
    #0,{ F11 Key }
    #0,{ F12 Key }
    #0,{ All other keys are undefined }
    #0,{ 90 }
    #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,{ 100 }
    #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,{ 110 }
    #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,{ 120 }
    #0,#0,#0,#0,#0,#0,#0{ 127 }
  );

var
  KeyStatus: TKeyStatusSet; // Byte = 0;
  { // Old implementation using single byte and bitwise operation
    bit 0 = ctrl  
    bit 1 = alt
    bit 2 = shift
    bit 3 = caps lock
    bit 4 = num lock
    bit 5 = scroll lock
    bit 6 = ???
    bit 7 = ???
    
    --THIS ISNT RIGHT.IGNORED FOR NOW.  --Jazz
  }
  ActiveKeyMap,ActiveShiftedKeyMap: TKeyMap;
  textattr:byte;

//turn on/off keyboard.
procedure EnableConsole;
begin
 writeportb($64,$AE);
end;

procedure DisableConsole;
begin
 writeportb($64,$AD);
end;


function GetKeyEventShiftState(KeyEvent: TKeyEvent): Byte;
begin
  GetKeyEventShiftState := (KeyEvent and $00FF0000) shr 16;
end;

function IsFunctionKey(KeyEvent: TKeyEvent): Boolean;
begin
  IsFunctionKey := KeyEvent and $03000000 = $02000000;
end;


procedure LoadKeyMap(const KeyMap,ShiftedKeyMap: TKeyMap);
begin
//assume us, not specified.
  ActiveKeyMap:=USKeyMap;
  ActiveShiftedKeyMap:=ShiftedUSKeyMap;
end;

procedure FlipNumPad;

begin
if (NumKeys) then ActiveKeyMap:=NumUSKeyMap else if not (NumKeys) then ActiveKeyMap:=USKeyMap;
end;


procedure KeyboardHandler(var r: TRegisters);
var
  ScanCode: Byte;
  c: Char;
  old,i,x,y:integer;
begin

  // Read from the keyboard's data buffer
  ScanCode:=ReadPortB($60);
  if (ScanCode and $80)=0 then begin // 7th bit isn't set, a key has been pressed
    case ScanCode of 
      42,54: if not(ksShift in KeyStatus) then // Left and Right Shift
       
        Include(KeyStatus,ksShift);
      58: begin //if not(ksCapsLock in KeyStatus) then begin  
       //   Caps Lock = off

        //while ReadPortB($64) and 2=0 do begin; // Will break if keyboard isn't busy
        	WritePort($60,$ED); 
        	WritePort($60,$04); // Turns on Caps Lock light via controller in keyboard.[see docs]
        	
        	//Include(KeyStatus,ksCapsLock);
	   // end;
	  end;  
	  //Num Lock
	  69:begin
	       WritePort($60,$ED); 
           WritePort($60,$02); 
           if not(NumKeys) then NumKeys:=true
	       else if (NumKeys) then NumKeys:=false;
           FlipNumPad;	  
	  end;
	  //scroll lock hit
	  
	  70: begin
	        WritePort($60,$ED); 
        	WritePort($60,$01); 
	       
	       if not(ScrollDisabled) then ScrollDisabled:=true
	       else if (ScrollDisabled) then begin
	           ScrollDisabled:=false;
	  		   clrscr;
	  		   write('FPOS> ');
	  	   end;   
	  end;
	  53:begin
           if (ksCtrl in KeyStatus) and (ksAlt in KeyStatus) then begin
              clrscr;
              writeln('Going down in Five..Four..Three...');
              delay(90);
	          //graceful reset
	          restart;
      end;
      end else begin
        while ReadPortB($64) and 2=0 do begin; // Will break if keyboard isn't busy
        	WritePort($60,$ED);
       		WritePort($60,$04); //told you the above was flawed.....
      	  	Exclude(KeyStatus,ksCapsLock);
	    end;
     end;
  end;
    { Shift priority is higher than Caps Lock, why?
      Try switching the code and you'll understand }
    if ksShift in KeyStatus then // Shift = on
      c:=ActiveShiftedKeyMap[ScanCode]
    else if not(ksCapsLock in KeyStatus) then // Caps Lock = off
      c:=ActiveKeyMap[ScanCode]
    else // Caps Lock = on
      c:=UpCase(ActiveKeyMap[ScanCode]);
    // Handle characters
    case c of
      #8: begin // Backspace --BugFIX FINALLY on 071609 by Jazz
        
        Delete(CommandBuffer,Length(CommandBuffer),1);      
	     clreol;  //remind me to adjust this to not remove 'all' of the line....Jazz.
        write('FPOS> ');
		write(CommandBuffer);
        if Length(CommandBuffer)=0 then 
			beep;
	
      end;
      #10: begin // MARIO, THINK.  we hit ENTER or return.
        WriteChar(c); //do that. return.
        if CommandBuffer='#10' then begin 
			write('FPOS> ');
			exit;
			 //otherwise we write the form feed to the 'buffer' and recall the form feed with up and down keys.
			//very annoying glitch I might add..
	     end;
        ProcessCommand(CommandBuffer);
        if CommandBuffer<>'' then begin
          AddToHistory(CommandBuffer);
          CommandBuffer:='';
        end;
        write('FPOS> '); //leave this HERE. it says 'if buffer=(NULL) then...'
	// to take out what is above will cause that exact glitch to happen.

      end;
      #0: begin // Control characters
  	//line cleanup not needed, on *NIXes put out nasty control chars, as they based on ANSI AND WE already have BIOS 
        //handler as such. we dont have to deal with this garbage.

        ScanCode:=ReadPortB($60); 
        case ScanCode of   
          72: begin // Up arrow
	     	  CommandBuffer:=PreviousCommand;
	     	  clreol;
	     	  write('FPOS> ');
             	  write(CommandBuffer);
	     if Length(CommandBuffer)=0 then
	       beep;	             
          end;
          75: begin
		while (length(CommandBuffer)<>0) and (CurSorPosX>6) do begin	

			gotoxy(x-1,y); // Left arrow ,define a stop at beginning of line for this key.
		end;
	      beep;
	  end;
          77: begin
		while  CurSorPosX<length(CommandBuffer) do begin
			gotoxy(x+1,y); // Right arrow
		end;
		beep;
	  end;
          80: begin // Down arrow
	  		CommandBuffer:=NextCommand;
	        	clreol;
			write('FPOS> ');
                	write(NextCommand);
		if Length(CommandBuffer)=0 then
	     
	    	  beep;
          end;
	  56:begin //alt key
	  end;
	  15: tabulate; //anyone want some tab?
	

        end; //watch we dont exit prematurely with a escape code or unhandled keycode.
      end;
      else // Other characters, non function key
        if Length(CommandBuffer)<255 then begin // ShortString limit
          WriteChar(c);  
          CommandBuffer:=CommandBuffer+c;
        end else begin
          writechar(#10);
          textcolor(Red);
          write('Maximum command length is 255!');
          writechar(#10);
	      textcolor(LightGrey);
	      write('FPOS> ');
        end;
    end;
  end else begin // A key has been released
    // Turns off 7th bit
    ScanCode:=ScanCode and not $80;
    case ScanCode of { in bitwise, KeyStatus and $4<>0 }
      42,54: if ksShift in KeyStatus then
        Exclude(KeyStatus,ksShift);
    end;
  end;
  
end;


procedure InstallKeyboard;
begin
  write('Installing Keyboard...'#9#9);
  LoadKeyMap(USKeyMap,ShiftedUSKeyMap);
  InstallIrqHandler(1,@KeyboardHandler); 
  ResetCommands;
  writeln('[ OK ]');
end;



end.
