home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
400-499
/
ff483.lzh
/
ButExchange
/
ButExchange.asm
< prev
next >
Wrap
Assembly Source File
|
1991-05-10
|
17KB
|
664 lines
* ButExchange V1.0
* By Preben Nielsen
*
* This program is intended as a help to left-handed Amiga-users.
* It installes an input-handler which reverses the function of the
* mouse buttons, so that the left button becomes the right and
* vice versa.
*
* Once installed, the program only uses 168 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 09-Apr-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 "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 ButExchange,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/ButExchange',0
Msg dc.b 10,$9B,'0;33m ButExchange V1.0',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 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 <'ButExchange V1.0 Port'>
* For each event in the event list:
* If it is LMB event then make it a RMB event and vice versa.
* 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 D1/Event/EList
move.w IHS+ihs_Flags(PC),D0
btst #HDisabled,D0 ; Future feature
bne.S NoMoreEvents
move.l EList,Event
ieLoop move.l Event,D0
beq.S NoMoreEvents
cmpi.b #IECLASS_RAWMOUSE,Class(Event)
bne.S DontRemove
move.w Code(Event),D0
move.w D0,D1
andi.w #IECODE_UP_PREFIX,D1
andi.w #~IECODE_UP_PREFIX,D0
cmpi.w #IECODE_LBUTTON,D0
beq.S ExchangeLR
cmpi.w #IECODE_RBUTTON,D0
bne.S DontRemove
ExchangeRL ori.w #IECODE_LBUTTON,D1
bra.S Exchanged
ExchangeLR ori.w #IECODE_RBUTTON,D1
Exchanged move.w D1,Code(Event)
* Just move on to next Event
DontRemove move.l Next(Event),Event
bra.S ieLoop
* Lets return
NoMoreEvents move.l EList,D0
Pop D1/Event/EList
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
* These defines are here for quick reference only
--- InputEvent.ie_Class ---
IECLASS_NULL 0x00 A NOP input event
IECLASS_RAWKEY 0x01 A raw keycode from the keyboard device
IECLASS_RAWMOUSE 0x02 The raw mouse report from the game port device
IECLASS_EVENT 0x03 A private console event
IECLASS_POINTERPOS 0x04 A Pointer Position report
IECLASS_TIMER 0x06 A timer event
IECLASS_GADGETDOWN 0x07 select button pressed down over a Gadget (address in ie_EventAddress)
IECLASS_GADGETUP 0x08 select button released over the same Gadget (address in ie_EventAddress)
IECLASS_REQUESTER 0x09 some Requester activity has taken place. See Codes REQCLEAR and REQSET
IECLASS_MENULIST 0x0A this is a Menu Number transmission (Menu number is in ie_Code)
IECLASS_CLOSEWINDOW 0x0B User has selected the active Window's Close Gadget
IECLASS_SIZEWINDOW 0x0C this Window has a new size
IECLASS_REFRESHWINDOW 0x0D the Window pointed to by ie_EventAddress needs to be refreshed
IECLASS_NEWPREFS 0x0E new preferences are available
IECLASS_DISKREMOVED 0x0F the disk has been removed
IECLASS_DISKINSERTED 0x10 the disk has been inserted
IECLASS_ACTIVEWINDOW 0x11 the window is about to be made active
IECLASS_INACTIVEWINDOW 0x12 the window is about to be made inactive
IECLASS_MAX 0x12 the last class
--- InputEvent.ie_Code ---
IECLASS_RAWKEY
IECODE_UP_PREFIX 0x80
IECODE_KEY_CODE_FIRST 0x00
IECODE_KEY_CODE_LAST 0x77
IECODE_COMM_CODE_FIRST 0x78
IECODE_COMM_CODE_LAST 0x7F
IECLASS_ANSI
IECODE_C0_FIRST 0x00
IECODE_C0_LAST 0x1F
IECODE_ASCII_FIRST 0x20
IECODE_ASCII_LAST 0x7E
IECODE_ASCII_DEL 0x7F
IECODE_C1_FIRST 0x80
IECODE_C1_LAST 0x9F
IECODE_LATIN1_FIRST 0xA0
IECODE_LATIN1_LAST 0xFF
IECLASS_RAWMOUSE
IECODE_LBUTTON 0x68 also uses IECODE_UP_PREFIX
IECODE_RBUTTON 0x69
IECODE_MBUTTON 0x6A
IECODE_NOBUTTON 0xFF
IECLASS_EVENT
IECODE_NEWACTIVE 0x01 active input window changed
IECLASS_REQUESTER Codes
REQSET is broadcast when the first Requester (not subsequent ones) opens
in the Window
IECODE_REQSET 0x01
REQCLEAR is broadcast when the last Requester clears out of the Window
IECODE_REQCLEAR 0x00
--- InputEvent.ie_Qualifier ---
IEQUALIFIER_LSHIFT 0x0001
IEQUALIFIER_RSHIFT 0x0002
IEQUALIFIER_CAPSLOCK 0x0004
IEQUALIFIER_CONTROL 0x0008
IEQUALIFIER_LALT 0x0010
IEQUALIFIER_RALT 0x0020
IEQUALIFIER_LCOMMAND 0x0040
IEQUALIFIER_RCOMMAND 0x0080
IEQUALIFIER_NUMERICPAD 0x0100
IEQUALIFIER_REPEAT 0x0200
IEQUALIFIER_INTERRUPT 0x0400
IEQUALIFIER_MULTIBROADCAST 0x0800
IEQUALIFIER_MIDBUTTON 0x1000
IEQUALIFIER_RBUTTON 0x2000
IEQUALIFIER_LEFTBUTTON 0x4000
IEQUALIFIER_RELATIVEMOUSE 0x8000
IEQUALIFIERB_LSHIFT 0
IEQUALIFIERB_RSHIFT 1
IEQUALIFIERB_CAPSLOCK 2
IEQUALIFIERB_CONTROL 3
IEQUALIFIERB_LALT 4
IEQUALIFIERB_RALT 5
IEQUALIFIERB_LCOMMAND 6
IEQUALIFIERB_RCOMMAND 7
IEQUALIFIERB_NUMERICPAD 8
IEQUALIFIERB_REPEAT 9
IEQUALIFIERB_INTERRUPT 10
IEQUALIFIERB_MULTIBROADCAST 11
IEQUALIFIERB_MIDBUTTON 12
IEQUALIFIERB_RBUTTON 13
IEQUALIFIERB_LEFTBUTTON 14
IEQUALIFIERB_RELATIVEMOUSE 15
struct InputEvent
{
struct InputEvent *ie_NextEvent ;the chronologically next event
UBYTE ie_Class ;the input event class
UBYTE ie_SubClass ;optional subclass of the class
UWORD ie_Code ;the input event code
UWORD ie_Qualifier ;qualifiers in effect for the event
union
{
struct
{
WORD ie_x ;the pointer position for the event
WORD ie_y
} ie_xy
APTR ie_addr
} ie_position
struct timeval ie_TimeStamp ;the system tick at the event
};
ie_X =ie_position.ie_xy.ie_x
ie_Y =ie_position.ie_xy.ie_y
ie_EventAddress =ie_position.ie_addr