Co by to bylo za grafickou unitu, kdyby nedokázala pracovat s myší. Která je dnes ve většině grafických programů samozřejmostí.
Ovladače myši (jejich dosovská část) neposkytují (alespoň mi to není známo) žádnou možnost, jak zobrazit grafický kurzor při vyšších VESA módech. (vyšších než 13h) Proto se při takových módech musíme o zobrazení kurzoru postarat sami.
Init myši
Nejdříve musíme zjistit, zda vůbec máme nainstalovaný driver myši. (V souboru config.sys .) Do registru ax dáme hodnotu 0 (init myši) a necháme vykonat přerušení 33h. Pokud po provedení přerušení máme v ax hodnotu FFFFh je ovladač myši nainstalován.
asm
mov ax,0
int $33
mov [zapnoutMys],al
end;
if not zapnoutMys then writeln('neni nainstalovan ovladac mysi...');
Pokud je myš k dispozici, nastavíme si rozsah jejího pohybu na rozměry naší obrazovky (640x480):
asm
mov ax,7h {nastav Xovy rozsah}
mov cx,0h
mov dx,639
int 33h
mov ax,8h {nastav Yovy rozsah}
mov cx,0h
mov dx,479
int 33h
end;
Jak už jsem zmínil, ovladače myši v dosu nenabízejí žádnou možnost jak zobrazit grafický kurzor při vyšších módech, proto si musíme vytvořit proceduru (zobrazmys) a tu nastavit jako obslužnou pro pohyb myši. Pokaždé, když se poté myš pohne je program přerušen a ovladač myši zavolá naši proceduru zobrazmys, která zobrazí kurzor na správné místo. Zaregistrování procedury jako obslužné pro pohyb myši provedeme následovně:
ukazatel:=@zobrazmys;
asm
mov ax,$c {nastavim si rutinu pri pohybu mysicky}
mov cx,$1 {volat pri pohybu}
les dx , ukazatel {vlozime adresu obsluzne funkce}
les bx , ukazatel {..nektere ovladace to prej chtej tady, tak pro jistotu to dam i sem}
int $33 {int mysi}
end;
Před ukončením programu musíme ovladači říct aby již proceduru nevolal. Jinak myš většinou namrzne.
asm
mov ax,$c
mov cx,$0
int $33
end;
V grafické unitě gr16b je init myši obstarán ve funkci init pokud voláme init(zapnouMys) a zapnoutMys=true.
Pro definici kurzoru, uchovávání polohy a stavu myši jsem definoval záznam Tmys.
Tmys=record
jeZobrazena:boolean;
{pokud je kurzor zrona na obrazovce (puze pro cteni)}
x,y:word; {aktualni souradnice (puze pro cteni)}
AkX,AkY:byte; {na jakem bodu je kurzor aktivni. [0,0] u sipky}
maska:array[0..15,0..15]of word;
{ [y,x]!! Tam kde je $0000 je kurzor cerny, $ffff pruhledny}
kurzor:array[0..15,0..15]of word;
{[y,x]!! Tam kde je $ffff je kurzor bily, $0000 pruhledny}
{hodnoty akx,aky,maska a kurzor upravujte pouze pokud je mys schovana}
{(proc. schovMys(true) , jinak by mohlo dojit k chybam pri vykreslovani}
zaKurzorem:array[0..15,0..15]of word;
{[y,x]!! mapa obrazovky za kurzorem (puze pro cteni)}
{vlasni obzaz kuroru vznikne:
((mys.zaKurzorem[y,x] and mys.maska[y,x])or mys.kurzor[y,x]) }
end;
var mys:Tmys;
Hodnoty jeZobrazena, x a y jsou používány pro vykreslování kurzoru a nedoporučuji jejich obsah měnit. Vlastní kurzor o rozměrech 16x16 je definován v polích maska a kurzor. (Pozor první z rozměrů pole je y!) V bodě kde je v masce hodnota $0000 je kurzor černý a kde $FFFF je průhledný. V poli kurzor znamená hodnota $FFFF bílou barvu kurzoru a $0000 průhlednou část. V poli zaKurzorem je uchovávána mapa obrazovky za kurzorem. Ta je na obrazovku vykreslena poté co se kurzor posune na jiné místo. Na obrázku vidíte hodnoty v polích záznamu Tmys a výsledný obraz na obrazovce:
Změnami hodnot v polích maska a kurzor si můžete vytvořit vlastní kurzor. V proměnných AkX a AkY je pak uložena aktivní pozice myši. Tyto hodnoty ale upravujte pouze pokud je myš schovaná (vis. schovMys, jinak by mohlo dojit k chybám při vykreslování!)
Zobrazení myši
Vlastní procedura zobrazmys která je volána při každém pohybu myši musí být napsaná v assembleru a návrat z ní musí být proveden instrukcí návratu retf. (Návrat z přerušení?) Pozici myši máme umístěnou v registrech cx a dx. Abychom v proceduře měli přístup k proměnným našeho programu, musíme si na jejím začátku nastavit registry segmentu dat na náš program. (Ovladač myši si jej při přerušení nastaví na sebe!)
procedure zobrazmys;assembler;
{tato procedura je volana pri jakemkoliv pohybu mysicky...}
{nevim proc ale musi byt napsana v assembleru, proto pote volam zobrazMysProc}
asm
mov si,seg @data {segment dat zpet na nas program}
mov ds,si {driver mysicky jej totiz nastavuje na sebe...}
mov [akx],cx
mov [aky],dx
call zobrazMysProc
retf {musime se vracet pomoci tohoto prikazu (vzdaleny navrat)}
{jinak to hodi chybu...}
end;
Nepodařilo se mi zjistit proč tato procedura musí být napsána v assembleru, dá se to ovšem velice snadno obejít pokud zavoláme proceduru jinou. V našem případě zobrazMysProc. Ta se postará o vlastní zobrazení kurzoru.
procedure zobrazMysProc;
{Obstara zobrazeni (pokud je zapnuta) mysi pri kazdem jejim pohybu }
var x,y:byte;
begin
if jeMys=true then begin
jeMys:=false; {aby se procedura nevolala sama, kdyz jsme ji zavolali my}
{ podle me je to ale asi nejspis zbytecne,
protoze v dobe vykonavani preruseni by volani dalsich preruseni
melo byt zakazano.... (ale co kdyby..) }
if mys.jeZobrazena then begin
{pokud je ted zobrazena na monitoru, tak ji schovame}
y:=0;
repeat
x:=0;
repeat
putPixel( (mys.x+x)-mys.AkX , (mys.y+y)-mys.AkY , mys.zaKurzorem[y,x]);
inc(x);
until x=16;
inc(y);
until y=16;
end;
mys.jeZobrazena:=false;
if zobrazovatMys then begin
mys.x:=akx;
mys.y:=aky;
{vykreslime mys a co bylo za ni dame do 'zaKurzorem'}
y:=0;
repeat
x:=0;
repeat
mys.zaKurzorem[y,x] := getPixel( (mys.x+x)-mys.AkX , (mys.y+y)-mys.AkY);
inc(x);
until x=16;
inc(y);
until y=16;
y:=0;
repeat
x:=0;
repeat
putPixel((mys.x+x)-mys.AkX , (mys.y+y)-mys.AkY , ((mys.zaKurzorem[y,x]
»» and mys.maska[y,x])or mys.kurzor[y,x]));
inc(x);
until x=16;
inc(y);
until y=16;
mys.jeZobrazena:=true;
end;
jeMys:=true;
end;
end;
Nejdříve na místo kde se myš nacházela při předchozím voláním procedury (pokud byla zobrazena) vykreslíme obsah pole zaKurzorem, poté si do tohoto pole umístíme mapu obrazovky z místa kde se kurzor nachází právě teď a nakonec vykreslíme obraz kurzoru přímo do videopaměti.
Tato procedura zapisuje přímo do videopaměti, nikoliv do virtuální obrazovky. (Dochází k přepínání banků obrazovky podle toho kde je kurzor.) Proto musíme před kopírováním virtuální obrazovky do VRAM myš na chvilku schovat, aby nám při kopírování dat z XMS do VRAM jiná procedura nepřepla bank. (Vis. presunVirtObr.) To ale způsobuje, že při častém volání presunVirtObr myš problikává… Pro schování a opětovné zobrazení kurzoru slouží procedura schovMys.
procedure schovMys(ano:boolean);
{pokud ano=true, procedura schova mys}
{pokud ano=false, procedura mys opet zobrazi}
{!Mys musi byt zinicializovana v (init) a musi byt k dispozici!}
begin
zobrazovatMys:=not ano;
zobrazMysProc;
end;
To je asi tak vše co unita gr16b s myší dokáže. Příště si ukážeme jak načítat obrázky ve formátu PCX a jak se dají s jejich pomocí vytvářet grafické fonty.