/* Copyright 2010 Fredrik Wikstrom. All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
**    notice, this list of conditions and the following disclaimer.
**
** 2. Redistributions in binary form must reproduce the above copyright
**    notice, this list of conditions and the following disclaimer in the
**    documentation and/or other materials provided with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
** POSSIBILITY OF SUCH DAMAGE.
*/

#include <exec/memory.h>
#include <exec/interrupts.h>
#include <dos/dos.h>
#include <devices/input.h>
#include <devices/inputevent.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <SDI_compiler.h>
#include <string.h>
#include "AmigaKeyRemapper_rev.h"

#define PROGNAME "AmigaKeyRemapper"
#define HANDLER_PRIORITY 55
const char USED verstag[] = VERSTAG;

#define KEYUP 0x80
#define KEY_ESCAPE 0x45
#define KEY_RETURN 0x44
#define KEY_UP 0x4C
#define KEY_DOWN 0x4D
#define KEY_LEFT 0x4F
#define KEY_RIGHT 0x4E
#define KEY_HELP 0x5F
#define KEY_MENU 0x6B
#define KEY_PAUSE 0x6E

#ifdef __AROS__
AROS_UFP2(struct InputEvent *, keyRemapper,
	AROS_UFPA(struct InputEvent *, events, A0),
	AROS_UFPA(APTR, handlerData, A1)
);
#else
static struct InputEvent * keyRemapper (REG(a0,struct InputEvent * events), REG(a1,APTR handlerData));
#endif
struct Interrupt keyRemapperInt;

int main () {
	struct MsgPort * InputMP;
	struct IOStdReq * InputIO;

	InputMP = CreateMsgPort();
	if (InputMP) {
		InputIO = (struct IOStdReq *)CreateIORequest(InputMP, sizeof(struct IOStdReq));
		if (InputIO) {
			if (!OpenDevice("input.device", 0, (struct IORequest *)InputIO, 0)) {
				ULONG sigmask = 0, waitsigs;

				memset(&keyRemapperInt, 0, sizeof(keyRemapperInt));
				keyRemapperInt.is_Node.ln_Pri = HANDLER_PRIORITY;
				keyRemapperInt.is_Node.ln_Name = PROGNAME;
				keyRemapperInt.is_Code = (void (*)())keyRemapper;
				
				/* add handler to system */
				InputIO->io_Command = IND_ADDHANDLER;
				InputIO->io_Data = (APTR)&keyRemapperInt;
				DoIO((struct IORequest *)InputIO);

				waitsigs = SIGBREAKF_CTRL_C;
				while (!(sigmask & SIGBREAKF_CTRL_C)) {
					sigmask = Wait(waitsigs);
				}

				/* remove handler from system */
				InputIO->io_Command = IND_REMHANDLER;
				InputIO->io_Data = (APTR)&keyRemapperInt;
				DoIO((struct IORequest *)InputIO);

				CloseDevice((struct IORequest *)InputIO);
			}
			DeleteIORequest((struct IORequest *)InputIO);
		}
		DeleteMsgPort(InputMP);
	}

	return 0;
}

#ifdef __AROS__
AROS_UFH2(struct InputEvent *, keyRemapper,
	AROS_UFHA(struct InputEvent *, events, A0),
	AROS_UFHA(APTR, handlerData, A1)
)
{
	AROS_USERFUNC_INIT
#else
static struct InputEvent * keyRemapper (REG(a0,struct InputEvent * events), REG(a1,APTR handlerData))
{
#endif
	struct InputEvent * event;
	UWORD new_qualifier;
	/* loop through events */
	event = events;
	while (event != NULL) {
		#if 1 /* remaps left amiga <-> right amiga */
		new_qualifier = event->ie_Qualifier & ~(IEQUALIFIER_LCOMMAND|IEQUALIFIER_RCOMMAND);
		if (event->ie_Qualifier & IEQUALIFIER_LCOMMAND)
			new_qualifier |= IEQUALIFIER_RCOMMAND;
		if (event->ie_Qualifier & IEQUALIFIER_RCOMMAND)
			new_qualifier |= IEQUALIFIER_LCOMMAND;
		event->ie_Qualifier = new_qualifier;
		#endif

		#if 0 /* remaps right amiga <-> left alt */
		new_qualifier = event->ie_Qualifier & ~(IEQUALIFIER_RCOMMAND|IEQUALIFIER_LALT);
		if (event->ie_Qualifier & IEQUALIFIER_RCOMMAND)
			new_qualifier |= IEQUALIFIER_LALT;
		if (event->ie_Qualifier & IEQUALIFIER_LALT)
			new_qualifier |= IEQUALIFIER_RCOMMAND;
		event->ie_Qualifier = new_qualifier;
		#endif

		#if 0 /* remaps menu <-> help (scroll-lock) */
		if (event->ie_Class == IECLASS_RAWKEY) {
			UWORD keyup, code;
			if (event->ie_Code & KEYUP) {
				keyup = KEYUP;
				code = event->ie_Code - KEYUP;
			} else {
				keyup = 0;
				code = event->ie_Code;
			}
			if (code == KEY_HELP)
				event->ie_Code = KEY_MENU|keyup;
			else if (code == KEY_MENU)
				event->ie_Code = KEY_HELP|keyup;
		}
		#endif

		event = event->ie_NextEvent;
	}
	return events;
#ifdef __AROS__
	AROS_USERFUNC_EXIT
#endif
}
