unit rezklav;
{Rezidentni obsluha klavesnice. Cte polohove kody, ktere pak pomoci tabulek}
{prevedu do ASCII znaku. Vse si udelam sam a nebudu zavisly na DOSovych}
{ovladacich klavesnice}
{Tato unita umi rozlisovat mezi normalnimi sipkami a sipkami na numericke
klavesnici. Pro pohodli programatora ale rovnez definuje kody, ktere mezi
nimi neodlisuji.
napr. Sipka vpravo na numericke klavesnici dava:
KEY_NUM_6 = true a KEY_CURSOR_RIGHT = true
Seda sipka vpravo dava:
KEY_G_CURSOR_RIGHT = true a KEY_CURSOR_RIGHT = true.
Vidite, ze KEY_CURSOR_RIGHT zustava spolecne.

Jestlize zavolate ZapniObsluhuKlavesnice s parametrem KL_S_BIOSEM, tak dal
budou normalne fungovat standardni funkce klavesnice jako
ReadKey, KeyPressed a vubec cely BIOS okolo klavesnice. Na druhou stranu se
musite starat, aby klavesnice nepipala.
Kdyz zavolate ZapniObsluhuKlavesnice(KL_BEZ_BIOSU) tak pipat zarucene nebude,
ale prestanou fungovat standardni pascali funkce okolo klavesnice.}


{Pri pohledu do zdrojaku zarazi velice bizarni chovani klavesy Pause.
Posila velmi exotickou sekvenci a hlavne nesignalizuje uvolneni klavesy.
Zvlastne se taky taky chova Printscreen. Pri zmacknuti totiz vysle 4-bajtovou
sekvenci. Pokud ho ale nepustime, ale drzime dal, tak periodicky vysila
jinou, a to 2-bajtovou sekvenci. Periodicke vysilani maji rovnez oba Alty.}


{$IFDEF FPC}
{$MODE FPC}
  {$IFDEF VER2}{$DEFINE NEWFPC}{$ENDIF}
  {$IFDEF VER3}{$DEFINE NEWFPC}{$ENDIF}
  {$IFDEF NEWFPC}{$CALLING OLDFPCCALL}{$ENDIF}
{$ENDIF}

{$Q-}     {debugovaci informace musi byt v kazdem pripade povypinana}
{$R-}     {jinak se to cele zhrouti}
{$S-}
{$D-}
{$F+}

{$DEFINE OPATRNOST}   {Zda se, ze je mozne ji vypnout...}

{$DEFINE _DEBUG_USER_HANDLER}

interface
{$IFDEF FPC}
uses go32;
{$ELSE}
uses dos;
{$ENDIF}

const KL_S_BIOSEM  = true;
      KL_BEZ_BIOSU = false;
      RK_MAX_KLAVES = 300;

type kevent = record
     mimoradny_kod:longint;
     scan:byte;       {polohovy kod klavesnice}
     dos_ascii:word;  {ASCII kod podle ovladace DOSu}
     ascii:longint;   {ASCII kod bud podle ovl. DOSu nebo podle vlastni...}
                      {...prevodni rutiny}
     uni:longint;     {ASCII znak prelozeny do Unicode podle nahrane tabulky}
     priznaky:word;
     psaci:boolean;   {zda jde o psaci, nebo funkcni klavesu}
     end;

Pklavesy_def = ^Tklavesy_def;
Tklavesy_def = array[1..RK_MAX_KLAVES] of record
   p:longint;    {scan kod (polohovy kod)}
   a:longint;    {pro ASCII}
   u:longint;    {pro unicode}
   c:byte;       {zda reaguje na shift a na Capslock}
   end;

rk_putf8conv = ^rk_utf8conv;
rk_utf8conv = array[128..255] of word;


rk_Punifiltr = ^rk_Tunifiltr;
   rk_Tunifiltr = record
   t_velke_na_male:pointer; {tabulka pro prevod znaku na mala pismena}
   t_male_na_velke:pointer; {a znovu tabulka pro prevod na velka pismena}
   soubor:string[32];
   nazev:string;
   tbl_prevodnik:string[32];
   mapa:pklavesy_def;       {deklarovano v unite RezKlav}
   end;

{_xReadkey_Doplnek = function(b:byte):kevent;}
_xKeyPressed_Doplnek = function(b:byte):boolean;
_xPrevod_mimoradneho_kodu_xKeyPressed = procedure(k:kevent);

_External_Kbd_Debug = procedure(l:longint;b:byte);

{Funkce starajici se o klavesnici pomoci sluzeb DOSu a BIOSu}
function xReadKey:kevent;
function xKeyPressed:boolean;
Procedure HlidejKlavesy;
Procedure ZhltniKlavesu;
Procedure PustKlavesu;
function lKeyPressed:boolean;  {nahrada KeyPressed - nejak mi to funguje lepe}
Function KeyPriznaky:word;     {detekce CTRL, ALT a podobne}
function Je_CapsLock:boolean;
function Je_NumLock:boolean;
function Je_CTRL:boolean;
function Je_ALT:boolean;
Function Je_Shift:boolean;
Function DOS_mem_Je_shift:boolean;
Function PrelozAlt(w:word):byte;
Procedure RK_Nastav_Prevodni_tabulku_DOSASCII_unicode(p:pointer);
Procedure RK_NahrajUTF8Tabulku(s:string;var u:rk_utf8conv);
Function RK_Nahraj_Mapu_Klavesnice_ze_souboru(cesta,tbl_cesta,soubor:string;var klav:rk_Punifiltr):boolean;
Procedure RK_Aktivuj_Mapu_Uzivatelske_Klavesnice(m:rk_Punifiltr);
Function RK_Aktivni_Uzivatelska_Klavesnice:rk_Punifiltr;
Function RK_Aktivni_Uzivatelska_Klavesnice_soubor:string;
Function RK_Aktivni_Uzivatelska_Klavesnice_nazev:string;
Function RK_Aktivni_Uzivatelska_Klavesnice_male_velke:pointer;
Function RK_Aktivni_Uzivatelska_Klavesnice_velke_male:pointer;

function Internal_Je_CapsLock(k:kevent):boolean;
function Internal_Je_NumLock(k:kevent):boolean;
function Internal_Je_CTRL(k:kevent):boolean;
function Internal_Je_ALT(k:kevent):boolean;
Function Internal_Je_Shift(k:kevent):boolean;

function Je_CapsLock_dbg:boolean;
function Je_NumLock_dbg:boolean;


{Obsluha handleru}
procedure ZapniObsluhuKlavesnice(rezim:boolean);
procedure VypniObsluhuKlavesnice;
Function Rez_Keypressed:boolean;

const
{kody klaves, jak je vraci funkce xReadkey (diky Mircosofte) }
xF1=315;  xShiftF1=340;  xCtrlF1=350;    xAltF1=360;
xF2=316;  xShiftF2=341;  xCtrlF2=351;    xAltF2=361;
xF3=317;  xShiftF3=342;  xCtrlF3=352;    xAltF3=362;
xF4=318;  xShiftF4=343;  xCtrlF4=353;    xAltF4=363;
xF5=319;  xShiftF5=344;  xCtrlF5=354;    xAltF5=364;
xF6=320;  xShiftF6=345;  xCtrlF6=355;    xAltF6=365;
xF7=321;  xShiftF7=346;  xCtrlF7=356;    xAltF7=366;
xF8=322;  xShiftF8=347;  xCtrlF8=357;    xAltF8=367;
xF9=323;  xShiftF9=348;  xCtrlF9=358;    xAltF9=368;
xF10=324; xShiftF10=349; xCtrlF10=359;   xAltF10=369;
xF11=389; xShiftF11=391; xCtrlF11=393;   xAltF11=395;
xF12=390; xShiftF12=392; xCtrlF12=394;   xAltF12=396;
xLSipka=331; {xShiftLSipka=331;} xCtrlLSipka=371;  xAltLsipka=411;
xPSipka=333; {xShiftPSipka=333;} xCtrlPSipka=372;  xAltPSipka=413;
xHSipka=328; {xShiftHSipka=328;} xCtrlHSipka=397;  xAltHSipka=408;
xDSipka=336; {xShiftDSipka=336;} xCtrlDSipka=401;  xAltDSipka=416;
xAltX =301;
xIns=338;xDel=339;xBackSpace=8;
xHome=327;xEndk=335;xPgUp=329;xPgDn=337;xCtrlPgUp=388;
xCtrlG=7;xEnter=13;xESC=27;xTAB=9;xCtrlPgDn=374;xMezera=32;
xCtrlHome=375;xCtrlEnd=373;

xDOS_DEAD_KEY = -8;
xSKIP_BIOS = -9;
xPREFIX_KEY = -10;

xsLSipka=75;  xsHome=71;  xsDel=83;
xsPSipka=77;  xsEndk=79;  xsBackSpace=14;
xsHSipka=72;  xspgup=73;  xsCTRLins=146;
xsDSipka=80;  xspgdn=81;  xsIns=82;


Je_klavesa:boolean = false;
xKlavesa:kevent = (mimoradny_kod:0;
                   scan:0;
                   dos_ascii:0;
                   ascii:0;
                   uni:0;
                   priznaky:0;
                   psaci:false);

rk_mapa_uzivatelske_klavesnice:rk_Punifiltr = nil;
rk_ascii_utf_prevod:pointer = nil;

{xReadkey_Doplnek : _xReadkey_Doplnek = nil;}
xKeyPressed_Doplnek : _xKeyPressed_Doplnek = nil;
xPrevod_mimoradneho_kodu_xKeyPressed : _xPrevod_mimoradneho_kodu_xKeyPressed = nil;

External_Kbd_Debug : _External_Kbd_Debug = nil;

prefix_key:longint = 0;  {je spolecny pro ASCII i Unicode mapu}

{$I rezklav.inc}  {kody klaves}
var

    rezklav_interface_lock_start:byte;
    je_int9_handler:boolean;
    kl_kod:word;
    kl_zmena:boolean;
    vsechny_klavesy : Array[0..160] of boolean;
    AltBuf:word;
    kl_skipbios:boolean;
    mimoradny_kod_xKeyPressed:longint;
    {kod specialne detekovanych klaves vyplyvnutych uz z xKeyPressed
     (namisto standardni pozdejsi detekce z xReadKey)}
    rezklav_interface_lock_end:byte;

implementation
uses konfig,vaznik;


const kbdint = $9;
      levy_shift = 42;
      pravy_shift = 54;
      odpocet:byte=0;
      nulovani_klavesnice:boolean = false;
      key_timer_stamp:dword = 0;
      old_kl_kod:word = 0;

alt_w: array [1..27] of word =
    (272,273,274,275,276,277,278,279,280,281,
     286,287,288,289,290,291,292,293,294,
     300,301,303,303,304,305,306,307);

alt_s: string = 'qwertyuiopasdfghjklzxcvbnm';

var
    {$IFDEF FPC}
    oldint9_handler:tseginfo;
    newint9_handler:tseginfo;
    backupDS:Word; external name '___v2prt0_ds_alias';
    {$ELSE}
    oldint9_handler:pointer;
    newint9_handler:pointer;
    {$ENDIF}

    paltbuf:array[0..6] of byte; {je to zahada, ale se stringem mi to nefungovalo}
    obsluha:pointer;
    bios:boolean;

    var_utf8conv:rk_utf8conv;

procedure CtiKod;{$IFNDEF FPC}interrupt;{$ENDIF}
  procedure ZpracujJednotu(alternativa,spolecna,ja:byte);
  {priklad funkce:
   stisknu levy CTRL -> pridela spolecny CTRL
   ulolnim levy CTRL -> uvolni spolecny CTRL a take pravy CTRL}
  begin
  if ja<>0 then vsechny_klavesy[ja]:=(kl_kod<128);
  if kl_kod<128 then vsechny_klavesy[spolecna]:=true else
     if vsechny_klavesy[alternativa]=false then
        vsechny_klavesy[spolecna]:=false;
  end;

  procedure PrectiAltovyBuffer;
  var i,j:longint;
  begin
  if vsechny_klavesy[SCANKEY_ALT]=false then
     begin
     altbuf:=0;
     j:=1;
     for i:=paltbuf[0] downto 1 do
         begin
         altbuf:=altbuf+paltbuf[i]*j;
         j:=j*10;
         end;
     paltbuf[0]:=0;
     end;
  end;

var klmod128,op:byte;
    ab:byte;
    cislo:boolean;

begin
{$IFDEF FPC}kl_kod:=InPortB($60);{$ELSE}kl_kod:=Port[$60];{$ENDIF}
if kl_kod=$e1 then
   if odpocet=0 then odpocet:=7 else else {krkolome osetreni Pause}
if kl_kod=$e0 then
   if odpocet=0 then odpocet:=2 else else

if odpocet<3 then
   begin
   kl_zmena:=true;
   klmod128:=kl_kod mod 128;

   vsechny_klavesy[SCANKEY_PAUSE]:=false;     {vopruz z Pause}
   vsechny_klavesy[SCANKEY_CTRLBREAK]:=false; {stejne se chova CTRL-break}

   op:=odpocet;
   odpocet:=0;
   case op of
      2:case klmod128 of
           69:vsechny_klavesy[SCANKEY_PAUSE]:=true;         {Pause}
           70:vsechny_klavesy[SCANKEY_CTRLBREAK]:=true;     {CTRL-break}
           55:vsechny_klavesy[SCANKEY_PRINT]:=(kl_kod<128); {Printscreen poprve}
        end;

      1:case klmod128 of
           71..83:ZpracujJednotu(klmod128,klmod128+Priznak_jednoty,klmod128+Priznak_sedych_sipek);
           28:ZpracujJednotu(SCANKEY_G_ENTER,SCANKEY_ENTER,SCANKEY_NUM_ENTER);{sedy Enter}
           56:begin
              ZpracujJednotu(SCANKEY_LALT,SCANKEY_ALT,SCANKEY_PALT);          {pravy Alt}
              PrectiAltovyBuffer;
              end;
           29:ZpracujJednotu(SCANKEY_LCTRL,SCANKEY_CTRL,SCANKEY_PCTRL);       {pravy Ctrl}
           55:vsechny_klavesy[SCANKEY_PRINT]:=(kl_kod<128); {Printscreen opakovane}
           42,70:odpocet:=4;  {4-bajtova sekvence E0,neco,E0,neco}
           else vsechny_klavesy[klmod128]:=(kl_kod<128);
        end;

      0:begin
        vsechny_klavesy[klmod128]:=(kl_kod<128);
        case klmod128 of
           71..83:ZpracujJednotu(klmod128+Priznak_sedych_sipek,klmod128+Priznak_jednoty,klmod128);
           28:ZpracujJednotu(SCANKEY_NUM_ENTER,SCANKEY_ENTER,0); {num Enter}
           56:begin
              ZpracujJednotu(SCANKEY_PALT,SCANKEY_ALT,0);        {levy Alt}
              PrectiAltovyBuffer;
              end;
           29:ZpracujJednotu(SCANKEY_PCTRL,SCANKEY_CTRL,0);      {l. Ctrl}
           42:ZpracujJednotu(SCANKEY_PSHIFT,SCANKEY_SHIFT,0);    {l. Shift}
           54:ZpracujJednotu(SCANKEY_LSHIFT,SCANKEY_SHIFT,0);    {p. Shift}
        end;

        if (kl_kod<128) and (vsechny_klavesy[SCANKEY_ALT]) then
           begin {drzime Alt a pritom byla}{zmacknuta klavesa na numericke klavesnici?}
           case kl_kod of
              71:ab:=7;
              72:ab:=8;
              73:ab:=9;
              75:ab:=4;
              76:ab:=5;
              77:ab:=6;
              79:ab:=1;
              80:ab:=2;
              81:ab:=3;
              82:ab:=0;
              56:ab:=11;    {komplikace - periodicke vysilani Altu}
              else ab:=10;
           end;
           if ab<>11 then
              if ab=10 then paltbuf[0]:=0 else
                 if paltbuf[0]<5 then
                    begin
                    inc(paltbuf[0]);
                    paltbuf[paltbuf[0]]:=ab;
                    end
                    else begin
                    paltbuf[0]:=1;
                    paltbuf[1]:=ab;
                    end;
           end;
        end;
   end; {case odpocet}
   if kl_kod>127 then kl_kod:=0 else
      if vsechny_klavesy[SCANKEY_SHIFT] then inc(kl_kod,1000); {musim mit na pameti shifty}
   end; {if odpocet}


if odpocet>0 then dec(odpocet);

kl_skipbios:=false;
{KL_skipbios = true: jsou stiskle klavesy, ktere nejsou vhodne na nacitani
                     pres BIOS a je vhodne pouzit prime cteni pole
                     vsechny_klavesy

 KL_skipbios = false: melo by byt bezpecne dalsi predani klavesy BIOSovemu
                       handleru}


cislo:=false;

(*
for ab:=SCANKEY_1 to SCANKEY_0 do
    if vsechny_klavesy[ab] then cislo:=true;   {je zmackle cislo v hor.rade?}
*)

(*
{????? -- kdyz nasledujici blok zakomentuju, tak v Blocku pri drzeni ALTu
          normalne blika kurzor a lze neco delat}
if vsechny_klavesy[KEY_ALT] then
   if vsechny_klavesy[KEY_SHIFT]
      then kl_skipbios:=kl_skipbios
      else kl_skipbios:=true;
{????? -- kdyz ho necham aktivni, tak se pri drzeni ALTu program jakovy zastavi}
*)


(*{and (cislo=true)} then kl_skipbios:=true;*)


if vsechny_klavesy[SCANKEY_CTRL] then   {zablokuje pro BIOS nektere komb. s CTRL}
   if vsechny_klavesy[SCANKEY_C] then kl_skipbios:=true else
   if cislo=true then kl_skipbios:=true;

{BIOSovy ovladac klavesnice "polyka" kombinace CTRL-C a CTRL-cislo.
 Proto pokud takovou situaci zdetekuji, tak BIOSovy handler preskocim}

{$IFDEF FPC}

if (bios=false) or (kl_skipbios=true) then
   asm
   mov dx,20h
   mov al,20h
   out dx,al
   stc        {nastavi CF, coz pouziju jako znak, ze mam preskocit BIOS}
   end else
   asm
   clc;       {vynuluje CF, tedy zavolam jeste BIOS}
   end;

{$ELSE}
if bios=false then
   Port[$20]:=$20 else
   begin
   asm
   call oldint9_handler
   end;
   end;
{$ENDIF}
end;
procedure CtiKod_dummy; begin end;

{$IFDEF FPC}
procedure int9_handler; {$IFDEF NEWFPC}nostackframe;{$ENDIF}assembler;
asm
cli
{$IFDEF OPATRNOST}
push ds
push es
push fs
push gs
pushad
{$ENDIF}
   mov ax,cs:[backupDS]
   mov ds,ax
   mov es,ax
   mov ax,dosmemselector
   mov fs,ax
   call obsluha
{$IFDEF OPATRNOST}
popad
pop gs
pop fs
pop es
pop ds
{$ENDIF}

clc

jc @preskoc_orig_handler  {pokud OBSLUHA nastavi CF, tak preskoc orig. handler}
jmp cs:[oldint9_handler]
@preskoc_orig_handler:

sti
iret  {Nutne. Pokud totiz neskocime do orig. handleru, tak to za nas nikdo jiny nezavola}
end;
procedure int9_dummy; begin end;

procedure int9_nbhandler; {$IFDEF NEWFPC}nostackframe;{$ENDIF}assembler;
asm
cli
{$IFDEF OPATRNOST}
push ds
push es
push fs
push gs
pushad
{$ENDIF}
   mov ax,cs:[backupDS]
   mov ds,ax
   mov es,ax
   mov ax,dosmemselector
   mov fs,ax
   call obsluha
{$IFDEF OPATRNOST}
popad
pop gs
pop fs
pop es
pop ds
{$ENDIF}
sti
iret; {Navrat z preruseni. Variantou by bylo zde IRET vypustit, ale v tom}
end;  {pripade bychom museli celou proceduru volat s modifikatorem INTERRUPT}
procedure int9_nbdummy; begin end;
{$ENDIF FPC}

procedure ZapniObsluhuKlavesnice(rezim:boolean);
begin
kl_zmena:=false;
bios:=rezim;
altbuf:=0;
FillChar(paltbuf,sizeof(paltbuf),0);
FillChar(vsechny_klavesy,sizeof(vsechny_klavesy),0);
obsluha:=@CtiKod;

{$IFDEF FPC}
lock_data(rezklav_interface_lock_start,
          longint(@rezklav_interface_lock_end) - longint(@rezklav_interface_lock_start)+1);

lock_data(obsluha, sizeof(obsluha));
lock_data(bios, sizeof(bios));
lock_data(odpocet, sizeof(odpocet));
lock_data(paltbuf, sizeof(paltbuf));
lock_data(dosmemselector, sizeof(dosmemselector));
lock_data(backupDS, sizeof(backupDS));
lock_data(oldint9_handler, sizeof(oldint9_handler));

lock_code(@CtiKod,longint(@CtiKod_dummy) - longint(@CtiKod));
if bios then
   begin
   lock_code(@int9_handler,longint(@int9_dummy)-longint(@int9_handler)+1);
   newint9_handler.offset:=@int9_handler;
   end
   else begin
   lock_code(@int9_nbhandler,longint(@int9_nbdummy)-longint(@int9_nbhandler)+1);
   newint9_handler.offset:=@int9_nbhandler;
   end;
newint9_handler.segment:=get_cs;
je_int9_handler:=true;
get_pm_interrupt(kbdint, oldint9_handler);
set_pm_interrupt(kbdint, newint9_handler);
{$ELSE}
newint9_handler:=@ctikod;
je_int9_handler:=true;
GetIntVec(kbdint, oldint9_handler);
SetIntVec(kbdint, newint9_handler);
{$ENDIF}
end;

procedure VypniObsluhuKlavesnice;

begin
if je_int9_handler = false then Exit;
{$IFDEF FPC}
unlock_data(rezklav_interface_lock_start,
          longint(@rezklav_interface_lock_end) - longint(@rezklav_interface_lock_start) + 1);

unlock_data(obsluha, sizeof(obsluha));
unlock_data(bios, sizeof(bios));
unlock_data(odpocet, sizeof(odpocet));
unlock_data(paltbuf, sizeof(paltbuf));
unlock_data(dosmemselector, sizeof(dosmemselector));
unlock_data(backupDS, sizeof(backupDS));
unlock_data(oldint9_handler, sizeof(oldint9_handler));

unlock_code(@CtiKod,longint(@CtiKod_dummy) - longint(@CtiKod));
if bios then
   unlock_code(@int9_handler,longint(@int9_dummy)-longint(@int9_handler)+1) else
   unlock_code(@int9_nbhandler,longint(@int9_nbdummy)-longint(@int9_nbhandler)+1);

asm cli end;
set_pm_interrupt(kbdint, oldint9_handler);
asm sti end;
{$ELSE}
SetIntVec(kbdint, oldint9_handler);
{$ENDIF}
je_int9_handler:=false;
end;


Procedure RK_Nastav_Prevodni_tabulku_DOSASCII_unicode(p:pointer);
begin
rk_ascii_utf_prevod:=p;
end;


Procedure RK_NahrajUTF8Tabulku(s:string;var u:rk_utf8conv);
var f:file;
    p:pointer;
    q:pchar;
    l:longint;
begin
Assign(f,s);
Reset(f,1);
l:=FileSize(f);
GetMem(p,l);
BlockRead(f,p^,l);
Close(f);
q:=p;
while q^<>#10 do inc(q);
inc(q,2);
Move(q^,u,sizeof(rk_utf8conv));
FreeMem(p,l);
end;


Function Rez_Keypressed:boolean;
begin
Rez_Keypressed:=kl_zmena and (kl_kod>0);
kl_zmena:=false;
end;


Function lKeyPressed:boolean;assembler;
asm
mov ah,11h
int 16h
mov al,1
jnz @stisknuto
mov al,0
@stisknuto:
end;

Function KeyPriznaky:word;assembler;
asm
mov ax,1200h
int 16h
end;


function xKeyPressed:boolean;
var b,c,d:boolean;
begin
mimoradny_kod_xKeyPressed:=0;   {nulovani priznaku, ktere slouzi k detekci...}
                                {...zda se nestiskla BIOSem nezdetekovana...}
                                {klavesa (kombinace klaves)}

if xKeyPressed_Doplnek=nil then b:=false else b:=xKeyPressed_Doplnek(0);
if B=true then begin Exit(mimoradny_kod_xKeyPressed<>0);end;



if mimoradny_kod_xKeyPressed=0 then
   begin
   if kl_skipbios then  {specialni kombinace klaves na kterou...}
      begin             {...nenechame BIOS sahnout. Tyka se to CTRL-C...}
                        {...a take CTRL-cislo}
      mimoradny_kod_xKeyPressed:=xSKIP_BIOS;
      Exit(true);
      end;


   if rk_mapa_uzivatelske_klavesnice<>nil then
      begin
      {Uzivatelske klavesnice musim detekovat zvlast z toho duvodu, ze DOSovy a
       BIOSovy handler zamlci stisteni DOSove "dead key"}
       c:=Rez_keypressed;             {co si mysli rezidentni detektor?}
       d:=LKeypressed;                {a co BIOSovy detektor?}
       if (c=true) and (d=false) and    {jestli neni shoda, tak mozna mame dead key}
          (kl_kod<>SCANKEY_PSHIFT+1000) and (kl_kod<>SCANKEY_LSHIFT+1000) then
          begin
          mimoradny_kod_xKeyPressed:=xDOS_DEAD_KEY;
          Exit(true);
          end;
      xKeyPressed:=d;
      end
      else xKeyPressed:=LKeyPressed;

   end else xKeyPressed:=true;    {Mimoradny_kod_xKeypressed je TRUE?}
                                  {Tak musi byt TRUE i vysledek funkce}

(*
if xKeyPressed_Doplnek=nil
   then xKeyPressed:=LKeyPressed
        {standardni BIOS/DOS detekce zmackle klavesy}
   else xKeyPressed:=xKeyPressed_Doplnek(0);
        {vlastni detekce zmacklych klaves - napr lze primo zkoumat pole...
         ...<vsechny_klavesy>. V takovem pripade lze nastavit promennou...
         ...mimoradny_kod_xKeyPressed}
*)
end;


Procedure xReadKey_cteni_z_dosu_a_biosu(var dosascii,priznaky:word;var scankod:byte);assembler;
asm
@znovu:
   mov ax,1100h
   int 16h
   jz @znovu             {cekej, nez se v bufferu neco objevi}

   mov edi,scankod   {nebo tu ma byt instrukce LEA?}
   mov ds:[edi],ah       {zapamatuj si scan kod/rozsireny kod}

   mov bh,255
@opet:
   mov ax,0600h
   mov dl,0ffh
   int 21h
   inc bh
   cmp al,0
   jz @opet
   mov ah,bh

   mov edi,dosascii  {nebo tu ma byt instrukce LEA?}
   mov ds:[edi],ax

   mov ax,1200h
   int 16h

   mov edi,priznaky  {nebo tu ma byt instrukce LEA?}
   mov ds:[edi],ax
end;


Function RK_PrelozZnak(b:longint;u:rk_putf8conv):longint;
begin
if (b<128) or (b>255) then RK_PrelozZnak:=b else RK_PrelozZnak:=u^[b];
end;


Procedure RK_Aktivuj_Mapu_Uzivatelske_Klavesnice(m:rk_Punifiltr);
begin
rk_mapa_uzivatelske_klavesnice:=m;
end;


Function RK_Aktivni_Uzivatelska_Klavesnice:rk_Punifiltr;
begin
RK_Aktivni_Uzivatelska_Klavesnice:=rk_mapa_uzivatelske_klavesnice;
end;


Function RK_Aktivni_Uzivatelska_Klavesnice_soubor:string;
begin
if RK_Aktivni_Uzivatelska_Klavesnice=nil
   then RK_Aktivni_Uzivatelska_Klavesnice_soubor:=''
   else RK_Aktivni_Uzivatelska_Klavesnice_soubor:=RK_Aktivni_Uzivatelska_Klavesnice^.soubor;
end;


Function RK_Aktivni_Uzivatelska_Klavesnice_nazev:string;
begin
if RK_Aktivni_Uzivatelska_Klavesnice=nil
   then RK_Aktivni_Uzivatelska_Klavesnice_nazev:=''
   else RK_Aktivni_Uzivatelska_Klavesnice_nazev:=RK_Aktivni_Uzivatelska_Klavesnice^.nazev;
end;


Function RK_Aktivni_Uzivatelska_Klavesnice_male_velke:pointer;
begin
if RK_Aktivni_Uzivatelska_Klavesnice=nil
   then RK_Aktivni_Uzivatelska_Klavesnice_male_velke:=nil
   else RK_Aktivni_Uzivatelska_Klavesnice_male_velke:=RK_Aktivni_Uzivatelska_Klavesnice^.t_male_na_velke;
end;


Function RK_Aktivni_Uzivatelska_Klavesnice_velke_male:pointer;
begin
if RK_Aktivni_Uzivatelska_Klavesnice=nil
   then RK_Aktivni_Uzivatelska_Klavesnice_velke_male:=nil
   else RK_Aktivni_Uzivatelska_Klavesnice_velke_male:=RK_Aktivni_Uzivatelska_Klavesnice^.t_velke_na_male;
end;


Function DOS_mem_funkcni_klavesy:byte;
begin
DOS_mem_funkcni_klavesy:=Mem[Seg0040:$17];
end;


Function DOS_mem_Je_shift:boolean;
var b:byte;
begin
b:=DOS_mem_funkcni_klavesy;
DOS_mem_Je_shift:=(b and 3)<>0;
end;


function Internal_Je_CapsLock(k:kevent):boolean;
begin
Internal_Je_CapsLock:=(k.priznaky and 64)<>0;
end;
function Je_CapsLock:boolean;
begin
Je_CapsLock:=Internal_Je_CapsLock(xKlavesa);
end;

function Internal_Je_NumLock(k:kevent):boolean;
begin
Internal_Je_Numlock:=(k.priznaky and 32)<>0;
end;
function Je_NumLock:boolean;
begin
Je_NumLock:=Internal_Je_NumLock(xKlavesa);
end;

function Internal_Je_CTRL(k:kevent):boolean;
begin
Internal_Je_CTRL:=(k.priznaky and 4)<>0;
end;
function Je_CTRL:boolean;
begin
Je_CTRL:=Internal_Je_CTRL(xKlavesa);
end;

function Internal_Je_ALT(k:kevent):boolean;
begin
Internal_Je_ALT:=(k.priznaky and 8)<>0;
end;
function Je_ALT:boolean;
begin
Je_ALT:=Internal_Je_ALT(xKlavesa);
end;

Function Internal_Je_Shift(k:kevent):boolean;
begin
Internal_Je_Shift:=(k.priznaky and 3)<>0;
end;
Function Je_Shift:boolean;
begin
Je_shift:=Internal_Je_Shift(xKlavesa);
end;



Function FromTimer:dword;assembler;
asm
mov eax,fs:[$400+$6c]
end;


Procedure Dummy_External_Kbd_Debug(l:longint;b:byte);
begin
{dummy}
end;


Procedure Zhodnot_zda_jde_o_psaci_klavesu(var e:kevent);
begin
{if e.scan=78 then
   write(#7);}
e.psaci:=false;
if Internal_Je_alt(e)=false then
   if e.mimoradny_kod=0 then
      begin
      if e.ASCII=0 then Exit;
      if e.ASCII=xPREFIX_KEY then Exit;

      if e.scan in [41,74{num-},78{num+},86] then e.psaci:=true;

      if (e.Scan>70) and (e.Scan<84) and (Internal_Je_NumLock(e)=false)
         then Exit;
      if (e.DOS_ASCII>31) and (e.DOS_ASCII<256) then e.psaci:=true else
      if (e.Scan>1) and (e.Scan<14) then e.psaci:=true else
      if (e.Scan>15) and (e.Scan<28) then e.psaci:=true else
      if (e.Scan>29) and (e.Scan<54) then e.psaci:=true else
      end;
end;


Procedure ProvedPrekladKlavesy(var e:kevent);
var mp:pklavesy_def;
    a,a2,kl,{km,}kk,scancode_z_mapy:longint;
    ft:dword;
    d,p:word;
    s:byte;
    je_treba_novy_pruchod:boolean;

begin
if e.mimoradny_kod<>0 then {Mimoradny kod? Jde o "dead key" ci o neco jineho?}
   if e.mimoradny_kod<>xDOS_DEAD_KEY then Exit;
   {Jestli slo o "dead key", tak to jeste budeme zkoumat, ale jestli o neco...}
   {...jineho, tak uz to resit nebudeme}

if rk_mapa_uzivatelske_klavesnice<>nil then  {Bezi podpora uziv. klavesnic?}
   if rk_mapa_uzivatelske_klavesnice^.mapa<>nil then {A je uziv. klavesnice...}
      begin                                          {...prave nastavena?}
      {Ano...}
      mp:=rk_mapa_uzivatelske_klavesnice^.mapa;
      je_treba_novy_pruchod:=false;
      kl:=kl_kod;
      {KL_KOD je globalni promenna z rezklav - scan kod stistene klavesy}
      {pokud je k tomu drzen SHIFT, tak je k nemu (jeste v obsluze preruseni)
       pricteno 1000}

      {km:=kl;}
      kk:=kl;


      {$IFDEF DEBUG_USER_HANDLER}
      External_Kbd_Debug(kl,1);
      {$ENDIF}


      {if prefix<>0 then while xkeypressed do xReadKey;}
      {?}{if (prefix_key<>0) then
            while lKeyPressed do xReadKey_cteni_z_dosu_a_biosu(d,p,s);}

      {Ted bude divny blok kodu, ktery by mel omezovat stavy, kdy se klavesa
       detekuje dvakrat. Divne je, ze se to stava v MS-DOSu, ale ne ve FreeDOSu}

      {
      ft:=FromTimer;
      if ft=Key_Timer_Stamp then begin e.ascii:=0;e.uni:=0;Exit;end;
      if (ft=Key_Timer_Stamp+1) and (kl=old_kl_kod) then begin e.ascii:=0;e.uni:=0;Exit;end;
      Key_Timer_Stamp:=ft;
      old_kl_kod:=kl;
      }


      {----------------------------------------------------------------------}

      {Ted dulezity predpoklad - prefixove klavesy se chovaji jako prefixove}
      {v obou modech - ASCII i Unicode}

      kl:=kl+prefix_key;  {pricteme prefix (byl-li nejaky nastradany)}


      repeat


      for a:=1 to RK_MAX_KLAVES do
      {budeme prohledavat pole scankodu klaves, tak jak bylo nacteno
       na zacatku programu funkci ZpracujMapyKlavesnic}

          begin
          scancode_z_mapy:=mp^[a].p;  {beru scan kody z pole...}
          if scancode_z_mapy=kl then  {shoduje se se stistenou klavesou?}
             begin
             e.ascii:=mp^[a].a;
             e.uni:=mp^[a].u;

             {if U then km:=aktualni_klavesnice^.mapa^[a].u
                  else km:=aktualni_klavesnice^.mapa^[a].a;}

             if e.ascii>=2000 then
                begin
                {Kod >=2000 neni kod klavesy, ale znak prefixu. V takovem pri-
                 pade si zapamatujeme prefix a koncime}
                prefix_key:=e.ascii;
                e.ascii:=xPREFIX_KEY;
                e.uni:=xPREFIX_KEY;
                Exit;                    {A tim muzeme ukoncit zpracovani}
                end;

             if (internal_je_capslock(e)=false) or (mp^[a].c=0)
             {pokud neni zaply CapsLock anebo CapsLock danou klavesu
              neovlivnuje, tak mame hotovo}
                then begin
                prefix_key:=0;

                {$IFDEF __DEBUG_USER_HANDLER}
                External_Kbd_Debug(e.ascii,2);
                {$ENDIF}

                Exit;
                end;

             {Pripad, ze je zmackly CapsLock, a ten ma na klasesu vratny vliv
              T.j. CapsLock zpusobi prevod na velka pismena, ale Shift to
              prebije zpet na mala. Tyka se pismen (q/Q, w/W, e/E atd)}
             if mp^[a].c=1 then
                begin
                if kk<1000 then a2:=a+1 else a2:=a-1;
                e.ascii:=mp^[a2].a;
                e.uni:=mp^[a2].u;
                prefix_key:=0;
                Exit;
                end;


             {Posledni moznost. Je zmackly CapsLock a ten ma na klavesu
              komplexni vliv. Pokud neni zmackly Shift, tak vraci velky
              ekvivalent pismena, ale pokud Shift zmackly je, tak to vraci
              nikoliv male pismeno, ale neco uplne jineho
              Tyka se napr. ceskych klaves jako (Ø/2, ç/3, Ÿ/4)}

             {1.podmoznost - je zmackly shift, ktery prebije CapsLock}
             if kk>1000 then
                begin   {Jeste v handleru Shift pricetl ke scan kodu 1000}
                prefix_key:=0;
                {Neni potreba nic menit, e.ASCII a e.UNI mame nastavene uz
                 od predtim}
                Exit;
                end;

             {2.podmoznost - Je zmackly CapsLock, ale nikoliv Shift}
             kl:=kl+mp^[a].c*1000;
             {v takovem pripade prictu specialni CapsLockovy prefix}

            (*{---Pro testovani kodu klaves---}
             bar(vga,400,0,500,20,64000);
             print_fn(410,18,mystr(kl),l_f);*)
             for a2:=1 to RK_MAX_KLAVES do {Znovu projedu cele pole scan kodu}
                 if mp^[a2].p=kl then
                    begin {zachyt?}
                    e.ascii:=mp^[a2].a;
                    e.uni:=mp^[a2].u;
                    prefix_key:=0;
                    Exit;
                    end;

             prefix_key:=0; {zachranna moznost - v definici klavesnice chybi}
             Exit;          {varianta klavesy s CapsLockovym prefixem...}
                            {...tak pouzijeme neprefixovanou variantu}
             end; {[if scancode_z_mapy=kl]}
             end; {[for a:=1 to RK_MAX_KLAVES]}



      {Ted jsme se dostali do bodu, kdy jsme proskenovali cele pole, ale
       nenasli jsme odpovidajici scan kod.}

       if prefix_key<>0 then
          begin
          {Muze to byt tim, ze byl od predtim namackly prefix, ale ted se
           zmackla klavesa, ktera neni s prefixem spojena}
          kl:=kl-prefix_key;
          prefix_key:=0;
          je_treba_novy_pruchod:=true;
          {V tom pripade prefix zahod a znovu proved scan pole klaves}
          end;

       until je_treba_novy_pruchod=false;


       {Porad nic?
        V takovem pripade jeste zkontroluju kody z numericke klavesnice}



      {---Pro testovani kodu klaves---}
      {bar(vga,400,0,500,20,64000);
      print_fn(410,18,mystr(km),l_f);}

      if Je_NumLock
         then Exit  {v tomto pripade akceptujeme prapuvodni kod}
         else begin
         {!_TODO_! -- nechavam puvodni kod k predelani}
         {//
         Function ZkontrolujNumerickou(o,kk:word):word;
         begin
         if Je_NumLock then Exit(o)
         else case o of
         KEY_NUM_7:o:=xHome;
         KEY_NUM_8:o:=xHSipka;
         KEY_NUM_9:o:=xPgUp;
         KEY_NUM_4:o:=xLSipka;
         KEY_NUM_5:o:=0;
         KEY_NUM_6:o:=xPSipka;
         KEY_NUM_1:o:=xEndk;
         KEY_NUM_2:o:=xDSipka;
         KEY_NUM_3:o:=xPgDn;
         KEY_NUM_0:o:=0;
         KEY_NUM_COMMA:o:=xIns;
         end;
         ZkontrolujNumerickou:=o;
         end;
         //}
         end;
  end {[if rk_mapa_uzivatelske_klavesnice^.mapa<>nil]}
end;


function xReadKey:kevent;
{Do xReadkey uz muze jit predem detekovany kod jeste z xKeyPressed. Timto
 "doprednym zpusobem" se detekuji napriklad BIOSem nezjistitelne kombinace
 klaves.
 Pokud xKeyPressed takto "dopredu zdetekovala" klavesu, tak bude nastavena
 v promenne <mimoradny_kod_xKeypressed>}
var e:kevent;
    dosascii:word;
    priznaky:word;
    scankod:byte;

begin
e.mimoradny_kod:=mimoradny_kod_xKeyPressed;
if e.mimoradny_kod<>0 then
   begin
   if xPrevod_mimoradneho_kodu_xKeyPressed=nil then
      begin {var 1: defaultni schema prevodu mimoradneho kodu na standardni kod}
      e.scan:=255;       {nastrkam se nejake definovane hodnoty}
      e.priznaky:=DOS_mem_funkcni_klavesy;
      {??? diskutabilni, zda je tento postup dostatecny}
      if e.mimoradny_kod=xDOS_DEAD_KEY then
         begin
         e.dos_ascii:=0;  {Defaultne se budeme chovat stejne jako DOS, t.j.}
         e.ascii:=0;      {mrtvou klavesu jakoby nevidime}
         e.uni:=0;
         end
         else begin                {pokud neslo o "dead key", ale o jinou}
         e.ascii:=e.mimoradny_kod; {mimoradne detekovanou klavesu, tak...}
         e.uni:=e.mimoradny_kod;   {...to prenes i do ASCII a UNI}
         e.dos_ascii:=255;
         end;
      end
      else  {var 2: lze definovat vlastni alternativni prevodni rutinu}
      xPrevod_mimoradneho_kodu_xKeyPressed(e);
   end
   else begin   {normalni detekovana klavesa, t.j. nikoliv pres <mimoradny_kod_xKeyPressed>}
   {Napred nechame pracovat DOS (bez ohledu na to, zda budeme pouzivat...
    ...vlastni rozvrzeni klavesnice)}
   xReadKey_cteni_z_dosu_a_biosu(dosascii,priznaky,scankod);
   if scankod=14 then dosascii:=8;  {zvlastni vec - pokud bylo soucasne zmacknuto...}
                                    {...CTRL, tak vracelo 127}

   e.dos_ascii:=dosascii;
   e.scan:=scankod;
   e.priznaky:=priznaky;

   {Ted prozatim budeme predpokladat, ze nemame uzivatelskou mapu...
    ...klavesnice a budeme se chovat podle DOSu. Eventualne to pozdeji...
    ...prebijeme v procedure <ProvedPrekladKlavesy>}
   e.ascii:=e.dos_ascii;

   if Internal_je_shift(e) {and (Internal_je_numlock(e)=false)} then
      begin
      if e.scan=SCANKEY_NUM_3 then e.ascii:=xPgDn else
      if e.scan=SCANKEY_NUM_9 then e.ascii:=xPgUp else
      if e.scan=SCANKEY_NUM_7 then e.ascii:=xHome else
      if e.scan=SCANKEY_NUM_8 then e.ascii:=xHSipka else
      if e.scan=SCANKEY_NUM_2 then e.ascii:=xDSipka else
      if e.scan=SCANKEY_NUM_4 then e.ascii:=xLSipka else
      if e.scan=SCANKEY_NUM_6 then e.ascii:=xPSipka;
      end;

   if rk_ascii_utf_prevod<>nil
      then e.uni:=RK_PrelozZnak(e.ascii,rk_ascii_utf_prevod)
      else e.uni:=0;
   end;

{Zhodnot_zda_jde_o_psaci_klavesu(e);}
ProvedPrekladKlavesy(e); {A ted eventualne nechame uradovat vlastni (non-DOS)}
                         {rozvrzeni}

Zhodnot_zda_jde_o_psaci_klavesu(e);
{puvodne bylo volano jeste pred <ProvedPrekladKlavesy>, ale to asi nebylo dobre}

xReadKey:=e;
End;{xreadkey}


Procedure HlidejKlavesy;
begin
Je_Klavesa:=xKeypressed;
if Je_klavesa=true then
   begin
   xKlavesa:=xReadKey;
   nulovani_klavesnice:=true;
   end
   else
   if nulovani_klavesnice then
      begin
      FillChar(xKlavesa,SizeOf(xKlavesa),0);
      nulovani_klavesnice:=false;
      end;
end;


Procedure PustKlavesu;
var dbgs:string;
    a,b,j:longint;
    w1,w2:word;
    b1:byte;
begin
{while Je_Klavesa do HlidejKlavesy;}

while LKeyPressed do xReadKey_cteni_z_dosu_a_biosu(w1,w2,b1);
{Puvodne zde bylo xKeyPressed a xReadkey, ale xReadkey nevidelo vsechny
 xKeypressed a cekalo pak ve smycce na pristi klavesu}


while (vsechny_klavesy[SCANKEY_CTRL]=true) do begin end;
while (vsechny_klavesy[SCANKEY_ALT]=true) do begin end;
{a ted pro jistotu jeste klavesy, ktere xReadKey_cteni_z_dosu_a_biosu nemusi
 videt}
end;


Procedure ZhltniKlavesu;
begin
xKlavesa.scan:=0;
xKlavesa.ascii:=0;
end;


Function PrelozAlt(w:word):byte;
var i: byte;
begin
for i:=1 to 27 do
   if alt_w[i]=w then Exit(byte(alt_s[i]));
PrelozAlt:=0;
end;


Function MyVal(s:string):longint;
var Pom2,pom1 : Integer;
begin
Val (S, Pom1, Pom2);
MyVal := Pom1;
end;


Function Convert_up(s:string):string;
var a:byte;
begin
for a:=1 to Length(s) do s[a]:=UpCase(s[a]);
Convert_up:=s;
end;


Function RK_PrelozZnak(b:longint):longint;
begin
if (b<128) or (b>255)
   then RK_PrelozZnak:=b
   else RK_PrelozZnak:=var_utf8conv[b];
end;



Procedure ZpracujZnakMapyKlavesnic(i,k:longint;s:string;v:PKlavesy_def;c:byte);
var a,b:longint;
begin
v^[i].p:=k;   {prefixovany ci neprefixovany scan kod s nebo bez shiftu}
v^[i].c:=c;   {je tato klavesa ovlivnitelna CapsLockem?}
a:=Pos('(',s);   {je explicitne definovan unicode znak?}
if a=0 then
   begin         {ne}
   v^[i].a:=MyVal(s);
   {priradim ASCII hodnotu}
   v^[i].u:=RK_PrelozZnak(v^[i].a);
   {a z TBL souboru vytahnu UTF ekvivalent}
   end
   else begin    {ano}
   v^[i].a:=MyVal(Copy(s,1,a-1));     {to pred zavorkou je ASCII hodnota}
   b:=Pos(')',s);
   v^[i].u:=MyVal(Copy(s,a+1,b-a-1)); {a to v zavorce je UTF}
   end;
end;


Function RK_Nahraj_Mapu_Klavesnice_ze_souboru(cesta,tbl_cesta,soubor:string;var klav:rk_Punifiltr):boolean;
{FALSE = neco bylo spatne, soubor se nepovedlo nacist
 TRUE = v poradku nacteno}

var v:PKlavesy_def;
    uni,s:string;
    kf:TKonfig;
    pp:PUzel;
    vv:PKFpolozka;
    a,i,b:longint;
    caps:byte;

begin
klav:=nil;     {pro jistotu se napred nachystame na variantu, ze...}
               {...definicni soubor neni ve spravnem formatu}

caps:=0;
for a:=Low(var_utf8conv) to High(var_utf8conv) do
    var_utf8conv[a]:=a;

kf.init;
kf.NactiKonfiguraci({EXEdir+'key_tbl\'}cesta+soubor);


if kf.NactiPolozku('version','.')<>'2' then Exit(false);

pp:=kf.Je_v_komentari('[keyboard layout]'); {V PP bude uzel na radku, kde je...}
                                            {...retezec [keyboard layout]}
if pp=nil then Exit(false);  {Pokud to v celem souboru neni, pak nejde o platny soubor}

{no, uff, snad muzeme predpokladat, ze je soubor ve spravnem formatu}
New(klav);          {alokace pameti pro definice}
New(v);             {alokace pro mapu klavesnice v uzsim smyslu}
FillChar(v^,sizeof(Tklavesy_def),0);
klav^.mapa:=v;

klav^.soubor:=Convert_UP(soubor);

klav^.nazev:=kf.NactiPolozku('title','???');
{timto titulkem se bude mapa klavesnice prezentovat}
if klav^.nazev[1]='"' then
   begin delete(klav^.nazev,1,1);delete(klav^.nazev,Length(klav^.nazev),1);end;

klav^.t_velke_na_male:=nil;
klav^.t_male_na_velke:=nil;

{
q^.t_velke_na_male:=@DOS_velke_na_male;
q^.t_male_na_velke:=@DOS_male_na_velke;

s:=kf.NactiMultiPolozku('collation','?',' ');
if s<>'?' then NahrajPrevodniTabulku(q,s);
}

uni:=kf.NactiPolozku('unicodetable','?');  {defaultni mapovani unicode znaku}
if uni<>'?'
   then begin
        klav^.tbl_prevodnik:=uni;
        RK_NahrajUTF8tabulku(tbl_cesta+uni,var_utf8conv);
        end
   else klav^.tbl_prevodnik:='';

i:=1;
pp:=pp^.dalsi;      {PP jsme si nacetlio neco vyse - je to radka, kde je...}
                    {...napis [keyboard layout]}
while pp<>nil do
   begin
   vv:=pp^.vazba;
   if vv^.z=nil then  {1.varianta: radek bez znaku <ROVNA SE>}
      begin
      s:=Convert_UP(vv^.k^);
      if Copy(s,1,9)='-CAPSLOCK' then caps:=0 else
      if Copy(s,1,9)='+CAPSLOCK' then caps:=1 else
      if Copy(s,1,9)='*CAPSLOCK' then
         caps:=MyVal(Copy(s,10,5)) div 1000;
      end
   else begin         {2.varianta: radek se znakem <ROVNA SE>}
   a:=Pos(',',vv^.c^);   {Jsou v jednom radku definovane obe varianty?}                         {(t.j. bez shiftu a se shiftem?)}
   if a=0 then
      begin
      ZpracujZnakMapyKlavesnic(i,MyVal(vv^.z^),vv^.c^,klav^.mapa,caps);
      ZpracujZnakMapyKlavesnic(i+1,MyVal(vv^.z^)+1000,vv^.c^,klav^.mapa,caps);
      end
      else begin
      ZpracujZnakMapyKlavesnic(i,MyVal(vv^.z^),Copy(vv^.c^,1,a-1),klav^.mapa,caps);
      ZpracujZnakMapyKlavesnic(i+1,MyVal(vv^.z^)+1000,Copy(vv^.c^,a+1,255),klav^.mapa,caps);
      end;
   inc(i,2);
   end;

   pp:=pp^.dalsi;
   end;
kf.Done;
RK_Nahraj_Mapu_Klavesnice_ze_souboru:=true;
end;


function Je_CapsLock_dbg:boolean;
var w:word;
begin
{$IFDEF FPC}
asm
mov ax,fs:[$400+$17]
and ax,64
mov w,ax
end;
{$ELSE}
w:=MemW[Seg0040:$17] and 64;
{$ENDIF}
Je_CapsLock_dbg:=w<>0;
end;

function Je_NumLock_dbg:boolean;
var w:word;
begin
{$IFDEF FPC}
asm
mov ax,fs:[$400+$17]
and ax,8192
mov w,ax
end;
{$ELSE}
w:=MemW[Seg0040:$17] and 8192;
{$ENDIF}
Je_NumLock_dbg:=w<>0;
end;



begin
{inicializace jednotky}
je_int9_handler:=false;       {takto pozname, ze handler jeste neni instalovan}
External_Kbd_Debug:=@Dummy_External_Kbd_Debug;
end.
