* RMBShift * By Preben Nielsen * * This small program makes it possible for the right mouse-button to * act as a shift key. This means that it will be possible to select * multiple icons on the workbench without having to press a Shift-Key. * * Once installed, the program only uses 174 bytes of memory. * To get back to normal simply run the program again. * * NOTE: There's no need to 'RUN' or 'RUNBACK' this program from the * CLI. It terminates immediately. * *HISTORY * Made with Hisoft V2.12 * * V1.0 01-Sep-91: First attempt. Works of course. OPT O+ OPT O1+ ; Tells when a branch could be optimised to short OPT i+ ; Tells when '#' is probably missing incdir "AsmInc:" include "P.i" include "relMacros.i" include "exec/exec_lib.i" include "exec/io.i" include "exec/memory.i" include "exec/interrupts.i" include "devices/input.i" include "devices/inputevent.i" include "libraries/dosextens.i" include "libraries/dos_lib.i" DB EQUR A4 dcDeclare A4 dcAPtr PProcess dcAPtr WBMsg dcAPtr DosBase dcAPtr HMem dcEnd Start dcAlloc ; Allocate memory for variables dcReset ; Clear the memory Prepare Exec_Call suba.l A1,A1 CallLib FindTask ; Find us move.l D0,PProcess(DB) movea.l D0,A2 tst.l pr_CLI(A2) bne.S GetLibs WBStart lea pr_MsgPort(A2),A0 CallLib WaitPort ; wait for a message lea pr_MsgPort(A2),A0 CallLib GetMsg ; then get it move.l D0,WBMsg(DB) ; save it for later reply GetLibs lea DosName(PC),A1 CallLib OldOpenLibrary move.l D0,DosBase(DB) beq.S Error lea IHSName(PC),A1 Call FindThisPort beq.S DoInstall DoRemove moveq #REMOVED,D7 lea IHS(PC),A0 lea PSEndIHS1(PC),A1 lea PSEndIHS2(PC),A2 Call RemoveHandler beq.S ShowMsg moveq #CANTREMOVE,D7 bra.S ShowMsg DoInstall moveq #INSTALLED,D7 lea IHS(PC),A0 lea PSPrepIHS1(PC),A1 lea PSPrepIHS2(PC),A2 Call InstallHandler beq.S ShowMsg moveq #CANTINSTALL,D7 ShowMsg move.l D7,D0 Call CONMsg Error Exit Prepare Exec_Call FreeDos move.l DosBase(DB),D0 beq.S ReplyWB move.l D0,A1 CallLib CloseLibrary ReplyWB move.l WBMsg(DB),D2 beq.S AllDone CallLib Forbid ; We were started from WB movea.l D2,A1 CallLib ReplyMsg ; Reply WBMessage AllDone dcFree moveq #0,D0 rts *»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» *»»» Console message routines »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» *»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» FHandle EQUR D5 *»»» Call: D0 = Msg-number *»»» Writes a general copyright message and then a more specific message. *»»» Writes to standard output when run from CLI, and opens its own window *»»» when run from Workbench. CONMsg Push D0-D7/A0-A6 Prepare Dos_Call move.l D0,D4 moveq #0,D6 CallLib Output move.l D0,FHandle bne.S 1$ moveq #1,D6 lea CONName(PC),A0 move.l A0,D1 move.l #MODE_OLDFILE,D2 CallLib Open move.l D0,FHandle beq.S 2$ 1$ moveq #INFOMSG,D0 Call SendMsg move.l D4,D0 Call SendMsg tst.l D6 beq.S 2$ moveq #127,D1 CallLib Delay move.l FHandle,D1 CallLib Close 2$ Pop D0-D7/A0-A6 rts *»»» Call: D0 = Msg-number SendMsg neg.l D0 lsl.l #1,D0 lea CONMsgTable(PC),A0 add.w 0(A0,D0),A0 move.l A0,D2 moveq #-1,D3 1$ addq.l #1,D3 tst.b (A0)+ bne.S 1$ move.l FHandle,D1 Prepare Dos_Call CallLib Write rts INFOMSG =0 INSTALLED =-1 REMOVED =-2 CANTINSTALL =-3 CANTREMOVE =-4 CONText MACRO dc.w \1-CONMsgTable ENDM CONMsgTable CONText Msg CONText Msg1 CONText Msg2 CONText Msg3 CONText Msg4 CONName dc.b 'CON:100/60/330/63/RMBShift',0 Msg dc.b 10,$9B,'0;33m RMBShift V1.0',10 dc.b $9B,'0;31m 1991 by ',$9B,'0;33mPreben Nielsen',$9B,'0;31m',10,' ',0 Msg1 dc.b 'has now been installed...',10,0 Msg2 dc.b 'has now been removed...',10,0 Msg3 dc.b "Error: Can't install handler",10,0 Msg4 dc.b "Error: Can't remove handler",10,0 EVEN *»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» *»»» End of Console message routines »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» *»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» *»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» *»»» Inputhandler removal and installation routines »»»»»»»»»»»»»»»»»»»»»»»» *»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» rtsValue EQUR D7 *»»» This is general-purpose inputhandler removal-routine *»»» It only needs an ihs with a port-name to remove the handler *»»» Call: A0 = ihs *»»» A1 = first ihs-installation-routine or NULL *»»» A2 = second ihs-installation-routine or NULL *»»» Return: D0 = 0 means succes RemoveHandler Push D1/rtsValue/A0-A3/A6 moveq #-1,rtsValue move.l A2,A3 move.l A0,A2 move.l A1,D1 beq.S 1$ jsr (A1) ; A0 = ihs beq.S 2$ move.l D0,A2 1$ move.l A2,A0 Prepare Exec_Call moveq #IND_REMHANDLER,D0 Call TellInputDevice move.l D0,rtsValue bne.S 2$ lea ihs_Port(A2),A1 CallLib RemPort moveq #0,D0 bra.S 3$ 2$ moveq #-1,D0 3$ move.l A3,D1 beq.S 4$ move.l A2,A0 jsr (A3) ; A0 = ihs, D0 = 0 means succes 4$ move.l rtsValue,D0 Pop D1/rtsValue/A0-A3/A6 rts *»»» This is general-purpose inputhandler installation-routine *»»» It only needs an ihs with a port-name to install the handler *»»» Call: A0 = ihs *»»» A1 = first ihs-installation-routine or NULL *»»» A2 = second ihs-installation-routine or NULL *»»» Return: D0 = 0 means succes InstallHandler Push D1/rtsValue/A0-A3/A6 moveq #-1,rtsValue move.l A2,A3 move.l A0,A2 move.l A1,D1 beq.S 1$ jsr (A1) ; A0 = ihs beq.S 2$ move.l D0,A2 1$ move.l A2,A0 moveq #IND_ADDHANDLER,D0 Call TellInputDevice move.l D0,rtsValue bne.S 2$ lea ihs_Port(A2),A1 move.l ihs_PortName(A2),MP+LN_NAME(A1) ;MsgPort->mp_Node.ln_Name=Name; clr.b MP+LN_PRI(A1) ;MsgPort->mp_Node.ln_Pri =0; move.b #NT_MSGPORT,MP+LN_TYPE(A1) ;MsgPort->mp_Node.ln_Type=NT_MSGPORT; move.b #PA_IGNORE,MP_FLAGS(A1) ;MsgPort->mp_Flags =PA_IGNORE; Prepare Exec_Call CallLib AddPort moveq #0,D0 bra.S 3$ 2$ moveq #-1,D0 3$ move.l A3,D1 beq.S 4$ move.l A2,A0 jsr (A3) ; A0 = ihs, D0 = 0 means succes 4$ move.l rtsValue,D0 Pop D1/rtsValue/A0-A3/A6 rts *»»» Open the input device. Set up the I/O block to add or remove the *»»» input handler, and send the request to the input device. Finally, *»»» close the device *»»» Call: A0 = ihs *»»» D0 = Function to perform (IND_ADDHANDLER/IND_REMHANDLER) *»»» Return: D0 = 0 means succes dcDeclare A5 dcArea IReq,IOSTD_SIZE dcArea IPort,MP_SIZE dcEnd TellInputDevice dcAlloc dcReset Push D1-D2/rtsValue/A0-A3/A6 Prepare Exec_Call moveq #-1,rtsValue move.l D0,D2 move.l A0,A2 lea IPort(A5),A3 move.b #NT_MSGPORT,MP+LN_TYPE(A3) ; mp_Node.ln_Type=NT_MSGPORT; move.b #PA_SIGNAL,MP_FLAGS(A3) ; mp_Flags =PA_SIGNAL; moveq #-1,D0 CallLib AllocSignal move.b D0,MP_SIGBIT(A3) ; mp_SigBit =MPSigBit; bmi.S 2$ suba.l A1,A1 CallLib FindTask move.l D0,MP_SIGTASK(A3) ; mp_SigTask =FindTask(0); lea MP_MSGLIST(A3),A0 NEWLIST A0 lea IReq(A5),A1 move.l A3,IO+MN_REPLYPORT(A1) ; ExtReq->io_Message.mn_ReplyPort =taskReplyPort; move.b #NT_MESSAGE,IO+MN+LN_TYPE(A1) ; ExtReq->io_Message.mn_Node.ln_Type=NT_MESSAGE; lea InputName(PC),A0 ; input.device moveq #0,D0 ; unit# moveq #0,D1 ; flags CallLib OpenDevice tst.w D0 ; flag: error if > 0 bne.S 1$ lea IReq(A5),A1 move.w D2,IO_COMMAND(A1) lea ihs_Interrupt(A2),A0 move.l A0,IO_DATA(A1) CallLib DoIO move.l D0,rtsValue lea IReq(A5),A1 CallLib CloseDevice 1$ move.b MP_SIGBIT(A3),D0 CallLib FreeSignal 2$ move.l rtsValue,D0 Pop D1-D2/rtsValue/A0-A3/A6 dcFree rts *»»» Each handler should have such a pair of installation-routines. *»»» The first one is passed to InstallHandler in A1, and it *»»» is called immediately when entering InstallHandler. *»»» The second one is passed to InstallHandler in A2, and it *»»» is called if installation of handler and message-port succeeds. *»»» ----------------------------------------------------------------- *»»» Call: A0 = ihs *»»» Return: D0 has to point to ihs to be used when installation proceeds. *»»» If D0 = 0 then installation is aborted. PSPrepIHS1 Push D1/A0-A1/A6 Prepare Exec_Call move.l #HandlerSize,D0 move.l #MEMF_PUBLIC|MEMF_CLEAR,D1 CallLib AllocMem move.l D0,HMem(DB) beq.S 2$ move.l D0,A1 lea IHS(PC),A0 move.l #HandlerSize,D0 Push D0/A0-A1 CallLib CopyMem Pop D0/A0-A1 move.l D0,ihs_Length(A1) ; This will enable removal by other programs lea HandlerCode-IHS(A1),A0 move.l A0,ihs_Interrupt+IS_CODE(A1) ; ihs_Interrupt.is_Code = Handler clr.l ihs_Interrupt+IS_DATA(A1) ; ihs_Interrupt.is_Data = 0 lea IHSName-IHS(A1),A0 move.l A0,ihs_PortName(A1) ; ihs_PortName = IHSName move.b #HPRI,ihs_Interrupt+LN_PRI(A1) ; ihs_Interrupt.is_Node.ln_Pri = HPRI move.l A1,D0 2$ Pop D1/A0-A1/A6 rts *»»» Call: A0 = ihs *»»» D0 = 0 means everything went perfect *»»» -1 means something went wrong during installation PSPrepIHS2 Push D0-D1/A0-A1/A6 tst.l D0 beq.S 1$ move.l HMem(DB),D0 beq.S 1$ move.l D0,A1 move.l #HandlerSize,D0 Prepare Exec_Call CallLib FreeMem 1$ Pop D0-D1/A0-A1/A6 rts *»»» Each handler should have such a pair of ending-routines. *»»» The first one is passed to RemoveHandler in A1, and it *»»» is called immediately when entering RemoveHandler. *»»» The second one is passed to RemoveHandler in A2, and it *»»» is called if removal of handler and message-port succeeds. *»»» ----------------------------------------------------------------- *»»» Call: A0 = ihs *»»» Return: D0 has to point to ihs to be used when removal proceeds *»»» If D0 = 0 then removal is aborted PSEndIHS1 Push A1 lea IHSName(PC),A1 Call FindThisPort Pop A1 rts *»»» Call: A0 = ihs *»»» D0 = 0 means everything went perfect *»»» -1 means something went wrong during removal PSEndIHS2 Push D0-D1/A0-A1/A6 tst.l D0 bmi.S 1$ Prepare Exec_Call move.l ihs_Length(A0),D0 move.l A0,A1 CallLib FreeMem 1$ Pop D0-D1/A0-A1/A6 rts *»»» Call: A1 = Portname *»»» Return: D0 = Port or NULL (cc reflects result also) FindThisPort Push D1-D2/A0-A1/A6 Prepare Exec_Call move.l A1,D2 CallLib Forbid move.l D2,A1 CallLib FindPort move.l D0,D2 CallLib Permit move.l D2,D0 Pop D1-D2/A0-A1/A6 rts *»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» *»»» Input-handler start »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» *»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» ihs_Port =0 ihs_Interrupt =MP_SIZE ihs_ID =MP_SIZE+IS_SIZE ihs_Length =MP_SIZE+IS_SIZE+4 ihs_Flags =MP_SIZE+IS_SIZE+8 ihs_PortName =MP_SIZE+IS_SIZE+10 ihs_LocalArea =MP_SIZE+IS_SIZE+14 ihs_SIZE =MP_SIZE+IS_SIZE+14 ihs_Start MACRO dcb.b MP_SIZE ; Message-Port structure dcb.b IS_SIZE ; Interrupt structure dc.l 'P_IH' ; ID dc.l 0 ; Length of handler dc.w 0 ; Flags dc.l 0 ENDM HPRI =55 HDisabled =0 HNoExtRemoval =1 *»»» This is the handler-block IHS ihs_Start *»»» Put local data here Shifted dc.w 0 *»»» IHS name IHSName dc.b 'RMBShift V1.0 Port',0 EVEN *»»» For each event in the event list: *»»» If we were waiting for this event then signal the task. *»»» When all the events have been checked, return the event list so that *»»» others can do their things. EList EQUR A0 Event EQUR A1 Next =ie_NextEvent Class =ie_Class Code =ie_Code Qual =ie_Qualifier * Call: A0 = List of InputEvents, A1 = HandlerData HandlerCode Push Event/EList/A2 move.l EList,Event ieLoop move.l Event,D0 beq.S NoMoreEvents cmpi.b #IECLASS_RAWMOUSE,Class(Event) bne.S DontRemove cmpi.w #IECODE_RBUTTON,Code(Event) beq.S PressRMB cmpi.w #IECODE_UP_PREFIX|IECODE_RBUTTON,Code(Event) bne.S DontRemove ReleaseRMB moveq #0,D0 bra.S ChangeStatus PressRMB btst #IEQUALIFIERB_LEFTBUTTON-8,Qual(Event) beq.S DontRemove clr.w Class(Event) ; Remove the event (make it an IECLASS_NULL event) moveq #1,D0 ChangeStatus lea Shifted(PC),A2 move.w D0,(A2) * Just move on to next Event DontRemove move.w Shifted(PC),D0 beq.S 1$ ori.w #IEQUALIFIER_LSHIFT,Qual(Event) ; Set a SHIFT qualifier 1$ move.l Next(Event),Event bra.S ieLoop * Lets returnaaa NoMoreEvents move.l EList,D0 Pop Event/EList/A2 rts HandlerSize = *-IHS *»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» *»»» Input-handler end »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» *»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» *»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» *»»» Data-definition start»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» *»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» DosName dc.b 'dos.library',0 InputName dc.b 'input.device',0 END