***********************************************
*           FakeKey                           *
*                                             *
*           by Douglas Nelson                 *
*           2006 N. 49 Avenue                 *
*           Omaha NE 68104                    *
*                                             *
*           Assemble with Macro68             *
***********************************************

	exeobj
	errfile	'ram:assem.output'
	objfile	'ram:test'
	listfile	'ram:list'
	strict
	escapestr

_LVOAllocMem	equ	-198
_LVOCloseDevice	equ	-450
_LVOCloseLibrary	equ	-414
_LVOFreeMem		equ	-210
_LVOOpenDevice	equ	-444
_LVOOpenLibrary	equ	-552
_LVOCreateIORequest	equ	-654
_LVODeleteIORequest	equ	-660
_LVOCreateMsgPort	equ	-666
_LVODeleteMsgPort	equ	-672
_LVOReadArgs	equ	-798
_LVOFreeArgs	equ	-858
_LVOParseIX		equ	-132
_LVODelay		equ	-198
_LVODoIO		equ	-456
_LVOOutput		equ	 -60
_LVOWrite		equ	 -48

	incpath	"mac:includes"
	macfile	"mac:includes/exec/io.i"
	macfile	"mac:includes/exec/memory.i"
	macfile	"mac:includes/devices/input.i"
	macfile	"mac:includes/libraries/commodities.i"

* register usage
dosbase	equr	d7
cxbase	equr	d6
rdargs	equr	d5
InputMP	equr	d4
args	equr	a5
InputIO	equr	a4
FakeEvent	equr	a3
ix	equr	a2

*local variables
rc	equ	-12	;return code
timeout	equ	-8	;arg1 from command line
keypress	equ	-4	;arg2 from command line

* This program needs memory for three local structures: an InputEvent, an
* InputXpression, and an array of two longs for use with ReadArgs(). We
* will allocate memory for the InputEvent and InputXpression, since these
* need to be zeroed, but the ReadArgs() array will be created on the stack
* with a LINK instruction.

* make local variables
	link	args,#-12

* initialize return code
	move.l	#0,(rc,args)

* zero register variables
	moveq	#0,dosbase
	moveq	#0,cxbase
	moveq	#0,rdargs
	moveq	#0,InputMP
	movea.l	#0,InputIO
	movea.l	#0,FakeEvent
	movea.l	#0,ix

* open dos.library
	movea.l	(4).w,a6
	lea	(dosname,pc),a1
	moveq	#37,d0		;version number
	jsr	(_LVOOpenLibrary,a6)
	move.l	d0,dosbase
	bne	opencx
	lea	(youneed,pc),a0
	bsr	outputmsg
	bra	failure

* open commodities.library
opencx	lea	(cxname,pc),a1
	moveq	#37,d0
	jsr	(_LVOOpenLibrary,a6)
	move.l	d0,cxbase
	bne	readarg
	lea	(nocxlib,pc),a0
	bsr	outputmsg
	bra	failure

* read arguments
readarg	movea.l	dosbase,a6
	lea	(template,pc),a0
	move.l	a0,d1
	lea	(timeout,args),a0
	move.l	a0,d2
	moveq	#0,d3
	jsr	(_LVOReadArgs,a6)
	move.l	d0,rdargs
	beq	failure

* wait for user-specified timeout
	movea.l	(timeout,args),a0	; this is ptr to timeout
	move.l	(a0),d1		; get value	of timeout
	mulu	#50,d1		; turn seconds into ticks
	jsr	(_LVODelay,a6)

* create Message port
	movea.l	(4).w,a6
	jsr	(_LVOCreateMsgPort,a6)
	move.l	d0,InputMP
	beq	failure

* create IO	request
	movea.l	InputMP,a0
	moveq	#IOSTD_SIZE,d0
	jsr	(_LVOCreateIORequest,a6)
	movea.l	d0,InputIO
	tst.l	d0
	beq	failure

* open input.device
	lea	(inputname,pc),a0
	moveq	#0,d0
	movea.l	InputIO,a1
	moveq	#0,d1
	jsr	(_LVOOpenDevice,a6)
	tst.l	d0
	bne	failure

* allocate InputEvent
	moveq	#ie_SIZEOF,d0	;22 bytes
	move.l	#MEMF_CLEAR,d1
	jsr	(_LVOAllocMem,a6)
	movea.l	d0,FakeEvent
	tst.l	d0
	beq	failure

* allocate InputXpression
	moveq	#ix_SIZEOF,d0	;12 bytes
	move.l	#MEMF_CLEAR,d1
	jsr	(_LVOAllocMem,a6)
	movea.l	d0,ix
	tst.l	d0
	beq	failure

* make InputXpression from user-specified string
	movea.l	cxbase,a6
	movea.l	(keypress,args),a0	; keypress is ptr to string
	movea.l	ix,a1		; load addr	of InputXpression
	jsr	(_LVOParseIX,a6)
	tst.l	d0
	beq	parseOK
	lea	(parseerr,pc),a0
	bsr	outputmsg
	bra	failure

* write keycodes from InputXpression to InputEvent
parseOK	move.b	(ix_Class,ix),(ie_Class,FakeEvent)
	move.w	(ix_Code,ix),(ie_Code,FakeEvent)
	move.w	(ix_Qualifier,ix),(ie_Qualifier,FakeEvent)

* Put ptr to InputEvent in InputIO
	movea.l	InputIO,a1
	move.l	FakeEvent,(IO_DATA,a1)	;ptr to InputEvent in DATA
	move.l	#ie_SIZEOF,(IO_LENGTH,a1)
	move.w	#IND_WRITEEVENT,(IO_COMMAND,a1)

* write key-down event to input.device
	movea.l	(4).w,a6
	jsr	(_LVODoIO,a6)
	tst.l	d0
	bne	failure

* write key-up event to	input.device
	movea.l	InputIO,a1
	ori.w	#IECODE_UP_PREFIX,(ie_Code,FakeEvent)
	jsr	(_LVODoIO,a6)	;if this fails, who cares?

* clean up everything
cleanup	move.l	rdargs,d1
	beq	freeIE
	movea.l	dosbase,a6
	jsr	(_LVOFreeArgs,a6)
freeIE	movea.l	(4).w,a6
	movea.l	FakeEvent,a1
	move.l	a1,d0		;test a1
	beq	freeIX
	moveq	#ie_SIZEOF,d0
	jsr	(_LVOFreeMem,a6)
freeIX	movea.l	ix,a1
	move.l	a1,d0		;test a1
	beq	closedev
	moveq	#ix_SIZEOF,d0
	jsr	(_LVOFreeMem,a6)
closedev	movea.l	InputIO,a1
	move.l	a1,d0		;test a1
	beq	closeMP
	jsr	(_LVOCloseDevice,a6)
	movea.l	InputIO,a0
	jsr	(_LVODeleteIORequest,a6)
closeMP	movea.l	InputMP,a0
	move.l	a0,d0		;test a0
	beq	closecx
	jsr	(_LVODeleteMsgPort,a6)
closecx	movea.l	cxbase,a1
	move.l	a1,d0
	beq	closedos
	jsr	(_LVOCloseLibrary,a6)
closedos	movea.l	dosbase,a1
	move.l	a1,d0
	beq	quit
	jsr	(_LVOCloseLibrary,a6)
quit	move.l	(rc,args),d0
	unlk	args
	rts


failure	move.l	#10,(rc,args)
	bra	cleanup


outputmsg	movem.l	a0/a6,-(sp)		;push ptr to text & a6
	movea.l	(4).w,a6
	lea	(dosname,pc),a1
	moveq	#0,d0		;any version
	jsr	(_LVOOpenLibrary,a6)
	movea.l	d0,a6		;If we can't find dosbase,
	jsr	(_LVOOutput,a6)	;we deserve to crash.
	move.l	d0,d1
	pop	d2                      ;ptr to text
	move.l	#30,d3                  ;text length
	jsr	(_LVOWrite,a6)
	pop	a6
	rts


dosname	cstr	'dos.library'
cxname	cstr	'commodities.library'
template	cstr	'timeout/N/A,keypress/F/A'
inputname	cstr	'input.device'
	db	'$VER: FakeKey 1.0 (2.2.93)   \N'
	db	'By Douglas Nelson. Freely distributable.'

youneed	db	'You need AmigaDOS 2.x!       \N'
nocxlib	db	'No commodities.library!      \N'
parseerr	db	'Invalid input!               \N'

	end
