TITLE   EXAM4 2001 - MOUSE DROPPINGS 
SUBTTL  Your name goes here
PAGE 60,132

Comment!
	 This program uses int33h to attach to the system mouse 
	 Interrupt Service Routine to control mouse movements.
	 Actions for mouse events are supplied by the student as 
         per EXAM4.TXT requirements.  Refer to the external
         documentation in EXAM4.DOC for exceptions and
         enhancements.   Non implemented components still under
         construction are identified in the external documentation
         and commented within the modules below. A separate file,
         EXAM4A.asm may contain an alternate version of your
         program with code that "almost" works.

	 
	 Assistance received:  (be very specific)
	 


	 On my honor, I am signing this document to swear that I 
	 have followed the Academic Honor Code without exception.


         HONOR CODE SIGNATURE:______________________ DATE:_______
	 
       !
PAGE

;  Constants
ENDST   equ 24H     ; end of string symbol '$'.
Public  ENDST       ; available to STRINGOUT10


; Set up the stack
SSEG    SEGMENT   PARA  STACK  'STACK'
    DB  551  DUP ('MY_STACK')   ; can find the stack under debug
SSEG    ENDS


CSEG    SEGMENT  PARA  
	; Tell MASM about our segment definitions.
	ASSUME  CS:CSEG, DS:CSEG, SS:SSEG

	; We are linking BIOS + INOUT10  - place the EXTRN 
	; statements here
        EXTRN clrscr:near
	EXTRN getch:near, kbhit:near
        EXTRN stringout10:near
	EXTRN DECOUT10:near
	EXTRN LOCATE:near
	EXTRN WRITEATTR:near
	EXTRN READATTR:near
	EXTRN CURSOROFF:near
	EXTRN CURSORON:near
	EXTRN WRITE:near
	

; Data placed with the code so that the mouse driver can easily
; find it.

error  db 'Cannot initialize mouse -- shutting down'
       db ENDST



CrapChar  db ' '     ; character used for droppings
CrapColor db 0F0h    ; color used for droppings
                     ; you will change this
colorcoord dw 0h    ; keeps last clicked palette coordinates, or 0 if no update needed.
crapcoord dw 0h    ; keeps last clicked coordinates for crapping
crapbool db 0	   ; checks whether to crap
foreback dw 0	   ; 0 = back, 1 = fore
fillerup db 0	   ; check to see if we should fill screen
movebool db 0	   ; checks if used mouse

mouseX  dw  0        ; horizontal value for mouse pointer
mouseY  dw  0        ; vertical value for mouse pointer
exit    dw  0        ; bool used to exit program - set by getch
                     ; or mouse

Xdisp   db  'X:  $' ; display template for coordinates
Ydisp   db  'Y:  $' ; display template for coordinates
boxtop  db  0D5h, 0CDh, 0CDh, 0CDh, 0CDh, 0B8h, '$'
box     db  0B3h, 020h, 020h, 020h, 020h, 0B3h, '$'
boxmid  db  0C3h, 0C4h, 0C4h, 0C4h, 0C4h, 0B4h, '$'
boxbottom db  0D4h, 0CDh, 0CDh, 0CDh, 0CDh, 0BEh, '$'
tixe	db 'tixe$'	;exit button label
fore 	db 'fore$'	;fore button label
back	db 'back$'	;back button label
fill	db 'fill$'	;fill button label

hi     db 'hi$'      ; used by dcp for debugging
; DATA ENDS HERE



MAIN:                   ; Life starts here.
	MOV   AX,CSEG   ; Make DS point to OUR data segment.
        MOV   DS,AX     ; Code and data live in one segment.
	
        call clrscr     
        mov  ax, 00h    ; initialize mouse
	int  33h        ; call mouse driver
	cmp  ax, 00h    ; mouse avail?
	jne   MAINinstalled       

	mov  SI, offset error  ; problems capturing our rodent
	call stringout10
	jmp  MAINquit


MAINinstalled:          ; OK the mouse is allocated to our window.
        mov  ax, 01h    ; Let's make the little rat visible.
	int  33h

	; Good place to get your menu and status bars on the screen
	CALL CURSOROFF
	PUSH AX
	PUSH BX
	PUSH CX
	PUSH DX
	PUSH SI
	MOV DX, 4Ah	;set up pos
	MOV CX, 6	;set up char repeat
	MOV AL, 20h	;set up space character
	MOV BL, 77h	;set up char attribute to gray on gray 
menubg: 
	CALL LOCATE		;set cursor pos
	CALL WRITEATTR	;draw menu bg char
	INC DH		;move down
	CMP DH, 1Ah		;check if past the bottom
	JE menudone		;if so, stop
	JMP menubg		;else, continue
menudone: 			
	CALL maketixe		;build tixe button
	CALL makeforeback	;build fore and back buttons
	CALL makefill		;build fill button
				;now draw status line
	MOV DX, 1800h			;move to the bottom left
	CALL LOCATE
	MOV CX, 04Eh			;get ready to draw 78 chars in a row
	CALL WRITEATTR
	MOV BL, 70h			;set the color to black on gray
	MOV DX, 1801h		;set the coords for the display
	CALL LOCATE
	MOV SI, offset Xdisp		;point to the string
	CALL STRINGOUT10		;write the label and two spaces for digits
	MOV DX, 1806h		;set the coords for the display
	CALL LOCATE
	MOV SI, offset Ydisp		;point to the string
	CALL STRINGOUT10		;write the label and two spaces for digits
	MOV DX, 044Ah		;set the coords for box top
	CALL LOCATE
	MOV SI, offset boxtop		;point to the string
	CALL STRINGOUT10		;write the label and two spaces for digits
	MOV DX, 054Ah			;get in position to draw palette box
	MOV SI, offset box	;point to the string for box sides
drawbox:
	CALL LOCATE
	CALL STRINGOUT10		;draw palette box sides
	INC DH			;go next line
	CMP DH, 0Dh			;check if done whole box yet
	JL drawbox

	CALL LOCATE			;get in position for the box middle
	MOV SI, offset boxmid	;point to the box middle string
	CALL STRINGOUT10		;draw box middle line
	INC DH			;go next line
	CALL LOCATE			;get in position for the paint pot sides
	MOV SI, offset box	;point to the box sides string
	CALL STRINGOUT10		;draw paint pot sides
	INC DH			;go next line
	CALL LOCATE			;get in position for the box bottom
	MOV SI, offset boxbottom	;point to the string for bottom
	CALL STRINGOUT10		;draw box bottom	

	MOV BL, 0			;initialize color value
	MOV AL, 20h			;initialize space character
	MOV DH, 5			;initialize row location
	MOV CX, 2			;prepare to write 2 chars at a time
makeswatch:
	MOV DL, 4Bh			;set col location
	CALL LOCATE			;go there
	CALL WRITEATTR		;draw dark swatch
	OR BL, 80h			;set intensity bit
	MOV DL, 4Dh			;move over
	CALL LOCATE
	CALL WRITEATTR		;draw light swatch
	AND BL, 01111111b		;turn off intensity bit
	SHR BL, 4			;get access to 4 high bits
	INC BL			;go next color
	SHL BL, 4			;put bits back
	INC DH			;move down a col
	CMP BL, 80h			;gone too far?
	JG makeswatch		;if not, go again

	CALL showstatus  ; update the cursor coords on the screen
	CALL updatepot	 ; set up the paint pot color

	POP SI
	POP CX
	POP BX
	POP AX
	POP DX

        ; Install our mouse event handler.
	; When the mouse does anything as described in CX below, 
	; the driver will automatically call our MouseEvent.

        mov  CX, 0003h  ; interrupt if moved
			; check out the mask in the documentation
                        ; for MouseEvent (same as AX value)
	push CS
        pop  ES                     ; ES must point to our CSEG
        mov  DX, offset MouseEvent  ; DX points to MouseEvent  
        mov  AX, 0Ch                ; Install our interrupt handler
	int  33h                    ; for mouse events.
        ; From this point on, we have control of mouse movement!


       ; We change the CrapChar through a busy-wait loop
       ; This is called programmed IO.
       ; Compare this the proc MouseEvent - interrupt IO.

MAINagain:        
        cmp [exit], 0   
	jne  MAINexit    ; exit program
	CMP [movebool], 1	 ; check if moved
	JE dochecks
moreMAIN:
	call kbhit       ; check to see if we have a visitor
	jz  MAINagain
	call getch       ; if so, remove the char from the buffer
	cmp  al, 27      ; if ESC, we are done
        jne   grabthekey ; any other key, we want
	mov   [exit], 1  ; set the flag to leave
	jmp  MAINagain

dochecks:
	MOV [movebool], 0 ; reset it
	CALL letscrap	 ; crap if necessary
	CALL showstatus  ; update the cursor coords on the screen
	CALL makeforeback	;update buttons
	CALL updatepot	 ; set up the paint pot color
	CMP [fillerup], 1
	JNE moreMAIN
	CALL letsfill
	JMP moreMAIN

grabthekey:
	MOV [crapchar], AL
	CALL updatepot	 ; put the char in the pot
	JMP MAINagain

MAINexit:               ; shutting down
	CALL maketixe	; redraw tixe button, hilighted now
	mov  ax, 02h    ; hide mouse pointer
	int  33h
        mov  ax, 00h    ; disconnect our mouse handler
	int  33h        
	CALL CURSORON	

MAINquit:
	MOV   AX,4C00h              ; Return control to DOS.
	INT   21h                   ; End of MAIN program.

PAGE
; ****************************************************************
showstatus PROC NEAR		;this updates the onscreen cursor coords
	PUSH AX	
	PUSH DX
	MOV DX, 1803h		;set coords for number
	CALL LOCATE		;go there
	MOV AX, [mouseX]		;get the cursor location
	CMP AX, 10			;is it less than 10?
	JL xunderten		;if so, take action
showx:
	MOV DX, AX		;get number ready for display
	CALL DECOUT10		;display it

	MOV DX, 1808h		;set coords for number
	CALL LOCATE		;go there
	MOV AX, [mouseY]		;get the cursor location
	CMP AX, 10			;is it less than 10?
	JL yunderten		;if so, take action
showy:
	MOV DX, AX		;get number ready for display
	CALL DECOUT10		;display it

	POP DX
	POP AX
	RET
xunderten:
	PUSH AX
	MOV AL, 30h			;set up a zero
	CALL WRITE			;write it
	MOV DX, 1804h		;move over one space
	CALL LOCATE
	POP AX
	JMP showx
yunderten:
	PUSH AX
	MOV AL, 30h			;set up a zero
	CALL WRITE			;write it
	MOV DX, 1809h		;move over one space
	CALL LOCATE
	POP AX
	JMP showy
showstatus ENDP

updatepot PROC NEAR		; keep the paint pot up to date
	PUSH AX
	PUSH BX
	PUSH CX
	PUSH DX
	CMP [colorcoord], 0
	JE nocolor
	MOV DX, [colorcoord]	; get the clicked coordinates in palette
	CALL LOCATE		;move cursor to where mouse is
	CALL READATTR	;find out what color is there
	MOV BL, [crapcolor]
	CMP [foreback], 1	; check which is on
	JE changefore
	SHL BL, 4		; get rid of old color
	SHR AH, 4		; put new color in position
	ADD BL, AH		; append new to old
	ROR BL, 4		; realign bits
	JMP thatwashard
changefore:
	SHR BL, 4		; get rid of old color
	SHL BL, 4		; realign bits
	SHR AH, 4		; position color for transfer
	ADD BL, AH		; append new to old

thatwashard:
	MOV [crapcolor], BL	;save the crap color just set
	MOV [colorcoord], 0	;reset this so it doesn't try to use it again
	JMP fillpot
nocolor:
	MOV BL, [crapcolor]	;use old color
fillpot:
	MOV CX, 4			;get ready to write 4 chars in a row
	MOV AL, [crapchar]			;get ready to write crapchar
	MOV DX, 0E4Bh		;get in position for paint pot
	CALL LOCATE
	CALL WRITEATTR		;fill paint pot
	POP DX
	POP CX
	POP BX
	POP AX
	RET
updatepot ENDP

letscrap PROC NEAR
	CMP [crapbool], 1
	JNE donecrapping
	PUSH AX
	PUSH BX
	PUSH CX
	PUSH DX
	MOV AL, [crapchar]
	MOV BL, [crapcolor]
	MOV CX, 1
	MOV DX, [crapcoord]
	CALL LOCATE
	CALL WRITEATTR
	MOV [crapbool], 0
	POP DX
	POP CX
	POP BX
	POP AX
donecrapping:
	RET
letscrap ENDP

maketixe PROC NEAR
	PUSH BX
	PUSH SI
	PUSH DX
	MOV DH, 0		;now let's make the exit button
	MOV DL, 04Bh
	CALL LOCATE
	MOV BL, 0F8h		;set color to dk gray on white
	ADD BX, [exit]		;hilight if exiting
	MOV SI, offset tixe	;point to the string
	CALL STRINGOUT10		;write it
	POP DX
	POP SI
	POP BX
	RET
maketixe ENDP

makefill PROC NEAR
	PUSH BX
	PUSH SI
	PUSH DX
	MOV DH, 16h		;now let's make the fill button
	MOV DL, 04Bh
	CALL LOCATE
	MOV BL, 0F8h		;set color to dk gray on white
	MOV SI, offset fill	;point to the string
	CALL STRINGOUT10		;write it
	POP DX
	POP SI
	POP BX
	RET
makefill ENDP

makeforeback PROC NEAR
	PUSH BX
	PUSH SI
	PUSH DX
	MOV DH, 011h		;now let's make the fore button
	MOV DL, 04Bh
	CALL LOCATE
	MOV BL, 0F8h		;set color to dk gray on white
	ADD BX, [foreback]	;hilight if fore is active
	MOV SI, offset fore	;point to the string
	CALL STRINGOUT10		;write it
	MOV DH, 013h		;now let's make the back button
	CALL LOCATE
	MOV BL, 0F9h		;set color to light blue on white
	SUB BX, [foreback]	;unhilight if fore is active
	MOV SI, offset back 	;point to the string
	CALL STRINGOUT10		;write it
	POP DX
	POP SI
	POP BX
	RET
makeforeback ENDP

letsfill PROC NEAR
	MOV [fillerup], 0
	MOV DX, 0
	MOV AL, [crapchar]
	MOV BL, [crapcolor]
	MOV CX, 4Ah
fillline:
	CALL LOCATE		;set cursor pos
	CALL WRITEATTR	;draw menu bg char
	INC DH		;move down
	CMP DH, 18h		;check if past the bottom
	JE filled		;if so, stop
	JMP fillline		;else, continue
filled:
	RET
letsfill ENDP

MouseEvent  Proc  FAR        
Comment  !   
This function is called by the mouse Interrupt Service Routine.
Make sure that you don't take up too much CPU time in here.
Input parameters:

	AX = events that occurred, depending on mask:   
	   bit 0 = mouse pointer moved
	   bit 1 = left button pressed
	   bit 2 = left button released
	   bit 3 = right button pressed
	   bit 4 = right button released
	   bit 5 = center button pressed
	   bit 6 = center button released

        DOCUMENTATION PATCH:
        I found that the value returned in AX differs from
        documentation on int 33h as follows:

        Bit 0 of AX is always set when a mouse event occurs (unless
        it was masked when the interrupt was initialized).  So, if
        the left eye was pressed (left eye pressed and movement
        were not masked), then MouseEvent will activate with AX = 3h.
        If MouseEvent was triggered by movement only, then AX = 1h.
        END DOCUMENTATION PATCH
                               
	BX = Current button state:
	   bit 0 = Left button (0 = up, 1 = pressed down)
	   bit 1 = Right button (0 = up, 1 = pressed down)
	   bit 2 = Center button (0 = up, 1 = pressed down)

	CX = Horizontal  coordinate
	DX = Vertical  coordinate

        Used to check how far mouse moved since we were last here.
	SI = Last vertical mickey count
	DI = Last horizontal mickey count

	DS = Data seg of the mouse ISR.  Reset to your data seg.

	USE only BIOS interrupts.  NO NOT use any DOS interrupts.
  !

	push ds
	push ax
	push dx
	push cx
	PUSH BX

       ; data for this driver will be in our code segment.
	push cs
        pop  ds   ; ds now points to our code segment       
	   
       ; test for events in the order you want priority 
       ; this is basically a case statement

MEtestmove:      
	MOV BX, AX  
	AND BL, 00000001b	; isolate move bit      
        cmp  BL, 1        ; the mouse moved
        jne  MEtestclick
	shr  cx, 03       ; 8 pixels per char position 
	shr  dx, 03
        mov  [mouseX], cx ; save the new position
	mov  [mouseY], dx
	mov [movebool], 1	;indicate that it has moved
MEtestclick:
	POP BX
	AND BL, 00000001b	; isolate button release bit
	CMP BL, 1		; check if clicked
	JNE MEretAlias

	mov [movebool], 1	;indicate that it has moved
	CMP [mouseY], 18h	; check if in status bar
	JE MEretAlias		; get outta there
	
	CMP [mouseX], 049h; check if it's in the bar
	JG inthebar
inthefield:
	MOV CX, [mouseY]
	MOV DH, CL
	MOV CX, [mouseX]
	MOV DL, CL		
	MOV [crapcoord], DX	; set the coordinates for drawing it
	MOV [crapbool], 1	; it'll get drawn next main cycle
JMP MEretAlias

inthebar:

	CMP [mouseX], 04Ah ; on the left edge?
	JE MEret		;no buttons there!
	CMP [mouseX], 04Fh ; on the right edge?
	JE MEret		;no buttons there!
	CMP [mouseY], 0 ;tixe button?
	JE letsquit
	CMP [mouseY], 11h ; fore button?
	JE setfore
	CMP [mouseY], 13h ; back button?
	JE setback
	CMP [mouseY], 16h ; fill button?
	JE setfill
	CMP [mouseY], 4	;past the top of the palette?
	JL MEret
	CMP [mouseY], 0Dh	;above the bottom of the palette?
	JL inpalette
	JMP MEret

MEretAlias:
	JMP MEret

letsquit:
	MOV [exit], 1
	JMP MEret

setfore:
	MOV [foreback], 1
	JMP MEret

setback:
	MOV [foreback], 0
	JMP MEret

setfill:
	MOV [fillerup], 1
	JMP MEret

inpalette:
	MOV CX, [mouseY]
	MOV DH, CL
	MOV CX, [mouseX]
	MOV DL, CL
	MOV [colorcoord], DX	;save coord of clicked color

MEret:
	pop cx
	pop dx
	pop ax
	pop ds
	ret          ; back to the mouse driver (ISR)
MouseEvent endP


;*****************************************************************
;**************************************************************

CSEG    ENDS            ; End of code segment.

END     MAIN            ; End of program. Start execution at MAIN
