sys7.1-doc-wip/OS/CrsrDev.a

2346 lines
77 KiB
Plaintext

;———————————————————————————————————————————————————————————————————————————————————————
;
; File: CrsrDev.a
;
; Contains: This file holds the new cursor device implementation, including new mouse
; /trackball handler and the new acceleration routines for jCrsrTask.
;
; Written by: Gary Rensberger (based on Dan Venolia's Cursory API) [11/20/91]
;
; Copyright: © 1991-1993 by Apple Computer, Inc. All rights reserved.
;
; Change History (most recent first):
;
; <SM7> 5/28/93 IH Add comment about Display Mgr usage of CrsrNew.
; <SM6> 12/01/92 HY Fix a bug with uncoupled cursors(fixes MS Flight Simulator v4.0).
; Fixed a cursor flicker problem on slower machines like LC930. The
; cursor is drawn prior to calculating new positions of devices. The
; calculations were using up all the available VBL time, causing the
; flicker (cursor is drawn every other VBL, and calculations performed
; every other VBL).
; <SM5> 8/26/92 kc Roll in Horror changes.
; <H18> 7/24/92 GMR Fixed comaptibility problem with Hypercard/MacPaint Grid drawing
; mode (Atkinsons MouseMask secret).
; <H17> 7/17/92 GMR Changed the double-click translation table to match the Mouse
; CDEVs double-click times.
; <H16> 7/14/92 GMR Reset MBState to button up in CrsrDevReInit code.
; <H15> 7/13/92 djw <GED> Added code in InitCrsrDev to initialize vectors for:
; DrawCursor, EraseCursor, the @drawCursor section of the new VBL,
; and a hook for SetCrsrData. Also added default vector code for
; the above.
; <H14> 7/13/92 GMR Re-arranged the initialization routine so that our expandmem
; globals are created before InitADB, then InitADB is called.
; Update MBTicks when a button goes down, since Andy looks at it
; (shame on you!).
; <H13> 7/6/92 GMR Update doubleTime lowmem when creating a new device.
; <H12> 6/29/92 BG Changed AERROR message in the overpatching check at the bottom
; of the file to refer to the correct file being too big (you're
; welcome, Steve).
; <H11> 6/26/92 GMR <SKH> Modified CrsrDevHandleADB to handle extended device data,
; ie: more than 2 buttons and up to 16bit resolution. Changed
; CrsrNewDevice to properly init cntButtons (it was moving a word
; into cntButtons). Changed CrsrDevSetAccel to enter the debugger
; if no 'accl' resources do not exist.
; <H10> 6/10/92 GMR Fixed bug with buttonCount not being reset after waking up from
; sleep.
; <H9> 6/5/92 GMR Changed the movem's in the trap selector dispatcher to be
; movem.l.
; <H8> 6/1/92 GMR Removed the extra 'default' device created for address 3, since
; testers complained. Now, if a second mouse (or 1st mouse on
; portables) is added while the machine is running, it's
; acceleration won't be correct. Tough shit).
; <H7> 5/12/92 JC Fixed problem with CrsrDevHandleVBL trashing registers.
; <H6> 4/3/92 SWC Added overpatch padding at the end of the file.
; <H5> 3/11/92 SWC <GMR> Setup so second trackball button will behave just like the first
; one. Exported CrsrDevDispatch now that we have a trap for it.
; <H4> 3/9/92 SWC <GMR> Fixed bug in CrsrDevSetAccel where the acceleration to set
; <SM4> 7/30/92 fau Made the MOVEM instructions in CrsrDevDispatch and StdExit be a
; MOVEM.L. This fixes a bug in the Mouse cdev in Cyclone where
; the MOVEM was assembled to a MOVEM.W which sign-extends to 32
; bits when writing back to a register!.
; <SM3> 7/7/92 CSS Change name of include from ApplDeskBusPriv.a to
; AppleDeskBusPriv.a to bring in line with Reality.
; The file "ApplDeskBusPriv.a" was inadvertently
; brought in from Horror.
; <SM2> 5/29/92 KW (JC,H7) Fixed problem with CrsrDevHandleVBL trashing registers.
; <SM1> 5/2/92 kc Roll in Horror. Comments follow:
; <H6> 4/3/92 SWC Added overpatch padding at the end of the file.
; <H5> 3/11/92 SWC Setup so second trackball button will behave just like the first
; one. Exported CrsrDevDispatch now that we have a trap for it.
; <H4> 3/9/92 SWC GMR/Fixed bug in CrsrDevSetAccel where the acceleration to set
; is 0. Added more compatiblity code to jCrsrTask so the VU test
; tool will work. Setup address 3 to be a default device with 100
; dpi resolution, so if a user unplugs then plugs in a mouse, it
; will work.
; <H3> 2/17/92 SWC Used different registers in FindResource since the _GetResource
; call can trash D0-D2. Changed references to CrsrDevRec.resolution
; to a long since it's a fixed point number.
; <H2> 2/14/92 SWC Added a RomMapInsert before all resource calls so we make sure
; we at least find our resources in the ROM.
; <H1> 2/12/92 GMR First checked in.
;———————————————————————————————————————————————————————————————————————————————————————
PRINT OFF
LOAD 'StandardEqu.d'
INCLUDE 'EgretEqu.a'
INCLUDE 'IOPEqu.a'
INCLUDE 'AppleDeskBusPriv.a'
INCLUDE 'CrsrDevEqu.a'
PRINT ON
MACHINE MC68020
_FixDiv OPWORD $A84D
CrsrDev PROC
EXPORT InitCrsrDev,CrsrDevDispatch
IMPORT CrsrVBLTask
WITH CrsrDevGlobals, CrsrDevRec, CrsrDevSegment, CrsrDataRec
WITH ADBDeviceEntry, ADBVars, ExpandMemRec
_______________________________________________________________________
;
; Routine: CrsrDevDispatch (trap # $AADB)
;
; Inputs: d0.w - selector
; 4(sp) - last parameter
; 8(sp) - 2nd to last parameter
;
; Outputs: d0 - result code
;
; Destroys: a0
;
; Function: This routine is our selector based dispatcher for the exported
; CrsrDev routines. It follows toolbox conventions (e.g. parameters
; are passed in on the stack, with the function selector in D0).
;_______________________________________________________________________
CrsrDevDispatch
link a6,#0 ; parameters referenced off a6
movem.l a1-a3/d1-d3,-(sp) ; save a bunch of registers
add.w d0,d0 ; (shift so we work on 68000's)
lea @jmpTable,a0 ; point to our jump table
adda.w (a0,d0.w),a0 ; add offset to routine
jmp (a0) ; jump to selected routine
;-------------------------------
@jmpTable dc.w CrsrDevMoveTrap- @jmpTable ; Selector 0
dc.w CrsrDevMoveToTrap- @jmpTable ; 1
dc.w CrsrDevFlushTrap- @jmpTable ; 2
dc.w CrsrDevButtonsTrap- @jmpTable ; 3
dc.w CrsrDevButtonDownTrap- @jmpTable ; 4
dc.w CrsrDevButtonUpTrap- @jmpTable ; 5
dc.w CrsrDevButtonOpTrap- @jmpTable ; 6
dc.w CrsrDevSetButtonsTrap- @jmpTable ; 7
dc.w CrsrDevSetAccelTrap- @jmpTable ; 8
dc.w CrsrDevDoubleTimeTrap- @jmpTable ; 9
dc.w CrsrDevSetUnitsPerInchTrap- @jmpTable ; 10
dc.w CrsrDevNextDeviceTrap- @jmpTable ; 11
dc.w CrsrDevNewDeviceTrap- @jmpTable ; 12
dc.w CrsrDevDisposeDevTrap- @jmpTable ; 13
;-------------------------------
stdExit movem.l (sp)+,a1-a3/d1-d3 ; restore registers
unlk a6
move.l (sp)+,a0
add.w d0,sp ; dump parameters
jmp (a0)
userFrame RECORD 0,increment
saveA6 ds.l 1
returnAddr ds.l 1
paramBase equ * ; ptr to base of parameters
ENDR
WITH userFrame
;====================================================================
;
; Routine: CrsrDevMoveTrap
;
; Inputs: 8(a6).l - delta Y
; 12(a6).l - delta X
; 16(a6).l - pointer to CrsrDevRec for this device
;
; Outputs: d0 - OSErr
;
; Destroys: d1-d2,a1-a2
;
; Function: This routine accumulates given deltas for crsrDev, and
; flags that is has new data. The next time the cursor position
; is computed, dh and dv will be run through the acceleration
; algorithm and will contribute to the cursor movement.
;====================================================================
CrsrDevMoveTrap
move.l paramBase(a6),d1 ; ∆y in d1
move.l paramBase+4(a6),d0 ; ∆x in d0
move.l paramBase+8(a6),a2 ; crsrDevRec in a2
bsr CrsrDevMove ; accumulate the deltas
move.w d0,paramBase+12(a6) ; result code
moveq #12,d0 ; dump three parameters on exit
jmp stdExit ;
;====================================================================
;
; Routine: CrsrDevMoveToTrap
;
; Inputs: 8(a6).l - V
; 12(a6).l - H
; 16(a6).l - pointer to CrsrDevRec for this device
;
; Outputs: d0 - OSErr
;
; Destroys: d1,a1-a2
;
; Function: This routine transforms the coordinates (h,v) to screen
; space so that the next time the cursor position is computed
; it jumps to that point and any relative movement will be ignored.
;====================================================================
CrsrDevMoveToTrap
move.l paramBase+8(a6),a2 ; crsrDevRec in a2
move.l whichCursor(a2),a1 ; a1 pts to cursor globals
moveq #0,d0
move.l paramBase(a6),d0 ; get V coord
swap d0 ; convert to fixed
move.l d0,whereY(a1) ; = whereY
moveq #0,d0
move.l paramBase+4(a6),d0 ; get H coord
swap d0 ; convert to fixed
move.l d0,whereX(a1) ; = whereX
st.b isAbs(a1) ; absolute mode
clr.w paramBase+12(a6) ; result code
moveq #12,d0 ; dump three parameters on exit
jmp stdExit ;
;====================================================================
;
; Routine: CrsrDevFlushTrap
;
; Inputs: 8(a6).l - pointer to CrsrDevRec for this device
;
; Outputs: d0 - OSErr
;
; Destroys: a2
;
; Function: This routine explicitly ends the relative device move,
; flushing out the error accumulators.
;====================================================================
CrsrDevFlushTrap
move.l paramBase(a6),a2 ; crsrDevRec in a2
move.l errorX(a2),d0 ; accumulate previous errors into
add.l d0,deltaX(a2) ; our deltas
move.l errorY(a2),d0
add.l d0,deltaY(a2)
clr.l errorX(a2) ; then flush the errors
clr.l errorY(a2)
move.w #-108,denom(a2) ; ???
clr.w paramBase+4(a6) ; result code
moveq #4,d0 ; dump one parameter on exit
jmp stdExit ;
;====================================================================
;
; Routine: CrsrDevButtonsTrap
;
; Inputs: 8(a6).w - new button states (1 = down, 0 = up)
; 10(a6).l - pointer to CrsrDevRec for this device
;
; Outputs: d0 - OSErr
;
; Destroys: a0-a2,d1-d3
;
; Function: This routine handles button debounce and event posting. If the
; mouse button bounces, we don't want it to look like a double click,
; so if we see a mouse down less than 2 VBLs after a mouse up, we will
; ignore it, and consider the mouse to still be up. We will never
; ignore a mouse up event, which could lead to menus hanging and
; continuous scrolling.
;====================================================================
CrsrDevButtonsTrap
move.w paramBase(a6),d0 ; button states in d0
move.l paramBase+2(a6),a2 ; crsrDevRec in a2
bsr CrsrDevButtons ; handle button debounce/actions
move.w d0,paramBase+6(a6) ; result code
moveq #6,d0 ; dump two parameters on exit
jmp stdExit ;
;====================================================================
;
; Routine: CrsrDevButtonDownTrap
;
; Inputs: 8(a6).l - pointer to CrsrDevRec for this device
;
; Outputs: d0 - OSErr
;
; Destroys: a0-a2,d1
;
; Function: Posts a button down event if this is the 1st button to go down
;====================================================================
CrsrDevButtonDownTrap
move.l paramBase(a6),a2 ; crsrDevRec in a2
bsr CrsrDevButtonDown ; handle button down actions
move.w d0,paramBase+4(a6) ; result code
moveq #4,d0 ; dump one parameter on exit
jmp stdExit ;
;====================================================================
;
; Routine: CrsrDevButtonUpTrap
;
; Inputs: 8(a6).l - pointer to CrsrDevRec for this device
;
; Outputs: d0 - OSErr
;
; Destroys: a0-a2,d1
;
; Function: Posts a button up event if this is the last button to go up.
;====================================================================
CrsrDevButtonUpTrap
move.l paramBase(a6),a2 ; crsrDevRec in a2
bsr CrsrDevButtonUp ; handle button up actions
move.w d0,paramBase+4(a6) ; result code
moveq #4,d0 ; dump one parameter on exit
jmp stdExit ;
;====================================================================
;
; Routine: CrsrDevButtonOpTrap
;
; Inputs: 8(a6).l - Operation specific data
; 12(a6).w - Operation code
; 14(a6).w - Button #
; 16(a6).l - pointer to CrsrDevRec for this device
;
; Outputs: d0 - OSErr
;
; Destroys: a2,d1-d2
;
; Function: This routine sets a new operation to be associated with the
; given button. The optional data field is set as well.
;====================================================================
CrsrDevButtonOpTrap
move.w paramBase+6(a6),d0 ; button # in d0
move.l paramBase+8(a6),a2 ; crsrDevRec in a2
move.b paramBase+5(a6),buttonOp(a2,d0.w) ; stuff the new operation code
lsl.w #2,d0
move.l paramBase(a6),buttonData(a2,d0.w) ; and the new data (if any)
clr.w paramBase+12(a6) ; result code
moveq #12,d0 ; dump four parameters on exit
jmp stdExit ;
;====================================================================
;
; Routine: CrsrDevSetButtonsTrap
;
; Inputs: 8(a6).w - # buttons for this device
; 10(a6).l - pointer to CrsrDevRec for this device
;
; Outputs: d0 - OSErr
;
; Destroys: a2
;
; Function: This routine sets the total # of buttons for the given
; device.
;====================================================================
CrsrDevSetButtonsTrap
move.l paramBase+2(a6),a2 ; crsrDevRec in a2
move.b paramBase+1(a6),cntButtons(a2) ; only use a byte of the word
clr.w paramBase+6(a6) ; result code
moveq #6,d0 ; dump two parameters on exit
jmp stdExit ;
;====================================================================
;
; Routine: CrsrDevSetAccelTrap
;
; Inputs: 8(a6).l - acceleration (Fixed)
; 12(a6).l - pointer to CrsrDevRec for this device
;
; Outputs: d0 - OSErr
;
; Destroys: a2,d1-d2
;
; Function: This routine installs the proper acceleration table for
; the specified device, based on the passed in acceleration
; value.
;====================================================================
CrsrDevSetAccelTrap
move.l paramBase(a6),d0 ; acceleration
move.l paramBase+4(a6),a2 ; crsrDevRec in a2
bsr CrsrDevSetAccel ; generate acceleration table
move.w d0,paramBase+8(a6) ; result code
moveq #8,d0 ; dump two parameters on exit
jmp stdExit ;
;====================================================================
;
; Routine: CrsrDevDoubleTimeTrap
;
; Inputs: 8(a6).l - duration (ticks)
; 12(a6).l - pointer to CrsrDevRec for this device
;
; Outputs: d0 - OSErr
;
; Destroys: a2
;
; Function: This routine changes the double-click time for crsrDev to
; the indicated value. When crsrDev is clicked, it's double-
; click time is stuffed into the low-memory global DoubleTime.
; An application responding to the mouse-down event can check
; DoubleTime to determine whether to interpret a double-click.
;====================================================================
CrsrDevDoubleTimeTrap
move.l paramBase+4(a6),a2 ; crsrDevRec in a2
move.l paramBase(a6),doubleClickTime(a2) ; stuff the new value
move.w #0,paramBase+8(a6) ; result code
moveq #8,d0 ; dump two parameters on exit
jmp stdExit ;
;====================================================================
;
; Routine: CrsrDevSetUnitsPerInchTrap
;
; Inputs: 8(a6).l - resolution (fixed)
; 12(a6).l - pointer to CrsrDevRec for this device
;
; Outputs: d0 - OSErr
;
; Destroys: a2
;
; Function: May be called if the software knows more about the resolution
; of the device than can be found from the ADB bus, e.g. for a
; serial device. Calls CrsrDevSetAcceleration (with the current
; accel value) to recompute the acceleration tables for the device,
; so the resource file that contains the 'accl' resource should be
; open.
;====================================================================
CrsrDevSetUnitsPerInchTrap
move.l paramBase+4(a6),a2 ; crsrDevRec in a2
move.l paramBase(a6),resolution(a2) ; set new resolution for this device
move.l acceleration(a2),d0 ; get current acceleration
bsr CrsrDevSetAccel ; generate acceleration table, based on new resolution
move.w #0,paramBase+8(a6) ; result code
moveq #8,d0 ; dump two parameters on exit
jmp stdExit ;
;====================================================================
;
; Routine: CrsrDevNextDeviceTrap
;
; Inputs: 8(a6).l - VAR ptr to CrsrDevRec
;
; Outputs: d0 - OSErr
;
; Destroys: none
;
; Function: When given NIL, returns the head of the global device list.
; When given a pointer to a cursor device reocrd, returns a
; pointer to the next one in the global device list.
;====================================================================
CrsrDevNextDeviceTrap
move.l paramBase(a6),a2 ; address of crsrDevRec ptr in a2
move.l (a2),a2 ; crsrDevRec ptr in a2
move.l a2,d0
beq.s @nil ; if NIL, special case
move.l nextCrsrDev(a2),a2 ; else, get next link
bra.s @exit
@nil movea.l ExpandMem,a2 ; get ptr to expandmem rec
movea.l emCursorGlobals(a2),a2 ; get cursory global ptr
move.l firstCrsrDev(a2),a2 ; get ptr to 1st CrsrDevRec
@exit move.l paramBase(a6),a0 ; get address of where to store crsrDevRec
move.l a2,(a0) ; return next crsrDevRec
move.w #0,paramBase+4(a6) ; result code
moveq #4,d0 ; dump one parameter on exit
jmp stdExit ;
;====================================================================
;
; Routine: CrsrDevNewDeviceTrap
;
; Inputs: 8(a6).l - VAR pointer to CrsrDevRec
;
; Outputs: d0 - OSErr
;
; Destroys: none
;
; Function: This routine creates a new CrsrDevRec, adds it to the
; linked list of device records, and initializes it's fields.
; Note: the caller must call CrsrDevSetAcceleration after
; calling this routine.
;====================================================================
CrsrDevNewDeviceTrap
bsr CrsrDevNewDevice ; create a new cursor device
move.l paramBase(a6),a0 ; address of crsrDevRec ptr in a2
move.l a2,(a0) ; return crsrDevRec pointer
move.w d0,paramBase+4(a6) ; result code
moveq #4,d0 ; dump one parameter on exit
jmp stdExit ;
;====================================================================
;
; Routine: CrsrDevDisposeDevTrap
;
; Inputs: 8(a6).l - pointer to CrsrDevRec for this device
;
; Outputs: d0 - OSErr
;
; Destroys: d1-d2,a0-a1
;
; Function: This routine eliminates CrsrDevRec from the linked list
; of device records, and disposes of all storage related to
; it.
;====================================================================
CrsrDevDisposeDevTrap
move.l paramBase(a6),a2 ; crsrDevRec in a2
bsr CrsrDevDisposeDev ; create a new cursor device
move.w d0,paramBase+4(a6) ; result code
moveq #4,d0 ; dump one parameter on exit
jmp stdExit ;
ENDWITH
;_______________________________________________________________________
;
; Routine: CrsrDevHandleADB
;
; Inputs: a0 - pointer to mouse data
; a2 - pointer to CrsrDevRec for this device
; d0 - command byte
;
; Outputs: -
;
; Destroys: a0-a3/d0-d3
;
; Function: This routine is installed as the ADB service routine for all
; ADDR=03 relative devices. It decodes the ADB packet and
; passes the information to CrsrDevMove and CrsrDevButtons.
; This routine now handles old or new style packets.
;
; The packet has the following format:
; Byte# bits: 7 6 5 4 3 2 1 0
; 0 b0 y6 y5 y4 y3 y2 y1 y0
; 1 b1 x6 x5 x4 x3 x2 x1 x0
; 2 b2 y9 y8 y7 b3 x9 x8 x7 (optional) <H11>
; 3 b4 y12 y11 y10 b5 x12 x11 x10 (optional) <H11>
; 4 b6 y15 y14 y13 b7 x15 x14 x13 (optional) <H11>
;
; Where bn is button n (1 = not pressed, 0 = pressed)
; xn is bit n of the x delta information
; yn is bit n of the y delta information
;
; NOTE: The current approach for extracting the extended
; resolution information is kinda ugly. However, it is
; fast and I have been unable to construct an efficent, general,
; function for extracting the awkward 3bit fields in bytes 2 through
; n (currently n is 4). - SKH
;
;_______________________________________________________________________
CrsrDevHandleADB
move.b d0,d2 ; save command in D2.
move.l a2,d0 ; do we have globals?
beq @exit ; no, exit
lea 1(a0),a3 ; skip over length byte, free up A0
@x0to6 moveq.l #$7F,d0 ; prepare to mask button off
and.b 1(a3),d0 ; get 2nd data byte (∆ horiz)
@y0to6 moveq.l #$7F,d1 ; prepare to mask off button
and.b (a3),d1 ; get 1st data byte (∆ vert)
@byte3 cmp.b #3,(a0) ; check to see if we have 3rd byte <H11>
bge.s @x7to9 ; if so, process it. else, extend sign <H11>
@byte3extx btst #6,d0 ; check sign bit (bit 6) <H11>
beq.s @byte3exty ; <H11>
or.w #$ff80,d0 ; fake a negative, faster than ext <H11>
@byte3exty btst #6,d1 ; check sign bit (bit 6) <H11>
beq @domove ; <H11>
or.w #$ff80,d1 ; fake a negative for y <H11>
bra.s @domove ; <H11>
@x7to9 moveq.l #$7,d2 ; move mask into workspace <H11>
and.b 2(a3),d2 ; get x bits 7-9 <H11>
lsl.w #7,d2 ; move them to add to running tally <H11>
or.w d2,d0 ; <H11>
@y7to9 moveq.l #$70,d2 ; mask the bits <H11>
and.b 2(a3),d2 ; get y bits 7-9 <H11>
lsl.w #3,d2 ; move and add to tally <H11>
or.w d2,d1 ; <H11>
@byte4 cmp.b #4,(a0) ; check to see if we have a 4th byte <H11>
bge.s @x10to12 ; <H11>
@byte4extx btst #9,d0 ; check sign bit (bit 9) <H11>
beq.s @byte4exty ; <H11>
or.w #$fc00,d0 ; fake a negative for x <H11>
@byte4exty btst #9,d1 ; check sign bit (bit 9) <H11>
beq.s @domove ; <H11>
or.w #$fc00,d1 ; fake a negative for y <H11>
bra.s @domove ; <H11>
@x10to12 moveq.l #$7,d2 ; move mask into workspace <H11>
and.b 3(a3),d2 ; get x bits 10-12 <H11>
lsl.w #8,d2 ; move them to add to running tally <H11>
lsl.w #2,d2 ; do a 10 bit shift <H11>
or.w d2,d0 ; <H11>
@y10to12 moveq.l #$70,d2 ; mask the bits <H11>
and.b 3(a3),d2 ; get y bits 10-12 <H11>
lsl.w #6,d2 ; move and add to tally <H11>
or.w d2,d1 ; <H11>
@byte5 cmp.b #5,(a0) ; check to see if we have a 5th byte <H11>
bge.s @x13to15 ; <H11>
@byte5extx btst #12,d0 ; check sign bit (bit 12) <H11>
beq.s @byte5exty ; <H11>
or.w #$e000,d0 ; fake a negative for x <H11>
@byte5exty btst #12,d1 ; check sign bit (bit 12) <H11>
beq.s @domove ; <H11>
or.w #$e000,d1 ; fake a negative for y <H11>
bra.s @domove ;
@x13to15 moveq.l #$7,d2 ; move mask into workspace <H11>
and.b 4(a3),d2 ; get x bits 13-15 <H11>
lsl.w #8,d2 ; move them to add to running tally <H11>
lsl.w #5,d2 ; do a 13 bit shift <H11>
or.w d2,d0 ; <H11>
@y13to15 moveq.l #$70,d2 ; mask the bits <H11>
and.b 4(a3),d2 ; get y bits 13-15 <H11>
lsl.w #8,d2 ; move and add to tally <H11>
lsl.w #1,d2 ; do a 9 bit shift <H11>
or.w d2,d1 ; <H11>
@domove ext.l d0 ; convert our words into longs
ext.l d1 ;
bsr.s CrsrDevMove ; accumulate movement
clr.l d0 ; assume all buttons up <H11>
@btn0 clr.l d1 ; start looking at button 0 <H11>
btst.b #7,(a3)+ ; is 1st button up? <H11>
bne.s @btn1 ; yes, check 2nd button <H11>
bset d1,d0 ; no, indicate button down <H11>
@btn1 addq.b #1,d1 ; go to the next button (button 1) <H11>
btst.b #7,(a3)+ ; is 2nd button up? <H11>
bne.s @btnn ; yes, handle all button states <H11>
bset d1,d0 ; no, indicate button down <H11>
@btnn
addq.b #1,d1 ; go to the next button <H11>
cmp.b cntButtons(a2),d1 ; compare current button number to num buttons <H11>
bge.s @setBtns ; set the buttons if we are done <H11>
btst.b #7,(a3) ; check the button for the high nibble <H11>
bne.s @btnn_high ; not pressed, check high nibble <H11>
bset d1,d0 ; record the press <H11>
@btnn_high addq.b #1,d1 ; other button in low nibble <H11>
btst.b #3,(a3)+ ; the button for this nibble <H11>
bne.s @btnn ; loop again <H11>
bset d1,d0 ; record the press <H11>
bra.s @btnn ; <H11>
@setBtns bsr CrsrDevButtons ; handle our buttons
@exit
rts
;_______________________________________________________________________
;
; Routine: CrsrDevMove
;
; Inputs: d0.l - delta X
; d1.l - delta Y
; a2 - pointer to CrsrDevRec for this device
;
; Outputs: d0 - OSErr
;
; Destroys: a0-a1,d0-d2
;
; Function: This routine accumulates given deltas for crsrDev, and
; flags that is has new data. The next time the cursor position
; is computed, dh and dv will be run through the acceleration
; algorithm and will contribute to the cursor movement.
;_______________________________________________________________________
tempParams RECORD 0,decrement
tempY ds.l 1 ; delta Y
tempX ds.l 1 ; delta X
tempSize EQU * ; size of our param block
ENDR
CrsrDevMove
WITH tempParams
link a6,#tempSize ; create temp area
tst.l d0 ; and X movement?
bne.s @cont ; yes, continue
tst.l d1 ; and Y movement?
beq @exit ; no, just exit
@cont move.l d0,tempX(a6) ; save delta X
move.l d1,tempY(a6) ; save delta Y
swap d0 ; word2Fix
clr.w d0
move.l d0,-(sp) ; convert delta X to Fixed (push on stack)
swap d1 ; word2Fix
clr.w d1
move.l d1,-(sp) ; convert delta Y to Fixed (push on stack)
tst.b newData(a2) ; was the previous poll after last VBL?
bne.s @accum ; yes, handle separately
move.l (sp)+,deltaY(a2) ; else, save it away
move.l (sp)+,deltaX(a2) ;
st.b newData(a2) ; indicate we have new data
bra.s @checkDir ; and see if direction changed
@accum move.l (sp)+,d0
add.l d0,errorY(a2) ; accumulate error y
move.l (sp)+,d0
add.l d0,errorX(a2) ; accumulate error x
move.w spread(a2),d0 ; adjust the length of the double-sample time
sub.w denom(a2),d0 ; this spread = old spread - denom
cmpi.w #30,d0
bge.s @spread ; skip if new spread >= 30
add.w d0,spread(a2) ; if new spread < 30 then
addq.w #1,spread(a2)
lsr.w spread(a2) ; spread := (spread + old spread + 1) / 2
@spread moveq #8,d0 ; else, spread out error over next several VBL's
move.w spread(a2),denom(a2)
cmp.w denom(a2),d0 ; clip demon to 0-8
bge.s @checkDir ;
move.w d0,denom(a2)
@checkDir move.l tempY(a6),d0 ; any dy?
beq.s @chkXchg ; no, check X
move.l errorY(a2),d1
eor.l d1,d0 ; yes, did it's direction change?
bpl.s @chkXchg ; no, check X
add.l d1,deltaY(a2) ; direction changed, adjust delta
clr.l errorY(a2) ; and stomp the error
@chkXchg move.l tempX(a6),d0 ; any dx?
beq.s @exit ; no, exit
move.l errorX(a2),d1
eor.l d1,d0 ; yes, did it's direction change?
bpl.s @exit ; no, exit
add.l d1,deltaX(a2) ; direction changed, adjust delta
clr.l errorX(a2) ; and stomp the error
@exit unlk a6
moveq #0,d0 ; result code
rts
ENDWITH
;_______________________________________________________________________
;
; Routine: CrsrDevButtons
;
; Inputs: d0.b - new button states (1 = down, 0 = up)
; a2 - pointer to CrsrDevRec for this device
;
; Outputs: d0 - OSErr
;
; Destroys: a0-a1,d1-d3
;
; Function: This routine handles button debounce and event posting. If the
; mouse button bounces, we don't want it to look like a double click, so if we
; see a mouse down less than 2 VBLs after a mouse up, we will ignore it, and
; consider the mouse to still be up. We will never ignore a mouse up event,
; which could lead to menus hanging and continuous scrolling.
;_______________________________________________________________________
CrsrDevButtons
move.b d0,d1 ; get current button(s) state in d1
moveq #8-1,d3 ; init our button counter...
@loop btst.l d3,d1 ; check next current button state
beq.s @nowUp ; branch if up
@nowDwn btst.b d3,buttons(a2) ; down now, was it down before?
bne.s @nextButton ; yes, do nothing, handle next button
move.l Ticks,d0
move.w d3,d2 ;
lsl.w #2,d2 ;
sub.l buttonTicks(a2,d2.w),d0 ;
add.l d0,RndSeed ; randomize our seed
subq.l #2,d0
bmi.s @nextButton ; exit if went down too quickly (bounce)
bset.b d3,buttons(a2) ; mark that we're really down...
bra.s @dispatch ; and handle the down event
@nowUp btst.b d3,buttons(a2) ; was it up before?
beq.s @nextButton ; yes, do nothing, handle next button
move.w d3,d2 ;
lsl.w #2,d2 ;
move.l Ticks,buttonTicks(a2,d2.w) ; time-stamp the button-up event
bclr.b d3,buttons(a2) ; mark that we're up
* bra.s @dispatch ; and handle the down event
@dispatch move.b buttonOp(a2,d3.w),d0 ; get the button operation in d0
ext.w d0
add.w d0,d0 ; button op * 2 (need to run on 68000)
lea @jmpTable,a0
adda.w (a0,d0.w),a0 ; base + offset = rtn address
jsr (a0) ; handle button (d3 = button#, a2 = CrsrDevRec)
; • routine must preserve d1 •
@nextButton dbra d3,@loop
moveq #0,d0 ; result code
rts ; we're done
;---------------------------------------------------------
@jmpTable dc.w doNop - @jmpTable ;
dc.w doSingle - @jmpTable ;
dc.w doDouble - @jmpTable ;
dc.w doClickLock - @jmpTable ;
dc.w d0CharStroke - @jmpTable ;
dc.w doAppleScript - @jmpTable ;
dc.w doCustom - @jmpTable ;
doNop rts
;---------------------------------------------------------
doSingle
btst.b d3,buttons(a2) ; are we down?
beq.s @up ; no, skip
bsr.s CrsrDevButtonDown ; yes, handle button down
bra.s @done
@up bsr CrsrDevButtonUp ; yes, handle button up
@done rts
;---------------------------------------------------------
doDouble
btst.b d3,buttons(a2) ; are we down?
beq.s @up ; no, skip
bsr.s CrsrDevButtonDown ; yes, generate 2 clicks
bsr.s CrsrDevButtonUp ;
bsr.s CrsrDevButtonDown ;
bra.s @done
@up bsr.s CrsrDevButtonUp ; and finally button up
@done rts
;---------------------------------------------------------
doClickLock
tst.b buttonData(a2,d3.w) ; is this the 1st time?
bne.s @secondHit ; no, skip
btst.b d3,buttons(a2) ; are we down?
beq.s @firstUp ; no, skip
bsr.s CrsrDevButtonDown ; yes, generate button down event
bra.s @done
@firstUp st.b buttonData(a2,d3.w) ; first up, mark it
bra.s @done
@secondHit btst.b d3,buttons(a2) ; are we up (2nd time)?
bne.s @done ; no, do nothing...
bsr.s CrsrDevButtonUp ; yes, post up event
clr.b buttonData(a2,d3.w) ; mark that we're really up
@done rts
;---------------------------------------------------------
d0CharStroke
rts
;---------------------------------------------------------
doAppleScript
rts
;---------------------------------------------------------
doCustom
pea buttonData(a2) ; push our custom routine address
rts ; and call it.
;_______________________________________________________________________
;
; Routine: CrsrDevButtonDown
;
; Inputs: a2 - pointer to CrsrDevRec for this device
;
; Outputs: d0 - OSErr
;
; Destroys: a0-a1,d0
;
; Function: Posts a button down event if this is the 1st button to go down
;_______________________________________________________________________
CrsrDevButtonDown
move.l whichCursor(a2),a1 ; get ptr to target cursor data
movea.l ExpandMem,a0 ; get ptr to expandmem rec
movea.l emCursorGlobals(a0),a0 ; get cursory global ptr
move.l firstCrsrData(a0),a0 ; a0 points to main cursor data record
cmpa.l a0,a1 ; is this the main cursor?
bne.s @count ; no, just count other cursor's button
move.l doubleClickTime(a2),doubleTime ; set our double-click time
tst.b buttonCount(a1) ; is this the first button to go down?
bne.s @count ; no, no need to post another event…
tst.b MBState ; yes, was mouse up before (should be)?
bpl.s @count ; no, just count the down event
clr.b MBState ; now say the button is down...
moveq #0,d0 ; no message for PostEvent
move.w #mButDwnEvt,a0 ; Get event number
_PostEvent ; post the mouse down event
@count move.l Ticks,MBTicks ; update MBTicks for compatibility <H14>
addq.b #1,buttonCount(a1) ; count the button down
moveq #0,d0 ; result code
rts
;_______________________________________________________________________
;
; Routine: CrsrDevButtonUp
;
; Inputs: a2 - pointer to CrsrDevRec for this device
;
; Outputs: d0 - OSErr
;
; Destroys: a0-a1,d0
;
; Function: Posts a button up event if this is the last button to go up.
;_______________________________________________________________________
CrsrDevButtonUp
move.l whichCursor(a2),a1 ; get ptr to target cursor data
movea.l ExpandMem,a0 ; get ptr to expandmem rec
movea.l emCursorGlobals(a0),a0 ; get cursory global ptr
move.l firstCrsrData(a0),a0 ; a0 points to main cursor data record
subq.b #1,buttonCount(a1) ; count the button up
bpl.s @chkMain ;
clr.b buttonCount(a1) ; clip at 0 (no negatives allowed)
@chkMain cmpa.l a0,a1 ; is this the main cursor?
bne.s @exit ; no, just exit
tst.b buttonCount(a1) ; is this the last button to go up?
bne.s @exit ; no, no need to post another event…
tst.b MBState ; yes, was mouse down before (should be)?
bmi.s @exit ; no, exit
bset.b #7,MBState ; now say the button is up...
moveq #0,d0 ; no message for PostEvent
move.w #mButUpEvt,a0 ; Get event number
_PostEvent ; post the mouse up event
@exit moveq #0,d0 ; result code
rts
;_______________________________________________________________________
;
; Routine: CrsrDevSetAccel
;
; Inputs: a2 - pointer to CrsrDevRec for device we want to set
; d0 - acceleration to set (0-1, fixed point)
;
; Outputs: d0 - OSErr
;
; Destroys: d0-d1,a0-a1
;
; Function: This routine installs the proper acceleration table for
; the specified device, based on the passed in acceleration
; value.
;_______________________________________________________________________
CrsrDevSetAccel
move.l d0,acceleration(a2) ; save new acceleration
movem.l d2-d7/a3-a4,-(sp) ; save a bunch of registers
move.l accelPoints(a2),d0 ; get ptr to old table
beq.s @cont
move.l d0,a0 ; if one existed,
_DisposPtr ; get rid of it
@cont move.w #mapTrue,RomMapInsert ; map ROM into resource chain <H2>
clr.w -(sp) ; room for function result
move.l #'accl',-(sp) ; we're looking for acceleration resources
_CountResources ; how many are there in the current resource file?
move.w (sp)+,d3 ; keep count in d3
beq.s @noaccl ; can't find any accl resources! <H11>
move.l devID(a2),d4 ; first try finding an 'accl' that matches our device ID<H3>
beq.s @tryClass ; if field NULL, use devClass
bsr FindResource ; did we find one?
beq.s @foundIt ; yes, skip below
@tryClass move.b devClass(a2),d4 ; try finding an 'accl' that matches our device class <H3>
ext.w d4 ; <H3>
ext.l d4 ; <H3>
bsr FindResource ; did we find one?
beq.s @foundIt ; yes, skip below
moveq #0,d4 ; otherwise, just load the flat ramp <H3>
bsr FindResource ; did we find one?
beq.s @foundIt
@noaccl _debugger ; •• break if we didn't find one (we should never get here!)
;----------------------------------------------
; first find the two tables which enclose the desired acceleration
;----------------------------------------------
@foundIt move.l acceleration(a2),d3 ; get new acceleration in d3
move.w (a0)+,d2 ; get # of acceleration tables in resource
move.l a0,a1 ; keep ptr to 'low' accel table in a1
@searchHi cmp.l (a0),d3 ; compare this acceleration to desired acceleration
ble.s @foundHi ; we found a table that is higher than us, done...
@nextEntry move.l a0,a1 ; update ptr to 'low' accel table in a1
addq.l #4,a0 ; skip past the acceleration
move.w (a0)+,d0 ; get # of points for this table
asl.w #3,d0 ; * 8 bytes for each entry
adda.w d0,a0 ; point to next table
bra.s @searchHi ; and try next acceleration
@foundHi move.l a0,a3 ; a3 = ptr to 'high' entry
cmpa.l a1,a3 ; are both tables same (matched 1st table) <H4>
bne.s @calcScale ; no, compute scale factor
addq.w #4,a1 ; bump past acceleration
addq.w #4,a3 ; in both tables
moveq #1,d7 ; yes, scale factor = 1
swap d7 ;
bra.s @scaleTable
@calcScale clr.l -(sp) ; room for function result
sub.l (a1),d3
move.l d3,-(sp) ; push (desired accel - low accel)
move.l (a3)+,d0
sub.l (a1)+,d0
move.l d0,-(sp) ; push (high accel - low accel)
_FixDiv ; divide to get our interpolation factor
move.l (sp)+,d7 ; d7 = scale factor
;----------------------------------------------
; now scale the lower resource table to the desired acceleration.
; The resulting table is pushed on the stack as it is created.
; d7 = scale factor
;
; uses d3,d4 to hold last dumped x1,y1
;----------------------------------------------
@scaleTable move.l sp,a4 ; keep ptr to stack buffer top
moveq #0,d3 ; init our 'prev' point 1
moveq #0,d4
clr.l -(sp) ; init x1
clr.l -(sp) ; init y1
move.w (a1)+,d5 ; d5 = # of points in lower table
move.w (a3)+,d6 ; d6 = # of points in upper table
cmpa.l a1,a3 ; did we find an exact match? <H4>
bne.s @scaleLoop ; yes, say no points left in one of the tables <H4>
moveq #0,d5 ; <H4>
@scaleLoop tst.w d5 ; any points left on lower line?
beq.s @lowLine ; no, then interpolate onto lower line
tst.w d6 ; any points left on upper line?
beq.s @highLine ; no, then interpolate onto upper line
move.l (a1),d0 ; see if next x point on lower accel table is
cmp.l (a3),d0 ; greater then next x point on higher accel table
bgt.s @lowLine ; yes, then use 2 points from lower table
;-----------
@highLine move.l (a3),-(sp) ; push x2 from upper curve
move.l 4(a3),-(sp) ; push y2 " "
move.l (a1),-(sp) ; push x3 from lower curve
move.l 4(a1),-(sp) ; push y3 " "
subq.w #1,d5 ; count the point
ble.s @doneLow ; if no more, we need to keep re-using last point
addq.w #8,a1 ; else, more points, point to next one
bra.s @int1
@doneLow moveq #0,d5 ; indicate no more points on lower line
@int1 bset #31,d7 ; indicate y3 is on lower curve
bsr Interpolate ; find new x' y'
bra.s @setPoint1 ; and set next point 1
;-----------
@lowLine move.l (a1),-(sp) ; push x2 from lower curve
move.l 4(a1),-(sp) ; push y2 " "
move.l (a3),-(sp) ; push x3 from upper curve
move.l 4(a3),-(sp) ; push y3 " "
subq.w #1,d6 ; count the point
ble.s @doneHigh ; if no more, we need to keep re-using last point
addq.w #8,a3 ; else, more points, point to next one
bra.s @int2
@doneHigh moveq #0,d6 ; indicate no more points on upper line
@int2 bsr Interpolate ; find new x' y'
;-----------
@setPoint1 tst.w d5 ; are we at end?
beq.s @restorePrevPt1 ; yes, restore previous pt1
tst.w d6 ; are we at end of upper line?
beq.s @restorePrevPt1 ; yes, restore previous pt1
move.l (a1),d0
cmp.l (a3),d0 ; is next point on upper curve before next point on low curve?
ble.s @swapLines ; no, skip below
@sameLine addq.w #8,sp ; dump last x3,y3 point
move.l 12(sp),4(sp) ; yes, old x1 becomes new x1
move.l 8(sp),(sp) ; old y1 becomes new y1
bra.s @nextPoint
@restorePrevPt1
addq.w #8,sp ; dump last x3,y3 point
move.l d3,4(sp) ; yes, previous x1 becomes new x1
move.l d4,(sp) ; previous y1 becomes new y1
bra.s @nextPoint
;-----------
@swapLines move.l (sp)+,4(sp) ; old y3 becomes new y1 data point
move.l (sp)+,4(sp) ; old x3 becomes new x1 data point
@nextPoint move.l 12(sp),d3 ; save last x1,y1 in case needed later
move.l 8(sp),d4
move.l d1,12(sp) ; set new x',y' data point on top of old x1,y1 point
move.l d2,8(sp) ;
move.w d5,d0 ; any more points in lower
or.w d6,d0 ; or upper table?
bne @scaleLoop ; yes, ok to continue
;------------------
addq.w #8,sp ; dump last x1,y1 point
move.l a4,d0 ; find out how big our computed buffer
sub.l sp,d0 ; is
lsr.l #3,d0 ; / 8 to find how many points
mulu #CrsrDevSegSize,d0 ; * size of each point
_NewPtr ,Sys,Clear ; allocate space for new table
move.l a0,accelPoints(a2) ; save ptr to table
;----------------------------------------------
; finally compute the table of accelPoints, based on the scaled accel resource
;----------------------------------------------
move.l a0,a3 ; keep working ptr to new table in a3
move.l a4,a1 ; ptr to top of table in a4 (grows toward low mem)
moveq #0,d1 ; init x1
moveq #0,d2 ; init y1
clr.l -(sp) ; first, calculate a couple of scaling constants
move.l resolution(a2),-(sp) ; device res
move.l #(frameRate<<16),-(sp) ; / frame rate
_FixDiv
move.l (sp)+,d6 ; = scale factor for device speed
clr.l -(sp)
move.l whichCursor(a2),a0
move.l CrsrDataRec.screenRes(a0),-(sp) ; screen res
move.l #(frameRate<<16),-(sp) ; / frame rate
_FixDiv
move.l (sp)+,d7 ; = scale factor for cursor speed
@loop clr.l -(sp) ; room for fixMul result
move.l -(a1),-(sp) ; get device speed for next point
move.l d6,-(sp) ;
_FixMul ; dev speed * [devRes / frameRate]
move.l (sp)+,d3 ; = x2
move.l d3,devUnits(a3) ; •• set max device speed for this segment
clr.l -(sp) ; room for fixMul result
move.l -(a1),-(sp) ; get cursor speed for next point
move.l d7,-(sp) ;
_FixMul ; y2 = cursor speed * [crsrRes / frameRate]
move.l (sp)+,d4 ;
clr.l -(sp) ; room for function result
move.l d4,d0
sub.l d2,d0 ; y2-y1
move.l d0,-(sp)
move.l d3,d0
sub.l d1,d0 ; x2-x1
move.l d0,-(sp)
_FixDiv ; calculate the slope
move.l (sp)+,slope(a3) ; •• set slope in table
clr.l -(sp)
move.l slope(a3),-(sp)
move.l d3,-(sp)
_FixMul ; slope * X
move.l d4,d0
sub.l (sp)+,d0 ; Y - slope * X = intercept
move.l d0,intercept(a3) ; •• set intercept
adda.w #CrsrDevSegSize,a3 ; bump to next segment
move.l d3,d1 ; old x2,y2 becomes new x1,y1
move.l d4,d2
cmpa.l a1,sp ; are we done?
blt.s @loop ; no, continue
move.l a4,sp ; dump buffer from stack
move.l #$7FFFFFFF,-12(a3) ; set last 'highest device speed' to max
movem.l (sp)+,d2-d7/a3-a4 ; restore registers
moveq #0,d0 ; result code
rts
;------------------------------------------------
;
; Routine: FindResource
;
; Inputs: d3 - # of 'accl' resources to search
; d4 - 'accl' resource tag we're looking for
;
; Outputs: a0 - ptr to 'accl' resource (past tag) if we found it
; ccr.Z - set if we matched
;
; Destroys: a0,d0,d1,d2,d5
;
; Function: This routine scans 'accl' resources, searching
; for one with a tag matching d1.
;------------------------------------------------
FindResource
move.w d3,d5 ; init our index <H3>
@loop move.w #mapTrue,RomMapInsert ; map ROM into resource chain <H2>
clr.l -(sp) ; room for function result
move.l #'accl',-(sp) ; we're looking for acceleration resources
move.w d5,-(sp) ; push current index <H3>
_GetIndResource ; get next 'accl' resource
move.l (sp)+,d0 ; did we get this one? <H3>
beq.s @NotFound ; -> no, try the next one <H3>
move.l d0,a0 ; handle in a0 <H3>
move.l (a0),a0 ; ptr in a0
cmp.l (a0)+,d4 ; does tag match our selector?
beq.s @exit ; yes, exit (with res ptr in a0)
@NotFound subq.w #1,d5 ; no, bump to next resource <H3>
bne.s @loop ; keep searching... <H3>
moveq #1,d0 ; set BNE if not found <H3>
@exit rts ; exit with Z-Flag set on match
;------------------------------------------------
;
; Routine: Interpolate
;
; Inputs: 18(sp) - x1
; 14(sp) - y1
; 10(sp) - x2
; 0C(sp) - y2
; 08(sp) - x3
; 04(sp) - y3
; d7 - scale, bit 31 set if 3rd point on lower accel curve.
;
; Outputs: d1 - x'
; d2 - y'
; d7.31 - reset
;
; Destroys: a0,d0-d1
;
; Function: This routine interpolates to find a point on the line [x1,y1] [x2,y2] which
; is intersected by the line [x3,y3] [x3,y"]. The resulting y' is calculated
; by interpolating between y3 and y", towards the higher acceleration curve.
;------------------------------------------------
stackFrame RECORD 0,increment
saveA6 ds.l 1
retAddr ds.l 1
y3 ds.l 1
x3 ds.l 1
y2 ds.l 1
x2 ds.l 1
y1 ds.l 1
x1 ds.l 1
ENDR
Interpolate
WITH stackFrame
link a6,#0 ; set our frame ptr
clr.l -(sp) ; room for function result
move.l y2(a6),d0 ; get y2
sub.l y1(a6),d0 ; y2 - y1
move.l d0,-(sp)
move.l x2(a6),d0 ; x2 - x1
sub.l x1(a6),d0
move.l d0,-(sp)
_FixDiv ; calculate slope, leave on stack
clr.l -(sp) ; room for function result
move.l 4(sp),-(sp) ; push copy of slope
move.l x1(a6),-(sp) ; push x1
_FixMul ; slope * x1
move.l y1(a6),d1
sub.l (sp)+,d1 ; d1 = intercept = y1 - (slope * x1)
move.l (sp),-(sp) ; push slope, leave room for function result
move.l x3(a6),-(sp) ; push x3
_FixMul
add.l (sp)+,d1 ; y" = slope * x3 + intercept
clr.l -(sp) ; room for function result
move.l y3(a6),d0
sub.l d1,d0
move.l d0,-(sp) ; push (y3 - y")
move.l d7,-(sp) ; push scale
bclr.b #7,(sp) ; make sure flag is off
_FixMul
bclr #31,d7 ; check if y3 is on lower curve
bne.s @lower ; yes, branch
@upper move.l (sp)+,d2 ; yes, interpolate upward
add.l d1,d2 ; y' = scale(y3-y") + y"
bra.s @exit
@lower move.l y3(a6),d2 ; interpolate downward,
sub.l (sp)+,d2 ; y' = y3 - scale(y3-y")
@exit move.l x3(a6),d1 ; return x'
unlk a6
rts
ENDWITH
;_______________________________________________________________________
;
; Routine: CrsrDevHandleVBL
;
; Inputs: -
;
; Outputs: -
;
; Destroys: d0 <H7>
;
; Function: This routine moves the cursor on the screen. It handles error
; distribution and delta acceleration for all the devices, then
; redraws the cursor.
;_______________________________________________________________________
EXPORT CrsrDevHandleVBL
CrsrDevHandleVBL
movem.l a0-a4/d1-d5,-(sp) ; save a bunch of registers <H7>
movea.l ExpandMem,a3 ; get ptr to expandmem rec
movea.l emCursorGlobals(a3),a3 ; get cursory global ptr
move.l firstCrsrDev(a3),d0 ; get ptr to 1st CrsrDevRec
beq @exit ; if not even 1 device, just exit
move.l d0,a2 ; ptr in a2
tst.b CrsrNew ; has anyone touched the old cursor
beq.s @drawCheck ; globals (compatibility - Display Mgr sets this <IH> ) ? <SM6>
clr.b CrsrNew ; yes, ok, we're handling it now
move.l firstCrsrData(a3),a4 ; get ptr to only CrsrDataRec in a4
tst.b isAbs(a4) ; are we in relative mode?
bne.s @drawCheck ; no, skip <SM6>
move.l MTemp,d0 ; does RawMouse <H4>
cmp.l RawMouse,d0 ; = MTemp? <H4>
bne.s @delta ; no, then they're doing deltas <H4>
@abs move.w d0,whereX(a4) ; yes, then just set our whereXY global to theirs
clr.w whereX+2(a4)
swap d0
move.w d0,whereY(a4)
clr.w whereY+2(a4)
bra.s @drawCheck ; <SM6>
@delta move.w Mouse+h,d0 ; add in their movement to ours
sub.w where+h(a4),d0 ; Mouse.h - crsrData->where.h
add.w MTemp+h,d0 ;
sub.w RawMouse+h,d0 ; + MTemp.h - RawMouse.h
swap d0 ; Word2fix
clr.w d0 ;
add.l d0,whereX(a4) ; update our global x position
move.w Mouse+v,d0 ; yes, add in their movement to ours
sub.w where+v(a4),d0 ; Mouse.v - crsrData->where.v
add.w MTemp+v,d0 ;
sub.w RawMouse+v,d0 ; + MTemp.v - RawMouse.v
swap d0 ; Word2fix
clr.w d0 ;
add.l d0,whereY(a4) ; update our global y position
; <SM6>begin
; See if it is time to draw the cursor.
;
@drawCheck ;
IF LC930 THEN
bclr.b #SkipDraw,CrsrDevFlags(a3) ; if this is the first CRSR VBL don't draw, do the calculations only
bne.s @accumLoop ; will draw on the next VBL
;==================================
@flushCrsrs
movem.l d0/a0-a4,-(sp) ; save registers used by CursorDraw Routines
move.l firstCrsrData(a3),a4 ; get ptr to first CrsrDataRec
@flushLoop clr.b isAbs(a4)
move.w whereX(a4),where+h(a4) ; update our h coordinate
move.w whereY(a4),where+v(a4) ; update our h coordinate
move.l nextCrsrData(a4),a4
move.l a4,d0
bne.s @flushLoop ; and clear flush next cursor (if any)
;-----------------
@drawCursor movea.l DrawCrsrVBLVector(a3),a0 ; call the DrawCursor vector <H15>
jsr (a0) ; <H15>
movem.l (sp)+,d0/a0-a4 ; restore registers trashed by CursorDraw routine
ENDIF ; <SM6>end
;------------------------------------------------------
; Now add and accelerate deltas for all cursor devices
; and combine into our only cursor data record.
;------------------------------------------------------
@accumLoop move.l whichCursor(a2),a4 ; get ptr to this devices CrsrDataRec in a4
tst.b isAbs(a4) ; are we in absolute mode?
beq.s @relative ; no, skip
clr.l deltaX(a2) ; yes, absolute cursor,
clr.l deltaY(a2) ; flush relative info for this device
clr.l errorX(a2) ;
clr.l errorY(a2) ;
move.w #-104,denom(a2)
clr.b newData(a2)
bra @nextDev ; and continue
;----------------
@relative tst.b newData(a2) ; relative cursor, do we have new data?
beq.s @noNewData ; no, skip
clr.b newData(a2) ; we're handling the new stuff now…
tst.w denom(a2) ; any errors?
ble.s @noError ; no, skip
clr.l -(sp) ; make room for fixDiv result
move.l errorX(a2),-(sp) ; 1st param for fixDiv
moveq #0,d0
move.w denom(a2),d0
swap d0 ; Word2Fix
move.l d0,-(sp) ; 2nd param for fixDiv
_FixDiv
move.l (sp)+,d3 ; dx = FixDiv(errorX,denom)
clr.l -(sp) ; make room for fixDiv result
move.l errorY(a2),-(sp) ; 1st param for fixDiv
moveq #0,d0
move.w denom(a2),d0
swap d0 ; Word2Fix
move.l d0,-(sp) ; 2nd param for fixDiv
_FixDiv
move.l (sp)+,d4 ; dy = FixDiv(errorY,denom)
sub.l d3,errorX(a2)
sub.l d4,errorY(a2)
bra.s @addDeltas
@noError clr.l d3
clr.l d4
@addDeltas add.l deltaX(a2),d3 ; add in the deltas
add.l deltaY(a2),d4
cmpi.w #-100,denom(a2) ; setup for next time
ble.s @findMag
subq.w #1,denom(a2)
bra.s @findMag
@noNewData move.l errorX(a2),d3 ; no new samples since last VBL,
move.l errorY(a2),d4 ; take all the error
clr.l errorX(a2)
clr.l errorY(a2)
move.w #-102,denom(a2)
;-----------------
@findMag move.l d3,d0 ; get dx
bpl.s @absDy ; ok if positive
neg.l d0 ; else, make positive
@absDy move.l d4,d1 ; get dy
bpl.s @chkMag ; ok if positive
neg.l d1 ; else, make positive
@chkMag cmp.l d1,d0
bgt.s @doY
lsr.l #1,d0
bra.s @setMag
@doY lsr.l #1,d1
@setMag add.l d0,d1 ; d1 = magnitude
beq.s @nextDev ; no magnitude, check next device
move.l accelPoints(a2),a1 ; a1 points to acceleration table
clr.w d0
@search cmp.l devUnits(a1,d0.w),d1 ; find entry in the table
ble.s @foundIt ; that matches our magnitude
add.w #CrsrDevSegSize,d0 ; not close yet, bump to next one
bra.s @search
;-----------------
@foundIt move.l intercept(a1,d0.w),-(sp) ; push intercept for later add
clr.l -(sp) ; room for function result
move.l slope(a1,d0.w),-(sp) ; push slope
move.l d1,-(sp) ; push mag
_FixMul
move.l (sp)+,d0
add.l (sp)+,d0 ; scale = intercept + slope*mag
clr.l -(sp) ; room for function result
move.l d0,-(sp) ; push scale
move.l d1,-(sp) ; magnitude
_FixDiv ; scale = scale / mag
clr.l -(sp) ; room for function result
move.l 4(sp),-(sp) ; push a copy of scale
move.l d3,-(sp) ; push dx
_FixMul
move.l (sp)+,d0
add.l d0,whereX(a4) ; accumulate the accelerated move
move.l (sp),-(sp) ; push scale, leave room for function result
move.l d4,-(sp) ; push dy
_FixMul
move.l (sp)+,d0
add.l d0,whereY(a4) ; accumulate the accelerated move
@nextDev move.l nextCrsrDev(a2),a2 ; get next device ptr
move.l a2,d0 ; done all devices?
bne @accumLoop ; no, continue looping
IF NOT LC930 THEN ; <SM6>
;==================================
@flushCrsrs move.l firstCrsrData(a3),a4 ; get ptr to first CrsrDataRec
@flushLoop clr.b isAbs(a4)
move.w whereX(a4),where+h(a4) ; update our h coordinate
move.w whereY(a4),where+v(a4) ; update our h coordinate
move.l nextCrsrData(a4),a4
move.l a4,d0
bne.s @flushLoop ; and clear flush next cursor (if any)
;-----------------
@drawCursor movea.l DrawCrsrVBLVector(a3),a0 ; call the DrawCursor vector <H15>
jsr (a0) ; <H15>
ENDIF ; <SM6>
@exit movem.l (sp)+,a0-a4/d1-d5 ; restore a bunch of registers <H7>
rts
;_______________________________________________________________________ <H15>
;
; Routine: DrawCursor
;
; Inputs: a3 - ptr to CrsrDevGlobals
;
; Outputs:
;
; Destroys: d0,a0,a4
;
; Function: This routine is the default ROM routine called through
; the DrawCrsrVBLVector. The vector is initialized by
; InitCrsrDev. (Pulled from the in-line VBL code).
;_______________________________________________________________________
DrawCursor movea.l firstCrsrData(a3),a4 ; get ptr to main CrsrDataRec <H15>
move.l where(a4),d0 ; get new mouse coords
cmp.l Mouse,d0 ; has cursor moved?
beq.s @exit ; no… exit
tst.b CrsrCouple ; is cursor coupled to mouse?
bne.s @coupled ; yes, continue <SM6>
move.l d0,MTemp ; no, just update lowmem MTemp <SM6>
bra.s @exit ; and exit without drawing cursor <SM6>
@coupled tst.b CrsrBusy ; is it locked? <SM6>
bne.s @exit ; yes… exit
lea CrsrPin,a0 ; it's ok to update cursor, get bounding rect
BSR.L CrsrVBLTask ; pin and draw the cursor
move.l Mouse,d0 ; has cursor been pinned?
cmp.l where(a4),d0 ;
beq.s @exit ; no… exit
move.l d0,where(a4) ; reflect pinned location
move.l MouseMask,d1 ; <H18>
not.l d1
tst.w d1 ; are we gridding in x direction?
beq.s @updateX ; no, force update
move.w whereX(a4),d0 ; yes, see if we clipped at screen bounds <H18>
sub.w Mouse+h,d0
bpl.s @xok
neg.w d0
@xok cmp.w d1,d0 ; compare our error to grid delta
ble.s @chkGridv ; <, so don't update our running x position
@updateX move.w RawMouse+h,whereX(a4) ; stamp our new running x position
clr.w whereX+2(a4)
@chkGridv swap d1 ; <H18>
tst.w d1 ; are we gridding in y direction?
beq.s @updateY ; no, force update
move.w whereY(a4),d0 ; yes, see if we clipped at screen bounds <H18>
sub.w Mouse+v,d0
bpl.s @yok
neg.w d0
@yok cmp.w d1,d0 ; compare our error to grid delta
ble.s @exit ; <, so don't update our running y position
@updateY move.w RawMouse+v,whereY(a4) ; stamp our new running x position
clr.w whereY+2(a4) ; loose the fraction
@exit rts
;_______________________________________________________________________
;
; Routine: CrsrDevNewDevice
;
; Inputs: ...
;
; Outputs: a2 - pointer to CrsrDevRec for device we initialized
; d0 - OSErr
;
; Destroys: d1-d2,a0-a1
;
; Function: This routine creates a new CrsrDevRec, adds it to the
; linked list of device records, and initializes it's fields.
; Note: the caller must call CrsrDevSetAcceleration after
; calling this routine.
;_______________________________________________________________________
CrsrDevNewDevice
move.l #CrsrDevSize,d0
_NewPtr ,Sys,Clear ; non-explicitly set fields will default to zeros
bne.s @error ; no memory, error exit
move.l a0,a2 ; keep ptr in a0
movea.l ExpandMem,a0 ; get ptr to expandmem rec
movea.l emCursorGlobals(a0),a0 ; get cursory global ptr
move.l firstCrsrDev(a0),nextCrsrDev(a2) ; link into our chain
move.l a2,firstCrsrDev(a0) ; " "
move.l firstCrsrData(a0),whichCursor(a2) ; init the cursor data ptr
move.b #classMouse,devClass(a2) ; we're a mouse type device
move.b #1,cntButtons(a2) ; and have 1 button <H11>
move.b #btnSingleClick,buttonOp+0(a2) ; standard single-click operation
move.l #(72<<16),resolution(a2) ; standard screen resolution
subq #4,sp
move.l sp,a0
move.l #$00020008,d0
_ReadXPram ; read mouse PRAM
move.l (sp)+,d1 ; get PRAM setting for double-click time
move.l d1,d0
rol.l #5+2,d0
andi.w #$1C,d0
lea @accelToFixed,a0
move.l (a0,d0.w),acceleration(a2) ; convert to fixed, and set our acceleration
moveq #8+4,d0
rol.l d0,d1 ; get PRAM setting for double-click time
andi.w #$0F,d1
lea @clickToFixed,a0
moveq #0,d0
move.b (a0,d1.w),d0
move.l d0,doubleClickTime(a2) ; set our double-click time
move.l d0,doubleTime ; update lowmem as well... <H13>
move.w #-101,denom(a2)
move.w #4,spread(a2)
moveq #0,d0 ; result code
rts
@error moveq #-1,d0 ; error exit
rts
@accelToFixed
dc.l $00000000 ; 0
dc.l $00002000 ; 1
dc.l $00005000 ; 2
dc.l $00008000 ; 3
dc.l $0000B000 ; 4
dc.l $0000E000 ; 5
dc.l $00010000 ; 6
dc.l $00010000 ; 7
@clickToFixed
dc.b $0C ; 0
dc.b $0C ; 1
dc.b $0C ; 2
dc.b $0C ; 3
dc.b $10 ; 4
dc.b $14 ; 5 fast
dc.b $17 ; 6
dc.b $1B ; 7
dc.b $20 ; 8 medium
dc.b $23 ; 9
dc.b $26 ; a
dc.b $2C ; b
dc.b $30 ; c slow
dc.b $34 ; d
dc.b $38 ; e
dc.b $3C ; f
;_______________________________________________________________________
;
; Routine: CrsrDevDisposeDev
;
; Inputs: a2 - pointer to CrsrDevRec for device we want to remove
;
; Outputs: d0 - OSErr
;
; Destroys: d0-d2,a0-a1
;
; Function: This routine eliminates CrsrDevRec from the linked list
; of device records, and disposes of all storage related to
; it.
;_______________________________________________________________________
CrsrDevDisposeDev
movea.l ExpandMem,a0 ; get ptr to expandmem rec
movea.l emCursorGlobals(a0),a0 ; get cursory global ptr
move.l firstCrsrDev(a0),a1 ; d1 points to main cursor data record
moveq #0,d1 ; prev := NIL
@loop cmpa.l a1,a2 ; is this the linked list element we want?
beq.s @gotIt ; yes, handle it
move.l a1,d1 ; no, prev := next
move.l nextCrsrDev(a1),d0 ; get next->nextCrsrDev
beq.s @exit ; exit if NIL (we never found it)
move.l d0,a1 ; next := next->nextCrsrDev
bra.s @loop
@gotIt move.l nextCrsrDev(a1),a1 ; next := next->nextCrsrDev
tst.l d1 ; was it the first one?
beq.s @firstOne ; yes, handle special case
move.l d1,a2
move.l a1,nextCrsrDev(a2) ; else, delete our element from middle of list
bra.s @dispose
@firstOne move.l a1,firstCrsrDev(a0)
@dispose move.l accelPoints(a2),d0
beq.s @ridRecord ; get rid of storage within CrsrDevRec
move.l d0,a0
_DisposPtr
@ridRecord move.l a2,a0
_DisposPtr ; get rid of CrsrDevRec itself
@exit moveq #0,d0 ; result code
rts
;_______________________________________________________________________
;
; Routine: CrsrDevReInit
;
; Inputs: d0 - 0 = pre-init, 1=post-init
;
; Outputs: d0 - 0 = pre-init, 1=post-init
;
; Destroys: a0-a3/d1-d3
;
; Function: This routine handles pre and post ADB ReInit processing.
; Before reinit, it trashes all the crsrDevRecs that are
; hanging off the ADB chain. After the re-init, it restores
; all the devices. Devices that can enter Handler XX, like PGE,
; are polled for information from register 01, which is used
; to fill in the CrsrDevRec. Other devices are used in the
; appropriate defaults.
;_______________________________________________________________________
ADBParamBlk RECORD 0,decrement
iDataAddr ds.l 1 ; ADB device data ptr
iCRAddr ds.l 1 ; ADB device completion rtn
iOrigAddr ds.b 1 ; ADB original address
iDeviceTy ds.b 1 ; ADB device type
iPBlock EQU iDeviceTy ; the start of our GetInfo param block
iSPBlock EQU iCRAddr ; the start of our SetInfo param block
adbPBSize EQU * ; size of our param block
ENDR
EXPORT CrsrDevReInit
CrsrDevReInit ; <H14>
WITH ADBParamBlk
movem.l d0-d3/a0-a3,-(sp)
link a6,#adbPBSize ; Make a stack frame for our param block
bne.s @PostInit ; Skip if post-processing
;---------------------
; pre-init processing
;---------------------
_CountADBs ; Get the number of ADB devices
move.w d0,d2 ; Save in D2
beq @exit ; Skip if none
@killLoop lea iPBlock(a6),a0 ; a0 is parameter block
move.w d2,d0
_GetIndADB ; Get a device entry
bmi.s @nextRec1 ; Skip if not valid
cmpi.b #mouseAddr,iOrigAddr(a6); mouse?
bne.s @nextRec1 ; Skip if not
move.l iDataAddr(a6),a2 ; Save the data address pointer
clr.l iDataAddr(a6) ; Clear it out, so the keyboard won't trash memory
lea iSPBlock(a6),a0 ; a0 ptr to our short param block
_SetADBInfo ; d0 already contains the ADB Address
bsr.s CrsrDevDisposeDev ; eliminate it from our globals also
@nextRec1 subq.w #1,d2
bgt.s @killLoop
movea.l ExpandMem,a0 ; get ptr to expandmem rec
movea.l emCursorGlobals(a0),a0 ; get cursory global ptr
clr.l firstCrsrDev(a0) ; clear out initial dev ptr
bra @exit
;---------------------
; post-init processing
;---------------------
@PostInit bset.b #7,MBState ; set current mouse button state to UP <H16>
clr.l MBTicks ; reset timestamp for mouse button <H16>
_CountADBs ; Get the number of ADB devices
move.w d0,d2 ; Save in D2
sub.w #10,sp ; allocate ADBOp reply buffer on stack for later
beq @postCheck ; Skip if no devices
@instLoop
lea iPBlock(a6),a0 ; a0 is parameter block
move.w d2,d0
_GetIndADB ; Get a device entry
move.w d0,d3 ; save ADB address
bmi @nextRec2 ; Skip if not valid
cmpi.b #mouseAddr,iOrigAddr(a6); mouse?
bne @nextRec2 ; Skip if not
bsr CrsrDevNewDevice ; create and chain in a new cursor record
; a2 points to crsrDevRec
move.b d3,d0 ; address in d0
lsl.b #4,d0 ; upper 4 bits
ori.b #%1111,d0 ; talk R3 command
move.l sp,a0 ; reply buffer ptr in a0
bsr syncADBTalk ; send command synchronously, reply in a0.
tst.b (a0) ; any data?
beq @nextRec2 ; no, skip (should not happen)
move.b #extDevHand,2(a0) ; yes, try to set to allow mouse extension
move.b d3,d0 ; address in d0
lsl.b #4,d0 ; upper 4 bits
ori.b #%1011,d0 ; Listen R3 command
bsr syncADBListen ; send command synchronously.
move.b d3,d0 ; now see if we switched be doing a talk R3 again
lsl.b #4,d0 ; addr in upper 4 bits
ori.b #%1111,d0 ; talk R3 command
move.l sp,a0 ; reply buffer ptr in a0
bsr syncADBTalk ; send command synchronously, reply in a0.
tst.b (a0) ; any data?
beq @nextRec2 ; no, skip (should not happen)
cmpi.b #extDevHand,2(a0) ; did we switch?
bne.s @preExisting ; no, doesn't
;--------------------------------
; We got an extended type device...
;--------------------------------
move.b d3,d0 ; now get the extended data from R1
lsl.b #4,d0 ; addr in upper 4 bits
ori.b #%1101,d0 ; talk R1 command
bsr syncADBTalk ; send command synchronously, reply in a0.
cmpi.b #8,(a0) ; did we get 8 bytes back?
bne.s @preExisting ; no, try handler 2 (maybe 1)
move.b 1(a0),devID+0(a2) ; copy the device ID (optimize later)
move.b 2(a0),devID+1(a2) ; "
move.b 3(a0),devID+2(a2) ; "
move.b 4(a0),devID+3(a2) ; "
move.b 5(a0),resolution+0(a2) ; Copy the resolution
move.b 6(a0),resolution+1(a2) ; "
clr.w resolution+2(a2) ; clear out the fraction part
move.b 7(a0),devClass(a2) ; Copy the device class
move.b 8(a0),cntButtons(a2) ; Copy the number of buttons
move.b #btnSingleClick,buttonOp+1(a2) ; single-click operation for 2nd button <H5>
bra.s @setInfo ; and setup globals/completion rtn for this device
;--------------------------------
; We got a pre-existing type device...
;--------------------------------
@preExisting
move.b #2,2(a0) ; yes, try to set to handler 2
move.b d3,d0 ; address in d0
lsl.b #4,d0 ; upper 4 bits
ori.b #%1011,d0 ; Listen R3 command
bsr syncADBListen ; send command synchronously.
move.b d3,d0 ; now see if we switched be doing a talk R3 again
lsl.b #4,d0 ; addr in upper 4 bits
ori.b #%1111,d0 ; talk R3 command
move.l sp,a0 ; reply buffer ptr in a0
bsr syncADBTalk ; send command synchronously, reply in a0.
tst.b (a0) ; any data?
beq.s @nextRec2 ; no, skip (should not happen)
cmpi.b #2,2(a0) ; did we switch to 2?
bne.s @brainDead ; no, must be stupid 4th party device
;-----------------------------------------
; We switched to 2, so adjust some paramters
;-----------------------------------------
move.l #'@200',devID(a2) ; set the device ID
move.w #200,resolution(a2) ; set the resolution
bra.s @setInfo
;-----------------------------------------
; We didn't switch to 2, so set back to 1 (is this necessary Dan?)
;-----------------------------------------
@brainDead move.b #1,2(a0) ; yes, try to set to handler 1
move.b d3,d0 ; address in d0
lsl.b #4,d0 ; upper 4 bits
ori.b #%1011,d0 ; Listen R3 command
bsr syncADBListen ; send command synchronously.
;--------------------------------
@setInfo move.l acceleration(a2),d0 ; d0 = acceleration for this device
bsr CrsrDevSetAccel ; set up the acceleration tables
lea CrsrDevHandleADB,a0
move.l a0,iCRAddr(a6) ; set our handler
move.l a2,iDataAddr(a6) ; set up the data area
lea iSPBlock(a6),a0 ; a0 ptr to our short param block
move.w d3,d0 ; d0 = ADB address
_SetADBInfo ; install the new info
@nextRec2 subq.w #1,d2
bgt @instLoop ; continue looping though all devices
bmi.s @postExit ; done when we've been through here twice (once to set default)
;---------------------
@postCheck move.b #mouseAddr,d3
moveq #numFDBAdr,d0 ; Number of table entries
move.l ADBBase,a3 ; get ADB globals in a3
move.l a3,a1 ; copy in a1
bra.s @chkMatch ;
@searchLoop adda.w #FRecSize,a1 ; Get to next record
@chkMatch cmp.b FDBAddr(a1),d3 ; Is this the right one?
beq.s @postExit ; If so, we're done
tst.b FDBAddr(a1) ; Is it 0?
dbeq d0,@searchLoop ; Loop until it is found or no more.
move.b #1,FDBDevTy(a1) ; assume handler 1
move.b d3,FDBOAddr(a1) ; set original address as 3
move.b d3,FDBAddr(a1) ; set FDB address as 3
bset.b d3,DevMap+1(a3) ; remember to poll it
bsr CrsrDevNewDevice ; else, create and chain in a default cursor record
bra.s @setInfo ; and set it it ADB unit table
@postExit add.w #10,sp ; • dump our ADBOp buffer
movea.l ExpandMem,a0 ; get ptr to expandmem rec <H10>
movea.l emCursorGlobals(a0),a0 ; get cursory global ptr <H10>
move.l firstCrsrData(a0),a0 ; get the cursor data ptr <H10>
clr.b buttonCount(a0) ; init button down count <H10>
;---------------------
@exit unlk a6 ; dump the adbInfo param block
movem.l (sp)+,d0-d3/a0-a3
rts
;_______________________________________________________________________
;
; Routine: syncADBTalk
;
; Inputs: d0 - address/command byte
; a0 - ptr to receive buffer
;
; Outputs: a0 - pts to pascal talk string
;
; Destroys: a1,d0
;
; Function: This routine makes a synchronous ADBOp call, and returns
; any data in the buffer pointed to by a0.
;_______________________________________________________________________
syncADBTalk
move.l a0,-(sp) ; save ptr to our buffer
clr.w -(sp) ; our 'sync' flag
move.l sp,a1 ; keep pointer to globals for later
move.l sp,-(sp) ; push pointer to globals
pea syncComp ; push pointer to our completion routine
move.l a0,-(sp) ; push pointer to our reply buffer
move.l sp,a0
_ADBOp
@spin tst.b (a1) ; have we completed?
beq.s @spin ; no, keep waiting
lea 14(sp),sp ; dump locals
move.l (sp)+,a0 ; restore a0
rts
;_______________________________________________________________________
;
; Routine: syncADBListen
;
; Inputs: d0 - address/command byte
; a0 - ptr to transmit buffer
;
; Outputs: a0 - pts to pascal talk string
;
; Destroys: a0-a1,d0
;
; Function: This routine makes a synchronous ADBOp call, and returns
; any data in the buffer pointed to by a0.
;_______________________________________________________________________
syncADBListen
clr.w -(sp) ; our 'sync' flag
move.l sp,a1 ; keep pointer to data area for later
move.l sp,-(sp) ; push pointer to data area
pea syncComp ; push our completion address
move.l a0,-(sp) ; push ptr to data to send
move.l sp,a0
_ADBOp
@spin tst.b (a1) ; have we completed?
beq.s @spin ; no, keep waiting
lea 14(sp),sp ; dump locals
rts
;_______________________________________________________________________
;
; Routine: syncComp
;
; Inputs: d0 - ADB command byte
; a0 - ptr to data (pascal string)
; a2 - ptr to data area
;
; Outputs: -
;
; Destroys: a0-a3,d0-d3
;
; Function: This is our ADB completion routine. It simply copies any
; data to our receive buffer in our data area, then sets our
; complete flag.
;_______________________________________________________________________
syncComp st.b (a2) ; set our complete flag
rts
;_______________________________________________________________________
;
; Routine: InitCrsrDev
;
; Inputs: -
;
; Outputs: -
;
; Destroys: a0-a1/d0
;
; Function: This routine allocates and initializes globals for the
; CursorDevice routines, keeping a pointer to them in ExpandMem.
;_______________________________________________________________________
InitCrsrDev
moveq #CrsrGlobSize,d0
_NewPtr ,Sys,Clear ; allocate storage for our globals
movea.l ExpandMem,a1 ; get ptr to expandmem rec
exg a0,a1
move.l a1,emCursorGlobals(a0) ; set cursory global ptr
lea SetCrsrDelCore,a0 ; addr of default ROM handler <H15>
move.l a0,SetCrsrDelayVector(a1) ; install into vector <H15>
lea DrawCursor,a0 ; addr of default ROM handler <H15>
move.l a0,DrawCrsrVBLVector(a1) ; install into vector <H15>
moveq #CrsrDataSize,d0 ; size of our (only) cursor data record
_NewPtr ,Sys,Clear ; allocate it's globals
move.l a0,firstCrsrData(a1) ; set ptr to main cursor data in our globals
moveq #$10,d0
swap d0
move.l d0,whereX(a0) ; init cursor position
move.l d0,whereY(a0)
moveq #72,d0 ; init default screen resolution to 72 dpi
swap d0 ; word2Fix
move.l d0,screenRes(a0)
lea vDrawCursor,a0 ; vector low level drawing routines
move.l a0,DrawCrsrVector
lea vEraseCursor,a0
move.l a0,EraseCrsrVector
IF LC930 THEN
bset.b #SkipDraw,CrsrDevFlags(a1) ; Do not draw the fisrt VBL just do the position calculations <SM6>
ENDIF
rts ; <H14>
;______________________________________________________________________________ <H15>
;
; Routine: SetCrsrDelay
;
; Inputs: a1 contains the ptr to the cursor gDevice being setup
;
; Outputs: -
;
; Destroys: a0,d0
;
; Function: This routine sets the screenDelay value in the CrsrDataRec
; to an appropriate delay value based on the screen type.
; This delay value is used by the cursor VBL as a minimum
; delay between subsequent cursor blits.
;______________________________________________________________________________
EXPORT SetCrsrDelay ; <H15>
SetCrsrDelay
movea.l ExpandMem,a0
cmpa.l #-1,a0 ;has ExpandMem been initialized?
beq.s @skipIt ; if not, then don't call b/c vector is not there
movea.l emCursorGlobals(a0),a0
move.l SetCrsrDelayVector(a0),d0 ;vector to the code that does the real work
beq.s @skipIt ;make sure the value has been initialized
movea.l d0,a0
jsr (a0) ; must preserve a1
@skipIt
IF padForOverpatch THEN
move.l CRSRPTR,A0 ;get handle to cursor data [padding]
MOVE.L (A0),A0 ;get pointer to cursor data
ENDIF
rts
;______________________________________________________________________________ <H15>
;
; Routine: SetCrsrDelCore
;
; Inputs: a1 contains the ptr to the cursor gDevice being setup
;
; Outputs: -
;
; Destroys: a0,d0
;
; Function: This routine sets the screenDelay value in the CrsrDataRec
; to an appropriate delay value based on the screen type.
; This delay value is used by the cursor VBL as a minimum
; delay between subsequent cursor blits.
;______________________________________________________________________________
SetCrsrDelCore
rts ; just a hook for now
;_____________________________________________________________________________________________ <H15>
; VDrawCursor - default DrawCursor routine
;
; The low level cursor routine DrawCursor, is now called through the expandmem vector
; emDrawCursorVector. This is the default routine which is set into the vector by
; the routine InitCrsrVects.
;
EXPORT VDrawCursor
IMPORT BLITCURSOR ;from ccrsrcore.a
VDrawCursor
MOVE.B #1,CRSRBUSY ;MARK CHANGE IN PROGRESS
TST CRSRSTATE
BMI.S DoneSho ;QUIT IF STILL HIDDEN
CLR CRSRSTATE ;DON'T LET CRSRSTATE GET > 0
TST.B CRSRVIS ;IS CURSOR ALREADY VISIBLE?
BNE.S DoneSho ;YES, DON'T TRY TO REDRAW
TST.B CrsrObscure ;Skip if obscured
BNE.S DoneSho
BSR.L BLITCURSOR ;Do the real work: put pixels up
DoneSho CLR.B CRSRBUSY ;CHANGE COMPLETE
RTS
;______________________________________________________________________________________________ <H15>
; VEraseCursor - default EraseCursor routine
;
; The low level cursor routine EraseCursor, is now called through the expandmem vector
; emEraseCursorVector. This is the default routine which is set into the vector by
; the routine InitCrsrVects.
;
EXPORT VEraseCursor
IMPORT UNBLITCURSOR ;from ccrsrcore.a
VEraseCursor
MOVE.B #1,CRSRBUSY ;MARK CHANGE IN PROGRESS
TST.B CRSRVIS ;IS CURSOR VISIBLE?
BEQ.S DoneHid ;NO, DON'T TRY TO REMOVE IT
BSR.L UNBLITCURSOR ;Zap Pixels
DoneHid CLR.B CRSRBUSY ;CHANGE COMPLETE
RTS
END