* Mouse-xy * 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). * V1.1 02-Aug-91: Damned - why didn't anyone tell me that Mouse-xy * looked awful (strange) under kickstart 1.3. It * shouldn't change its appearance like that except * under kickstart 2.x ! Well, it has been fixed now. * 15-Aug-91: Rewrote code to make it more safe to jump from * screen to screen. * 22-Aug-91: Now Mouse-xy can perfecty emulate the 2.x way of * using colors in windows. OPT O+ OPT O1+ ; Tells when a branch could be optimised to short ; OPT i+ ; Tells when '#' is probably missing LMBBUT =$BFE001 ; Bit 6 incdir "AsmInc:" include "P.i" include "Intui.i" include "Detach.i" include "relMacros.i" include "exec/exec_lib.i" include "exec/memory.i" include "exec/interrupts.i" include "intuition/intuition.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 dcAlloc ; Allocate memory for variables dcReset ; Clear the memory Prepare Exec_Call suba.l A1,A1 CallLib FindTask ; Find us move.l D0,xyProcess(DB) lea WProcess(PC),A1 move.l D0,(A1) move.l D0,A2 tst.l pr_CLI(A2) bne.S GetLibs 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,GraphBase(DB) beq.S Error lea IntuiName(PC),A1 CallLib OldOpenLibrary move.l D0,IntuiBase(DB) beq.S 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 GetFont Prepare Gfx_Call lea TxtAttr(PC),A0 CallLib OpenFont move.l D0,Font(DB) beq.S Error GetWindow suba.l A0,A0 ; Find any suitable screen Call FindOtherScreen beq.S Error move.l D0,A1 Call OpenNewWindow beq.S Exit move.l D0,A0 Call UseNewWindow SetPatches Call AddPatches bra.S Main Error Exit Prepare Exec_Call FreeInterrupt lea xyInterrupt(DB),A1 tst.l IS_CODE(A1) ; If this is set then server has been added beq.S FreeFont moveq #INTB_VERTB,D0 CallLib RemIntServer FreeFont Prepare Gfx_Call move.l Font(DB),D0 beq.S FreeIntui move.l D0,A1 CallLib CloseFont FreeIntui Prepare Exec_Call move.l IntuiBase(DB),D0 beq.S FreeGfx move.l D0,A1 CallLib CloseLibrary FreeGfx move.l GraphBase(DB),D0 beq.S ReplyWB move.l D0,A1 CallLib CloseLibrary ReplyWB move.l WBenchMsg(DB),D2 beq.S AllDone CallLib Forbid move.l D2,A1 CallLib ReplyMsg ; Reply WBenchMessage if we are started from WB AllDone dcFree 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 CheckMouse GetNextMsg move.l Up(DB),A0 ; Recieved a signal from intuition Prepare Exec_Call CallLib GetMsg tst.l D0 beq CheckMouse 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),D1 cmp.l #CLOSEWINDOW,D1 beq.S DoExit cmp.l #MOUSEBUTTONS,D1 beq.S DoButtons tst.w Version(DB) ; No need to change color beq.S 3$ ; under 1.2/1.3 cmp.l #ACTIVEWINDOW,D1 bne.S 1$ Call GetBackColor move.w D0,D2 Call GetFrontColor bra.S 2$ 1$ cmp.l #INACTIVEWINDOW,D1 bne.S 3$ moveq #0,D2 moveq #1,D0 2$ Prepare Gfx_Call move.l Rp(DB),A1 CallLib SetAPen move.w D2,D0 move.l Rp(DB),A1 CallLib SetBPen 3$ Call UpdateDisplay ; Do some refreshing bra GetNextMsg DoExit Call RemPatches bne.S 1$ Call CloseOldWindow bra Exit 1$ Call TellUser bra GetNextMsg DoButtons cmp.w #MENUDOWN,Code(DB) bne GetNextMsg Prepare Intuition_Call ; Check for double-click movem.l Seconds(DB),D2-D3 movem.l OldSeconds(DB),D0-D1 movem.l D2-D3,OldSeconds(DB) CallLib DoubleClick tst.l D0 beq GetNextMsg move.l ThisScreen(DB),A0 ; Yes, a double-click Call FindOtherScreen ; Find new suitable screen beq.S 1$ move.l D0,A1 Call OpenNewWindow beq.S 1$ Call CloseOldWindow ; We got a new window move.l D0,A0 ; Close the old window Call UseNewWindow ; Start using the new window 1$ bra GetNextMsg 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.S CheckScreen 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 MakeSNumber 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 MakeSNumber 4$ move.l my(DB),oy(DB) move.l ThisScreen(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 tst.l D0 bge.S 6$ 5$ lea xyTxt+20(PC),A0 move.b #' ',(A0)+ move.b #' ',(A0)+ move.b #'?',(A0)+ bra Change 6$ cmp.w OldColor(DB),D0 beq.s 7$ move.w D0,OldColor(DB) lea xyTxt+20(PC),A0 Call MakeUNumber 7$ bra Change CheckScreen btst #Remove_Screen_B,D5 beq.S 1$ move.l ThisScreen(DB),A0 move.l A0,DeadScreen(DB) Call FindOtherScreen ; Find new suitable screen beq.S 2$ move.l D0,A1 Call OpenNewWindow beq.S 2$ Call CloseOldWindow ; We got a new window move.l D0,A0 ; Close the old window Call UseNewWindow ; Start using the new window 1$ bra EventLoop *»»» Couldn't jump to another screen. Now try to exit 2$ Call RemPatches bne.S 3$ Call CloseOldWindow bra Exit 3$ Call TellUser bra EventLoop *»»» Call: A1 = Screen to open on *»»» Open a window OpenNewWindow Push D1/A0-A2/A6 Prepare Intuition_Call lea NW(PC),A0 move.l A1,nw_Screen(A0) move.w Width(DB),nw_Width(A0) move.w Height(DB),nw_Height(A0) CallLib OpenWindow tst.l D0 Pop D1/A0-A2/A6 rts *»»» Call: A0 = Window to use *»»» Use new window from now on UseNewWindow Push D1/A0-A2/A6 Prepare Intuition_Call move.l A0,ThisWindow(DB) move.l wd_WScreen(A0),ThisScreen(DB) 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 ThisScreen(DB),A0 CallLib ScreenToFront Prepare Gfx_Call move.l Rp(DB),A2 moveq #0,D0 ; Assume 1.3 colors moveq #1,D2 tst.w Version(DB) beq.S 1$ exg D0,D2 ; Well, use 2.0 colors 1$ move.l A2,A1 CallLib SetAPen move.l A2,A1 move.w D2,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 ThisScreen(DB),(A0) Pop D1/A0-A2/A6 rts *»»» Close the window and perhaps a screen CloseOldWindow Push D0-D1/A0-A1/A6 Prepare Intuition_Call lea WLayer(PC),A0 clr.l (A0) ; Disable patches lea WScreen(PC),A0 clr.l (A0) ; Disable patch move.l ThisWindow(DB),A0 CallLib CloseWindow move.l DeadScreen(DB),D0 beq.S 1$ move.l D0,A0 CallLib CloseScreen ; Close pending screen 1$ clr.l ThisWindow(DB) clr.l ThisScreen(DB) clr.l DeadScreen(DB) not.l my(DB) 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 CheckThisScreen 1$ move.l sc_NextScreen(A0),D0 NextScreen tst.l D0 bne.S CheckThisScreen move.l ib_FirstScreen(A6),D0 CheckThisScreen 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) bgt.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-D2 movem.l D1-D2,Version(DB) ; Initialize variables (8 bytes !!!) moveq #0,D1 move.b sc_BarHeight(A1),D1 tst.w Version(DB) beq.S 3$ addq.w #1,D1 3$ move.w D1,Height(DB) subq.w #7,D1 lsr.w #1,D1 addq.w #6,D1 move.w D1,yPos(DB) 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 *»»» Write the string 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 *»»» These routines return the colors that Kickstart 2.x uses for *»»» title-text and window-frames in active windows. Perhaps I *»»» am using system-private values here - I didn't have access *»»» Kickstart 2.x includes and autodocs when I wrote this. *»»» *»»» Return: D0 = Color used for title-text in active windows. GetFrontColor moveq #12,D0 bra.S GetColor *»»» Return: D0 = Color used for window-frames in active windows. GetBackColor moveq #10,D0 GetColor move.l ThisWindow(DB),A0 move.l wd_WScreen(A0),A0 move.l $1DE+4(A0),A0 move.w 0(A0,D0.W),D0 rts *»»» Make an unsigned number MakeUNumber moveq #' ',D1 bra.S NEG *»»» Make a signed number MakeSNumber 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 *»»» Call: A0 = Text to display TellUser Push D0-D3/A0-A3/A6 lea ITxtAUTOBody(PC),A1 move.l ThisWindow(DB),A0 suba.l A2,A2 lea ITxtAUTOPos(PC),A3 moveq #0,D0 moveq #0,D1 move.w #220,D2 moveq #47,D3 Prepare Intuition_Call CallLib AutoRequest Pop D0-D3/A0-A3/A6 rts *»»» Patch the 'LockLayerRom', *»»» the 'UnlockLayerRom' and *»»» the 'CloseScreen' functions AddPatches Push D0-D1/A0-A1/A6 Prepare Exec_Call CallLib Forbid lea LockPatch(PC),A0 ; Patch 'LockLayerRom' move.l A0,D0 move.l GraphBase(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 GraphBase(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 IntuiBase(DB),A1 move.w #_LVOCloseScreen,A0 CallLib SetFunction move.l D0,JmpOldCloseS+2 CallLib Permit Pop D0-D1/A0-A1/A6 rts *»»» Restore the old 'LockLayerRom', *»»» the old 'UnlockLayerRom' and *»»» the old 'CloseScreen' functions *»»» If any of these functions has patched since we did it, then fail ! RemPatches Push D1-D2/A0-A1/A6 Prepare Exec_Call CallLib Forbid moveq #1,D2 move.l IntuiBase(DB),A0 lea CloseSPatch(PC),A1 cmp.l _LVOCloseScreen+2(A0),A1 ; Anyone else patching 'CloseScreen' ? bne.S 1$ move.l GraphBase(DB),A0 lea UnlockPatch(PC),A1 cmp.l _LVOUnlockLayerRom+2(A0),A1 ; Anyone else patching 'UnLockLayerRom' ? bne.S 1$ lea LockPatch(PC),A1 cmp.l _LVOLockLayerRom+2(A0),A1 ; Anyone else patching 'LockLayerRom' ? bne.S 1$ move.l JmpOldCloseS+2(PC),D0 ; Restore 'CloseScreen' ! move.l IntuiBase(DB),A1 move.w #_LVOCloseScreen,A0 CallLib SetFunction move.l JmpOldUnlock+2(PC),D0 ; Restore 'UnlockLayerRom' ! move.l GraphBase(DB),A1 move.w #_LVOUnlockLayerRom,A0 CallLib SetFunction move.l JmpOldLock+2(PC),D0 ; Restore 'LockLayerRom' ! move.l GraphBase(DB),A1 move.w #_LVOLockLayerRom,A0 CallLib SetFunction moveq #0,D2 1$ CallLib Permit move.l D2,D0 Pop D1-D2/A0-A1/A6 rts *»»» Call: 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 ThisScreen(A1),A0 move.l sc_MouseY(A0),my(A1) move.l #LMB_Change_F,D0 bra.S 2$ 1$ move.l ThisScreen(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 WLayer dc.l 0 ; Layer to compare against Counter dc.w 0 ; Coordination counter *»»» 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 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-D1/A0-A1/A6 move.l #Remove_Screen_F,D0 move.l WProcess(PC),A1 Prepare Exec_Call CallLib Signal Pop D0-D1/A0-A1/A6 rts JmpOldCloseS jmp 12345678 ; Not my windows screen WScreen dc.l 0 ; Screen to compare against WProcess dc.l 0 ; Process to signal 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 *»»» Defines for lores under kickstart 1.2-1.3 (and below ?) Width1.3L =51+StringSpace Height1.3L =10 xPos1.3L =16 Kick2 =1 *»»» Defines for hires under kickstart 2.0 (and up ?) Width2.0H =51+StringSpace Height2.0H =11 xPos2.0H =23 *»»» Defines for lores under kickstart 2.0 (and up ?) Width2.0L =40+StringSpace Height2.0L =11 xPos2.0L =18 Settings1.3H dc.w Kick1,Width1.3H,Height1.3H,xPos1.3H Settings1.3L dc.w Kick1,Width1.3L,Height1.3L,xPos1.3L Settings2.0H dc.w Kick2,Width2.0H,Height2.0H,xPos2.0H Settings2.0L dc.w Kick2,Width2.0L,Height2.0L,xPos2.0L GfxName dc.b 'graphics.library',0 IntuiName 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.1 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 ITxtAUTOBody IntuiText AUTOFRONTPEN,AUTOBACKPEN,AUTODRAWMODE,8,4,TxtCantLeave1,0 ;ITxtAUTOBody2 ITxtAUTOPos IntuiText AUTOFRONTPEN,AUTOBACKPEN,AUTODRAWMODE,6,3,TxtPos,0 TxtPos dc.b 'Stay',0 TxtCantLeave1 dc.b "Mouse-xy: Can't exit !!",0 EVEN TxtAttr dc.l FontName dc.w TOPAZ_EIGHTY dc.b FS_NORMAL,FPB_ROMFONT FontName dc.b 'topaz.font',0 END