'===========================================================================
' Subject: MOUSE REG/CALL INTERRUPT DEMO      Date: 10-13-99 (18:48)       
'  Author: Walt Decker                        Code: PB                     
'  Origin: wdecker@the-onramp.net           Packet: MOUSE.ABC
'===========================================================================
'****************************************************************************
' AUTHOR:   WALT DECKER
' DATE:     OCTOBER 13, 1999
' LANGUAGE: POWERBASIC 3.5
' PURPOSE:  DEMONSTRATE THE USE OF REG AND CALL INTERRUPT TO PRODUCE A MOUSE
'           INTERFACE FOR POWERBASIC 3.5 AND TO SHOW THE SPEED OF USING THE
'           POWERBASIC POINTERS FOR GRAPHICS RATHER THAN DEF SEG, POKE, AND
'           PEEK.
'****************************************************************************

DEFINT A-Z             '*** define integer range

'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
'   the following sets up a structure similar to that used in QB4.5 and PDS.
'   this could be set up so that each variable in the structure is a constant.
'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

TYPE RegType
	Flags AS INTEGER         'Each variable in the structure corresponds to one
	Ax    AS INTEGER         'of the CPU registers
	Bx    AS INTEGER        
	Cx    AS INTEGER
	Dx    AS INTEGER
	Si    AS INTEGER
	Di    AS INTEGER
	Bp    AS INTEGER
	Ds    AS INTEGER
	Es    AS INTEGER
END TYPE

'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
'   the following structure corresponds to one of the parameters passed
'   through the registers from the mouse buffer interface
'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

TYPE Rodent
	Lb    AS INTEGER      'Left mouse button
	Rb    AS INTEGER      'Right mouse button
	Msx   AS INTEGER      'X coordinate of mouse cursor "hot spot"
	Msy   AS INTEGER      'Y coordinate of mouse cursor "hot spot"
	MinX  AS INTEGER      'Minimum X coordinate for mouse movement
	MaxX  AS INTEGER      'Maximum X coordinate for mouse movement
	MinY  AS INTEGER      'Minimum Y coordinate for mouse movement
	MaxY  AS INTEGER      'Maximum Y coordinate for mouse movement
END TYPE

'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
'   define variables for the registers, the mouse parameters, and the
'   pointers
'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

DIM InRegs AS RegType, OutRegs AS RegType, Mice AS Rodent
DIM Mode13 AS BYTE PTR, Pixel AS BYTE PTR

'*********** Initialize variables *******************************************

	InRegs.Flags = 0
	InRegs.Ax = 1
	InRegs.Bx = 2
	InRegs.Cx = 3
	InRegs.Dx = 4
	InRegs.Si = 5
	InRegs.Di = 6
	InRegs.Bp = 7
	InRegs.Ds = 8
	InRegs.Es = 9

OutRegs = InRegs
Mode13 = &HA000 * 65536    '32-bit address for graphics video buffer
Pixel = &HA000 * 65536     '  ditto

'**************** Switch to screen mode 13 **********************************

! mov AX, &H13
! int &H10

'****************************************************************************
'   initialize the mouse.  By passing the value of zero to the mouse routine
'   the routine determines if a mouse is present.  If a mouse is not present
'   the value in "Init" is zero otherwise it is -1
'****************************************************************************

CALL Mouse(Init, InRegs, OutRegs, Mice)

CALL Mouse(1, InRegs, OutRegs, Mice)    'show mouse cursor

'*************** Structure to wait for button press *************************
DO
	CALL Mouse(3, InRegs, OutRegs, Mice)
LOOP WHILE Mice.Lb = 0                  'exit if left button was pressed

'****************************************************************************
'   SUB Bounce is used to allow the mouse buffer to clear once a button is
'   pressed. If a strucure similar to bounce is not used the buffer will not
'   clear properly and the next call to mouse will indicate that a button was
'   pressed when it actually was not.
'****************************************************************************

CALL Bounce(InRegs, OutRegs, Mice)     

CALL Mouse(2, InRegs, OutRegs, Mice)      'hide the mouse cursor

DO                                        'wait for left button press
	CALL Mouse(3, InRegs, OutRegs, Mice)
LOOP UNTIL Mice.Lb > 0

CALL Bounce(InRegs, OutRegs, Mice)        'allow time to clear mouse buffer

CALL Mouse(1, InRegs, OutRegs, Mice)      'show mouse cursor

'****************************************************************************
'   the following strucure looks for a right button press.  If the left
'   button is pressed, a white dot is placed on the screen at the point of
'   the cursor "hot spot".  The location is determined by adding the video
'   offset to the "Pixel" pointer.  DEF SEG and POKE are not used.
'****************************************************************************
DO
	CALL Mouse(3, InRegs, OutRegs, Mice)   
	IF Mice.Lb THEN                          'check for left button press
		Posn& = Mice.Msy * 320& + Mice.Msx     'calculate video offset
		Pixel = Pixel + Posn&                  'increase pointer address
		CALL Mouse(2, InRegs, OutRegs, Mice)   'hide mouse cursor
		@Pixel = 15                            'change pixel color at video address
		Pixel = Mode13                         'reset pointer
		CALL Mouse(1, InRegs, OutRegs, Mice)   'show mouse cursor
		CALL Bounce(InRegs, OutRegs, Mice)     'clear mouse buffer
	END IF
LOOP UNTIL Mice.Rb > 0

SCREEN 0                       							'set screen to text mode
WIDTH 80
END                                        'end of prog

SUB Bounce (InRegs AS RegType, OutRegs AS RegType, Mice AS Rodent)

'*************** used to allow sufficient time for mouse buffer to clear ****
	Init = 3
	DO
		CALL Mouse(Init, InRegs, OutRegs, Mice)
	LOOP WHILE Mice.Lb OR Mice.Rb
END SUB

SUB Mouse (Init, InRegs AS RegType, OutRegs AS RegType, Mice AS Rodent)

'*********  this is the mouse handler routine

MouseInterrupt = &H33

'****************************************************************************
'   variables My, Mx, and Nadd must be changed if a different video mode or
'   text mode is used.
'****************************************************************************

My = 1
Mx = 2
Nadd = 0

Rat.Start:    '
	 SELECT CASE Init
		CASE 0                                   '** initialize
			REG InRegs.Ax, 0                       'set AX register to zero
			CALL INTERRUPT(MouseInterrupt)         'call mouse interrupt
			Init = REG(OutRegs.Ax)                 'check result

		CASE 1                                   '** show cursor
			REG InRegs.Ax, 1                       'set AX register to one
			CALL INTERRUPT(MouseInterrupt)
		CASE 2                                   '** hide cursor
			REG InRegs.Ax, 2                       'set AX register to two
			CALL INTERRUPT(MouseInterrupt)

		CASE 3                                   '** button pressed
			Mice.Lb = 0                            'zero mouse buttons
			Mice.Rb = 0

			REG InRegs.Ax, 3                       'set AX register to three
			CALL INTERRUPT(MouseInterrupt)

			SELECT CASE REG(OutRegs.Bx)            'check BX register for button press
				CASE 1
					Mice.Lb = 1
				CASE 2
					Mice.Rb = 2
				CASE 3
					Mice.Rb = 3
			 END SELECT                          
																						'check DX and CX registers for
																						'cursor coordinates and adjust
																						'for video mode

			 Mice.Msy = REG(OutRegs.Dx) \ My + Nadd
			 Mice.Msx = REG(OutRegs.Cx) \ Mx + Nadd

		CASE 4                                   '** Move Cursor

			Mice.Msx = Mice.Msx * (Mx - Nadd)      'adjust for screen mode
			REG InRegs.Dx, Mice.Msy * (My - Nadd)
			REG InRegs.Cx, Mice.Msx
			REG InRegs.Ax, 4
			CALL INTERRUPT(MouseInterrupt)

	 '****************************************************************************
	 '    cases 5, 55, 6, and 66 check for the number of left and right button
	 '    presses and releases.  This can be useful when continuse mouse poling is
	 '    not practical.
	 '****************************************************************************

		CASE 5                                   '** #of button presses
			REG InRegs.Bx, 0                       '** needs to be 1 for
			REG InRegs.Ax, 5                       '** right button
			CALL INTERRUPT(MouseInterrupt)

			Mice.Lb = REG(OutRegs.Bx)
			Mice.Msy = REG(OutRegs.Dx) \ My + Nadd
			Mice.Msx = REG(OutRegs.Cx) \ Mx + Nadd      '\ 2
		CASE 55
			REG InRegs.Bx, 1                             '** needs to be 0 for
			REG InRegs.Ax, 5                          '** left button
			CALL INTERRUPT(MouseInterrupt)

			Mice.Rb = REG(OutRegs.Bx)
			Mice.Msy = REG(OutRegs.Dx) \ My + Nadd
			Mice.Msx = REG(OutRegs.Cx) \ Mx + Nadd       ' \ 2

		CASE 6                                  '** #of button releases
			REG InRegs.Bx, 0  ' Button                   '** needs to be 1 for
			REG InRegs.Ax, 6                         '** right button
			CALL INTERRUPT(MouseInterrupt)

			Mice.Lb = REG(OutRegs.Bx)
			Mice.Msy = REG(OutRegs.Dx) \ My + Nadd
			Mice.Msx = REG(OutRegs.Cx) \ Mx + Nadd

		CASE 66
			REG InRegs.Bx, 1                            '** needs to be 0 for
			REG InRegs.Ax, 6                         '** left button
			CALL INTERRUPT(MouseInterrupt)

			Mice.Rb = REG(OutRegs.Bx)
			Mice.Msy = REG(OutRegs.Dx) \ My + Nadd
			Mice.Msx = REG(OutRegs.Cx) \ Mx + Nadd

	 '****************************************************************************
	 '    cases 7 and 8 set the screen limits for mouse cursor movement.  This can
	 '    be useful when drawing in a window or for use in a menu box.
	 '****************************************************************************

		CASE 7                                 '** horizontal range
			IActMinMx = Mice.MinX * (Mx - Nadd)                'adjust for screen mode
			IActMaxMx = Mice.MaxX * (Mx - Nadd)                'adjust for screen mode
			REG InRegs.Cx, IActMinMx
			REG InRegs.Dx, IActMaxMx
			REG InRegs.Ax, 7
			CALL INTERRUPT(MouseInterrupt)

		CASE 8                                 '** vertical range
			REG InRegs.Cx, Mice.MinY * (My - Nadd)
			REG InRegs.Dx, Mice.MaxY * (My - Nadd)
			REG InRegs.Ax, 8
			CALL INTERRUPT(MouseInterrupt)
	 END SELECT

END SUB
