Obsługa myszy w asemblerze

W tej części dowiemy się, jak dodać w naszych programach obsługę myszy.
Do naszych celów potrzebne nam będą załadowane sterowniki myszy w pamięci oraz przerwanie int 33h.

Zapoznajmy się z kilkoma podstawowymi funkcjami tegoż przerwania (patrzymy oczywiście w listę przerwań Ralfa Brown'a - RBIL):


(przeskocz opis funkcji int 33h)
	INT 33 - MS MOUSE - RESET DRIVER AND READ STATUS
	        AX = 0000h
	Return: AX = status
            		0000h hardware/driver not installed
            		FFFFh hardware/driver installed
        	BX = number of buttons
            		0000h other than two
            		0002h two buttons (many drivers)
            		0003h Mouse Systems/Logitech three-button mouse
            		FFFFh two buttons

	INT 33 - MS MOUSE v1.0+ - SHOW MOUSE CURSOR
	        AX = 0001h

	INT 33 - MS MOUSE v1.0+ - HIDE MOUSE CURSOR
	        AX = 0002h

	INT 33 - MS MOUSE v1.0+ - POSITION MOUSE CURSOR
	        AX = 0004h
	        CX = column
	        DX = row

	INT 33 - MS MOUSE v1.0+ - RETURN BUTTON RELEASE DATA
	        AX = 0006h
	        BX = button number (see #03169)
	Return: AX = button states (see #03168)
	        BX = number of times specified button has been released since
	        	 last call
	        CX = column at time specified button was last released
	        DX = row at time specified button was last released

	(Table 03169)
	Values for mouse button number:
 	0000h  left
 	0001h  right
 	0002h  middle

Tyle powinno nam wystarczyć. Są też funkcje, które na przykład definiują zasięg poziomy i pionowy kursora (można ustawić tak, że kursor będzie się mógł poruszać tylko w wyznaczonym oknie), ale tymi nie będziemy się zajmować.

Na dobry początek resetujemy sterownik i sprawdzamy, czy w ogóle jest jakaś mysz zainstalowana (jeszcze wcześniej można byłoby sprawdzić, czy sam sterownik nie jest procedurą, która nic nie robi, ale pominę to). Kod jest wyjątkowo krótki:

	xor	ax, ax
	int	33h			; sprawdzamy, czy jest mysz
	or	ax, ax
	jz	brak_myszy

Jak było widać wcześniej, pokazanie kursora nie jest trudne i sprowadza się do:

	mov	ax, 1
	int	33h			; pokaż kursor

Do szczęścia brakuje nam już tylko sprawdzenie, czy i gdzie naciśnięto jakiś przycisk. Do tego posłuży nam funkcja numer 6. Wystarczy w BX podać interesujący nas przycisk, a w CX i DX powinniśmy otrzymać współrzędne (dobrze jest przed rozpoczęciem pracy wywołać raz tę funkcję dla wszystkich przycisków, aby wyzerować liczniki naciśnięć). Przykład:

	mov	ax, 6
	xor	bx, bx
	int	33h
	or	bx, bx
	jz	nie_wcisnieto_lewego

	mov	[kolumna], cx
	mov	[wiersz], dx

Nie ma w tym dużo wysiłku, na szczęście. Wszystko za nas robi sterownik, a my tylko potem sprawdzamy rejestry.
Dlatego też od razu przejdę do finału tego artykułu i zaprezentuję program, w którym zawarłem wszystko to, o czym mówiłem. Zadaniem programu jest nic innego, jak tylko wyświetlenie odpowiedniego napisu, gdy użytkownik naciśnie jakiś klawisz myszki (naciśnięcie czegoś na klawiaturze spowoduje wyjście z programu). Napis zostanie wyświetlony w miejscu, gdzie naciśnięto przycisk.

Oto kod:


(przeskocz kod programu)
; Program wyświetlający napis w miejscu, gdzie został naciśnięty
; klawisz myszki.
;
; POD WINDOWS URUCHAMIAĆ W TRYBIE PEŁNOEKRANOWYM
;
;
; Autor: Bogdan D.
; kontakt: bogdandr (at) op (dot) pl
;
; nasm -O999 -o mysz.com -f bin mysz.asm


org 100h

	xor	ax, ax			; AX = 0
	int	33h			; sprawdzamy, czy jest mysz
	or	ax, ax
	jnz	mysz_ok

	mov	dx, nie_ma_myszy
	mov	ah, 9
	int	21h

	mov	ax, 4c01h		; zwracamy kod błędu=1
	int	21h


mysz_ok:
	mov	ax, 3
	int	10h			; czyścimy ekran

	mov	ax, 1
	int	33h			; pokazujemy kursor myszki

					; zerujemy liczniki naciśnięć:
	mov	ax, 6
	xor	bx, bx			; lewy przycisk
	int	33h

	mov	ax, 6
	mov	bx, 1			; prawy przycisk
	int	33h

petla:
	mov	ah, 1
	int	16h		; czy naciśnięto klawisz na klawiaturze?
	jnz	koniec		; jeśli tak, to wychodzimy z programu

	mov	ax, 6
	xor	bx, bx			; sprawdzamy lewy przycisk
	int	33h

	or	bx, bx		; jeśli naciśnięto, to idziemy coś wyświetlić
	jnz	pokaz_l

	mov	ax, 6
	mov	bx, 1			; sprawdzamy prawy przycisk
	int	33h

	or	bx, bx		; jeśli naciśnięto, to idziemy coś wyświetlić
	jnz	pokaz_p

	jmp	short petla

pokaz_l:
				; wiemy, ze CX=kolumna, DX=wiersz, gdzie
				;naciśnięto klawisz, ale to są numery pikseli
				; Aby otrzymać kolumnę i wiersz, dzielimy je
				; przez 8 (bo jest 8 pikseli/znak):
	shr	dx, 3
	shr	cx, 3

	mov	ah, 2			; funkcja ustawiania kursora
	mov	dh, dl			; DH = wiersz
	mov	dl, cl			; DL = kolumna
	int	10h			; ustaw nasz kursor tam

	mov	dx, lewy_p
	mov	ah, 9
	int	21h

	jmp	short petla

pokaz_p:
				; wiemy, ze CX=kolumna, DX=wiersz, gdzie
				;naciśnięto klawisz, ale to są numery pikseli
				; Aby otrzymać kolumnę i wiersz, dzielimy je
				; przez 8 (bo jest 8 pikseli/znak):
	shr	dx, 3
	shr	cx, 3

	mov	ah, 2			; funkcja ustawiania kursora
	mov	dh, dl			; DH = wiersz
	mov	dl, cl			; DL = kolumna
	int	10h			; ustaw nasz kursor tam

	mov	dx, prawy_p
	mov	ah, 9
	int	21h

	jmp	short petla


koniec:
	mov	ax, 4c00h
	int	21h

nie_ma_myszy	db	"Sterowniki myszy nie sa zainstalowane.$"
lewy_p		db	"Lewy$"
prawy_p		db	"Prawy$"

Jak widać, korzystanie z myszy niekoniecznie musi być tak trudne, jak to się mogło wydawać. Po bardziej zaawansowane funkcje radzę sięgnąć do RBIL, gdzie zawsze znajdziecie więcej informacji o danym przerwaniu niż w moim kursie, który skupia się przecież na przedstawianiu algorytmów a nie na zapamiętywaniu każdego szczególiku.

Miłego eksperymentowania.



Spis treści off-line (Alt+1)
Spis treści on-line (Alt+2)
Ułatwienia dla niepełnosprawnych (Alt+0)