;KeyMous.ASM
; mouse driver for Turbo Pascal
;Copyright 1989
;by Kenneth A. Hill, P.E.

MouseInt	Equ	33h		;Mouse interrupt

MoveRight	Equ	01h		;right motion byte mask
MoveLeft	Equ	02h		;left motion mask
MoveDown	Equ	04h		;down motion mask
MoveUp		Equ	08h		;up motion mask

Bios_Data	Equ	40h		;Bios data Segment
Buffer_Head	Equ	1Ah		;offset to keyboard buffer head
Buffer_Tail	Equ	Buffer_Head+2	;offset to buffer tail
Buffer_Start	Equ	80h		;starting keyboard buffer address offset
Buffer_End	Equ	Buffer_Start+2	;ending Kb Buffer addr offset

data		segment byte public	;Pascal variables
		Extrn	LKey:Word
		Extrn	RKey:Word
		Extrn	DKey:Word
		Extrn	UKey:Word
		Extrn	LBKey:Word
		Extrn	RBKey:Word
                Extrn   MBKey:Word
		Extrn	VDly:Word
                Extrn   HDly:Word
                Extrn	Msk : Word
                Extrn	MouseMotion:Byte
		Extrn	VCount : Word
		Extrn	HCount : Word

	VFlag	DW	0		;Word for +/- V. movem't flag
	HFlag	DW	0		;Word for +/- H. Movem't flag
	Evnts	DW	?		;Event storage (AX)
	Btns	DW	?		;Button storage (BX)
	XCoord	DW	?		;X-coord storage (CX)
	YCoord	DW	?		;Y-coord storage (DX)
	VMicks	DW	?		;V Mickey count (SI)
	HMicks	DW	?		;H Mickey count (DI)
	MousDat DW	?		;Mouse DS

Data		Ends

code		segment byte public
 		assume cs:code,DS:DATA
		PUBLIC MousKey
;
;
;--------------------------------------------------------------------------
;MousKey subroutine is handed control by the mouse driver when its mask matches
;a mouse action.
;  At Entry Registers are:
;	AX 	Event Flags (same format as mask)
;	BX	Button State
;	CX	X pointer coordinate
;	DX	Y pointer coordinate
;	SI	last raw vertical mickey count
;	DI	last raw horizontal mickey count
;	DS	mouse driver data segment! (Mouse.Com's or Mouse.Sys's)
;--------------------------------------------------------------------------
MousKey		proc far                ;Must be far proc for Mouse driver.
;
;Set up our data segment & save mouse environ for genius mouse
;
		Mov  Evnts,AX		;save AX
		Mov  Btns,BX		;Save BX
		Mov  XCoord,CX		;Save CX
		Mov  YCoord,DX		;SAve DX
		Mov  VMicks,SI		;Save SI
		Mov  HMicks,DI		;Save DI
		Mov  MousDat,DS		;Save DS
		mov  BX,Seg Data	;Set up our data segment
		mov  DS,BX		;in DS
		Mov  BX,Btns		;Restore BX
;
;Determine which event occurred and branch accordingly
;
 		And  AX,Msk		;clear unused bits
		test AX,1		;was there movement?
		Jnz  Moved		;yes, then branch
		Jmp  CheckButtons	;no, check for button action
;
;Respond to motion
;
Moved:
		Mov HFlag,0		;0 flag registers
		Mov VFlag,0		;
		mov ax,11		;function 11 (read motion counters)
		int MouseInt		;read motion counters
					;CX = mickeys moved horiz
					;DX = mickeys moved vertically
					;positive if right or DOWN!
		cmp cx,0		;horizontal motion positive?
		jge  Moved1		;yes, then jump
		Inc  HFlag		;no, set hflag
		Neg  CX			;set CX to positive count
Moved1:		Cmp  DX,0		;Vertical motion positive?
		JGE	Moved2		;Yes, then jump
		Inc	VFlag		;No, then set VFlag
		Neg	DX		;and set DX to positive count
Moved2:		Cmp	CX,DX		;which motion was it?
		JAE	MovedH		;  Jump if horizontal
                Jmp  MovedV             ; Else process vert.
MovedH:                                 ;yes, process horiz.
                Mov BX,HCount		;check H Delay
                Dec BX			;decrement the counter
                Mov HCount,BX		;save the counter
                JZ MovedH0		;continue if 0
                Ret			;if not
MovedH0:        Mov BX,HDly		;get Horiz delay
		Mov HCount,BX		;in Hcount
		cmp HFlag,0		;was motion positive?
		JZ  MovedH1             ;yes, then branch
		Mov Al,MouseMotion	;get motion byte
		Test Al,MoveLeft	;is movement authorized?
 		Jz MoveExit		;no, then exit
		mov AX,LKey		;yes, load ax with left keycode
		jmp insert		;and stuff it
MovedH1:
		Mov AL,MouseMotion	;get motion byte
		Test AL,MoveRight	;is movement authorized?
		Jz MoveExit		;no, then exit
		mov AX,RKey		;load AX with Right keycode
		jmp insert		;and insert that in keybuffer
MovedV:		
; DX = Mickeys of vertical motion
                Mov BX,VCount		;check delay
                dec BX			;decrement the counter
		Mov VCount,Bx		;save the counter
                Jz  MovedV0		;branch if 0
                Ret			;return if not
MovedV0:	Mov BX,VDly		;get delay
		mov VCount,BX		;restore count		
		cmp VFlag,0		;was motion Down?
		JZ  MovedV1		;yes then branch
		Mov Al,MouseMotion	;get motion byte
		Test Al,MoveUp		;was motion authorized?
		Jz MoveExit		; no then exit
		mov AX,UKey		;load ax with up keycode
		jmp insert		; and stuff it
MovedV1:
		Mov AL,MouseMotion	;get motion byte
		Test AL,MoveDown	;was motion authorized?
		Jz	MoveExit	;no then exit
		mov AX,DKey		;load ax with Dn keycode
		jmp insert		; and stuff it

MoveExit:	Jmp KeyMousExit		;exit if motion attempt invalid

CheckButtons:
		test ax,2		;was the left button pressed?
		jnz  LBtn               ;yes, then branch
		test ax,4		;was left button released?
		jnz  LBtn		;yes, then branch
		test ax,8		;was the right button pressed?
		jnz  RBtn               ;yes, then branch
		test ax,10h		;was right button released?
		jnz  RBtn		;yes, then branch
		test ax,20h		;was mid button pressed?
		jnz  MBtn		;yes then branch
		test ax,40h		;was mid button released?
		jnz  MBtn               ;yes, then branch
                Jmp  KeyMousExit       ;we get here by a glitch

;
;The left button was pressed/released.  Load AX with keycode for left button.
;
LBtn:		Mov AX,05h		;get button Press inf function
		Mov BX,0		;LBtn stats
		Int MouseInt		;clear counters
		Mov Ax,06H		;get button release inf
		Mov Bx,0		;LBtn stats
		Int MouseInt		;clear counters
		mov ax,LBKey		;load keycode
		jmp insert		;insert it in the keyboard buffer
;
;The right button was pressed.  Load AX with the keycode for right button.
;
RBtn:		Mov Ax,05h		;get button inf
		Mov Bx,1		;RBtn stats
		Int MouseInt		;clear counters
		Mov Ax,06H		;get button release inf
		Mov Bx,1		;Rbtn stats
		Int MouseInt		;clear counters		
		mov ax,RBKey		;load keycode
		Jmp Insert		;and insert
;
;The mid button was pressed.  Load AX with keycode for mid button.
;
MBtn:		Mov AX,05h		;get button inf
		Mov BX,02		;Mid button stats
		Int MouseInt		;and clear counters
		Mov Ax,06h		;get button inf
		Mov Bx,2		;MBtn stats
		Int MouseInt		;clear counters
		mov ax,MBKey		;load keycode
					;fall through to insert

;
;Insert the keycode in AX into the keyboard buffer.
;
insert:		mov bx,bios_data	;point DS to BIOS data area
		mov DS,bx
		cli			;disable interrupts
Insert0:
		mov bx,DS:Word Ptr [buffer_tail]
					;get buffer tail address
		mov dx,bx		;transfer it to DX
		add dx,2		;calculate next buffer position
		cmp dx,DS:Word Ptr [buffer_end]	
					;did we overshoot the end?
		jne insert1		;no, then continue
		mov dx,DS:Word Ptr [buffer_start]
					;yes, then wrap around
insert1:	cmp dx,DS: Word Ptr [buffer_head]
					;is the buffer full?
		je insert2		;yes then end now
		mov DS:[bx],ax		;insert the keycode
		mov bx,dx		;advance the tail
		mov DS:Word Ptr [buffer_tail],bx
					;record its new position
insert2:	sti			;enable interrupts
KeyMousExit:				;Restore regs and ret
		Mov ax,Evnts		;restore AX
		Mov Bx,Btns		;restore BX
		Mov CX,XCoord		;Restore CX
		Mov DX,Ycoord		;Restore DX
		Mov SI,VMicks		;Restore SI
		Mov DI,HMicks		;Restore DI
		Mov DS,MousDat		;Restore DS
		ret			;exit user defined subroutine
MousKey		endp
;
;
code		ends
		END
