/*****************************************************************************\
 * AltKeyQ.c                     DICE/LATTICE C/SAS C/AZTEC C + AmigaOS 2.04 *
 *                 _                                                         *
 *            _   // (c)1992 by "Quarky" Dieter Temme                        *
 *            \\ //                                                          *
 *             \X/ --- Freeware --- ONLY AMIGA MAKES IT POSSIBLE             *
 *                                                                           *
 * the left ALT key with keypad numbers are assembled to ASCII values,       *
 * analog to the same function found on MS-DOS PCs (don't hate me for        *
 * mentioning the latter words)                                              *
 *                                                                           *
 * NOTE: 2.1-Includes needed!                                                *
\*****************************************************************************/

#define PRGNAME "AltKeyQ"
#define VERSION "1.0"
#define PRGDATE "17.9.92"

#include "amigacompq.h"

#include <ctype.h>
#include "stdarg.h"
#include <stdlib.h>
#include <string.h>
#include <exec/types.h>
#include <clib/alib_protos.h>
#include <clib/alib_stdio_protos.h>
#include <clib/commodities_protos.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/icon_protos.h>
#include <clib/intuition_protos.h>
#include <clib/keymap_protos.h>
#include <clib/locale_protos.h>
#include <dos/dos.h>
#include <exec/libraries.h>
#include <exec/ports.h>

#ifdef PRAGMAS_
 #include <pragmas/commodities_lib.h>
 #include <pragmas/dos_lib.h>
 #include <pragmas/exec_lib.h>
 #include <pragmas/icon_lib.h>
 #include <pragmas/intuition_lib.h>
 #include <pragmas/keymap_lib.h>
 #include <pragmas/locale_lib.h>
#endif

#ifdef LATTICE
 int CXBRK(void) { return 0; }  /* Disable Lattice CTRL-C handling */
 int chkabort(void) { return 0; }
#endif

#ifdef AZTEC_C
 void _wb_parse(void) {	extern long Enable_Abort; Enable_Abort= FALSE; }
 void _abort(void) {} /* Disable Aztec CTRL-C handling */
#endif

TEXT VersionString[]= "\0$VER: " PRGNAME " " VERSION " (" PRGDATE ")";

extern struct Library *SysBase;
struct Library *CxBase, *IconBase, *IntuitionBase, *LocaleBase;
struct Locale *locale;
struct Catalog *cat;

#define STRINGARRAY
#include "AltKeyQ.h"

struct NewBroker newbroker=	/* description of commodity's details */
{	5, PRGNAME, "V" VERSION " (c)1992 by \"Quarky\" Dieter Temme", NULL,
	NBU_UNIQUE|NBU_NOTIFY
};
ULONG sendsig;				/* flag to inform main() of IEvents to send */
BYTE sendsigbit= -1;		/* signal bit for flag of above */
struct Task *thistask;		/* pointer to main()'s task structure */
CxObj *broker;				/* commodities broker object */
struct MsgPort *brokport;	/* pointer to port for commodities' messages */
struct						/* structure with information to send: */
{	UBYTE value;			/*     ASCII value for the IEvent to send */
	UBYTE nul;				/*     ASCII NUL byte for InvertString() */
} send;

#define IECODE_LALT 0x64	/* rawkey number of left ALT key */


/*==== clean up all before exit ====*/
void ExitQ_(void)
{	if (broker) DeleteCxObjAll(broker);
	if (brokport)
	{	struct Message *msg;
		while (msg= GetMsg(brokport)) ReplyMsg(msg);
		DeleteMsgPort(brokport);
	}
	FreeSignal(sendsigbit);
	ArgArrayDone();
	if (LocaleBase)
	{	CloseCatalog(cat);
		CloseLocale(locale);
		CloseLibrary(LocaleBase);
	}
	if (CxBase) CloseLibrary(CxBase);
	if (IconBase) CloseLibrary(IconBase);
	if (IntuitionBase) CloseLibrary(IntuitionBase);
}

/*==== get catalog string localized if locale.library is open ====*/
TEXT *GetCatalogStrQ_(UBYTE num)
{	if (LocaleBase) return GetCatalogStr(cat, num, AppStrings[num].as_Str);
	return AppStrings[num].as_Str;
}

/*==== bring error text to the user ====*/
void ExitError_(TEXT *format, ...)
{	static struct EasyStruct easystruct=
	{	sizeof(struct EasyStruct), 0, NULL, NULL, NULL
	};
	va_list ap;

	if (IntuitionBase)
	{	DisplayBeep(NULL);
		easystruct.es_TextFormat= format;
		easystruct.es_GadgetFormat= GetCatalogStrQ_(MSG_ABORT_GAD);
		va_start(ap, format);
		EasyRequestArgs(NULL, &easystruct, NULL, &va_arg(ap, ULONG));
		va_end(ap);
	}

	exit(RETURN_FAIL);
}

void ExitMemError_(void)
{	ExitError_(GetCatalogStrQ_(MSG_NOMEMORY));
}

/*==== open library ====*/
struct Library *OpenLibraryQ_(TEXT *str)
{	struct Library *base;

	if (!(base= OpenLibrary(str, 0)))
		ExitError_(GetCatalogStrQ_(MSG_NOTFOUND), str);
	return base;
}

/*==== signal our task if ALT key is released ====*/
GETA4TYPE_ void CollectKeys_(CxMsg *cxmsg, CxObj *cxobj)
{	static TEXT keys[]= "\x0f\x1d\x1e\x1f\x2d\x2e\x2f\x3d\x3e\x3f";
	static BOOL collflag;	/* TRUE if collection of keys has started */
	static UBYTE value;		/* actual value of collected number keys */
	struct InputEvent *ie;	/* pointer to actual input event */
	TEXT *s;				/* pointer to rawkey, s-key is value of key */

	GETA4FUNC_;
	ie= (struct InputEvent *)CxMsgData(cxmsg);
	/* filter rawkey events */
	if (ie->ie_Class == IECLASS_RAWKEY)
	{	if (ie->ie_Code == (IECODE_LALT|IECODE_UP_PREFIX))
		{	if (collflag)
			{	/* User released left ALT key */
				send.value= value;
				Signal(thistask, sendsig);
				goto setinactive;
			}
		} else if (ie->ie_Qualifier&IEQUALIFIER_LALT)
		{	if (s= strchr(keys, ie->ie_Code))
			{	/* collect value */
				ie->ie_Code|= IECODE_UP_PREFIX;
				value= value*10+(s-keys);
				collflag= TRUE;
			}
		} else
setinactive:
		{	value= 0;
			collflag= FALSE;
		}
	}
}

/*==== main program ====*/
int main(int argc, TEXT *argv[])
{	ULONG cxsig;			/* signal flag of commodity message port */
	ULONG sigrcvd;			/* signal flags received thru Wait() */
	BOOL end= FALSE;		/* TRUE when program is to end */

	atexit(ExitQ_);

	/*- exit program if OS version not >= 2.04 -*/
	if (SysBase->lib_Version < 37)
	{	BPTR file;

		file= argc? Output() : Open("CON:0/0/350/30/" PRGNAME, MODE_NEWFILE);
		Write(file, "Sorry, you'll need at least AmigaOS 2.04!\n", 42);
		Delay(100);
		Close(file);
		return RETURN_FAIL;
	}

	/*- open libraries -*/
	IntuitionBase= OpenLibraryQ_("intuition.library");
	CxBase= OpenLibraryQ_("commodities.library");
	IconBase= OpenLibraryQ_("icon.library");
	if (LocaleBase= OpenLibrary("locale.library", 0))
	{	locale= OpenLocale(NULL);
		cat= OpenCatalogA(locale, "AltKeyQ.catalog", NULL);
	}

	/*- process arguments or tool types -*/
	argv= ArgArrayInit(argc, argv);
	newbroker.nb_Pri= (BYTE)ArgInt(argv, "CX_PRIORITY", 0);

	/*- initialize as commodity with custom object -*/
	{	CxObj *custom;

		newbroker.nb_Descr= GetCatalogStrQ_(MSG_CXDESCR);
		if (!(brokport= newbroker.nb_Port= CreateMsgPort())) ExitMemError_();
		cxsig= 1<<brokport->mp_SigBit;
		if (!(broker= CxBroker(&newbroker, 0))
			|| !(custom= CxCustom(CollectKeys_, 0))
			|| (AttachCxObj(broker, custom), CxObjError(custom)))
			ExitError_(GetCatalogStrQ_(MSG_INITFAIL));
		sendsig= 1<<(sendsigbit= (UBYTE)AllocSignal(-1));
		thistask= FindTask(NULL);
		ActivateCxObj(broker, TRUE);
	}

	/*- main loop -*/
	while (!end)
	{	sigrcvd= Wait(sendsig|cxsig|SIGBREAKF_CTRL_C);

		/* user break received */
		if (sigrcvd&SIGBREAKF_CTRL_C) end= TRUE;

		/* send collected value */
		if (sigrcvd&sendsig)
		{	struct InputEvent *ie;

			ie= InvertString((TEXT *)&send, NULL);
			AddIEvents(ie);
			FreeIEvents(ie);
		}

		/* commodity server loop */
		if (sigrcvd&cxsig)
		{	CxMsg *cxmsg;

			while (cxmsg= (CxMsg *)GetMsg(brokport))
			{	ULONG i;
				switch (i= CxMsgID(cxmsg))
				{	case CXCMD_DISABLE:
					case CXCMD_ENABLE:
						ActivateCxObj(broker, i == CXCMD_ENABLE);
						break;
					case CXCMD_KILL:
					case CXCMD_UNIQUE:
						end= TRUE;
				}
				ReplyMsg((struct Message *)cxmsg);
			}
		}
	}

	return RETURN_OK;
}

#ifdef _DCC
int wbmain(struct WBStartup *wbstart)
{	return main(0, (TEXT **)wbstart);
}
#endif
