PROGRAM Typing_Tutor;

USES CRT, DOS;

TYPE ScreenArray = array[0..3999] of byte;

VAR x, y, Col, Row : byte;
    Ch : char;
    InitScrMem : ScreenArray;
    SavedMem   : ^ScreenArray;
    VideoStart : word;
    ScreenType : byte;

CONST KeysArr : array[1..64] of string[4] =

(' Esc',' F1 ',' F2 ',' F3 ',' F4 ',' F5 ',' F6 ',' F7 ',' F8 ',' F9 ', {  1..10 }
 ' F10',' F11',' F12',' `~ ',' 1  ',' 2  ',' 3  ',' 4  ',' 5  ',' 6  ', { 11..20 }
 ' 7  ',' 8  ',' 9  ',' 0  ',' -  ',' =  ',' \  ',' BS ',' Tab',' Q  ', { 21..30 }
 ' W  ',' E  ',' R  ',' T  ',' Y  ',' U  ',' I  ',' O  ',' P  ',' [  ', { 31..40 }
 ' ]  ',' A  ',' S  ',' D  ',' F  ',' G  ',' H  ',' J  ',' K  ',' L  ', { 41..50 }
 ' ;  ',' "  ',' Z  ',' X  ',' C  ',' V  ',' B  ',' N  ',' M  ',' ,  ', { 51..60 }
 ' .  ',' /  ',' Bar',' <Ù ');  { 61..64 }

Function DetectScreenType: byte;
   Var Regs : registers;
   Begin
      Regs.AH := $12;
      Regs.BL := $10;
      intr($10,Regs);

      if Regs.BL <> $10 then
         begin
         Regs.AH := $12;
         Regs.BL := $10;
         intr($10,Regs);
         if Regs.CL = $09 then
            begin
            DetectScreenType := 1;               { coloured VGA/EGA }
            VideoStart := $B800;
            end
         else
            begin
            DetectScreenType := 2;               { mono VGA }
            VideoStart := $B000;
            end;
         end
      else
         DetectScreenType := 0;                  { not EGA/VGA }

      SavedMem := ptr(VideoStart,0);
   End;

Procedure Say(x,y: byte; S: string);
Begin gotoxy(x,y); write(S); End;

Procedure Colour(FC,BC: byte);
Begin
   if ScreenType in [1,2] then textcolor(FC+128)
      else textcolor(FC);
   textbackground(BC);
End;

Procedure InsentiveColor(Insentive: boolean);
   Var Regs : registers;
   Begin
      Regs.AX := $1003;
      if Insentive then Regs.BL := 0
         else Regs.BL := 1;
      intr($10,Regs);
   End;

Procedure SaveInitScr;
Begin
   move(SavedMem^,InitScrMem,4000);
End;

Procedure RestoreInitScr;
Begin
   if ScreenType in [1,2] then InsentiveColor(false);
   move(InitScrMem,SavedMem^,4000);
   window(1,1,80,25); textcolor(7); textbackground(0);
   gotoxy(1,25); writeln;
End;

Procedure Put(x,y,m : byte);
   Begin
      colour(0,15);
      say(x,y,KeysArr[m]);
      delay(40);
      if ScreenType = 1 then colour(15,5) else colour(15,0);
      say(x,y,KeysArr[m]);
      if ScreenType = 1 then colour(15,1) else colour(15,0);
   End;

Procedure Display_Char;
   Begin
     if ScreenType = 1 then colour(13,1) else colour(13,0);
     say(Col,Row,Ch);
     if ScreenType = 1 then colour(15,1) else colour(15,0);
     inc(Col);
     if Col = 77 then
        begin
        Col := 1;
        inc(Row);
        if Row = 22 then
           begin
           window(1,19,80,24);
           clrscr;
           window(3,3,80,24);
           Col := 1; Row := 18;
           gotoxy(Col,Row);
           end;
        end;
   End;

BEGIN

ScreenType := DetectScreenType;
SaveInitScr;
if ScreenType in [1,2] then InsentiveColor(true);

Col := 1; Row := 18;
if ScreenType = 1 then colour(14,1) else colour(14,0);
clrscr;
colour(0,15); gotoxy(1,1); write(' Alt_Q = Quit ³',' ':12);
colour(1,15); write('T Y P I N G     T U T O R');
colour(0,15); write(' ':12,'³ Alt_C = Clear ');
colour(15+blink,7); gotoxy(1,25); write('':12,'Copyright(c) by Thanh Hai ~12/1994 - www.thanhhai.com'); clreol;
window(3,3,80,24);
if ScreenType = 1 then colour(15,5) else colour(15,0);

say(01,1,'ÉÍÍÍÍ»'); say(11,1,'ÉÍÍÍÍÑÍÍÍÍÑÍÍÍÍÑÍÍÍÍ»');
say(33,1,'ÉÍÍÍÍÑÍÍÍÍÑÍÍÍÍÑÍÍÍÍ»'); say(55,1,'ÉÍÍÍÍÑÍÍÍÍÑÍÍÍÍÑÍÍÍÍ»');
say(01,2,'º Escº'); say(11,2,'º F1 ³ F2 ³ F3 ³ F4 º');
say(33,2,'º F5 ³ F6 ³ F7 ³ F8 º'); say(55,2,'º F9 ³ F10³ F11³ F12º');
say(01,3,'ÈÍÍÍÍ¼'); say(11,3,'ÈÍÍÍÍÏÍÍÍÍÏÍÍÍÍÏÍÍÍÍ¼');
say(33,3,'ÈÍÍÍÍÏÍÍÍÍÏÍÍÍÍÏÍÍÍÍ¼'); say(55,3,'ÈÍÍÍÍÏÍÍÍÍÏÍÍÍÍÏÍÍÍÍ¼');

say(1,5, 'ÉÍÍÍÍÑÍÍÍÍÑÍÍÍÍÑÍÍÍÍÑÍÍÍÍÑÍÍÍÍÑÍÍÍÍÑÍÍÍÍÑÍÍÍÍÑÍÍÍÍÑÍÍÍÍÑÍÍÍÍÑÍÍÍÍÑÍÍÍÍÑÍÍÍÍ»');
say(1,6, 'º `~ ³ 1  ³ 2  ³ 3  ³ 4  ³ 5  ³ 6  ³ 7  ³ 8  ³ 9  ³ 0  ³ -  ³ =  ³ \  ³ BS º');
say(1,7, 'ÇÄÄÄÄÁÄÄÂÄÁÄÄÂÄÁÄÄÂÄÁÄÄÂÄÁÄÄÂÄÁÄÄÂÄÁÄÄÂÄÁÄÄÂÄÁÄÄÂÄÁÄÄÂÄÁÄÄÂÄÁÄÄÂÄÁÄÄÂÄÁÄÄÄÄ¶');
say(1,8, 'º  Tab  ³ Q  ³ W  ³ E  ³ R  ³ T  ³ Y  ³ U  ³ I  ³ O  ³ P  ³ [  ³ ]  ³      º');
say(1,9, 'ÇÄÄÄÄÄÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÙ  <Ù  º');
say(1,10,'º  Caps   ³ A  ³ S  ³ D  ³ F  ³ G  ³ H  ³ J  ³ K  ³ L  ³ ;  ³ "  ³         º');
say(1,11,'ÇÄÄÄÄÄÄÄÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÁÄÂÄÄÁÄÄÄÄÄÄÄÄÄ¶');
say(1,12,'º  Shift    ³ Z  ³ X  ³ C  ³ V  ³ B  ³ N  ³ M  ³ ,  ³ .  ³ /  ³    Shift   º');
say(1,13,'ÇÄÄÄÄÄÄÄÄÒÄÄÁÄÒÄÄÁÄÄÄÂÁÄÄÄÄÁÄÄÄÄÁÄÄÄÄÁÄÄÄÄÁÄÄÄÄÁÄÄÄÄÁÄÄÄÂÁÄÄÄÄÁÒÄÄÄÄÒÄÄÄÄÄÄ¶');
say(1,14,'º  Ctrl  º');

say(15,14,'º Alt  ³                Bar               ³ Alt  º');
say(69,14,'º Ctrl º');
say(01,15,'ÈÍÍÍÍÍÍÍÍ¼');
say(15,15,'ÈÍÍÍÍÍÍÏÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÏÍÍÍÍÍÍ¼');
say(69,15,'ÈÍÍÍÍÍÍ¼');

gotoxy(Col,Row);

repeat
   Ch := readkey;
   if Ch = #0 then
      begin
      Ch := readkey;
      case Ch of
         #16 : begin                  { Alt_Q }
               RestoreInitScr;
               writeln('Typing Tutor - Copyright(C) by Thanh Hai, www.thanhhai.com.');
               halt;
               end;
         #46 : begin                  { Alt_C }
               window(1,19,80,24);
               clrscr;
               window(3,3,80,24);
               Col := 1; Row := 18;
               gotoxy(Col,Row);
               end;
         #59 : put(12,2,2);
         #60 : put(17,2,3);
         #61 : put(22,2,4);
         #62 : put(27,2,5);
         #63 : put(34,2,6);
         #64 : put(39,2,7);
         #65 : put(44,2,8);
         #66 : put(49,2,9);
         #67 : put(56,2,10);
         #68 : put(61,2,11);

         end;  { case }
      end   { if Ch = #0 ... }

   else
      begin
      case Ch of
         #27 : put(2,2,1);

         '`','~' : put(2,6,14);
         '1','!' : put(7,6,15);
         '2','@' : put(12,6,16);
         '3','#' : put(17,6,17);
         '4','$' : put(22,6,18);
         '5','%' : put(27,6,19);
         '6','^' : put(32,6,20);
         '7','&' : put(37,6,21);
         '8','*' : put(42,6,22);
         '9','(' : put(47,6,23);
         '0',')' : put(52,6,24);
         '-','_' : put(57,6,25);
         '=','+' : put(62,6,26);
         '\','|' : put(67,6,27);

         #8 : begin
              dec(Col); gotoxy(Col,Row);
              write(' ');
              if (Col = 0) then
                 begin
                 if Row = 18 then Col := 1
                 else begin Col := 77; dec(Row); end
                 end;
              put(72,6,28);
              gotoxy(Col,Row);
              end;
         #9 : put(3,8,29);
         #13: begin
              put(71,9,64);
              inc(Row);
              if Row = 22 then
                 begin
                 window(1,19,80,24);
                 clrscr;
                 window(3,3,80,24);
                 Row := 18;
                 end;
              Col := 1;
              gotoxy(Col,Row);
              end;

         'Q','q' : put(10,8,30);
         'W','w' : put(15,8,31);
         'E','e' : put(20,8,32);
         'R','r' : put(25,8,33);
         'T','t' : put(30,8,34);
         'Y','y' : put(35,8,35);
         'U','u' : put(40,8,36);
         'I','i' : put(45,8,37);
         'O','o' : put(50,8,38);
         'P','p' : put(55,8,39);
         '{','[' : put(60,8,40);
         '}',']' : put(65,8,41);

         'A','a' : put(12,10,42);
         'S','s' : put(17,10,43);
         'D','d' : put(22,10,44);
         'F','f' : put(27,10,45);
         'G','g' : put(32,10,46);
         'H','h' : put(37,10,47);
         'J','j' : put(42,10,48);
         'K','k' : put(47,10,49);
         'L','l' : put(52,10,50);
         ':',';' : put(57,10,51);
         '"','''' : put(62,10,52);

         'Z','z' : put(14,12,53);
         'X','x' : put(19,12,54);
         'C','c' : put(24,12,55);
         'V','v' : put(29,12,56);
         'B','b' : put(34,12,57);
         'N','n' : put(39,12,58);
         'M','m' : put(44,12,59);
         '<',',' : put(49,12,60);
         '>','.' : put(54,12,61);
         '?','/' : put(59,12,62);

         #32 : put(38,14,63);
         end;    { case Ch of ... }
      if (Ch > #31) and (Ch <> #8) and (Ch <> #13) then Display_Char;
      end;

   until false;

END.
