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
4 komentáre na “6.díl: Klávesnice”
Je nám líto, ale formulář pro přidávání komentářů je momentálně uzavřen.
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…