Myši a ZX Spectrum

Úvod

V následujícím textu jsem se pokusil shrnout pár drobností o oblíbeném polohovacím zařízení, které se mimo jiné používalo i u ZX Spectra. S prvními zmínkami o myši u ZX Spectra jsem se setkal poměrně brzy, snad už v 90tém roce, ale tenkrát nebylo ještě snadné sehnat rozumnou myš za rozumné peníze. Velmi často bylo možné koupit myši jen velmi nepraktické do ruky často velmi hranaté a silně neergonomické (např. třítlačítkové modely od firmy Genius, případně všelijaké stavebnice - mám jednu s pingpongovým míčkem a tlačítky realizovanými ze svěracích špendlíků s papírovými clonkami). Myši se samozřejmě poprvé začaly vyskytovat u počítačů orientovaných na grafiku, což byly všelijaké Apple Macintosh, Atari, Amiga a později i IBM PC. Koncem osumdesátých a začátkem devadesátých let, tj. v době největšího rozmachu ZX Spectra byly např. u Amigy myši standardní součástí výbavy u IBM PC je uživatelé teprve objevovali.

Není divu, že uživatelé ZX Spectra uživatelům "grafických" počítačů (tenkrát mezi ně IBM PC nepatřilo) trochu záviděli a přemýšleli jak si taky takovou myšku připojit a naučit se s ní pracovat. Bohužel to nebylo tak jednoduché. U ZX Spectra se vyskytovalo mnoho různých rozhranní, jak paralelních tak sériových, ale žádné nebylo rozšířeno globálně, žádné z rozhranní nikdy nemělo status standardu (byť nepsaného v rámci platformy). Takového standardu jako stavu dosáhly porty sériové, paralelní a USB na platformě PC (tím spíš, že jmenovaná rozhranní jsou skutečně standardizovaná, ale o to ani tak nejde, jde spíš o rozšířenost mezi uživateli).

Bylo tedy nutné použít rozhranní, když ne globálně rozšířené, tak alespoň trochu rozšířené a pokud možno snadno sehnatelné a levné, aby připojení už tak drahé myši (tenkrát stály často kolem 500Kčs i víc a platy se pohybovaly někde od 2,5 - 5000Kčs) nebylo zbytečně zatěžováno i drahým rozhranním. Jednou z možností byl sériový port. Sériové myši byly snadněji sehnatelné, levnější a byl v nich výrazně větší výběr. Ale ZX Spectrum jak známo nemělo standardně sériový port, kromě modelů ZX Spectrum 128kB, a šedivých ZX Spectrum +2, +2A, +3, které však měly naprosto nestandardní konektory, notabene nevhodně umístěné, protože byly zakryty prakticky jakýmkoliv zařízením připojeným k systémové sběrnici (např. Betadiskem). Tato jediná rozšířenější implementace sériového portu používá obvod AY-3-8912 jako IO port, takže řízení signálů jednak musel provádět software a druhak se v různých přídavných rozhranních používaly i jiné varianty čipu AY, případně jeho klony a často verze bez IO portů. Takže sériová myš existuje, ale je velmi obtížně připojitelná (má-li být zachována kompatibilita) s 48kB verzemi ZX Spectra včetně těch rozšířených na 128kB a doplněných AY, protože těm i po rozšíření chyběly převodníky z TTL <-> RS232 a napájecí zdroj dodávající napětí +12V a -12V. (Dnes dostupný např. MAX232 neexistoval.)

Další volbou byl logicky port paralelní a to nejčastěji UR-4. Zapojení myši do UR-4 je extrémně jednoduché, vlastně není potřeba provádět vůbec žádnou úpravu, pokud se spokojíte jen s jedním tlačítkem. Bohužel velmi zásadní nevýhodou je obrovské výkonové zatížení CPU, protože myš je potřeba obsluhovat zcela kompletně programově. Pro další činnosti, krom obsluhy myši zbývá nejvýše 50% výkonu CPU, obvykle spíš méně, pokud má být pohyb kurzoru opravdu plynulý. U klikacích menu to nevadí, ale je to zcela nepoužitelné v náročnějších hrách. Nicméně tato implementace se přesto v mém okolí rozšířila nejvíce. Částečně kvůli ART Studiu v češtině pro tento typ myši a Betadisk, trochu i kvůli mému Bootu a dalším drobnostem. Této myši se říkalo "Amiga Mouse" (zkráceně jen A-Mouse) podle typu použité myši, ta se vyráběla pro Amigu a Atari a neměla sériové rozhranní, ale paralelní - viz. dále.

V souvislosti s UR-4 není možné nezmínit pokus Proximy o rozšíření kompatibilnější a méně náročné varianty, tzv. "Kempston Mouse". Bohužel ji znám jen z doslechu, ale vím určitě, že byla použitelná místo Kemston Joysticku. Někdo mi říkal cosi o specielním interface, snad s jednočipovým mikroprocesorem PIC, takže její připojení zcela jednoduché nebylo. Ale extrémně jednoduché bylo využití v programech. Interface myši emuloval Kemston Joystick pomocí PWM takže bylo možné v několika málo krocích měnit i rychlost kurzoru v závislosti na rychlosti pohybu myší. Díky tomu fungovala s naprostou většinou programů používajících Kemston Joystick a to buď stejně jako joystick, nebo v lepším případě podobně jako skutečná myš. Tato verze se v mém okolí nevyskytovala vůbec, ale často jsem o ní slýchal na různých setkávacích akcích (Samcon) a možná byla v ČR podobně rozšířená jako A-Mouse.

Poslední variantou je vytvoření vlastního interface s alespoň minimální hardwareovou akcelerací, aby se o myš nemusel starat procesor. Tím spíš, když je výkon Z80 v ZX Spectru velmi nízký a každý ušetřený takt je užitečný. Nejzajímavější varianta pochází odněkud z Ruska a připojuje s k ní taky Amiga myš s TTL rozhranním. Výsledkem činnosti nepříliš složitého a vcelku levného rozhranní jsou tři čísla na třech portech. Dvě čísla udávají polohu myši v rozsahu od 0 do 255 včetně a bity ve třetím bytu určují stisknutá tlačítka. Je sice nutné provést jednoduchou softwarovou korekci pro výšku obrazovky, ale to je zanedbatelné vzhledem k ostatním variantám. A jedná se o skutečnou myš, takže pohyb kursoru zcela kopíruje pohyb myši včetně změn rychlosti pohybu. S touto variantou jsem se setkal prakticky až v době, kdy jsem se dostal poprvé k internetu a ZX Spectrum už řadu uživatelů nezajímalo (1995 - 1996).

Shrnutí nejznámějších myší

Typ myširozhrannívýhodynevýhodyostatní
Kempston Mouse (Rusko)Nutný specielní interface, schéma zde.Skoro vůbec nezatěžuje procesor. Stačí číst 3 čísla na 3 portech a to je vše.Obsazuje 3 porty což není málo, vrací nevhodně stav tlačítek (podle mého názoru).Vyskytuje se u ruských počítačů Pentagon, Scorpion a zcela určitě v počítači Sprinter, emulována v X128.
Kempston Mouse ProximaSpecielní rozhranní od Proximy, prý dokonce s jednočipem PIC.Není třeba specielní software, pracuje v programech, které umí pracovat s Kempston Joystickem.Je nutné specielní relativně složité rozhranní.Není to skutečná myš. Pohyb kurzoru není zcela dokonalý. Spíše se jedná o joystick s možností zpomalení pohybu kurzoru.
Amiga Mouse ( Heptau ? Nejsem si jistý.)UR-4, nebo lehce upravený interface Kempston Joysticku. Viz. popisu 8255 a UR-4.MHB8255 je velmi rozšířený interface na území české a slovenské republiky. Máte-li UR-4 nic jiného nepotřebujete.Velmi hodně zatěžuje procesor, vše musí obsloužit program (zabere nejméně 1/2 přerušení). Dobře použitelné užitkových programech se spoustou ikon a tlačítek, horší ve hrách.V ČR a SR velmi rozšířený typ myši a to především, kvůli jednoduchosti připojení. Tuto myš podporuje většina mých programů.
Sériová Myš (ing. Petr Simandl)RS232, které je součástí Spectra 128 kBRelativně málo zatěžuje procesor, nutné pouze čtení několika bytů jednou za přerušení ovšem ze sériového rozhranní.Rozumně použitelná jen u ZX Specter 128kB, u ostatních jsou kompatibilní sériové porty jen vyjímečně. Viz. výše.Nutno upravit konektor RS232 na cannon 9pinů, úprava myši na konektor Spectra není vhodné. Originální konektor není normálně sehnatelný.

Amiga Mouse

V následujícím textu se budu zabývat především Amiga myší připojenou do UR-4, protože ji znám nejlépe z výše vyjmenovaných typů a protože její softwarové ovládání, resp. čtení je nejsložitější.

Předně Amiga myš není v žádném případě zaměnitelná s jinými typy, rozhodně ne sériovými. Komunikuje na úrovních TTL a v podstatě je paralelní, protože používá 4 dráty pro přenos pulzů ze čtyř čidel, další tři dráty pro přenos stavu tlačítek a dva dráty pro napájení. tj. minimálně 7, maximálně 9 vodičů, víc nemá smysl, protože se u ní stejně jako u myši sériové používá devítipinový konektor canon. Narozdíl od sériové myši, kde se napětí pulzů může pohybovat od -15V do -3V pro log. 0 a od 3V do +15V pro log. 1 (běžně to bývá +/-5V nebo +/-12V) a data se přenáší protokolem RS232 tak u Amiga myši jsou signály TTL, tj. log 0 je 0V až cca 1V a log 1 přibližně 3V až 5V (není to přesně, ale pro orientaci postačí).

Pro zajímavost se můžete podívat jak taková myš vypadá zevnitř. Všimněte si obvodu 74HC14N (Což je invertující Schmittův klopný obvod viz. datasheet), který v myši funguje prakticky jen jako tvarovač impulzů.

Stavový diagram pulzů na výstupu myši

stavovy diagram výstupu z Amiga myši

Délka pulzů záleží na rychlosti pohybu myši. Aby se kursor myši mohl pohnout musí být dokončena celá sekvence pulzů od stavu 0, 0 do stavu 0, 0. Pořadí pulzů udává směr pohybu, resp. směr pohybu je možné zjistit z toho, který pulz přijde první. Pokud sekvence začíná jedním z pulzů a končí tímtéž, pohyb není detekován (odpovídá pohybu myši o stejnou vzdálenost tam a zpět) a kurzorem myši nebude pohnuto.

Význam pinů na konektoru myši

Pro srovnání uvádím i význam pinů Kempston Joysticku, který je známější.

bitpinKemston joystickAmiga Myšpoznámka
04vpravoosa X2 (XB)---
13vlevoosa Y1 (YA)---
22dolůosa X1 (XA)---
31nahoruosa Y2 (YB)---
46firetlačítko 1---
55---tlačítko 2nutné přidat invertor i do UR-4
69---tlačítko 3 nutné přidat invertor i do UR-4
7------------

Myší pracujících na úplně stejném principu se běžně vyskytují dva typy lišící se pouze jiným rozmístěním vývodů na konektoru. V praxi se obvykle jedná o jedinou myš s malým přepínačem vespod a polohami označenými jako "MS AM" a "PC AT". správná poloha je "MS AM". Jedna z poloh je pro počítače Amiga a druhá pro Atari (ST, STE a pod.).

Kempston Mouse - RU

S touto myší jsem se setkal v emulátoru X128 a také jsem ji objevil na nějakých ruských www stránkách. Skládá se z rozhranní převádějícího TTL signál z myši na souřadnice (v podstatě stejně jako níže uvedený program) a standardní Amiga myši. Obrovskou výhodou této varianty jsou zcela zanedbatelné nároky na výkon CPU. Ruská Kemston Mouse je asi jako jediná bez problémů použitelná ve hrách, velmi rozumně je využitá například v předělávce WarCraft 1 na ZX Spectrum (Čornyj Varon), dokonce není problém ji používat v Basicu což s jinou plnohodnotnou myší možné není.

Jak je u ruských periferií pro ZX Spectrum zvykem adresuje se šestnáctibitově (což není tak docela přesné, jak se později ukázalo viz. popis kmouse) a to na portech uvedených v tabulce. Podle mého zkoumání je jisté, že myš pracuje nejméně se dvěma tlačítky, ale nikdy se mi nepodařilo najít program, nebo popis, kde by bylo využité tlačítko třetí (i to se časem změnilo, tlačítko se využívá a přibylo kolečko) ačkoliv tomu principielně nebrání vůbec nic, dokonce by jich mohlo být třeba i osum (právě v poslední variantě byly horní čtyři bity portu využity pro kolečko).

porty ruské Kempston mouse

HexDecoznačenípoznámka
#FADF64223tlačítkaB0=pravé, B1=levé, B2=střední (0=stisknuto, 1=nestisknuto)
#FBDF64479souřadnice Xsouřadnice v intervalu <0,255>
#FFDF65503souřadnice Ysouřadnice v intervalu <0,255>
#FEDF65247souřadnice Zkolečko/a myši implementované Velesoftem (později opět odstraněno kvůli kompatibilitě s ruskou verzí)

Tato myš obravdu vrací i pro Y-ovou souřadnici hodnotu od 0 do 255, je tedy potřeba provést jednoduchou korekci. Jinak funguje vše velice dobře a jak se zdá nedochází k žádným (zřejmým) kolizím zařízení. Toto ovšem raději vyzkouším u skutečného Spectra. (Opět mírná aktualizace, kolize u nejstarší varianty byly, viz. popis kmouse.)

Program zobrazující šipku ovládanou myší

Šipku zobrazovanou následujícím programem lze ovládat buď klávesami (Sinclair Joystick, OPQAM), Kempston joystickem, nebo Amiga myší. Program je napsán dost univerzálně, takže podle bitu 7 v log. 1 (což na UR-4 nenastane) detekuje přítomnost korektního interface pro Kempston joystick, nebo Amiga myš a podle současně nastavených bitů pro směry vlevo a vpravo, nebo nahoru a dolů dokáže rozlišit Amiga myš od joysticku. Případně lze obojí vypnout, kdyby to náhodou na nějaké hardwarové konfiguraci nefungovalo.

Program umožňující volat myš z Basicu (kvůli HL')

Nezapomeňte si upravit cesty ke vkládaným zdrojovým textům sipka.za a downhl.za.

;==============================================================================
;  TESTOVACÍ PROGRAM PRO ŠIPKU
;==============================================================================

          cpu       z80undoc
          org       60000

START     di
          push      ix
          exx
          push      hl                  ; HL' nutno zachovat kvůli Basicu, dělal by problémy
          exx

          ld        a,6
          out       (254),a

          call      MOUSE

          ld         a,2
          out       (254),a
END       exx
          pop       hl
          exx
          pop       ix
          ei
          ret

EXIT      ld        a,1
          out       (254),a
          jr        END

XYIKON    db        0,255,0,192         ; x1,x2,y1,y2 (celá obrazovka)
          dw        EXIT
          db        255

          include ../libs/sipka.za
          include ../libs/downhl.za

Vlastní ovladač myši

Program byl zkoušen v emulátoru FUSE a kompilován kompilerem AS, nicméně s drobnými úpravami konstant by měl být zkompilovatelný kdekoliv. Zdrojový text je mimochodem odsazován po 10 znacích, některé řádky jsou proto trochu rozházené.

;==============================================================================
;     KOMPLEXNÍ PROGRAM PRO ČTENÍ KLÁVESNICE, AMIGA MYŠI A K-MOUSE
;==============================================================================

; Stručný princip:
;
;	Vezmi původní souřadnice, spočítej adresu na obrazovce (MOUSE_XY).
;	Vykresli šipku na obrazovku, zároveň ulož co bylo pod ní.
;	Zpracuj vstup ze zvoleného HID a spočítej nové souřadnice.
;	Zapiš nové souřadnice.
;	Zapiš stav tlačítek HID (proměnná MOUSE_B)
;	Čekej na přerušení.
;	Smaž šipku a místo ní vykresli původní obsah obrazovky.
;	Opakuj celý proces dokud není stisknuto tlačítko "fire".
;	Zjisti jestli a na jakou ikonu bylo kliknuto, jinak opakuj.
;	Skoč na obslužnou rutinu ikony (JP).


; Význam bitů proměnné MOUSE_B:
;
;	bit 0	=	klávesa 1, nebo levé tlačítko myši
;	bit 1	=	klávesa 2, nebo pravé tlačítko myši
;	bit 2	=	klávesa 3, nebo prostřední tlačítko myši
;
;	další tlačítka nejsou definována %00000xxx - horní bity jsou vždy 0
;
;	update (spíše jen úvaha do budoucna):
;	bit 3	=	kolečko myši nahoru?, resp. tlačítko 4
;	bit 4	=	kolečko myši dolu, resp. tlačítko 5
;	bit 5	=	tlačítko 6, resp. tlačítko pod kolečkem myši

MOUSE_X	equ	MOUSE+2		; poslední známé souřadnice šipky
MOUSE_Y	equ	MOUSE+1
MOUSE_XY	equ	MOUSE_Y		; 16ti bitové souřadnice
MOUSE_T	equ	MOUSE_S+1		; typ zařízení  0=KEYS, 1=AMOUSE, 2=KMOUSE
MOUSE_B	equ	MOUSEBUTT+1	; stav tlačítek
MOUSE_KS	equ	MOUSEKS		; KEYSTEP, velikost kroku při ovládání pomocí kláves


MOUSE	ld	hl,96+128*256	; souřadnice šipky X do L, Y do H
	push	hl		; náhrada za neexistující instrukci ld bc,hl
	pop	bc		; takže X je v C, Y v B
	ld	ix,MSIPKA		; do IX adresu spritu
	exx
	ld	hl,MSIPKA_B	; do HL' adresu bufferu na pozadi sipky
	exx
	ld	a,b		; vezmi Y-ovou souradnici (jaký význam má v A?)
	call	8881		; ze souřadnic v BC spočítej adresu ve VRAM do HL
	ld	(MOUSEC+1),hl	; ulož tuto adresu, bude užitečná při mazání šipky
	ld	(MOUSE2+1),a	; toto cislo budu odecitat, co znamena ????

; vykreslení šipky  - pochází z knihy Assembler a ZX Spectrum II, komentáře jsem přepsal

	ld	b,15		; sprite šipky je vysoký 15 pixelů (mimochodem široký je 1 byte)
MOUSE1	push	bc		; ulož kolik opakování - mikrořádků zbývá
	push	hl		; dvakrát ulož adresu šipky ve VRAM, na kterou se bude kreslit
	push	hl
	ld	h,0		; do H ulož 0, sem se bude rotovat sprite/maska, pokud to bude třeba
	ld	l,(ix+0)		; do L přečti byte spritu
	ld	d,h		; vynuluj D (to samé jako H)
	ld	e,(ix+15)		; do E přečti byte masky
	inc	ix		; posuň ukazatel na grafiku spritu
	ld	a,8		; rotovat můžu nejvýše 8x
MOUSE2	sub	0		; od počtu rotací odečtu počet rotací vlevo a získám počet rotací vpravo
	ld	b,a		; počet rotací vpravo si uložím do B
MOUSE3	add	hl,hl		; HL *= 2 (náhrada rr hl)
	ex	de,hl		; prohoď HL a DE (add de,de taky bohužel neexistuje)
	add	hl,hl		; HL *= 2 (náhrada rr de)
	ex	de,hl		; HL a DE prohoď zase zpátky
	djnz	MOUSE3		; jednobytový sprite a maska jsou uloženy v HL a DE posunuté jak je třeba

	ex	(sp),hl		; prohoď poslední hodnotu v zásobníku (adresa šipky ve VRAM) a obsahem HL
	pop	bc		; do BC tak ze zásobníku vyzvednu odrotovanou předlohu
	ld	a,(hl)		; do A načtu původní obsah obrazovky
	exx
	ld	(hl),a		; uložím na (HL') - adresa bufferu na původní pozadí (1. levý byte, budou dva)
	inc	hl		; posunu ukazatel do bufferu
	exx
	ld	a,d		; vezmu do a pravou část masky
	cpl			; invertuju ji (kdybych ji uložil už invertovanou, měl bych problém s rotací)
	and	(hl)		; a z pozadí vymažu ty pixely, kde měla maska 0
	or	b		; a do vykousnutého pozadí zaoruju předlohu
	ld	(hl),a		; a nakonec uložím do VRAM
;	call	RIGHTL		; spočítej adresu o byte vpravo
	inc	hl
	ld	a,(hl)		; celé kreslení provedu ještě jednou pro 2. byte více vpravo
	exx
	ld	(hl),a
	inc	hl
	exx
	ld	a,e
 	cpl
	and	(hl)
	or	c
	ld	(hl),a
	pop	hl		; obnov adresu levého bytu ve VRAM
	call	DOWNHL		; spočítej adresu o pixel níž
	pop	bc		; obnov počítadlo
	djnz	MOUSE1		; a opakuj, dokud nejsou vykresleny všechny mikrořádky šipky

; volba polohovacího zařízení 0=KEYS, 1=AMOUSE, 2=KMOUSE

MOUSE_S	ld	a,0
	or	a
	jp	z,MOUSEB	; A=0	; Buttons - klávesy
	dec	a
	jp	z,MOUSEA	; A=1	; Amiga mouse (myška z Amigy zapojená do UR-4)
	dec	a
	jp	z,MOUSEK	; A=2	; ruská Kempston mouse vracející přímé souřadnice
				; v ostatních případech čtu klávesy

;------------------------------------------------------------------------------
; ZMĚNA SOUŘADNIC [X,Y] pomocí klávesnice
;------------------------------------------------------------------------------

MOUSEB	call	MOUSRKEY		; prečti porty definovaných kláves, v D bude stav testovaných kláves
	ld	hl,(MOUSE_XY)	; do HL přečti souřadnice šipky

MOUSEKS	ld	c,2		; velikost kroku šipky, o kolik se šipka pohne při stisku klávesy
	bit	5,d		; testování 1. klávesy (UP)
	jr	z,MOUSEB1		; Z = klávesa nebyla stisknuta => přeskoč zpracování
	ld	a,h		; vezmi z H Y-ovou souřadnici
	sub	c		; odečti krok posunu
	ld	h,a		; ulož novou Y-ovou souřadnici do H
	jr	nc,MOUSEB1	; nedošlo-li k podtečení, přeskoč korekci
	ld	h,0		; C = šipka narazila do horního okraje => proveď korekci, aby neprošla

MOUSEB1	bit	6,d		; testování 2. klávesy (DOWN)
	jr	z,MOUSEB2		; Z = klávesa nebyla stisknuta => přeskoč zpracování
	ld	a,h		; vezmi z H Y-ovou souřadnici
	add	a,c		; pričti krok posunu
	ld	h,a		; ulož novou Y-ovou souřadnici do H
	cp	189		; a otestuj jestli šipka neprošla dolním okrajem
	jr	c,MOUSEB2		; není-li souřadnice větší než 189, přeskoč korekci
	ld	h,190		; C = šipka narazila do dolního okraje => proveď korekci, aby neprošla

MOUSEB2	bit	3,d		; testování 3. klávesy (LEFT)
	jr	z,MOUSEB3		; Z = klávesa nebyla stisknuta => přeskoč zpracování
	ld	a,l		; vezmi z L X-ovou souřadnici
	sub	c		; odečti krok posunu
	ld	l,a		; ulož novou X-ovou souřadnici do L
	jr	nc,MOUSEB3	; nedošlo-li k podtečení, přeskoč korekci
	ld	l,0		; C = šipka narazila do levého okraje => proveď korekci, aby neprošla

MOUSEB3	bit	4,d		; testování 4. klávesy (RIGHT)
	jr	z,MOUSEB4		; Z = klávesa nebyla stisknuta => přeskoč zpracování
	ld	a,l		; vezmi z L X-ovou souřadnici
	add	a,c		; přičti krok posunu
	ld	l,a		; ulož novou X-ovou souřadnici do L
	cp	252		; a otestuj jestli šipka neprošla pravým okrajem
	jr	c,MOUSEB4		; není-li souřadnice větší než 252, přeskoč korekci
	ld	l,252		; C = šipka narazila do pravého okraje => proveď korekci, aby neprošla

MOUSEB4	ld	a,d		; vezmi do A stav prečtených kláves
	and	00000111b		; ponech jen bity, které označují tlačítka jako fire (jako tlač. myši)
	ld	(MOUSE_B),a	; a stav tlačítek zapiš do proměnné MOUSE_B
	ld	(MOUSE_XY),hl	; ulož nové souřadnice šipky pro příští použití
	jp	MOUSE50

; Rutina na čtení kláves z knihy "Assembler a ZX Spectrum 2"
; Může být společná pro klávesu a Kempston Joystick (nemá s ruskou Kempston Myší nic společného, jen jméno)
MOUSRKEY	ld	hl,MOUSEKTAB	; vezmi adresu tabulky kláves
	ld	de,7		; v E je počet kláves a v D bude výsledek (1 = stisknuto)
MOUSRK1	ld	c,(hl)		; do BC prečti z tabulky adresu portu
	inc	hl
	ld	b,(hl)
	inc	hl
	in	a,(c)		; prečti port (BC - 16ti bitové adresování)
	bit	7,c		; otestuj bit 7, u kempston joysticku je tam vždy 0 (leda by byl vadný)
	jp	z,MOUSRK2		; přeskoč CPL jedná-li se o kempston joystick
	cpl			; 1 = klávesa stisknuta (normálně to je u kláves obráceně)
MOUSRK2	and	(hl)		; ponech jen testovaný bit (filtrace tabulkou)
	inc	hl		; a posuň HL na začátek dalšího řádku tabulky
	jr	z,MOUSRK3
	set	7,d		; nastav bit 7 na 1
MOUSRK3	srl	d		; a posuň ho dolů (tím se do D postupně uloží stav všech kláves)
	dec	e		; sniž počítadlo portů k prečtení
	jr	nz,MOUSRK1	; opakuj dokud není vše přečteno
	ret

; Tabulka kódů kláves, kterou je možné měnit - první 2 byty jsou adresou portu, 3. byte je bitový filtr.
; Tímto způsobem je možno definovat i Kempston joystick, ale není možné ho rozumně detekovat, pokud je
; zároveň připojena amiga mouse, uživatel musí sám rozhodnout co chce používat, nejlépe stiskem klávesy.
; Kempston joystick a klávesy je samozřejmě možné libovolně kombinovat, i když to asi není praktické.

MOUSEKTAB	db	254, 127, 00000100b	; FIRE 1	(M)
	db	254, 127, 00001000b	; FIRE 2	(N)
	db	254, 127, 00010000b	; FIRE 3	(B)
	db	254, 223, 00000010b	; LEFT	(O)
	db	254, 223, 00000001b	; RIGHT	(P)
	db	254, 251, 00000001b	; UP	(Q)
	db	254, 253, 00000001b	; DOWN	(A)

;------------------------------------------------------------------------------
; ZMĚNA SOUŘADNIC [X,Y] pomocí AMIGA MOUSE
;------------------------------------------------------------------------------
; Pozor! Interface s MHB8255 je nutné inicializovat mimo tento program.

MOUSEA	ld	bc,130*256	; B = počet průchodů čtecí smyčkou (rozumný kompromis)
	ld	a,(MOUSE_X)	; souřadnice se budou uvnitř smyčky měnit a je lépe budou-li operandem
	ld	(MOUSAX+1),a
	ld	a,(MOUSE_Y)
	ld	(MOUSAY+1),a
MOUSEA1	push	bc		; uloz BC do zasobniku - zde zacina smycka
	ld	b,c		; a do B ?????
	in	a,(31)		; čti port
	ld	de,MOUSEAP	; pomocná proměnná
	call	MOUS_SM		; zjisti jakym smerem se mys pohnula
MOUSAX	ld	a,77h		; vezmi souradnice mysi
	add	a,(hl)
	jr	z,MOUSAKX		; Z = preskoc zapis X-ove souradnice
	ld	(MOUSAX+1),a

MOUSAKX	inc	de
	in	a,(31)		; čti port
	rrca			; posun o 1 bit vpravo, kvuli detekci smeru
	call	MOUS_SM		; a ted se da pouzit stejna rutina jako pro X
MOUSAY	ld	a,60h		; vezmi starou Y-ovou souradnici
	add	a,(hl)		; a pricti cislo prectene z tabulky
	jr	z,MOUSAKY		; Z = preskoc zapis a korekci Y-ove souradnice
	cp	192		; otestuj jestli sipka neprosla spodnim okr.
	jr	nz,MOUSADO	; pokud prosla (Z)
	ld	a,191		; proced korekci
MOUSADO	ld	(MOUSAY+1),a	; zapis novou Y-ovou souradnici
MOUSAKY	pop	bc		; obnov pocitadlo pruchodu
	djnz	MOUSEA1		; a opakuj pokud tento nebyl posledni
	ld	a,(MOUSAX+1)	; zapis nove souradnice do promennych
	ld	(MOUSE_X),a
	ld	a,(MOUSAY+1)
	ld	(MOUSE_Y),a
	in	a,(31)		; naposledy precti port mysi
	rra
	rra
	rra
	rra
	and	00000111b		; ponech jen bity tlacitek
	ld	(MOUSE_B),a
	jp	MOUSE50

MOUS_SM	and	5		; testuje jakym smerem se amiga mys pohnula
	ld	c,a		; na zaklade Karnaughovych map
	ld	a,(de)
	rlca
	and	10
	or	c
	ld	(de),a
	ld	c,a
	ld	hl,MOUSTAB
	add	hl,bc
	ret

MOUSTAB	db	0,255,1,0		; tabulka kódů pro výpočet pohybu AMOUSE
	db	1,0,0,255
	db	255,0,0,1
	db	0,1,255,0

MOUSEAP	dw	0		; promenna tykajici se vyhradne detekce smeru
				; pohybu AMIGA MOUSE

;------------------------------------------------------------------------------
; ZMENA SOURADNIC [X,Y] pomocí KMOUSE (Ruská verze - později i od Velesofta)
;------------------------------------------------------------------------------
; .... OTESTOVAT V PRAXI!

MOUSEK	ld	a,251		; cti X-ovou souradnici z portu 64479
	in	a,(223)
	ld	(MOUSE_X),a	; uloz pro pristi zavolani programu MOUSE
	ld	a,255
	in	a,(223)		; cti Y-ovou souradnici z portu 65503
	cpl			; u souradnice Y nam nevyhovuje hodnota nad 192
	cp	191		; takze provedu jednoduchou korekci
	jp	c,MOUSEKK		; IF A>191 THEN A=191
	ld	a,191
MOUSEKK	ld	(MOUSE_Y),a	; a uloz pro dalsi volani programu MOUSE
	ld	a,250		; cti port 64223 - BUTTONS
	in	a,(223)		; ale ziskal jsem nevhodny zpusob ulozeni stavu
	cpl			; takze zase provedu korekci, nejdrive neguju
	and	00000111b		; byte a pak z nej necham jen dolni 3 bity
	ld	b,a		; zalohuju do B a ted prehodim bit 0 a bit 1
	rla			; bit 0 v A posunu na pozici bitu 1
	and	00000010b		; ponecham jen bit 1
	ld	c,a		; a ulozim do C
	ld	a,b		; znovu vezmu puvodni byte
	rra			; posunu bit 1 v A na pozici bitu 0
	and	00000001b		; ponecham jen bit 0
	or	c		; pridam bit 1 ulozeny v C
	ld	c,a		; ted budu mit v C ulozene prehozene bity 0 a 1
	ld	a,b		; naposledy vezmu puvodni byte
	and	00000100b		; ponecham z nej jen bit 2
	or	c		; pridam k nemu bity 0 a 1
	ld	(MOUSE_B),a	; ulozim do pameti a je hotovo
	jp	MOUSE50

; Před HALT (za MOUSE50) je možno přidat automatickou detekci polohovacího zařízení a
; následnou změnu proměnné MOUSE_T. V dalším volaní pak bude takto zvolené zařízení
; normálně používáno.

; autodetect KEYBOARD - Je-li stisknuta klávesa přepne se ovladač na čtení klávesnice, užitečné
;                       pokud uživatel potřebuje z jakéhokoliv důvodu ovládat program klávesnicí
;                       ale byla zvolena myš.

;	xor	a		; ctu port 0*256+254
;	in	a,(254)
;	cpl
;	and	%00011111	; ponecham dolnich 5 bitu
;	jr	nz,MOUSE50
;	ld	a,0		; do A cislo odpovidajici klavesnici
;	ld	(MOUSE_T),a	; a zapisu ho do promenne MOUSE_T

; autodetect AMIGA MOUSE  - Amiga mouse se oproti Kempston joystiku liší tím, že u ní mohou běžně
;                           nastat log. 1 na bitech, které u joysticku znamenají protilehlé směry,
;                           takže je není možno zvolit bez jeho mechanického zničení.
;                           Bohužel detekce nemůže být 100% spolehlivá, ačkoli většinou funguje.

;	in	a,(31)		; čti port na němž je připojena myš
;	bit	a,7		; je-li bit 7 log. 1 pravděpodobně port 31 není funkční
;	jp	nz,MOUSE50	; takže zbytek rutiny přeskoč
;	and	%101		; tyto bity nemohou být nikdy v log. 1 pokud
;	cp	%101		; je připojen jenom Kempston Joystick
;	jp	nz,MOUSE50	; Z = bity byly v log. 1 => myš je pravděpodobně připojena
;	ld	a,1		; do A číslo odpovídající amiga myši
;	ld	(MOUSE_T),a	; a zapíšu ho do proměnné MOUSE_T

; Jak jednoduše detekovat KEMPSTON MOUSE nevím!
; Jak jednoduše detekovat KEMPSTON JOYSTICK nevím (resp. vím, ale ne v kombinaci s Amiga mouse)!

MOUSE50	ei			; povolím přerušení, pokud náhodou povolené nebylo
	halt			; a počkám na něj (paprsek začíná kreslit obrazovku)
				; případný zákaz přerušení si přidejte sami

; smazání šipky a vykreslení původního obsahu obrazovky

MOUSEC	ld	hl,0		; do operandu je místo 0 zapisována adresa šipky ve VRAM
	ld	b,15		; počet pixelů na výšku
	ld	de,MSIPKA_B	; adresa uloženého původnho pozadí pod šipkou
MOUSEC1	ld	a,(de)		; vezmu byte z původního pozadí
	ld	(hl),a		; a zapíšu ho do VRAM
	inc	de		; posunu DE o 1
	push	hl		; zapamatuju HL
	call	RIGHTL		; a spočítám adresu HL o byte vpravo (inc HL nestačí, kus šipky může zmizet)
	ld	a,(de)		; vezmi další byte z původního pozadí
	ld	(hl),a		; a zapíšu ho do VRAM
	inc	de		; posunu DE o 1
	pop	hl		; obnovím v HL adresu levého bytu
	call	DOWNHL		; a z ní spočítám adresu o pixel níž
	djnz	MOUSEC1		; opakuj tolikrát, kolik pixelů na výšku šipka má

MOUSEBUTT	ld	a,0		; vezmi stav stisknutí tlačítek
	or	a		; 0 = žádné nebylo stisknuto
	jp	z,MOUSE		; pokud nebylo tlačítko stisknuto, opakuj činnost celého programu

	ret         		; nějaké tlačítko bylo stisknuto, vrať se, záleží na programu
				; využívajícím šipku jak tlačítka zpracuje (tím může být NOIKON)

;==============================================================================
;  GRAFIKA A NĚKTERÉ PROMĚNÉ
;==============================================================================

MSIPKA	db	00000000b		; sprite šipky
	db	01000000b
	db	01100000b
	db	01110000b
	db	01111000b
	db	01111100b
	db	01111110b
	db	01111000b
	db	01001000b
	db	00001000b
	db	00000100b
	db	00000100b
	db	00000010b
	db	00000010b
	db	00000000b

MSIPKA_M	db	11100000b		; maska šipky - musí následovat hned za spritem
	db	11110000b
	db	11111000b
	db	11111100b
	db	11111110b
	db	11111111b
	db	11111111b
	db	11111111b
	db	11111100b
	db	11111110b
	db	00011110b
	db	00001111b
	db	00001111b
	db	00000111b
	db	00000111b

MSIPKA_B	ds	30		; sem se ukládá z VRAM to co šipka překryla

;==============================================================================
;  PODPŮRNÉ RUTINY
;==============================================================================

RIGHTL	ld	a,l		; RIGHTL zajištuje posun adresy spritu ve
	inc	l		; VRAM o byte vpravo a jeho spravné vykreslení,
	xor	l		; pokud je jeho levá půlka přímo u pravého
	bit	5,a		; okraje obrazovky. V takovém případě se
	ret	z		; pravá půlka kreslí do ROM, takže vlastně
	ld	h,0		; nekreslí / BACHA NA WRITEABLE ROMky!! (nahradit 0 číslem 60, poškodí font)
	ret

;	include	downhl.za		; tato rutina by mela byt soucasti programu, který myš používá
;==============================================================================
; RUTINA, KTERÁ ZAVOLÁ ŠIPKU A VOLÁ JI TAK DLOUHO DOKUD UŽIVATEL NEKLIKNE
; NA NĚKTEROU PLATNOU IKONU (POLOHA DEFINOVANÁ V TABULCE). V TOM OKAMŽIKU
; RUTINA SKOČÍ NA ADRESU PŘÍSLUŠNÉ RUTINY, KTERÁ IKONĚ ODPOVÍDÁ.
;==============================================================================

NOICON	call	MOUSE		; zavolej program pro obsluhu HID a kreslení šipky na obrazovku
				; rutinu NOICON možno volat pomocí CALL a instrukci
				; RET umístit do rutiny reagující na kliknuti na ikonu

TSTXY	ld	de,(MOUSE_XY)	; souřadnice šipky do DE (D = X, E = Y)
	ld	bc,6		; do BC délku souřadnic v tabulce ikon a adresy příslušné rutiny
	ld	ix,XYIKON-6	; do IX adresu tabulky ikon a adres rutin mínus jednu položku

TSTXY_1	add	ix,bc		; pričti BC k registru IX
	ld	a,(ix+0)		; čti X1
	cp	255		; porovnej s 255 - znamená konec tabulky
	jr	z,NOICON		; je-li 255 (Z) nebylo kliknuto na ikonu a bude opakováno kreslení šipky
	ld	a,(ix+0)		; jinak porovnávej dál, dokud není nalezena ikona, nebo konec tabulky
	cp	d
	jr	nc,TSTXY_1
	ld	a,(ix+1)
	cp	d
	jr	c,TSTXY_1
	ld	a,(ix+2)
	cp	e
	jr	nc,TSTXY_1
	ld	a,(ix+3)
	cp	e
	jr	c,TSTXY_1
	ld	h,(ix+5)		; bylo kliknuto na nějakou ikonu, takže
	ld	l,(ix+4)		; přečti do HL adresu obslužné rutiny
	jp	(hl)		; a skoč na tuto adresu


; TOTO JE JEN UKAZKA - takovato tabulka by mela byt soucasti programu
;
;XYIKON	db 0,16,0,16		; x1,x2,y1,y2
;	defw EXIT_I		; adresa vykonne rutiny
;	db 255			; konec tabulky ikon (NUTNE! Nikdy nesmí chybět!)
;
;EXIT_I				; priklad
;	ret


;==============================================================================
Program už je v podstatě zastaralý, stahujte z popisu KMouse

Celý ovladač myši je nutné spouštět od adresy NOICON. Rutina TEST_M je skutečně jen k testování, to není vstupní bod programu. Je nutné mít správně vyplněnou tabulku XYIKON, která obsahuje souřadnice ikon a adresu rutiny, která bude zavolána po kliknutí na ikonu. A za poslední, před tuto rutinu doporučuju přidat možnost volby ovládání, rozhodně bych si ve svém programu nedovolil jako defaultní ovladač použít jednu z myší. Když už, tak klávesy. A pokud má uživatel možnost změnit šipkou (třeba v menu) ovládání, musí existovat možnost totéž provést klávesnicí i po změně na myš.


Download

Zdroje informací: Tak různě z webu (porty a schéma připojení Kempston mouse), knížka Assembler a ZX Spectrum (prapůvodní základy pro kreslení šipky ovládané klávesami), a dost vlastních zkušeností.

Související odkazy

Opravené chyby

  • 28.2.2004 - celý článek přepracován, výrazně rozšířen úvod, opraveny chyby, doplněn datasheet 74HC14 a obrázek myši zevnitř.
  • 11.4.2005 - opraveny přehozené bity 0 a 1 (v tabulce i diagramu), doplněny odkazy na HWBook s popisem konektorů, vše znovu pečlivě zkontrolováno podle reálného fungujícího hardwaru, upozornil Velesoft

[ Zpět na hlavní stránku ]

Cygnusova stránka o ZX Spectru a kompatibilních počítačích byla napsána (přepsána) výhradně pomocí svobodného Open Source softwaru. V případě že naleznete chybu, nebo byste rádi cokoliv co se ZX Spectrem souvisí, neváhejte mi napsat na některý z mých emailů. A tady se můžete něco málo dozvědět o tomto webu. Zvláště pokud používáte M$IE, tak byste si to měli přečíst.