;/* Execute me to Compile and link
shelltimer start verbose
; For debugging, use the following command:
;lc -. -b1 -cfistq -j73 -v -Lit -d3 -isrc:memlib -dMWDEBUG=1 CloneCommandKeys.c
; For develpoment, use the following commands:
lc -. -O -ms -b1 -cfistq -j73 -v CloneCommandKeys.c
blink define __main=__tinymain MAP mapfile NODEBUG SMALLCODE SMALLDATA FROM lib:c.o,CloneCommandKeys.o to CloneCommandKeys LIBRARY LIB:lc.lib,LIB:amiga.lib
; For production, use the following command:
;lc -. -O -ms -b0 -cfistq -j73 -Lit -tr CloneCommandKeys.c
echo "Time to compile and link: " NOLINE
shelltimer stop
quit
*/

/***
****	CLONECOMMANDKEYS.C
****
****	Creation:		John Lindwall
****					12 Feb 1992
****
****	Description:	CloneCommandKeys is a Commodity that maps the
****		AmigaDOS 2.04 Shell's CUT and PASTE  commands  to  any keys.
****		By default,  CloneCommandKey  will make LEFT-amiga-c also
****		operate as COPY, and LEFT-amiga-v  will  also  act  as PASTE.
****		Alternately, you can specify any key-mapping you like by
****		using ToolTypes.
****
****		This program requires AmigaDOS 2.04.
****
****		CloneCommandKeys is released into the Public Domain by the
****		author, John Lindwall.  I ask that the archive be kept intact
****		with the docs and the source code.
****		Bug reports should be sent to me at johnl@crash.cts.com.
****
****		The code looked nicer before I optimized for space...
****
****	Overhauls:
***/

#include <exec/libraries.h>
#include <libraries/commodities.h>
#include <dos/dos.h>
#include <devices/inputevent.h>

#include <clib/exec_protos.h>
#include <clib/alib_protos.h>
#include <clib/commodities_protos.h>
#include <clib/dos_protos.h>

#include <stdlib.h>

void main(int, char **);
LONG ProcessMessages(void);
BOOL SetupBroker(int argc, char *argv[], char **copyKey, char **pasteKey);
BOOL CloneCommandKey(char *copyKey, struct InputEvent *event);

/* Error codes */
#define ERR_OPENLIBFAIL		20
#define ERR_BROKERFAIL		0	/* Uniqueness violation */
#define ERR_CLONEFAIL		10

#define OPENLIBRARIES() 	\
	(((CxBase = OpenLibrary("commodities.library", 37L))!=NULL) &&  \
	((IconBase = OpenLibrary("icon.library", 36L))!=NULL) )
#define CLOSELIBRARIES()	\
	if( IconBase ) CloseLibrary(IconBase); \
	if( CxBase ) CloseLibrary(CxBase);
#define SHUTDOWNBROKER()	\
	if( broker ) DeleteCxObjAll(broker); \
	if( newbroker.nb_Port != NULL )	DeleteMsgPort(newbroker.nb_Port); \
	ArgArrayDone();

UBYTE versionTag[] = "\0$VER: CloneCommandKeys 1.0 (14.02.92)";

struct Library *CxBase, *IconBase;
CxObj *broker;
ULONG cxSignal;

struct NewBroker newbroker =
{
	NB_VERSION,
	"CloneCommandKeys",
	&versionTag[7],
	"Clones the COPY and PASTE command keys",
	NBU_UNIQUE | NBU_NOTIFY,
	0, 0, 0, 0
};

/*
 * Here are the InputEvents that our translate CxObjects jam into the
 * event stream.  The copyEvent is the "rcommand c" keycode; the pasteEvent
 * is the "rcommand v" keycode.
 */
struct InputEvent copyEvent =
{
	NULL, IECLASS_RAWKEY, IESUBCLASS_COMPATIBLE, 0x33, IEQUALIFIER_RCOMMAND
};


struct InputEvent pasteEvent =
{
	NULL, IECLASS_RAWKEY, IESUBCLASS_COMPATIBLE, 0x34, IEQUALIFIER_RCOMMAND
};


void
main(int argc, char **argv)
{
	char *copyKey, *pasteKey;
	int status;

	status = 0;
	if( ! OPENLIBRARIES() )
	{
		status = ERR_OPENLIBFAIL;
		if( argc != 0 )
		{
			Write(Output(), "Error opening libraries\n", 24);
		}
		goto exit;
	}
	if( SetupBroker(argc, argv, &copyKey, &pasteKey) == FALSE )
	{
		status = ERR_BROKERFAIL;
		goto exit;
	}
	if( CloneCommandKey(copyKey, &copyEvent) == FALSE ||
	    CloneCommandKey(pasteKey, &pasteEvent) == FALSE )
	{
		status = ERR_CLONEFAIL;
		goto exit;
	}
	ActivateCxObj(broker, 1L);
	while( ProcessMessages() )
	{
		;	/* Empty */
	}

exit:
	SHUTDOWNBROKER();
	CLOSELIBRARIES();
	exit(status);
}


BOOL
SetupBroker(int argc, char *argv[], char **copyKey, char **pasteKey)
{
	struct MsgPort *brokerPort;
	char **toolTypes;

	if( brokerPort = CreateMsgPort() )
	{
		newbroker.nb_Port = brokerPort;
		cxSignal = 1L << brokerPort->mp_SigBit;
		toolTypes = ArgArrayInit(argc, argv);
		newbroker.nb_Pri = (BYTE)ArgInt(toolTypes, "CX_PRIORITY", 0);
		*copyKey = ArgString(toolTypes, "COPYKEY", "lcommand c");
		*pasteKey = ArgString(toolTypes, "PASTEKEY", "lcommand v");
		if( broker = CxBroker(&newbroker, NULL) )
		{
			return(TRUE);
		}
	}
	return(FALSE);
}


BOOL
CloneCommandKey(char *key, struct InputEvent *event)
{
	CxObj *filter, *translate;

	if( filter = CxFilter(key) )
    {
		AttachCxObj(broker, filter);
		if( translate = CxTranslate(event) )
		{
			AttachCxObj(filter, translate);
		}
	}
	if( ! CxObjError(filter) )
	{
		return(TRUE);
	}
	return(FALSE);
}

LONG
ProcessMessages(void)
{
	CxMsg *msg;
	ULONG signalReceived;
	LONG returnValue = 1L;

	signalReceived = Wait( SIGBREAKF_CTRL_C | cxSignal);

	while( msg = (CxMsg *) GetMsg(newbroker.nb_Port))
	{
		switch( CxMsgType(msg) )
		{
			case CXM_COMMAND:
				switch( CxMsgID(msg) )
				{
					case CXCMD_DISABLE:
						ActivateCxObj(broker, 0L);
						break;
					case CXCMD_ENABLE:
						ActivateCxObj(broker, 1L);
						break;
					case CXCMD_KILL:
					case CXCMD_UNIQUE:
						returnValue = 0L;
						break;
				}
				break;
		}
		ReplyMsg((struct Message *) msg);
	}

	if( signalReceived & SIGBREAKF_CTRL_C )
	{
		returnValue = 0L;
	}
	return(returnValue);
}
