Úno 092005
 

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”

  1. Vyřešil už někdo tento domácí úkol?

  2. sweet: "KEY_SCAN…uplny prepis rutiny z ROM…beztak stejne nevim jak funguje…" Potřebuješ snad s něčím poradit?

  3. 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.

  4. 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…

Je nám líto, ale formulář pro přidávání komentářů je momentálně uzavřen.