* Mouse-xy V1.0 * By Preben Nielsen * * This utility opens a little window in which it shows * the mouse coordinates and the color at that position * If the left mousebutton is being held down, the coordinates * is relative to the spot where the mouse was when button got * pressed. * * Double-clicking the right mousebutton while the window is * active will make it try to jump to another screen (if any). * * The size of the window and the use of colors in it depends on * the version of the Kickstart/Workbench (1.2/1.3 vs. 2.?) and * the screen mode (LORES vs. HIRES) * * NOTE: There's no need to 'RUN' or 'RUNBACK' this program from the * CLI. It is auto-detaching. * *HISTORY * Made with Hisoft V2.12 * * V1.0 17-Mar-91: First attempt * 19-Mar-91: Added color monitoring * 21-Mar-91: Even Works while intuition locks all layers because * I now patch 'LockLayerRom' and 'UnLockLayerRom'. * You can now monitor the coordinates even while you * are sizing window, dragging window/icons and even * when you select menus * 07-Apr-91: I Now patch 'CloseScreen' so that the window * automatically evacuates any closing screen. * 19-Apr-91: Made some modifications to make it look better * under WB2.0 (haven't actually tried it yet) OPT O+ OPT O1+ ; Tells when a branch could be optimised to short ; OPT i+ ; Tells when '#' is probably missing LMBBUT =$BFE001 ; Bit 6 Prepare MACRO IFC '\1','Exec_Call' movea.l 4.W,A6 ENDC IFC '\1','Intuition_Call' movea.l IntBase(DB),A6 ENDC IFC '\1','Gfx_Call' movea.l GfxBase(DB),A6 ENDC IFC '\1','Dos_Call' movea.l DosBase(DB),A6 ENDC ENDM CallLib MACRO jsr _LVO\1(A6) ENDM Call MACRO bsr \1 ENDM Push MACRO Push IFC '\1','All' movem.l D0-D7/A0-A6,-(SP) ENDC IFNC '\1','All' movem.l \1,-(SP) ENDC ENDM Pop MACRO Pop IFC '\1','All' movem.l (SP)+,D0-D7/A0-A6 ENDC IFNC '\1','All' movem.l (SP)+,\1 ENDC ENDM rAPtr MACRO Name DefSiz set DefSiz+4 DefPtr set DefPtr-4 \1 = DefPtr ENDM rLong MACRO Name DefSiz set DefSiz+4 DefPtr set DefPtr-4 \1 = DefPtr ENDM rWord MACRO Name DefSiz set DefSiz+2 DefPtr set DefPtr-2 \1 = DefPtr ENDM rByte MACRO Name DefSiz set DefSiz+1 DefPtr set DefPtr-1 \1 = DefPtr ENDM rStorage MACRO Name,Size ; Define storage DefSiz set DefSiz+\2 DefPtr set DefPtr-\2 \1 = DefPtr ENDM rEVEN MACRO ; Word boundary IFNE DefPtr&1 DefPtr set DefPtr-1 DefSiz set DefSiz+1 ENDC ENDM rStart MACRO ; Define var section DefPtr set 0 DefSiz set 0 ENDM rEnd MACRO ; End var section RelSize = DefSiz ENDM rAlloc MACRO ; Allocate storage link DB,#-RelSize ENDM rFree MACRO ; De-allocate storage unlk DB ENDM rClear MACRO ; Reset all variables movem.l D0/A0,-(SP) move.w #RelSize-1,D0 move.l DB,A0 rClr.\@ clr.b -(A0) dbf D0,rClr.\@ movem.l (SP)+,D0/A0 ENDM Detach MACRO ; Detach <'process name'>,stacksize,processpri SECTION SingleSplit,CODE Start Prepare Exec_Call suba.l A1,A1 CallLib FindTask ; Find us move.l D0,A2 tst.l pr_CLI(A2) bne.S SegSplit jmp ProcessStart ; from WorkBench SegSplit CallLib Forbid ; From Dos lea DName(PC),A1 CallLib OldOpenLibrary move.l D0,D5 beq.S 3$ moveq #ML_SIZE+1*ME_SIZE,D0 move.l #MEMF_PUBLIC|MEMF_CLEAR,D1 CallLib AllocMem ; Allocate Memlist move.l D0,A2 tst.l D0 beq.S 2$ move.l #ProcessName,D1 moveq #\3,D2 ; Priority move.l Start-4(PC),D3 move.l #\2,D4 ; StackSize move.l D5,A6 CallLib CreateProc Prepare Exec_Call tst.l D0 beq.S 1$ move.l D0,A0 lea -pr_MsgPort(A0),A0 ; Now we have process not.l pr_CLI(A0) ; All MY programs will now think they were started from the CLI lsl.l #2,D3 subq.l #4,D3 move.l D3,A1 move.w #1,ML_NUMENTRIES(A2) ; MemList -> ml_NumEntries = 1 move.l A1,ML_ME+ME_ADDR(A2) ; MemList -> ml_me[0].me_Addr = Segment move.l (A1),ML_ME+ME_LENGTH(A2); MemList -> ml_me[0].me_Length = Length lea TC_MEMENTRY(A0),A0 move.l A2,A1 CallLib AddTail ; AddTail(&Process->pr_Task.tc_MemEntry,&MemList->ml_Node); lea Start-4(PC),A0 clr.l (A0) ; Split the segments bra.S 2$ 1$ move.l A2,A1 ; CreateProc failed. Can't do anything then moveq #ML_SIZE+1*ME_SIZE,D0 CallLib FreeMem 2$ move.l D5,A1 CallLib CloseLibrary 3$ CallLib Permit moveq #0,D0 rts DName dc.b 'dos.library',0 ProcessName dc.b \1,0 ; CreateProc makes a copy of this name SECTION ProcessCode,CODE ProcessStart ENDM incdir "AsmInc:" include "exec/exec_lib.i" include "exec/memory.i" include "exec/interrupts.i" include "intuition/intuition.i" include "intuition/intuitionbase.i" include "intuition/intuition_lib.i" include "graphics/graphics_lib.i" include "libraries/dos_lib.i" include "libraries/dosextens.i" include "hardware/intbits.i" xy_Change_B =SIGBREAKB_CTRL_D xy_Change_F =1<,4000,0 rAlloc ; Allocate memory for variables rClear ; Clear the memory lea SpareA4(PC),A0 move.l DB,(A0) Prepare Exec_Call suba.l A1,A1 CallLib FindTask ; Find us move.l D0,xyProcess(DB) movea.l D0,A2 tst.l pr_CLI(A2) bne.S GetLibs WBenchStartup lea pr_MsgPort(A2),A0 CallLib WaitPort ; Wait for a message lea pr_MsgPort(A2),A0 CallLib GetMsg then get it move.l D0,WBenchMsg(DB) ; Save it for later reply GetLibs lea GfxName(PC),A1 CallLib OldOpenLibrary move.l D0,GfxBase(DB) beq Error lea IntName(PC),A1 CallLib OldOpenLibrary move.l D0,IntBase(DB) beq Error SetInterrupt Prepare Exec_Call lea xyInterrupt(DB),A1 ; Start vertical-blanking interrupt-Server move.b #NT_INTERRUPT,LN_TYPE(A1); xyInterrupt->is_Node.ln_Type=NT_INTERRUPT lea xyIntName(PC),A0 move.l A0,LN_NAME(A1) ; xyInterrupt->is_Node.ln_Name=xyIntName lea xyIntServer(PC),A0 move.l A0,IS_CODE(A1) ; xyInterrupt->is_Code =xyIntServer move.l DB,IS_DATA(A1) ; xyInterrupt->is_Data =DB moveq #INTB_VERTB,D0 CallLib AddIntServer SetPatches CallLib Forbid lea LockPatch(PC),A0 : Patch 'LockLayerRom' move.l A0,D0 move.l GfxBase(DB),A1 move.w #_LVOLockLayerRom,A0 CallLib SetFunction move.l D0,JmpOldLock+2 lea UnlockPatch(PC),A0 ; Patch 'UnlockLayerRom' move.l A0,D0 move.l GfxBase(DB),A1 move.w #_LVOUnlockLayerRom,A0 CallLib SetFunction move.l D0,JmpOldUnlock+2 lea CloseSPatch(PC),A0 ; Patch 'CloseScreen' move.l A0,D0 move.l IntBase(DB),A1 move.w #_LVOCloseScreen,A0 CallLib SetFunction move.l D0,JmpOldCloseS+2 CallLib Permit GetFont Prepare Gfx_Call lea TxtAttr(PC),A0 CallLib OpenFont move.l D0,Font(DB) beq.S Error GetWindow suba.l A0,A0 Call FindOtherScreen move.l D0,DScreen(DB) beq.S Error Call OpenW bne Main Error Exit Prepare Exec_Call lea xyInterrupt(DB),A1 tst.l IS_CODE(A1) ; If this is set then server has been added beq.S FreeFont FreePatches CallLib Forbid move.l JmpOldCloseS+2(PC),D0 move.l IntBase(DB),A1 move.w #_LVOCloseScreen,A0 CallLib SetFunction move.l JmpOldLock+2(PC),D0 move.l GfxBase(DB),A1 move.w #_LVOLockLayerRom,A0 CallLib SetFunction move.l JmpOldUnlock+2(PC),D0 move.l GfxBase(DB),A1 move.w #_LVOUnlockLayerRom,A0 CallLib SetFunction CallLib Permit FreeInterrupt lea xyInterrupt(DB),A1 moveq #INTB_VERTB,D0 CallLib RemIntServer FreeFont Prepare Gfx_Call move.l Font(DB),D0 beq.S FreeWindow move.l D0,A1 CallLib CloseFont FreeWindow Call CloseW FreeInt Prepare Exec_Call move.l IntBase(DB),D0 beq.S FreeGfx move.l D0,A1 CallLib CloseLibrary FreeGfx move.l GfxBase(DB),D0 beq.S ReplyWB move.l D0,A1 CallLib CloseLibrary ReplyWB move.l WBenchMsg(DB),D2 beq.S AllDone CallLib Forbid movea.l D2,A1 CallLib ReplyMsg ; Reply WBenchMessage if we are started from WB AllDone rFree moveq #0,D0 rts Main Change Call UpdateDisplay EventLoop move.l Up(DB),A0 moveq #0,D0 moveq #0,D1 move.b MP_SIGBIT(A0),D1 bset D1,D0 ori.l #WaitMask,D0 Prepare Exec_Call CallLib Wait move.l D0,D5 move.b Relative(DB),D7 move.l Up(DB),A0 moveq #0,D0 move.b MP_SIGBIT(A0),D0 btst D0,D5 beq.S CheckBits GetNextMsg move.l Up(DB),A0 Prepare Exec_Call CallLib GetMsg tst.l D0 beq.S CheckBits move.l D0,A1 move.l im_Class(A1),Class(DB) move.w im_Code(A1),Code(DB) move.l im_Seconds(A1),Seconds(DB) move.l im_Micros(A1),Micros(DB) CallLib ReplyMsg move.l Class(DB),D0 cmp.l #CLOSEWINDOW,D0 beq Exit cmp.l #MOUSEBUTTONS,D0 beq DoButtons tst.w Version(DB) ; No need to change color beq.S 3$ ; under 1.2/1.3 cmp.l #ACTIVEWINDOW,D0 bne.S 1$ move.w BColorA(DB),D0 bra.S 2$ 1$ cmp.l #INACTIVEWINDOW,D0 bne.S 3$ move.w BColorI(DB),D0 2$ move.l Rp(DB),A1 Prepare Gfx_Call CallLib SetBPen 3$ Call UpdateDisplay ; Do some refreshing bra.S GetNextMsg CheckBits btst #Remove_Screen_B,D5 beq.S CheckMouse move.l RemScreen(DB),D0 beq.S CheckMouse Call CloseW Prepare Intuition_Call clr.l RemScreen(DB) move.l D0,A0 CallLib CloseScreen sub.l A0,A0 Call FindOtherScreen move.l D0,DScreen(DB) beq Exit Call OpenW beq Exit CheckMouse btst #LMB_Change_B,D5 beq.S 1$ move.l my(DB),ry(DB) tst.b D7 bne.S 2$ clr.l ry(DB) ; Released LMB not.l oy(DB) ; ox/oy != mx/my bra.S 2$ 1$ btst #xy_Change_B,D5 beq EventLoop 2$ move.w mx(DB),D0 sub.w rx(DB),D0 cmp.w ox(DB),D0 beq.S 3$ lea xyTxt+2(PC),A0 Call DecStr1 3$ move.w my(DB),D0 sub.w ry(DB),D0 cmp.w oy(DB),D0 beq.S 4$ lea xyTxt+9(PC),A0 Call DecStr1 4$ move.l my(DB),oy(DB) move.l DScreen(DB),A1 lea sc_RastPort(A1),A1 move.w mx(DB),D0 bmi.S 5$ move.w my(DB),D1 bmi.S 5$ Prepare Gfx_Call CallLib ReadPixel move.w D0,Color(DB) bmi.S 5$ cmp.w oColor(DB),D0 beq.s 6$ lea xyTxt+20(PC),A0 Call DecStr2 bra.S 6$ 5$ lea xyTxt+20(PC),A0 move.b #' ',(A0)+ move.b #' ',(A0)+ move.b #'?',(A0)+ 6$ move.w Color(DB),oColor(DB) bra Change DoButtons cmp.w #MENUDOWN,Code(DB) bne GetNextMsg Prepare Intuition_Call movem.l Seconds(DB),D2-D3 movem.l oSeconds(DB),D0-D1 movem.l D2-D3,oSeconds(DB) CallLib DoubleClick tst.l D0 beq GetNextMsg move.l DScreen(DB),A0 Call FindOtherScreen beq.S 1$ move.l D0,DScreen(DB) Call CloseW Call OpenW beq Exit 1$ bra GetNextMsg OpenW Push D1/A0-A2/A6 Prepare Intuition_Call lea NW(PC),A0 move.l DScreen(DB),nw_Screen(A0) move.w Width(DB),nw_Width(A0) move.w Height(DB),nw_Height(A0) CallLib OpenWindow move.l D0,DWindow(DB) beq.S 2$ move.l D0,A0 move.l wd_RPort(A0),Rp(DB) move.l wd_UserPort(A0),Up(DB) suba.l A1,A1 lea ScrTitle(PC),A2 CallLib SetWindowTitles move.l DScreen(DB),A0 CallLib ScreenToFront Prepare Gfx_Call move.l Rp(DB),A2 move.l A2,A1 move.w AColor(DB),D0 CallLib SetAPen move.l A2,A1 move.w BColorI(DB),D0 CallLib SetBPen move.l A2,A1 moveq #RP_JAM2,D0 CallLib SetDrMd move.l Font(DB),A0 move.l A2,A1 CallLib SetFont lea Counter(PC),A0 clr.w (A0) lea WLayer(PC),A0 move.l rp_Layer(A2),(A0) lea WScreen(PC),A0 move.l DScreen(DB),(A0) moveq #1,D0 2$ Pop D1/A0-A2/A6 rts CloseW Push D0-D1/A0-A1/A6 Prepare Intuition_Call move.l DWindow(DB),D0 beq.S 1$ lea WLayer(PC),A0 clr.l (A0) ; Disable patches lea WScreen(PC),A0 clr.l (A0) ; Disable patch move.l D0,A0 CallLib CloseWindow clr.l DWindow(DB) not.l my(DB) 1$ Pop D0-D1/A0-A1/A6 rts * Call : A0 = current screen or NULL * Return: D0 = new screen or NULL * Tries to find a new screen big enough to open the window on FindOtherScreen Push D1-D5/A1-A2/A6 Prepare Exec_Call CallLib Forbid Prepare Intuition_Call move.l A0,D0 bne.S 1$ move.l ib_FirstScreen(A6),D0 bra.S CheckScreen 1$ move.l sc_NextScreen(A0),D0 NextScreen tst.l D0 bne.S CheckScreen move.l ib_FirstScreen(A6),D0 CheckScreen cmp.l A0,D0 beq.S 5$ ; Have we checked all screens ? move.l D0,A1 move.w sc_ViewPort+vp_Modes(A1),D1 andi.w #V_HIRES,D1 Prepare Exec_Call lea Settings1.3H(PC),A2 cmp.w #34,LIB_VERSION(A6) bge.S 1$ tst.w D1 bne.S 2$ lea Settings1.3L(PC),A2 bra.S 2$ 1$ lea Settings2.0H(PC),A2 tst.w D1 bne.S 2$ lea Settings2.0L(PC),A2 2$ movem.l (A2),D1-D4 movem.l D1-D4,Version(DB) ; Initialize variables tst.w Version(DB) beq.S 3$ moveq #0,D1 move.b sc_BarHeight(A1),D1 move.w D1,Height(DB) subq.w #7,D1 lsr.w #1,D1 addq.w #6,D1 move.w D1,yPos(DB) 3$ move.w sc_Width(A1),D1 cmp.w Width(DB),D1 blt.S 4$ move.w sc_Height(A1),D1 cmp.w Height(DB),D1 bge.S 6$ 4$ move.l D0,A1 move.l sc_NextScreen(A1),D0 ; Screen was too small, try another bra.S NextScreen 5$ moveq #0,D0 6$ move.l D0,D2 Prepare Exec_Call CallLib Permit move.l D2,D0 Pop D1-D5/A1-A2/A6 rts UpdateDisplay Prepare Gfx_Call move.l Rp(DB),A1 move.w xPos(DB),D0 move.w yPos(DB),D1 CallLib Move lea xyTxt(PC),A0 move.l Rp(DB),A1 moveq #StringLength,D0 CallLib Text rts DecStr2 moveq #' ',D1 bra.S NEG DecStr1 moveq #' ',D1 ext.l D0 bge.S POS neg.l D0 move.b #'-',(A0)+ bra.S NEG POS move.b D1,(A0)+ NEG move.b D1,(A0)+ move.b D1,(A0)+ moveq #'0',D1 move.b D1,(A0)+ 1$ tst.l D0 beq.S 2$ divu #10,D0 swap D0 add.w D1,D0 move.b D0,-(A0) clr.w D0 swap D0 bra.S 1$ 2$ rts * A1=DB * Inside the server the registers D0-D1/A0-A1/A5-A6 can be used * without restoring them on exit xyIntServer btst #6,LMBBUT seq D1 cmp.b Relative(A1),D1 beq.S 1$ move.b D1,Relative(A1) move.l DScreen(A1),A0 move.l sc_MouseY(A0),my(A1) move.l #LMB_Change_F,D0 bra.S 2$ 1$ move.l DScreen(A1),A0 move.l sc_MouseY(A0),D1 cmp.l my(A1),D1 beq.S 3$ move.l D1,my(A1) move.l #xy_Change_F,D0 2$ move.l xyProcess(A1),A1 Prepare Exec_Call CallLib Signal 3$ moveq #0,D0 ; Set the Z flag rts * These patch-functions prevents the graphics functions to * 'LockLayerRom' and 'UnlockLayerRom' on my windows layer * * Any calls to 'LockLayerRom' that had not yet been matched * by a 'UnlockLayerRom' when these pathches got installed, can * still use 'UnlockLayerRom' normally because of the counter. LockPatch cmp.l WLayer(PC),A5 bne.S JmpOldLock addq.w #1,Counter rts JmpOldLock jmp 12345678 ; Not my windows layer UnlockPatch cmp.l WLayer(PC),A5 bne.S JmpOldUnlock subq.w #1,Counter bmi.S JmpOldUnlock rts JmpOldUnlock jmp 12345678 ; Not my windows layer Counter dc.w 0 WLayer dc.l 0 ; My windows layer * This patch-function helps Mouse-xy evacuate any closing screen. * I don't just close the window here because I don't know what the * Mouse-xy is process is doing to the window at this moment. I don't * even close the screen here but instead I signal process to close * the window and screen under more controlled circumstances. CloseSPatch cmp.l WScreen(PC),A0 bne.S JmpOldCloseS Push D0-D7/A0-A6 move.l SpareA4(PC),DB move.l A0,RemScreen(DB) move.l #Remove_Screen_F,D0 move.l xyProcess(DB),A1 Prepare Exec_Call CallLib Signal Pop D0-D7/A0-A6 rts JmpOldCloseS jmp 12345678 ; Not my windows screen WScreen dc.l 0 SpareA4 dc.l 0 * Stack variables rStart rAPtr RemScreen rWord Relative ; 0 means absolute coordinates rAPtr xyProcess rAPtr GfxBase rAPtr IntBase rAPtr WBenchMsg ; Message from Workbench rAPtr DWindow ; APtr to Window rAPtr DScreen ; APtr to Screen rAPtr Rp ; APtr to RastPort rAPtr Up ; APtr to UserPort rAPtr Font ; Window-font rWord BColorI ; Background color (Inactive) rWord BColorA ; Background color (Active) rWord AColor ; Foreground color rWord yPos ; y-position of text in window rWord xPos ; x-position of text in window rWord Height ; Height of window rWord Width ; Width of window rWord Version ; Kickstart version ID rWord mx ; \The order is important rWord my ; / rWord ox ; \The order is important rWord oy ; / rWord rx ; \The order is important rWord ry ; / rWord Color rWord oColor rLong Class ; im_Class rWord Code ; im_Code rLong Micros ; \The order is important rLong Seconds ; / rLong oMicros ; \The order is important rLong oSeconds ; / rStorage xyInterrupt,IS_SIZE ; Interrupt structure rEnd StringLength =23 StringSpace =StringLength*8 Kick1 =0 * Defines for hires under kickstart 1.2-1.3 (and below ?) Width1.3H =84+StringSpace Height1.3H =10 xPos1.3H =30 yPos1.3H =7 AColor1.3H =0 BColor1.3H =1 * Defines for lores under kickstart 1.2-1.3 (and below ?) Width1.3L =51+StringSpace Height1.3L =10 xPos1.3L =16 yPos1.3L =7 AColor1.3L =0 BColor1.3L =1 Kick2 =1 * Defines for hires under kickstart 2.0 (and up ?) Width2.0H =51+StringSpace Height2.0H =11 xPos2.0H =23 yPos2.0H =8 AColor2.0H =1 BColor2.0HA =3 ; Active background color BColor2.0HI =0 ; Inactive background color * Defines for lores under kickstart 2.0 (and up ?) Width2.0L =40+StringSpace Height2.0L =11 xPos2.0L =18 yPos2.0L =8 AColor2.0L =1 BColor2.0LA =3 ; Active background color BColor2.0LI =0 ; Inactive background color Settings1.3H dc.w Kick1,Width1.3H,Height1.3H,xPos1.3H,yPos1.3H,AColor1.3H,BColor1.3H,BColor1.3H Settings1.3L dc.w Kick1,Width1.3L,Height1.3L,xPos1.3L,yPos1.3L,AColor1.3L,BColor1.3L,BColor1.3L Settings2.0H dc.w Kick2,Width2.0H,Height2.0H,xPos2.0H,yPos2.0H,AColor2.0H,BColor2.0HA,BColor2.0HI Settings2.0L dc.w Kick2,Width2.0L,Height2.0L,xPos2.0L,yPos2.0L,AColor2.0L,BColor2.0LA,BColor2.0LI GfxName dc.b 'graphics.library',0 IntName dc.b 'intuition.library',0 xyIntName dc.b 'xy Interrupt',0 xyTxt dc.b 'x: 0 y: 0 Color: 0',0 ScrTitle dc.b 'Mouse-xy V1.0 1991 by Preben Nielsen',0 EVEN IDCMP_Flags = CLOSEWINDOW|MOUSEBUTTONS|INACTIVEWINDOW|ACTIVEWINDOW Other_Flags = RMBTRAP|WINDOWCLOSE|WINDOWDEPTH|WINDOWDRAG NW dc.w 0,0,0,0 dc.b 0,1 dc.l IDCMP_Flags,Other_Flags,0,0,0,0,0 dc.w 0,0,0,0,CUSTOMSCREEN TxtAttr dc.l FontName dc.w TOPAZ_EIGHTY dc.b FS_NORMAL,FPB_ROMFONT FontName dc.b 'topaz.font',0 END