home *** CD-ROM | disk | FTP | other *** search
/ HomeWare 14 / HOMEWARE14.bin / utils2 / mymous12.arj / MYMOUSE.ASM < prev    next >
Assembly Source File  |  1994-02-12  |  26KB  |  946 lines

  1. ;$VER: MyMouse.asm 1.2 (12.02.93)
  2. ;Written by Andrew Forrest
  3. ;Based on QMouse by Dan Babcock
  4.  
  5. ;Assembled with Devpac 3
  6.     nolist
  7.  
  8. ; How it works:
  9. ;  The program spawns a child process which remains resident in memory and
  10. ;  does the funky stuff. If the resident process already exists, the program
  11. ;  alters the child's parameters and sends it an update signal. The main
  12. ;  program allocates stuff that's _always_ needed, the child allocates other
  13. ;  stuff on the fly (input.device, for example).
  14.  
  15. ;  While it is setting up, the child makes itself invisible by changing its
  16. ;  name. This ensures that a seach for the child (by name) will always find
  17. ;  the child prepared.
  18.  
  19. ; PROCESS IS GUARUNTEED TO STAY PUT (cos you can't totally unpatch functions)
  20.  
  21.     include    everything.i
  22.     include    hardware/dmabits.i
  23.     
  24. Execbase    equ    4
  25. _custom    equ    $dff000
  26.  
  27.     ;*╗╗  Semaphore macros
  28.     ; Use carefully!
  29.     ; Take a5=GlobalPtr; a6=ExecBase
  30.     ; Scratch a0
  31. CriticalSection    macro
  32.       lea      MySemaphore(a5),a0
  33.       just      ObtainSemaphore
  34.     endm
  35. EndCritical    macro
  36.       lea      MySemaphore(a5),a0
  37.       just      ReleaseSemaphore
  38.     endm
  39.  
  40. BlankScreen    macro
  41.       move.w      #DMAF_COPPER+DMAF_RASTER,dmacon+_custom.l
  42.       clr.w      color+_custom.l
  43.     endm
  44. UnBkScreen    macro
  45.       move.w      #DMAF_SETCLR+DMAF_COPPER+DMAF_RASTER,dmacon+_custom.l
  46.     endm
  47.  
  48.     ;*╗╗  Code entrypoint
  49.     move.l    Execbase,a6
  50.     cmp.w    #37,LIB_VERSION(a6)
  51.     bhs    GoodVersion
  52.     
  53. ;Oh no, we're running under 1.3 or something
  54.     lea    DosName(pc),a1
  55.     moveq.l    #0,d0
  56.     just    OpenLibrary
  57.     tst.l    d0
  58.       beq.s      ErrorEnd
  59.     move.l    d0,a6
  60.     just    Output
  61.     move.l    d0,d1
  62.     moveq    #SorryLength,d3
  63.     lea    Sorry(pc),a0
  64.     move.l    a0,d2
  65.     just    Write
  66.     move.l    a6,a1
  67.     move.l    Execbase,a6
  68.     just    CloseLibrary
  69. ErrorEnd:    moveq    #RETURN_FAIL,d0
  70.     rts
  71.  
  72.     dc.b    '$VER: MyMouse 1.2 (08.02.94)',LF,0
  73.  
  74. Sorry    dc.b    'You need (at least) Kickstart 2.0 to run this program.',LF,0
  75. SorryLength    equ    *-Sorry
  76.     even
  77.  
  78. GoodVersion:
  79. ***************************************************************************
  80. * Start of Main program
  81. ***************************************************************************
  82. ; Registers:
  83. ;  A5=^Global data structure
  84. ;  D7=^Installed process, _if it exists yet_, else NULL
  85.  
  86.     lea    ProcName(pc),a1
  87.     just    FindTask
  88.     move.l    d0,d7
  89.     bne.s    .else    ; If process doesn't exist then
  90.       bsr      Allocate    ;   Reserve some space for it
  91.        bne       Deallocate
  92.       bsr.s      Read_Args    ; (returns Z flag success)
  93.        bne       Deallocate
  94.       bsr      Install    ; (returns pointer to new task)
  95.        beq       Deallocate
  96.     bra.s    .end_ok    ; else
  97. .else      move.l      d7,a1
  98.       move.l      TC_Userdata(a1),a5    ; Get global structure
  99.       bsr.s      Read_Args
  100.        bne.s       .end_fail    ;(If couldn't read args, fail)
  101.       move.l      d7,a1
  102.       move.l      UpdateSig(a5),d0
  103.       just      Signal    ;   Send task a signal to wake it up
  104. .end_ok    moveq      #RETURN_OK,d0
  105. .end_fail    rts
  106.  
  107. ***************************************************************************
  108. Read_Args:    ;*╗╗  Replace arguments in global structure with new ones
  109. ; Takes a5=GlobalPtr; Returns OK or FAIL code; a6=Execbase
  110. ; Scratches d0-d4/a0-a1/a4
  111.     CriticalSection
  112.     lea    Template(pc),a0
  113.     move.l    a0,d1
  114.     lea    Options(a5),a0
  115.     move.l    a0,d2
  116.     moveq    #NumOptions-1,d0
  117. .clear_loop      clr.l      (a0)+
  118.     dbra    d0,.clear_loop
  119.     moveq    #0,d3    ;no custom rdarg structure
  120.     move.l    DosBase(a5),a6
  121.     just    ReadArgs
  122.     tst.l    d0
  123.       beq.s      .fail
  124.     move.l    ArgPtr(a5),d1    ; get _old_ arguments
  125.     beq.s    .use
  126.       push.l      d0
  127.       just      FreeArgs    ; and free them if necessary
  128.       pop.l      d0
  129. .use    move.l    d0,ArgPtr(a5)    ; then install _new_ arguments
  130.     move.l    Execbase,a6
  131.     moveq.l    #RETURN_OK,d0
  132.  
  133. .end    EndCritical
  134.     tst.l    d0        ; (return D0 and CCR)
  135.     rts
  136.      
  137. .fail    move.l    Execbase,a6
  138.     moveq.l    #RETURN_FAIL,d0
  139.     bra.s    .end
  140.  
  141. ***************************************************************************
  142. Install:
  143. ; Takes a5=GlobalPtr; a6=Execbase; Returns d0=^NewTask or NULL
  144. ; Scratches a0-a1/d0-d1
  145.     ;*╗╗  Copy resident part of code into allocated memory
  146.     lea    StartResidentCode(pc),a0    ;source
  147.     lea    ResidentCode(a5),a1    ;destination
  148.     move.l    #ResidentCodeLength,d0    ;size
  149.     just    CopyMem
  150.     just    CacheClearU    ;for 020/030/040
  151.  
  152.     ;*╗╗  Initialize static data
  153.     move.b    #HANDLERPRI,InputInterrupt+LN_PRI(a5)
  154.     move.l    a5,InputInterrupt+IS_DATA(a5)
  155.     lea    IntRoutine-StartResidentCode+ResidentCode(a5),a0
  156.     move.l    a0,InputInterrupt+IS_CODE(a5)
  157.  
  158.     move.l    a5,GlobalPtr-StartResidentCode+ResidentCode(a5)
  159.  
  160.     ;*╗╗  Get stack for command.
  161.     move.l    DosBase(a5),a6
  162.     just    Cli
  163.     move.l    d0,a0
  164.     move.l    cli_DefaultStack(a0),d0
  165.     lsl.l    #2,d0
  166.     move.l    d0,CmdStackSize-StartResidentCode+ResidentCode(a5)
  167.  
  168.     ;*╗╗  Start the baby process
  169.     lea    NewProcTags-StartResidentCode+ResidentCode(a5),a0
  170.     lea    NEW_LIFE-StartResidentCode+ResidentCode(a5),a1
  171.     move.l    a1,EntryPointTag(a0)
  172.     lea    ProcName-StartResidentCode+ResidentCode(a5),a1
  173.     not.b    (a1)    ; (So task is initially invisible)
  174.     move.l    a1,ProcNameTag(a0)
  175.     move.l    a0,d1    ; Get tag list into d1
  176.     just    CreateNewProc
  177.     tst.l    d0
  178.  
  179.     move.l    Execbase,a6
  180.     rts
  181.  
  182. ***************************************************************************
  183. Allocate:
  184. ; Takes a6=Execbase; Returns OK or FAIL; a5=GlobalPtr or NULL
  185. ; Scratches a0-a3/d0-d1
  186.     ;*╗╗  Allocate global data structure
  187.     move.l    #Data_SIZEOF,d0
  188.     move.l    #MEMF_CLEAR|MEMF_PUBLIC,d1    ;(Got to be PUBLIC)
  189.     just    AllocMem
  190.     move.l    d0,a5    ; Need to store in a5 _before_ testing
  191.     tst.l    d0
  192.       beq.s      .cant_alloc
  193.  
  194.     ;*╗╗  Allocate Chip RAM data
  195.     move.l    #MouseData_SIZEOF,d0
  196.     move.l    #MEMF_CLEAR|MEMF_PUBLIC|MEMF_CHIP,d1
  197.     just    AllocMem
  198.     move.l    d0,MouseChipData(a5)
  199.       beq.s      .cant_alloc
  200.  
  201.     ;*╗╗  Open libraries
  202.     lea    LibTable(pc),a2
  203.     lea    FirstLibBase(a5),a3
  204.     moveq    #NumLibs-1,d2
  205. .loop      move.w      (a2)+,d0    ; library version to open
  206.       ext.l      d0    ; version should be longword
  207.       move.w      (a2)+,a1
  208.       lea      LibTable(pc,a1.w),a1    ; name of library
  209.       just      OpenLibrary
  210.       move.l      d0,(a3)+
  211.       beq.s      .cant_alloc
  212.     dbra    d2,.loop
  213.  
  214.     ;*╗╗  Set up semaphore
  215.     lea    MySemaphore(a5),a0
  216.     just    InitSemaphore
  217.  
  218.     moveq    #RETURN_OK,d0    ; Set d0 and CCR
  219.     rts
  220.     
  221. .cant_alloc    moveq    #RETURN_FAIL,d0
  222.     rts
  223.  
  224. ***************************************************************************
  225. LibTable:    dc.w    37,DosName-LibTable
  226.     dc.w    33,IntName-LibTable
  227.     dc.w    33,LayName-LibTable
  228. NumLibs:    equ    (*-LibTable)/4
  229.  
  230. ***************************************************************************
  231. ***************************************************************************
  232. StartResidentCode:    ;The following code is copied into allocated memory.
  233. ***************************************************************************
  234. ; Everything except Deallocate is called only from child process
  235. ***************************************************************************
  236. Deallocate:    ;*╗╗ Close libraries (called either from parent or child)
  237. ; Takes a5=GlobalPtr; a6=Execbase; No return value.
  238. ; Scratches a0-a2/d0-d2
  239.     move.l    a5,d0    ; Does global structure exist?
  240.       beq.s      .noData
  241.  
  242.     lea    FirstLibBase(a5),a2
  243.     moveq    #NumLibs-1,d2
  244. .loop    move.l    (a2)+,d0
  245.     beq.s    .endif
  246.       move.l      d0,a1
  247.       just      CloseLibrary
  248. .endif    dbra    d2,.loop
  249.  
  250.     ;*╗╗ Free chip data.
  251.     move.l    MouseChipData(a5),d0
  252.     beq.s    .noChipData
  253.       move.l      d0,a1
  254.       move.l      #MouseData_SIZEOF,d0
  255.       just      FreeMem
  256. .noChipData
  257.     ;*╗╗ Free global structure
  258.     lea    (a5),a1
  259.     move.l    #Data_SIZEOF,d0
  260.     jmp    _LVOFreeMem(a6)    ; Jump in case we are
  261. .noData                ; deallocating _this_ code
  262.     rts
  263.  
  264. ***************************************************************************
  265. ; Here lies the start of the child process' program
  266. ; Except where noted, subroutines should preserve a5-a6 (and the stack
  267. ; pointer of course), but may trash other registers
  268. NEW_LIFE:    move.l    Execbase,a6
  269.     move.l    GlobalPtr(pc),a5
  270.     bsr    InitialiseResident    ; Get signals
  271.       bne.s      Deallocate    ; (_not_ a branch to subrtn)
  272.  
  273. BIG_LOOP:    bsr    EvaluateOptions
  274.       bne.s      KillHandler
  275.     bsr    AllocateResident    ; Get so far ungot resources
  276. wait_loop:    move.l    AllSignals(a5),d0
  277.     just    Wait    ; \ Routines called from this section
  278.     move.l    d0,d7    ; / may trash any register except a5 or d7
  279.     and.l    CLISig(a5),d0
  280.     beq.s    .noCLI
  281. *      move.l      Execbase,a6    (already the case)
  282.       bsr      CLI    ; Expects a6=Execbase (nobody's perfect:-)
  283. .noCLI    move.l    d7,d0
  284.     and.l    MouseBlankSig(a5),d0
  285.     beq.s    .noMB
  286.       bsr      MouseBlankUpdate
  287. .noMB    tst.l    ActivateScreenOption(a5)
  288.     beq.s    .noActiWind    ; If window-activation is off anyway then
  289.       move.l      d7,d0    ; ...don't bother to check for the signals
  290.       and.l      CloseScreenSig(a5),d0
  291.       beq.s      .noClose
  292.         bsr        Closure
  293. .noClose      move.l      d7,d0
  294.       and.l      ScreenDepthSig(a5),d0
  295.       beq.s      .noDepth
  296.         bsr.s        Depth
  297. .noDepth
  298. .noActiWind    move.l    Execbase,a6
  299.     and.l    UpdateSig(a5),d7
  300.       beq.s      wait_loop
  301.     bra.s    BIG_LOOP
  302.  
  303. KillHandler:
  304.     bclr    #STB_HandlerInstalled,Status(a5)
  305.       beq.s      .end
  306.     move.l    InputIORequest(a5),a1
  307.     move.w    #IND_REMHANDLER,IO_COMMAND(a1)
  308.     lea    InputInterrupt(a5),a0
  309.     move.l    a0,IO_DATA(a1)
  310.     just    DoIO
  311.     bclr    #STB_DoMBlank,Status(a5)
  312.     bsr    MouseBlankUpdate    ; Switch off mouse-blanking
  313.     bclr    #STB_SBlanked,Status(a5)
  314.     UnBkScreen            ; Switch off screen-blanking
  315. .end    bra.s    wait_loop
  316.  
  317. ;****************************************************************************
  318. ; This routine is called asynchronously whenever Intuition's ScreenDepth
  319. ; routine gets called (i.e. any time a screen is rearranged).
  320. Depth:    move.l    IntBase(a5),a6
  321.     moveq    #0,d0
  322.     just    LockIBase    ; Start critical section
  323.     move.l    d0,d2
  324.     move.l    ib_ActiveScreen(a6),a0    ; \  Remember to keep track
  325.     move.l    ib_ActiveWindow(a6),a1    ;  | of _previous_ screen-
  326.     bsr    AssociateWindow    ; /  window combination
  327.     move.l    ib_FirstScreen(a6),a0    ; \ Look up `active' window
  328.     bsr    IndexScreenTable    ; / of newly frontmost screen
  329.     tst.l    d0
  330.     beq.s    .fail    ; If we can find a window for screen,
  331.       move.l      d0,a0    ; ...then activate that window
  332.       just      ActivateWindow ; (Defered so should be OK inside lock)
  333. .fail    move.l    d2,a0
  334.     just    UnlockIBase    ; End critical section
  335.     rts
  336.  
  337. ; This one gets called on screen closure.
  338. Closure:    move.l    IntBase(a5),a6
  339.     moveq    #0,d0
  340.     just    LockIBase    ; Start critical section
  341.     move.l    d0,a0
  342.     bsr    PruneScreenTable    ; (Alters no registers)
  343.     just    UnlockIBase    ; End critical section
  344.     or.l    ScreenDepthSig(a5),d7    ; (Must change window too)
  345.     rts
  346.  
  347. ; Executes a CLI command (like NewShell, for example)
  348. ; *** Expects a6=Execbase
  349. CLI:    CriticalSection    ; Critical so CMD parameter can't change
  350.     move.l    CmdOption(a5),d1    ;Pop CLI
  351.     beq.s    .fail
  352.       pushm.l      d1/a6
  353.       move.l      IntBase(a5),a6    ;Workbench To Front
  354.       just      WBenchToFront
  355.       popm.l      d1/a6
  356.       move.l      DosBase(a5),a6
  357.       lea      Tags(pc),a1
  358.       bsr.s      OpenNil
  359.       move.l      d0,InputTag(a1)
  360.     beq.s    .end
  361.       bsr.s      OpenNil
  362.       move.l      d0,OutputTag(a1)
  363.     beq.s    .closeinput
  364.       move.l      a1,d2    ;tags
  365.       just      SystemTagList
  366.       tst.l      d0
  367.       beq.s      .end    ; If sucessful, should deallocate itself
  368.         move.l        OutputTag+Tags(pc),d1
  369.         just        Close
  370. .closeinput        move.l        InputTag+Tags(pc),d1
  371.         just        Close
  372. .end      move.l      Execbase,a6
  373. .fail    EndCritical
  374.     rts    
  375.  
  376. Tags:
  377.     dc.l    SYS_UserShell,0
  378.     dc.l    SYS_Asynch,0
  379.     dc.l    SYS_Input,0
  380. InputTag    equ    *-4-Tags
  381.     dc.l    SYS_Output,0
  382. OutputTag    equ    *-4-Tags
  383.     dc.l    NP_Priority,ShellPriority
  384.     dc.l    NP_StackSize
  385. CmdStackSize:
  386.     dc.l    0
  387.     dc.l    0    ;end of tag list
  388.  
  389. OpenNil:    pushm.l    a0-a1/d1-d2
  390.     lea    NilName(pc),a0
  391.     move.l    a0,d1
  392.     move.l    #MODE_READWRITE,d2
  393.     just    Open
  394.     popm.l    a0-a1/d1-d2
  395.     rts
  396.  
  397. ;****************************************************************************
  398. InitialiseResident:
  399. ; Takes a5=GlobalPtr; a6=Execbase; Returns OK or FAIL
  400. ; Scratches d0-d2/a0-a1
  401.     suba.l    a1,a1
  402.     just    FindTask    ; _Find_ yourself.
  403.     move.l    d0,a0
  404.     move.l    a5,TC_Userdata(a0)
  405.     move.l    d0,Task(a5)
  406.     bsr    InitialiseScreenTable    ; Just set it up
  407.  
  408.     ;*╗╗  Allocate signals
  409.     moveq    #NumSigs-1,d2
  410.     lea    Sigs(a5),a2
  411. .sigloop      moveq      #-1,d0
  412.       just      AllocSignal
  413.       tst.l      d0
  414.     bmi.s    .fail
  415. .ok      moveq      #0,d1
  416.       bset      d0,d1
  417.       move.l      d1,(a2)+
  418.       or.l      d1,AllSignals(a5)
  419.     dbra    d2,.sigloop
  420.  
  421.     just    Forbid
  422.     lea    ProcName(pc),a1
  423.     move.b    #InitialLetter,(a1)
  424.     just    FindTask    ; Search for process with same name
  425.     tst.l    d0
  426.       bne.s      .found_twin    ; Oh, no -- duplicate name
  427.     move.l    Task(a5),a1
  428.     move.l    LN_NAME(a1),a1
  429.     move.b    #InitialLetter,(a1)    ; make process visible
  430.     just    Permit
  431.  
  432.     ;*╗╗  Patch three Intuition routines. (Do this last)
  433.     ;*╗╗  (all but first patch must be on V39 library)
  434.     lea    PatchTable(pc),a2
  435.     lea    OldRoutines(a5),a3
  436.     move.l    IntBase(a5),a1    ; Library to patch
  437. .patchloop      move.w      (a2)+,d1    ; LVO offset
  438.     beq.s    .endpatch    ; (exit if hit null-terminator)
  439.       move.w      (a2)+,d0    ; Offset to new routine
  440.       tst.l      (a3)    ; If it is already patched
  441.       bne.s      .nextpatch    ;   skip to the next one
  442.         lea        PatchTable(pc,d0.w),a0 ; Get address of new routine
  443.         move.l        a0,d0    ; d0 <- address of new routine
  444.         move.w        d1,a0    ; a0 <- LVO offset
  445.         just        SetFunction
  446.         move.l        d0,(a3)+    ; Store ^old routine for posterity
  447. .nextpatch      move.l      IntBase(a5),a1    ;\ Get ^Intuition for next
  448.       cmp.w      #39,LIB_VERSION(a1)    ;/ iteration and check version
  449.     bhs.s    .patchloop    ; Patch V39 Intuition only
  450. .endpatch    
  451.  
  452.     moveq    #RETURN_OK,d0
  453.     rts
  454.     
  455. .found_twin    
  456. .fail    moveq    #31,d2
  457. .loop      btst      d2,AllSignals(a5)
  458.       beq.s      .next
  459.         move.l        d2,d0
  460.         just        FreeSignal
  461. .next    dbra    d2,.loop
  462.     moveq    #RETURN_FAIL,d0
  463.     rts
  464.  
  465. PatchTable:    dc.w    _LVODisplayBeep,NewDisplayBeep-PatchTable
  466.     dc.w    _LVOCloseScreen,NewCloseScreen-PatchTable
  467.     dc.w    _LVOScreenDepth,NewScreenDepth-PatchTable
  468.     dc.w    0    ; NULL-terminate list
  469.  
  470. ***************************************************************************
  471. NewDisplayBeep:
  472.     move.l    GlobalPtr(pc),a1
  473.     tst.l    NoBeepOption(a1)
  474.     bne.s    .endif
  475.       move.l      OldDisplayBeep(a1),-(sp)
  476. .endif    rts
  477.  
  478. NewCloseScreen:
  479.     pushm.l    a2/a5-a6
  480.     move.l    GlobalPtr(pc),a5
  481.     move.l    OldCloseScreen(a5),a2
  482.     jsr    (a2)
  483.     move.l    d0,a2    ; (Preserve return value)
  484.     move.l    CloseScreenSig(a5),d0
  485.     bra.s    sig
  486.  
  487. NewScreenDepth:
  488.     pushm.l    a2/a5-a6
  489.     move.l    GlobalPtr(pc),a5
  490.     move.l    OldScreenDepth(a5),a2
  491.     jsr    (a2)
  492.     move.l    ScreenDepthSig(a5),d0
  493.  
  494. sig    move.l    Task(a5),a1
  495.     move.l    Execbase,a6
  496.     just    Signal
  497.     move.l    a2,d0    ; (Restore return value)
  498.     popm.l    a2/a5-a6
  499.     rts
  500.  
  501.  
  502. ***************************************************************************
  503. ; Here is the routine for allocating the baby task's resources
  504. ; If they cannot be allocated at first, the program tries again every time
  505. ; an update signal is recieved.
  506. AllocateResident:
  507. ; Takes a5=GlobalPtr; a6=Execbase
  508. ; Scratches a0-a3/d0-d1
  509.     ;*╗╗  Create an IORequest structure
  510.     move.l    InputMsgPort(a5),d0
  511.       bne.s      .endCreatePort    ; Skip if port already there
  512.     just    CreateMsgPort
  513.     move.l    d0,InputMsgPort(a5)
  514.     beq.s    .fail
  515. .endCreatePort
  516.     move.l    d0,a0
  517.     move.l    InputIORequest(a5),d0    ; n.b. _not_ "tst.l Inpu..."
  518.       bne.s      .endCreateReq    ; Skip if req already there
  519.     moveq    #IOSTD_SIZE,d0
  520.     just    CreateIORequest
  521.     move.l    d0,InputIORequest(a5)
  522.     beq.s    .fail
  523. .endCreateReq
  524.  
  525.     ;*╗╗  Open the input.device
  526.     btst    #STB_InputDeviceOpened,Status(a5)
  527.       bne.s      .endOpenInput
  528.     move.l    d0,a1    ;IO request
  529.     lea    InputName(pc),a0    ;device name
  530.     moveq    #0,d0    ;unit number
  531.     moveq    #0,d1    ;flags
  532.     just    OpenDevice
  533.     tst.l    d0
  534.     bne.s    .fail
  535.       bset      #STB_InputDeviceOpened,Status(a5)
  536. .endOpenInput
  537.  
  538.     ;*╗╗  Install the input handler
  539.     bset    #STB_HandlerInstalled,Status(a5)
  540.       bne.s      .endInstallHandl
  541.     move.l    InputIORequest(a5),a1
  542.     move.w    #IND_ADDHANDLER,IO_COMMAND(a1)
  543.     lea    InputInterrupt(a5),a0
  544.     move.l    a0,IO_DATA(a1)
  545.     just    DoIO
  546. .endInstallHandl
  547.  
  548. .fail    rts
  549.  
  550. ***************************************************************************
  551. EvaluateOptions:
  552. ; Takes a5=GlobalPtr; a6=Execbase; Scratches d0-d1/a0-a2
  553.     ;*╗╗  Copy some parameters (for input-handler)
  554.     CriticalSection    ; So no one changes them while we do it
  555.     lea    CacheTable(pc),a1
  556.     lea    OptionCaches(a5),a2
  557.     move.w    #CacheNum-1,d1
  558. .loop      move.w      (a1)+,d0
  559.       move.l      (a5,d0.w),d0
  560. .if      beq.s      .else
  561.         move.l        d0,a0
  562.         move.l        (a0),d0
  563.       bra.s      .endif
  564. .else        moveq        #-1,d0    ; Unselected options become -1
  565. .endif      move.l      d0,(a2)+
  566.     dbra    d1,.loop
  567. .endloop    EndCritical
  568.  
  569.     ;*╗╗  Ensure mouse/screen is never left blanked
  570.     tst.l    MouseBlank(a5)
  571.     bge.s    .mblnk_on    ; Skip if mouse blanking was turned on
  572.       bclr      #STB_DoMBlank,Status(a5)
  573.       bsr      MouseBlankUpdate 
  574. .mblnk_on    tst.l    ScreenBlank(a5)
  575.     bgt.s    .sblnk_on    ; Skip if screen blanking was turned on
  576.       bclr      #STB_SBlanked,Status(a5)
  577.       UnBkScreen
  578. .sblnk_on
  579.  
  580.     ;*╗╗  Initialize damping constant.
  581.     move.l    Acceleration(a5),d0
  582.       bmi.s      .no_damp
  583.     move.l    d0,a0
  584.     move.l    (a0),d0
  585.     subq.l    #1,d0
  586.     move.l    Threshold(a5),d1
  587.     bpl.s    .use_thresh
  588.       moveq      #0,d1
  589. .use_thresh    addq.l    #1,d1
  590.     mulu.w    d0,d1
  591.     move.w    d1,DampingConstant(a5)
  592. .no_damp
  593. .okay
  594.     *╗╗  Check that at least one command-line option was specified
  595.     lea    Options(a5),a0
  596.     moveq    #NumOptions-1,d0
  597. .chk_loop      tst.l      (a0)+
  598.       bne.s      .dontdie
  599.     dbra    d0,.chk_loop
  600.     bsr    ShutDownScreenTable    ; If no options deallocate mem
  601.     moveq    #RETURN_FAIL,d0    ; Return nonzero if no options
  602.     rts
  603. .dontdie    moveq    #RETURN_OK,d0    ; Return zero if at least 1 selected
  604.     rts
  605.  
  606. CacheTable    dc.w    MBlankOption
  607.     dc.w    SBlankOption
  608.     dc.w    AccelOption
  609.     dc.w    ThreshOption
  610.     dc.w    CTFOption
  611.     dc.w    ClickBorderOption
  612. CacheNum    equ    (*-CacheTable)/2
  613.  
  614. ;****************************************************************************
  615.     include    MM-Handler.asm
  616.     include    ScreenTable.asm
  617.  
  618. ;****************************************************************************
  619. ;Utility routines
  620.  
  621.     ;*╗╗  Get window associated with current mouse position.
  622. ; Takes a5=GlobalPtr; a6=IntBase; Returns d0=Window; D1=Screen
  623.     ; (assume we don't need to lock IntuitionBase)
  624. GetWindow:
  625.     pushm.l    d4/a0-a1/a4/a6
  626.     lea    (a6),a4
  627.     move.l    LayBase(a5),a6
  628.     move.l    ib_FirstScreen(a4),d4
  629. .loop      tst.l      d4
  630.     beq.s    .err_end
  631.       move.l      d4,a0
  632.       move.l      sc_NextScreen(a0),d4
  633.       move.w      sc_MouseX(a0),d0
  634.     bmi.s    .loop
  635.       move.w      sc_MouseY(a0),d1
  636.     bmi.s    .loop
  637.     push.l    a0
  638.     lea    sc_LayerInfo(a0),a0
  639.     just    WhichLayer
  640.     pop.l    d1
  641.     tst.l    d0
  642.       beq.s      .end
  643.     move.l    d0,a0
  644.     move.l    lr_Window(a0),d0
  645. .end    popm.l    d4/a0-a1/a4/a6
  646.     rts
  647. .err_end:    moveq    #0,d0
  648.     moveq    #0,d1
  649.     bra    .end
  650.  
  651. DoWindowToFront:
  652. ; Takes d0=^Window or NULL (no effect); a5=GlobalPtr
  653. ; scratches nothing
  654.     tst.l    d0
  655.       beq.s      .abort
  656.     pushm.l    d0-d1/a0-a1/a6
  657.     move.l    IntBase(a5),a6
  658.     move.l    d0,a0
  659.     move.l    wd_WLayer(a0),d0
  660.       beq.s      .end
  661.     move.l    d0,a1
  662.     move.l    lr_ClipRect(a1),d0
  663.       beq.s      .end
  664.     move.l    d0,a1
  665.     tst.l    cr_Next(a1)    ; Do nothing if it is not covered
  666.       beq.s      .end
  667.     move.l    wd_Flags(a0),d0
  668.     and.l    #WFLG_BACKDROP,d0
  669.       bne.s      .end    ; or if it is a backdrop window
  670.     just    WindowToFront
  671. .end    popm.l    d0-d1/a0-a1/a6
  672. .abort    rts
  673.  
  674. ; Blank or unblank the mouse, depending on Globals.Status.DoMBlank.
  675. ; Takes nil (but needs a5=^Globals); Trashes/Returns nil;
  676. ; NEVER call with Intbase locked
  677. MouseBlankUpdate:
  678.     pushm.l    a0-a1/a6/d0-d2
  679.     move.l    IntBase(a5),a6
  680.     moveq    #0,d0
  681.     just    LockIBase    ; *** Critical section
  682.     move.l    d0,d2
  683.     move.l    Execbase,a6
  684.     just    Forbid    ; (make sure no one changes mouse)
  685.     btst    #STB_DoMBlank,Status(a5)
  686.     beq.s    .restore
  687. .blank      bsr      BlankMouse
  688.     bra.s    .endif
  689. .restore      bsr      RestoreMouse
  690. .endif    just    Permit    ; (allow other tasks)
  691.     move.l    d2,a0
  692.     move.l    IntBase(a5),a6
  693.     just    UnlockIBase    ; *** End critical section
  694.     popm.l    a0-a1/a6/d0-d2
  695.     rts
  696.  
  697. ;*╗╗  Blank the current window's mouse pointer
  698. ; Takes a5=GlobalPtr; IBase must be locked; Scratches nothing
  699. BlankMouse:    pushm.l    a0-a1/a6/d0-d3
  700.     move.l    IntBase(a5),a6
  701.     move.l    ib_ActiveWindow(a6),a0
  702.     cmp.l    MBlankWindow(a5),a0
  703.     beq.s    .same_wind    ; If a different window is now active then
  704. .other_win      bsr.s      RestoreMouse    ;   unblank it first
  705.     bra.s    .notblanked    ; Else
  706. .same_wind      move.l      wd_Pointer(a0),d0
  707.       cmp.l      MouseChipData(a5),d0 ; If still blanked, give up
  708.       beq.s      .end_blank
  709. .notblanked    move.l    a0,MBlankWindow(a5)    ; Remember window & its pointer
  710.       beq.s      .no_blank    ; Quit if no current window(!)
  711.     move.l    wd_WScreen(a0),MBlankScreen(a5)    ; Remember screen
  712.     clr.l    OldPointer+Ptr_Image(a5)    ; Assume no custom image
  713.     move.l    wd_Pointer(a0),d0
  714.     cmp.l    MouseChipData(a5),d0
  715.       beq.s      .end_blank    ; Quit if already blanked
  716.     move.l    d0,OldPointer+Ptr_Image(a5)
  717.     move.l    wd_PtrDimensions(a0),OldPointer+Ptr_Dimensions(a5)
  718.     move.l    MouseChipData(a5),a1
  719.     moveq    #1,d0    ;height
  720.     moveq    #16,d1    ;width
  721.     moveq    #0,d2    ;xoffset
  722.     moveq    #0,d3    ;yoffset
  723.     just    SetPointer
  724. .end_blank    bset    #STB_MBlanked,Status(a5)
  725. .no_blank    popm.l    a0-a1/a6/d0-d3
  726.     rts
  727.  
  728. ;*╗╗  Restore old mouse image
  729. ; Takes a5=GlobalPtr; IBase must be locked; Scratches nil
  730. RestoreMouse:
  731.     pushm.l    a0-a1/a6/d0-d3
  732.     move.l    IntBase(a5),a6
  733.     move.l    MBlankWindow(a5),d0
  734.     bne.s    .knownblnk    ; If nothing is apparently blanked then
  735. .unknwnblnk      move.l      ib_ActiveWindow(a6),d0 ; Try the active window
  736.         beq.s        .end_RMouse    ; (quit if no active window)
  737.       move.l      d0,a0
  738.       clr.l      OldPointer+Ptr_Image(a5) ;(whose image we don't know)
  739.       bra.s      .foundwind
  740. .knownblnk    move.l    MBlankScreen(a5),d2    ; We know it's on this screen
  741.     move.l    ib_FirstScreen(a6),d1    ; Start with the first screen
  742. .screenloop    beq.s    .end_RMouse    ; While screen^ =/= NULL
  743.       move.l      d1,a0        ;   Get ^ into address reg
  744.       cmp.l      d1,d2        ;   Compare screen to target
  745.     beq.s    .foundscrn    ; Exit if found target screen
  746.       move.l      sc_NextScreen(a0),d1    ;  Get next screen
  747.     bra.s    .screenloop    ; End while
  748. .foundscrn    move.l    sc_FirstWindow(a0),d1    ; Start with first window
  749. .windowloop    beq.s    .end_RMouse    ; While window^ =/= NULL
  750.       move.l      d1,a0
  751.       cmp.l      d0,d1        ;   Compare window with target
  752.     beq.s    .foundwind    ; Exit if this is the window
  753.       move.l      wd_NextWindow(a0),d1    ;   Next window
  754.     bra.s    .windowloop    ; End while
  755. .foundwind    ; We now know window exists and that a0=^window
  756.     move.l    wd_Pointer(a0),d0
  757.     cmp.l    MouseChipData(a5),d0
  758.     bne.s    .end_RMouse    ; Skip if already unblanked
  759.       move.l      OldPointer+Ptr_Image(a5),a1
  760.       move.l      a1,d0
  761.       bne.s      .restoreold    ; If no image pointer then
  762.         just        ClearPointer    ;   Restore default pointer
  763.       bra.s      .end_RMouse    ; Else
  764. .restoreold        move.b        OldPointer+Ptr_Height(a5),d0
  765.         move.b        OldPointer+Ptr_Width(a5),d1
  766.         move.b        OldPointer+Ptr_XOffset(a5),d2
  767.         move.b        OldPointer+Ptr_YOffset(a5),d3
  768.         ext.w        d0
  769.         ext.w        d1
  770.         ext.w        d2
  771.         ext.w        d3
  772.         just        SetPointer    ;   Restore custom pointer
  773. .end_RMouse    bclr    #STB_MBlanked,Status(a5)
  774.     popm.l    a0-a1/a6/d0-d3
  775.     rts
  776.  
  777. ***************************************************************************
  778.  
  779. GlobalPtr:    ds.l    1
  780.  
  781. NorthgateTable:
  782.     ;*╗╗  Assign PageUp/PageDown/Home/End to shift-cursor sequences
  783.     dc.b    $6b,$4f,IEQUALIFIER_LSHIFT
  784.     dc.b    $6c,$4e,IEQUALIFIER_LSHIFT
  785.     dc.b    $6d,$4c,IEQUALIFIER_LSHIFT
  786.     dc.b    $6e,$4d,IEQUALIFIER_LSHIFT
  787. ;    ;*╗╗  Change a couple keypad key assignments to be more Amiga-like.
  788. ;    dc.b    $5c,$5b,0    ;'/' key -> ')' key
  789. ;    dc.b    $5d,$5c,0    ;'*' key -> '/' key
  790. ;    dc.b    $4a,$5d,0    ;'-' key -> '*' key
  791.     dc.b    0
  792.  
  793. ProcName:    dc.b    'Funky baby Mouse process 1.2',0 ;╗╗ Name of child process
  794. InitialLetter    equ    'F'    ;╗╗ child's first initial
  795. InputName:    dc.b    'input.device',0
  796. NilName:    dc.b    'NIL:',0
  797.     even
  798.  
  799. NewProcTags:    ; In allocated memory so command can be pure
  800.     dc.l    NP_Entry
  801. EntryPointTag    equ    *-NewProcTags
  802.     dc.l    0
  803.     dc.l    NP_Name
  804. ProcNameTag    equ    *-NewProcTags
  805.     dc.l    0
  806.     dc.l    NP_Cli,-1
  807.     dc.l    NP_Priority,TaskPriority
  808.     dc.l    0    ;end of tags
  809.  
  810. ***************************************************************************
  811. EndResidentCode:    ;end of code copied into allocated memory
  812. ***************************************************************************
  813. ***************************************************************************
  814. ResidentCodeLength    equ    EndResidentCode-StartResidentCode
  815.  
  816.  
  817. ***************************************************************************
  818. * Global data and constants
  819. ***************************************************************************
  820.  
  821. HANDLERPRI        equ    100    ;Higher than pesky AMOS
  822. TaskPriority    equ    20
  823. ShellPriority    equ    0
  824.  
  825. NULL    equ    0
  826. KEYCODE_ESC    equ    $45
  827.  
  828.     BITDEF    BB,TOP,0
  829.     BITDEF    BB,BOTTOM,1
  830.     BITDEF    BB,LEFT,2
  831.     BITDEF    BB,RIGHT,3
  832.  
  833. DosName    dc.b    "dos.library",0
  834. IntName    dc.b    "intuition.library",0
  835. LayName    dc.b    "layers.library",0
  836.  
  837. ;*****************************************************************
  838. ;* Global data structure definitions
  839.  
  840.     STRUCTURE    PointerStruct,0
  841.     APTR    Ptr_Image
  842.     LABEL    Ptr_Dimensions
  843.     BYTE    Ptr_Height
  844.     BYTE    Ptr_Width
  845.     BYTE    Ptr_XOffset
  846.     BYTE    Ptr_YOffset
  847.     LABEL    Ptr_SIZEOF
  848.  
  849. wd_PtrDimensions    equ    wd_PtrHeight
  850.  
  851.     STRUCTURE    Data,0
  852.     APTR    MouseChipData
  853.     LABEL    FirstLibBase
  854.     APTR    DosBase
  855.     APTR    IntBase
  856.     APTR    LayBase
  857.  
  858.     LABEL    Sigs
  859.     LONG    CLISig
  860.     LONG    UpdateSig
  861.     LONG    MouseBlankSig
  862.     LONG    ScreenDepthSig
  863.     LONG    CloseScreenSig
  864.     LABEL    EndSigs
  865. NumSigs    equ    (EndSigs-Sigs)/4
  866.     LONG    AllSignals    ;Logical OR of all signals
  867.  
  868.     APTR    Task
  869.     APTR    ArgPtr
  870.     LABEL    OldRoutines
  871.     APTR    OldDisplayBeep
  872.     APTR    OldCloseScreen
  873.     APTR    OldScreenDepth
  874.     LONG    MouseTime    ;timeout for mouse blanking
  875.     APTR    MBlankWindow
  876.     APTR    MBlankScreen
  877.     STRUCT    OldPointer,Ptr_SIZEOF
  878.     LONG    ScreenTime    ;for screen blanking
  879.     APTR    ClickWindow
  880.     LONG    ClickCount
  881.     STRUCT    ClickTime,TV_SIZE
  882.     APTR    InputMsgPort
  883.     APTR    InputIORequest
  884.  
  885. Template:    dc.b    'M=MBLANK/K/N,'
  886.     dc.b    'S=SBLANK/K/N,'
  887.     dc.b    'A=ACCELERATION/K/N,'
  888.     dc.b    'T=THRESHOLD/K/N,'
  889.     dc.b    'CTF=CLICKTOFRONT/K/N,'
  890.     dc.b    'CTFB=CLICKTOFRONTBORDER/K/N,'
  891.     dc.b    'CTB=CLICKTOBACK/S,'
  892.     dc.b    'AFS=ACTIVATEFRONTSCREEN/S,'
  893.     dc.b    'CMD=COMMAND/K,'
  894.     dc.b    'SUNMOUSE/S,'
  895.     dc.b    'NORTHGATE/S,'
  896.     dc.b    'NOBEEP/S'
  897.     dc.b    0
  898.  
  899.     LABEL    Options
  900.     LONG    MBlankOption
  901.     LONG    SBlankOption
  902.     LONG    AccelOption
  903.     LONG    ThreshOption
  904.     LONG    CTFOption
  905.     LONG    ClickBorderOption
  906.     LONG    CTBOption
  907.     LONG    ActivateScreenOption
  908.     LONG    CmdOption
  909.     LONG    SunMouseOption
  910.     LONG    NorthgateOption
  911.     LONG    NoBeepOption
  912.     LABEL    EndOptions
  913. NumOptions    equ    (EndOptions-Options)/4
  914.  
  915.     LABEL    OptionCaches
  916.     LONG    MouseBlank
  917.     LONG    ScreenBlank
  918.     LONG    Acceleration    ; Copies of parameters
  919.     LONG    Threshold    ; ..to avoid having to wait on semaphore
  920.     LONG    CTF    ; ..which could deadlock input handler
  921.     LONG    CTFB
  922.  
  923.     STRUCT    InputInterrupt,IS_SIZE
  924.     STRUCT    MySemaphore,SS_SIZE
  925.     STRUCT    ScreenTable,ST_SIZEOF
  926.     WORD    CurrentX
  927.     WORD    CurrentY
  928.     WORD    DampingConstant
  929.     BYTE    Status    ; Various status bits (defined below)
  930.     BYTE    Padding    ; To fill out to even number of bytes
  931.  
  932.     STRUCT    ResidentCode,ResidentCodeLength
  933.     LABEL    Data_SIZEOF
  934.  
  935. ;Bit definitions for Status
  936.     BITDEF    ST,SBlanked,0
  937.     BITDEF    ST,MBlanked,1
  938.     BITDEF    ST,SunMouse,2
  939.     BITDEF    ST,HandlerInstalled,3
  940.     BITDEF    ST,InputDeviceOpened,4
  941.     BITDEF    ST,DoMBlank,5
  942.  
  943.     STRUCTURE    MouseData,12
  944.     LABEL    MouseData_SIZEOF
  945.  
  946.     END