Pro napsání první samostatné aplikace nám ještě schází si vysvětlit, jak funguje vstup od uživatele: z klávesnice. Jestli jste četli Assembler a ZX Spectrum 1, tak dnešní díl nepřinese nic nového, většinou budu čerpat z této publikace a nakonec si ukážeme na ROM nezávislý program na čtení klávesnice, který je v MDOS3.
Takže se do toho pustíme vysloveně po hlavě. Nejjednodušší je využít hotové rutiny v ROM ZX. V minulém dílu jsme si něco říkali o im 1, takže ho můžeme okamžitě využít. Pokud v našem programu povolíme přerušení ei a nastavíme im 1 , každé přerušení dojde k otestování klávesnice a nastavení příslušných systémových proměnných. První ukázka nám bude na obrazovku vypisovat znaky pěkně za sebou podle toho, co bylo na klávesnici stištěno.
start ei ;povol preruseni
im 1 ;v modu IM 1
loop1
call INKEY1 ;zavolej test klavesnice
call ZNAK ;ten vraci v A klavesu
jr loop1 ;a rovnou ji naklesli na obrazovku
;znamym programem
INKEY1 halt ;cekej na preruseni
bit 5,(iy+1) ;zjisti, jestli byla stistena jakakoliv klavesa
jr z,INKEY1 ;jestli ne, cekej znovu na klavesu v preruseni
res 5,(iy+1) ;bit je nahozen, musime ho shodit na priste
ld a,(23560) ;precti si klavesu ze systemovych promennych
ret
include znak.a80 ;rutina na tisk znaku
Zkuste si program spustit z basicu s nastaveným klávesovým módem C (tedy velká písmena). Okamžitě poznáte, že tomu ještě něco chybí, protože napsat malé písmeno je nemožné (nebo vaše pyžamo je nemožné?). Co teprve pokud uživatel před spuštěním vašeho programu zapne EXTEND mód a pak stiskne ENTER? Bude to házet úplné bluby. Takže je třeba programově přepnout do klávesového režimu L (to je ten základní). Ostatní klávesové módy jsou většinou ve vlastním programu nepoužitelné.
ld (iy+1),204 ld (iy+7),0 ld (iy+48),0
Pokud by vás jiné módy zajímaly, tak koukněte do Universumovy knihy, nebo si hodnoty zjistěte prohlédnutím těchto hodnot z basicu.
Jistě vám neuniklo, že to nějakou chvilku trvá, než se začne klávesa po podržení opakovat. Tomu se říká autorepeat. Dá se nastavit pomocí systémové proměnné na adrese 23561 a to v padesátinách sekundy. Nastavit se může i prodleva, mezi opakováním stále stisknuté klávesy na adrese 23562. Zkuste si například obě tyto hodnoty nastavit na 1. Uvidíte, že není možné napsat pouze jedno samostatné písmenko.
Tento systém je velice vhodný pro vstupy textů, protože se programátor (tedy vy) nemusí starat o autorepeat a tak. Není ale vhodný například pro ovládání šipky právě kvůli autorepeatu.
Na to se spíše hodí rutina, která vrátí hodnotu stištěné klávesy přesně v okamžiku dotazu. Při použití ROM to může být rutina na adrese 654. Ve všech komentovaných výpisech a jiných příčurkách se jmenuje KEY-SCAN.
KEY-SCAN vrací v registu e hodnotu stištěné klávesy v rozsahu 0-39 (přesně tolik má gumák kláves). Pokud nebyla stištěna žádná klapka, vrací hodnotu 255. Pokud je stisknuta současně s nějakým SHIFTem, je hodnota SHIFTu uložena v registru d. Jsou-li stištěny SHIFTy oba, je CAPS-SHIFT v registru d a SYMBOL SHIFT v registru e. CAPS-SHIFT má hodnotu $27 a SYMBOL SHIFT hodnotu $18.
Zkuste si v ukázkovém programu změnit volání INKEY1 za následující INKEY2:
INKEY2 call 654 ;volej KEY-SCAN
jr nz,INKEY2 ;vice klaves najednou, znovu
call 798 ;volani K-TEST v ROM
jr nc,INKEY2 ;nevyhovuje, znovu
dec d ;nastaveni modu L
ld e,a ;hlavni kod do E
jp 819 ;skoc na dekodovani
Tato rutina nepoužívá přerušení im 1, ale čeká na stisk klávesy a pak provede přepočítání na klávesy. Rutinku lze volat i při zakázaném přerušení, a nečeká na prodlevy při autorepatu nebo opakování. Je tedy vhodná třeba na ovládání šipky nebo i do her, ale pozor: vlastní řešení sice zabere více paměti, ale je rychlejší. K jejímu provozu nepotřebujeme systémové proměnné.
Obě naznačená řešení jsou skvělá, protože jsou krátká, využívají ROM. Ale co až budeme potřebovat testovat klávesy tam, kde ROM k dispozici nemáme: v operačním systému ať už jakéhokoliv zařízení, co překrývá ROM, a stránkovat nelze. Nezbývá nám nic jiného, než opsat z ROM rutinu KEY-SCAN a naprogramovat si vlasní dékódování. To má hlavní výhodu v tom, že si můžete definovat vlastní kódy „nestandartních“ kláves, jako je EDIT, DELETE, CAPS LOCK a tak, nebo úplně změnit smysl kláves.
INKEY4 call KEY_SCAN ;cekej na klavesu
jr nz,INKEY4 ;vice klaves naraz, znovu
ld a,e ;je to vubec nejaka klavesa?
cp 255 ;
jr z,INKEY4 ;neni, znovu
cp $18 ;jde o SS?
jr nz,INKEY4C ;ne, skoc
ld a,d ;a druha klavesa
cp 255 ;je prazdna
jr z,INKEY4 ;ano, to nas nezajima
ld a,e ;jinak normalni prubeh
INKEY4C cp $27 ;jde o CS?
jr nz,INKEY4B ;ne, skoc
ld a,d ;druha klavesa
cp 255 ;je prazdna?
jr z,INKEY4 ;ano, tak to nas taky nezajima
INKEY4B ld a,d ;do A pripadny SHIFT navic
ld hl,SYMTAB ;tabulka pro SS
cp $18 ;je to SS?
jr z,INKEY4A ;ano, skoc na cteni z nastavene tabulky
ld hl,CAPSTAB ;tabulka CS
cp $27 ;je to CS?
jr z,INKEY4A ;ano, skoc na cteni z tabulky
ld hl,KEYTAB ;neni to ani jeden SHIFT, tak normal
INKEY4A ld d,0 ;vynulovani D
add hl,de ;pricteni (posun v tabulce)
ld a,(hl) ;precteni kodu z tabulky pro dany kod
ret ;co vyleze z KEYSCAN.
SYMTAB db 42,94,91,38,37,62,125,47,44,45,93
db 39,36,60,123,63,46,43,127,40,35
db 32,92,96,32,61,59,41,64,32
db 124,58,32,13,34,95,33,32,126,0
CAPSTAB db "BHY"
db 10,8
db "TGVNJU"
db 11,5
db "RFCMKI"
db 9,4
db "EDX LO"
db 15,6
db "WSZ "
db 13,'P',12,7
db "QA "
KEYTAB db "bhy65tgv"
db "nju74rfc"
db "mki83edx"
db " lo92wsz "
db 13
db "p01qa "
KEY_SCAN ;uplny prepis rutiny z ROM
ld l,$2F ;nemusim komentovat
ld de,$FFFF ;beztak stejne nevim jak funguje
ld bc,$FEFE ;ale funguje dobre
NXTROW in a,(c) ;to uz mam vyzkousene
cpl
and $1F
jr z,NOKEY
ld h,a
ld a,l
TEST3 inc d
ret nz
KEYNO sub 8
srl h
jr nc,KEYNO
ld d,e
ld e,a
jr nz,TEST3
NOKEY dec l
rlc b
jr c,NXTROW
ld a,d
inc a
ret z
cp $28
ret z
cp $19
ret z
ld a,e
ld e,d
ld d,a
cp $18
ret
Zkuste opět nahradit volání v hlavní smyčce za call INKEY4. Vidíte, že se chová úplně stejně jako INKEY2. Ale co když tedy potřebujeme v našem operačním systému (třeba MDOS3) psát text. To nám zajistí mnou vyvinutá rutina, která si hlídá poslední a předposlední stištěnou klávesu, definuje timeout pro autorepeat a prodlevu (delay) pro repeat.
Zkuste nahradit volání call INKEY4 za call KEY:
KEY ld de,(autorepeat+1) ;uz vyprsel timeout pro autorepeat?
ld a,d
or e
jr z,releasekey1 ;z=klavesa stale drzena v repeatu
call INKEY4 ;neni, testuj klavesnici
LASTKEY ld b,0 ;jaka je minula klavesa
cp b ;je stejna jako aktualni?
ld (LASTKEY+1),a ;uloz ji na priste
ret nz ;neni, vrat se do volajici smycky
ld a,e ;je stale stejna
ld (lastkey2+1),a ;uloz ji na priste
releasekey1 call KEY_SCAN ;musime pockat na uvolneni klavesy
; LASTKEY2+1
lastkey2 ld a,0 ;uz se drzena klavesa uvolnila?
cp e
jr nz,releasekey2 ;nz=je uvolněna (nebo stistena jina)
autorepeat ld de,1500 ;hodnota autorepeatu
ld a,d ;nebo uz se ma klavesa opakovat?
or e
jr z,repeatkey ;z=vyprsel timeout pro autorepeat
dec de ;sniz o 1
ld (autorepeat+1),de ;a uloz na dalsi zavolani
ld a,d ;nebo uz ted doslo k opakovani -
or e ;- (repeat)
jr nz,releasekey1 ;ne,stale cekej na uvolneni klavesy
repeatkey ld a,(lastkey+1) ;zde uz je repeat klavesy
jp DELAY ;cekej chvilku a vrat hodnotu
;opakovane klavesy
releasekey2 ld de,1500 ;defaultni hodnota pro timeout
ld (autorepeat+1),de ;uloz, doslo k uvolneni klavesy
repeat xor a ;vynuluj posledni klavesu
ld (lastkey+1),a ;uloz ji
jr key ;a vrat se znovu na zacatek maratonu
DELAY push bc ;zpozdovaci smycka
push af
ld bc,10000
DELAY1 dec bc
ld a,b
or c
jr nz,DELAY1
pop af
pop bc
ret
Rutina vypadá velice děsivě, ale funguje i na rychlé, desetiprsté psaní. Jestli máte lepší nápad jak psát text pod zakázaným přerušením, tak ho rád přivítám.
Nesmí chybět domácí úkol: rutina INKEY4 není zrovna nejlepší. Navrhněte jiné řešení, jak zajistit čtení ze správné tabulky (KEYTAB, SYMTAB, CAPSTAB) v závislosti na stištěném SHIFTu. Nezapomeňte, že klávesová kombinace SS+CS není povolena a rutina by měla zajistit návrat k volání KEY SCAN.
V přístím díle budeme s klávesnicí pokračovat, ukážeme si, jak lze klávesy testovat pomocí čtení portů.
Stažení: 6dil.zip
Vyřešil už někdo tento domácí úkol?
sweet: "KEY_SCAN…uplny prepis rutiny z ROM…beztak stejne nevim jak funguje…" Potřebuješ snad s něčím poradit?
Komentář ke KEY-SCAN není úmyslně kvůli následujícímu sedmému dílu. Potřebuju poradit s domácím úkolem, abych vylepšené řešení vložil do MDOS3.
Taky zkus najít v příkladu ze 7.dílu chybu. Je tam a to taková, že je na první pohled zkušeného programátora vidět. Je to takový testík, který prověří, zda ty rutinky někdo zkusil pustit.
fakt se stydim; jeste jsem na to nesahl – zastrelte me…
…doprekladam pro sweeta co mam prelozit a pak MUSIM ukol udelat i kdybych nemel tyden spat, jist, vylucovat a tak vubec…