	OPT	A+,O+,OW-		;enable optimizing

;------------------ MouseShift.asm   ©1992 Garrick Meeker ---------------
;
; Installs an input handler that converts a middle mouse button press to
; a left shift key press.
;
; Version 2.0 - This program now installs a commodity under V37.
;-----------------------------------------------------------------------

	include	"exec/types.i"
	include	"dos/dos.i"
	include	"exec/exec_lib.i"
	include	"exec/memory.i"
	include	"exec/io.i"
	include	"devices/input.i"
	include	"devices/inputevent.i"
	include	"libraries/commodities.i"
	include	"misc/easystart.i"

	XREF	_CreatePort
	XREF	_CreateExtIO
	XREF	_DeletePort
	XREF	_DeleteExtIO

	XDEF	_SysBase

CALLCX	MACRO
	XREF	_LVO\1
	move.l	_CxBase,a6
	jsr	_LVO\1(a6)
	ENDM

	moveq	#0,d5

	move.l	4.W,a6
	cmp.w	#37,LIB_VERSION(a6)
	bcc	Release2_Code

	move.l	#0,-(sp)
	move.l	#0,-(sp)
	jsr	_CreatePort
	addq.l	#8,sp
	move.l	d0,d2
	beq	exit

	move.l	#IS_SIZE,d0
	move.l	#MEMF_PUBLIC!MEMF_CLEAR,d1
	CALLEXEC AllocMem
	move.l	d0,d3
	beq	quit4

	move.l	#IOSTD_SIZE,-(sp)
	move.l	d2,-(sp)
	jsr	_CreateExtIO
	addq.l	#8,sp
	move.l	d0,d4
	beq	quit3

	lea	devname,a0		;name
	moveq	#0,d0			;unit
	move.l	d4,a1			;iORequest
	moveq	#0,d1			;flags
	CALLEXEC OpenDevice
	tst.l	d0
	bne	quit2

	move.l	#_HandlerSize,d0
	move.l	#MEMF_PUBLIC,d1
	CALLEXEC AllocMem
	move.l	d0,d5
	beq	quit1

	lea	_ChangeEvent,a0
	move.l	d5,a1
	move.l	#_HandlerSize,d0
	CALLEXEC CopyMem

	move.l	d3,a0
	move.l	d4,a1

	clr.l	IS_DATA(a0)
	move.l	d5,IS_CODE(a0)
	move.b	#60,LN_PRI(a0)
	move.l	#name,LN_NAME(a0)

	move.l	d3,IO_DATA(a1)
	move.w	#IND_ADDHANDLER,IO_COMMAND(a1)

;IO struct already in A1
	CALLEXEC DoIO

	moveq	#0,d3

quit1	move.l	d4,a1
	CALLEXEC CloseDevice

quit2	move.l	d4,-(sp)
	jsr	_DeleteExtIO
	addq.l	#4,sp

quit3	tst.l	d3			;can't be freed if handler installed
	beq	quit4
	move.l	d3,a1
	move.l	#IS_SIZE,d0
	CALLEXEC FreeMem

quit4	move.l	d2,-(sp)
	jsr	_DeletePort
	addq.l	#4,sp

byebye	tst.l	d5			;set return code
	beq	exit
	moveq	#0,d0
	rts

exit	move.l	#20,d0
	rts

devname	dc.b	'input.device',0
	EVEN

*** HANDLER CODE ***

* The event list is passed in a0.
* The is_Data field is passed in a1.

* On exit the event list must be returned in d0.

_ChangeEvent	move.l	a0,-(sp)

CheckLoop
	bsr	change
	move.l	(a0),d0
	move.l	d0,a0
	bne.s	CheckLoop

	move.l	(sp)+,d0
	rts

CxChange
	movem.l	d0-1/a0-1/a6,-(sp)
	move.l	4(sp),a0
	CALLCX	CxMsgData
	move.l	d0,a0
	bsr	change
	movem.l	(sp)+,d0-1/a0-1/a6
	rts

change
	bclr.b	#IEQUALIFIERB_MIDBUTTON-8,ie_Qualifier(a0)
	beq.s	CheckRaw
	bset.b	#IEQUALIFIERB_LSHIFT,ie_Qualifier+1(a0)

CheckRaw
	cmp.b	#IECLASS_RAWMOUSE,ie_Class(a0)
	bne.s	NextEvent

	move.w	ie_Code(a0),d0
	and.w	#~IECODE_UP_PREFIX,d0
	cmp.w	#IECODE_MBUTTON,d0
	bne.s	NextEvent
	sub.w	#IECODE_MBUTTON-$60,ie_Code(a0)		;left shift
	move.b	#IECLASS_RAWKEY,ie_Class(a0)

NextEvent
	rts

name	dc.b	'Mouse Shift',0
	EVEN

_HandlerSize	equ	*-_ChangeEvent

;--- LEFT AMIGA ---- LEFT ALT ---- LEFT SHIFT ---
;       -66-           -64-           -60-
;--- RIGHT AMIGA --- RIGHT ALT --- RIGHT SHIFT ---
;       -67-           -65-           -61-
;--- CTRL ---
;    -63-

Release2_Code
	lea	comlib_name,a1			;get library
	moveq	#37,d0
	CALLEXEC OpenLibrary
	move.l	d0,_CxBase
	beq	byebye

	CALLEXEC CreateMsgPort			;get msgport
	move.l	d0,msgport
	beq	abort1
	move.l	d0,broker_struct+nb_Port

	move.l	d0,a0				;get port signal
	move.b	MP_SIGBIT(a0),d0
	move.l	#SIGBREAKF_CTRL_C,d1
	bset	d0,d1
	move.l	d1,signums

	lea	broker_struct,a0
	moveq	#0,d0
	CALLCX	CxBroker
	move.l	d0,broker
	beq	abort2

	moveq	#CX_CUSTOM,d0
	lea	CxChange,a0
	sub.l	a1,a1
	CALLCX	CreateCxObj
	tst.l	d0
	beq	abort3
	move.l	d0,a1
	move.l	broker,a0
	CALLCX	AttachCxObj

	move.l	broker,a0
	moveq	#1,d0
	CALLCX	ActivateCxObj

*** Release 2 Handler ***
wait	move.l	signums,d0
	CALLEXEC Wait
	btst	#SIGBREAKB_CTRL_C,d0
	bne	abort3			;CTRL-C hit

ie_loop	move.l	msgport,a0
	CALLEXEC GetMsg
	tst.l	d0
	beq	wait
	move.l	d0,a2

	move.l	a2,a0
	CALLCX	CxMsgType
	move.l	d0,d6
	move.l	a2,a0
	CALLCX	CxMsgID
	move.l	d0,d4

	move.l	a2,a1
	CALLEXEC ReplyMsg

	cmp.l	#CXM_COMMAND,d6
	bne	ie_loop
	cmp.l	#CXCMD_DISABLE,d4
	bne	.on
	move.l	broker,a0
	moveq	#0,d0
	CALLCX	ActivateCxObj
	bra	ie_loop
.on	cmp.l	#CXCMD_ENABLE,d4
	bne	.kill
	move.l	broker,a0
	moveq	#1,d0
	CALLCX	ActivateCxObj
	bra	ie_loop
.kill	cmp.l	#CXCMD_KILL,d4
	bne	.unique
	bra	abort3			;exit
.unique	cmp.l	#CXCMD_UNIQUE,d4
	bne	ie_loop

abort3	move.l	broker,a0		;delete CxObject
	CALLCX	DeleteCxObjAll

.remmsg	move.l	msgport,a0
	CALLEXEC GetMsg
	tst.l	d0
	beq	abort2
	move.l	d0,a1
	CALLEXEC ReplyMsg
	bra	.remmsg

abort2	move.l	msgport,a0		;delete message port
	CALLEXEC DeleteMsgPort

abort1	move.l	_CxBase,a1		;close commodities.library
	CALLEXEC CloseLibrary
	bra	byebye

broker_struct
	dc.b	NB_VERSION,0
	dc.l	name
	dc.l	CommTitle
	dc.l	CommDesc
	dc.w	NBU_UNIQUE!NBU_NOTIFY
	dc.w	0
	dc.b	60,0			;priority
	dc.l	0
	dc.w	0

msgport	dc.l	0
signums	dc.l	0
broker	dc.l	0
_CxBase	dc.l	0

comlib_name	dc.b	'commodities.library',0
CommTitle	dc.b	'Mouse Shift by Garrick Meeker',0
CommDesc	dc.b	'Turns middle button into a shift key',0
	EVEN

