* InputLock * By Preben Nielsen * * This program is intended as a help to Amiga-users who has cats * or other pets (or children) that messes with the Amiga as soon * as you leave it for a second. * * It installes an input-handler which lets you lock the keyboard * and mouse by pressing a few buttons (currently LALT-CTRL-'l'). * * Once installed, the program only uses 190 bytes of memory. To * remove the handler 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 11-Apr-91: First attempt. Works of course. * V1.1 19-May-91: Help, I just found out that my "TellInputDevice" * routine trashes memory-address 0 because it didn't * do a "NewList" on its Message-port. It didn't cause * any problems most of the time, but it has now been * cured. OPT O+ OPT O1+ ; Tells when a branch could be optimised to short OPT i+ ; Tells when '#' is probably missing incdir "AsmInc:" 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" 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 CallS MACRO bsr.S \1 ENDM Push MACRO movem.l \1,-(SP) ENDM Pop MACRO movem.l (SP)+,\1 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 vars link DB,#-RelSize ENDM rFree MACRO ; Deallocate vars unlk DB ENDM rClear MACRO ; Reset all vars movem.l D0/DB,-(SP) move.w #RelSize-1,D0 rClr.\@ clr.b -(DB) dbf D0,rClr.\@ movem.l (SP)+,D0/DB ENDM DB EQUR A4 SECTION InputLock,CODE InitProcess rAlloc ; Allocate memory for variables rClear ; 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 CallLib Forbid lea IHS(PC),A1 lea ihs_PortName(A1),A1 CallLib FindPort move.l D0,D2 CallLib Permit move.l D2,D0 ; Does Forbid/Permit destroy scratch-registers ? 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 rFree moveq #0,D0 rts FHandle EQUR D5 * Call: D0 = Msg-number 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 MsgTable(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 MsgText MACRO dc.w \1-MsgTable ENDM MsgTable MsgText Msg MsgText Msg1 MsgText Msg2 MsgText Msg3 MsgText Msg4 CONName dc.b 'CON:100/60/330/63/InputLock',0 Msg dc.b 10,$9B,'0;33m InputLock V1.1',10 dc.b $9B,'0;31m 1991 by ',$9B,'0;33mPreben Nielsen',$9B,'0;31m',10,' ',0 Msg1 dc.b 'has just been installed...',10,0 Msg2 dc.b 'has just been removed...',10,0 Msg3 dc.b 'Error: Cannot install handler',10,0 Msg4 dc.b 'Error: Cannot remove handler',10,0 EVEN 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 lea ihs_PortName(A2),A0 move.l A0,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 TellInputDevice Push D1-D2/rtsValue/A0-A3/A6 Prepare Exec_Call moveq #-1,rtsValue move.l D0,D2 move.l A0,A2 lea IReq(DB),A0 moveq #IOSTD_SIZE,D0 Call MemClear lea IPort(DB),A0 moveq #MP_SIZE,D0 Call MemClear move.l A0,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(DB),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(DB),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(DB),A1 CallLib CloseDevice 1$ move.b MP_SIGBIT(A3),D0 CallLib FreeSignal 2$ move.l rtsValue,D0 Pop D1-D2/rtsValue/A0-A3/A6 rts * Call: A0 = Memory area * D0:16 = Count MemClear Push D0-D1/A0 moveq #0,D1 bra.S 2$ 1$ move.b D1,(A0)+ 2$ dbf D0,1$ Pop D0-D1/A0 rts * Call: A0 = Source * A1 = Destination * D0:16= Count MemCopy Push D0/A0-A1 bra.S 2$ 1$ move.b (A0)+,(A1)+ 2$ dbf D0,1$ Pop D0/A0-A1 rts * Each handler should have such a pair of installation-routine * 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 after attempt to install handler and message-port * ----------------------------------------------------------------- * 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 Call MemCopy 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) ; HandlerBlock.HInterrupt.is_Code = Handler clr.l ihs_Interrupt+IS_DATA(A1) ; HandlerBlock.HInterrupt.is_Data = 0 move.b #HPRI,ihs_Interrupt+LN_PRI(A1) ; HandlerBlock.HInterrupt.is_Node.ln_Pri = PRI 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-routine * 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 after attempt to remove handler and message-port * ----------------------------------------------------------------- * 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 D1-D2/A0-A1/A6 Prepare Exec_Call CallLib Forbid lea ihs_PortName(A0),A1 CallLib FindPort move.l D0,D2 CallLib Permit move.l D2,D0 ; Does Forbid/Permit destroy scratch-registers ? Pop D1-D2/A0-A1/A6 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 *====================== 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_Start MACRO dcb.b MP_SIZE ; Message-Port structure dcb.b IS_SIZE ; Interrupt structure dc.l 'P_IH' ; ID (Handler made by me) dc.l 0 ; Length of handler dc.w 0 ; Flags dc.b \1,0 EVEN ENDM HPRI =127 ; Handler-priority HDisabled =0 HNoExtRemoval =1 ; Future * This is the handler-block IHS ihs_Start <'InputLock V1.1 Port'> * Local variables Chain dc.l 0 Status dc.w 0 INPUTDISABLED =0 * For each event in the event list: * If we were waiting for this event then process it. * When all the events have been checked, return the event list so that * others can do their things. PEvent EQUR A2 ; Previous Event Event EQUR A1 ; This Event Bits EQUR A0 Next =ie_NextEvent Class =ie_Class Code =ie_Code Qual =ie_Qualifier * These are the qualifier-keys the input-handler waits for QUALIFIERS =IEQUALIFIER_LALT|IEQUALIFIER_CONTROL * These are the keys the input-handler acts on Toggle_Key =$28 ; 'l' * Call: A0 = List of InputEvents, A1 = HandlerData HandlerCode Push Bits/Event/PEvent move.w IHS+ihs_Flags(PC),D0 btst #HDisabled,D0 ; Future feature bne.S NoMoreEvents lea Chain(PC),PEvent move.l A0,Next(PEvent) lea Status(PC),Bits ieLoop move.l Next(PEvent),Event move.l Event,D0 beq.S NoMoreEvents cmpi.b #IECLASS_RAWMOUSE,Class(Event) beq.S CheckLock cmpi.b #IECLASS_RAWKEY,Class(Event) bne.S DontRemove move.w Qual(Event),D0 andi.w #QUALIFIERS|IEQUALIFIER_REPEAT,D0 cmpi.w #QUALIFIERS,D0 bne.S CheckLock cmp.w #Toggle_Key,Code(Event) bne.S CheckLock bchg #INPUTDISABLED,(Bits) bra.S Remove CheckLock btst #INPUTDISABLED,(Bits) bne.S Remove * Just move on to next Event DontRemove move.l Event,PEvent bra.S ieLoop * Remove event from chain and move on to next Event Remove move.l Next(Event),Next(PEvent) bra.S ieLoop * Lets return NoMoreEvents Pop Bits/Event/PEvent move.l Chain(PC),D0 ; Return (shortened ?) chain rts HandlerSize = *-IHS *====================== Input-handler end =========================== *====================== Data-definition start ======================= rStart rAPtr PProcess rAPtr WBMsg rAPtr DosBase rStorage IReq,IOSTD_SIZE rStorage IPort,MP_SIZE rAPtr HMem rEnd DosName dc.b 'dos.library',0 InputName dc.b 'input.device',0 END