*	InputLock V1.0
*	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
                   
	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.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	<'InputLock V1.0 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

* 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

