//	Zinc Application Framework - D_KEYBRD.CPP
//	COPYRIGHT (C) 1990-1999.  All Rights Reserved.
//	Zinc Software Incorporated.  Pleasant Grove, Utah  USA

#include <z_cset.hpp>
#include <z_evtmgr.hpp>
#include <z_keybrd.hpp>
#define USE_RAW_KEYS
#include <z_keymap.hpp>
#include <z_logevt.hpp>
#include <z_string.hpp> // For strcmp().
#include <z_sysevt.hpp>
#include "d_hware.hpp"
#define ZAF_KEYBOARD_INFO
#include "gbl_def.cpp"

#if defined(USE_UGL_INPUT)
#	include <uglinput.h>
#	include <input/k8255.h>
UGL_INPUT_Q_ID InputQueueGet(void);
bool InputQueuePoll(ugl_input_event &event, ZafEventType type);
void InputQueueRelease();
#endif

// ----- ZafKeyboard -------------------------------------------------------

ZafEventType ZafKeyboard::breakHandlerSet = L_EXIT;

void TranslateKeyEvent(ZafEventStruct &event);

ZafKeyboard::ZafKeyboard(ZafDeviceState _state) :
	ZafDevice(E_KEY, _state)
{
#if defined(USE_UGL_INPUT)
	driver = 0;
#endif
	if (installed)
		return;

	// Initialize the keyboard device.
	installed = true;
#if defined(USE_UGL_INPUT)
	UGL_INPUT_Q_ID inputQ = InputQueueGet();
	driver = ugl8255KbdDevCreate(inputQ, 1, 0x60);
#else
	I_KeyboardOpen();
#endif
	SetStringID(className);
	SetNumberID((ZafNumberID)classID);
}

ZafKeyboard::~ZafKeyboard(void)
{
	if (!installed)
		return;
#if defined(USE_UGL_INPUT)
	uglInputDevDestroy(driver);
	InputQueueRelease();
#else
	I_KeyboardClose();
#endif
	installed = false;
}

ZafEventType ZafKeyboard::Event(const ZafEventStruct &event)
{
	// Switch on the rawCode.
	switch (event.type)
	{
	case D_OFF:
	case D_ON:
		deviceState = event.type;
		break;
	}

	// Return the keyboard state.
	return (deviceState);
}

bool ZafKeyboard::IsA(ZafClassID compareID) const
{
	return ((compareID == classID) ? true : ZafDevice::IsA(compareID));
}

bool ZafKeyboard::IsA(ZafClassName compareName) const
{
	return (!strcmp(compareName, className) ? true : ZafDevice::IsA(compareName));
}

void ZafKeyboard::Poll(void)
{
	// Make sure the keyboard is valid.
	if (!installed)
		return;
#if !defined(USE_UGL_INPUT)
	unsigned shiftState;
	ZafEventStruct event;
	if (!I_KeyboardQuery(&shiftState))
	{
		// Put L_ALT_KEY on queue if pressed and released alone.
		if (AltPressed(shiftState) && altState == ZAF_ALT_NOT_PRESSED)
			altState = ZAF_ALT_PRESSED_NO_EVENTS;
		else if (!AltPressed(shiftState))
		{
			if (altState == ZAF_ALT_PRESSED_NO_EVENTS)
			{
				event.rawCode = 0;
				event.key.value = 0;
				event.key.shiftState = 0;
				event.type = L_ALT_KEY;
				if (deviceState != D_OFF)
					eventManager->Put(event, Q_END);
			}
			altState = ZAF_ALT_NOT_PRESSED;
		}
		return;
	}

	// Set the key information and call the event manager.
	if (altState == ZAF_ALT_PRESSED_NO_EVENTS)
		altState = ZAF_ALT_PRESSED_EVENTS;

	// Get the key from the low level driver.
	event.type = E_KEY;
	I_KeyboardRead(&event.rawCode, &event.key.shiftState, &event.key.value);
	if (event.rawCode > 0xFF)
		TranslateKeyEvent(event);
#if defined(ZAF_CURSES)
	event.modifiers = event.key.shiftState;
#elif defined(ZAF_INDEPENDENT)
	if (ShiftPressed(event.key.shiftState))
		event.modifiers |= S_SHIFT;
	if (CtrlPressed(event.key.shiftState))
		event.modifiers |= S_CTRL;
	if (AltPressed(event.key.shiftState))
		event.modifiers |= S_ALT;
#endif

	event.modifiers |= S_KEYDOWN;

#if defined(ZAF_UNICODE)
#	if (OS_API_CHAR_size == 1)
	OSAPIChar tmp[2] = { ((event.key.value >> 8) & 0xff), (event.key.value & 0xff) };
	if (tmp[0] == 0) tmp[0] = tmp[1];
	event.key.value = zafCodeSet->ConvertToZafChar(tmp);
#	else
	OSAPIChar tmp = event.key.value;
	zafCodeSet->ConvertToZafChar(&tmp, event.key.value);
#	endif
#elif defined(ZAF_ISO8859_1)
	OSAPIChar tmp = event.key.value;
#	if defined(USE_ZAF_CODE_SET_DATA)
	zafCodeSet->ConvertToZafChar(&tmp, event.key.value);
#	endif
#else
	// do nothing for OEM.
#endif
	// Place event on the queue.
	if (deviceState != D_OFF && eventManager)
	{
/* START BLOCK COMMENT
**			if (event.rawCode == CTRL_C || event.rawCode == CTRL_BREAK)
**			{
**				event.type = BreakHandlerSet();
**				eventManager->Put(event, Q_BEGIN);
**			}
**			else
**				eventManager->Put(event, Q_END);
END BLOCK COMMENT */
			eventManager->Put(event, Q_END);
	}
#else
	ugl_input_event uglEvent;
	ZafEventStruct event;
	if (InputQueuePoll(uglEvent, E_KEY) && deviceState != D_OFF && eventManager)
	{
		event.type = E_KEY;
		event.key.value = uglEvent.event.keyboard.key;
		event.rawCode   = uglEvent.event.keyboard.key & 0xffff; //??? Shouldn't have to mask
		event.modifiers = 0;
		if (uglEvent.event.keyboard.modifiers & UGL_INPUT_EVENT_KEYBOARD_KEYCAP_STATE)
			event.modifiers |= S_KEYDOWN;
		else
		{
			event.modifiers |= S_KEYUP;
			return; // Don't allow up events for now.
		}
		if (uglEvent.event.keyboard.modifiers & UGL_INPUT_EVENT_KEYBOARD_ALT)
			event.modifiers |= S_ALT;
		if (uglEvent.event.keyboard.modifiers & UGL_INPUT_EVENT_KEYBOARD_CTRL)
			event.modifiers |= S_CTRL;
		if (uglEvent.event.keyboard.modifiers & UGL_INPUT_EVENT_KEYBOARD_SHIFT)
			event.modifiers |= S_SHIFT;

		eventManager->Put(event, Q_END);
	}
#endif
}

struct ZafRawKeyMapStruct
{
	ZafRawCode unmappedCode;
	ZafRawCode mappedCode;
};

#if !defined(USE_UGL_INPUT)
static ZAF_EXPORT ZafRawKeyMapStruct rawKeyMap[] = 
{
	{ ALT_F1,							F1 },
	{ ALT_F2,							F2 },
	{ ALT_F3,							F3 },
	{ ALT_F4,							F4 },
	{ ALT_F5,							F5 },
	{ ALT_F6,							F6 },
	{ ALT_F7,							F7 },
	{ ALT_F8,							F8 },
	{ ALT_F9,							F9 },
	{ ALT_F10,							F10 },
	{ ALT_F11,							F11 },
	{ ALT_F12,							F12 },

	{ CTRL_ENTER,						ENTER },
	{ CTRL_BACKSPACE,					BACKSPACE },
	{ ALT_BACKSPACE,					BACKSPACE },
	{ CTRL_TAB,							TAB },
	{ BACKTAB,							TAB },
//	{ CTRL_BACKTAB,					TAB }, // Need a rawCode for this.

	{ ALT_A,								'a' },
	{ ALT_B,								'b' },
	{ ALT_C,								'c' },
	{ ALT_D,								'd' },
	{ ALT_E,								'e' },
	{ ALT_F,								'f' },
	{ ALT_G,								'g' },
	{ ALT_H,								'h' },
	{ ALT_I,								'i' },
	{ ALT_J,								'j' },
	{ ALT_K,								'k' },
	{ ALT_L,								'l' },
	{ ALT_M,								'm' },
	{ ALT_N,								'n' },
	{ ALT_O,								'o' },
	{ ALT_P,								'p' },
	{ ALT_Q,								'q' },
	{ ALT_R,								'r' },
	{ ALT_S,								's' },
	{ ALT_T,								't' },
	{ ALT_U,								'u' },
	{ ALT_V,								'v' },
	{ ALT_W,								'w' },
	{ ALT_X,								'x' },
	{ ALT_Y,								'y' },
	{ ALT_Z,								'z' },
	{ ALT_1,								'1' },
	{ ALT_2,								'2' },
	{ ALT_3,								'3' },
	{ ALT_4,								'4' },
	{ ALT_5,								'5' },
	{ ALT_6,								'6' },
	{ ALT_7,								'7' },
	{ ALT_8,								'8' },
	{ ALT_9,								'9' },
	{ ALT_0,								'0' },

	// ONLY CTRL_C is defined.
/* START BLOCK COMMENT
**		{ CTRL_A,							'a' },
**		{ CTRL_B,							'b' },
**		{ CTRL_C,							'c' },
**		{ CTRL_D,							'd' },
**		{ CTRL_E,							'e' },
**		{ CTRL_F,							'f' },
**		{ CTRL_G,							'g' },
**		{ CTRL_H,							'h' },
**		{ CTRL_I,							'i' },
**		{ CTRL_J,							'j' },
**		{ CTRL_K,							'k' },
**		{ CTRL_L,							'l' },
**		{ CTRL_M,							'm' },
**		{ CTRL_N,							'n' },
**		{ CTRL_O,							'o' },
**		{ CTRL_P,							'p' },
**		{ CTRL_Q,							'q' },
**		{ CTRL_R,							'r' },
**		{ CTRL_S,							's' },
**		{ CTRL_T,							't' },
**		{ CTRL_U,							'u' },
**		{ CTRL_V,							'v' },
**		{ CTRL_W,							'w' },
**		{ CTRL_X,							'x' },
**		{ CTRL_Y,							'y' },
**		{ CTRL_Z,							'z' },
**		{ CTRL_1,							'1' },
**		{ CTRL_2,							'2' },
**		{ CTRL_3,							'3' },
**		{ CTRL_4,							'4' },
**		{ CTRL_5,							'5' },
**		{ CTRL_6,							'6' },
**		{ CTRL_7,							'7' },
**		{ CTRL_8,							'8' },
**		{ CTRL_9,							'9' },
**		{ CTRL_0,							'0' },
END BLOCK COMMENT */

	{ SHIFT_F1,							F1 },
	{ SHIFT_F2,							F2 },
	{ SHIFT_F3,							F3 },
	{ SHIFT_F4,							F4 },
	{ SHIFT_F5,							F5 },
	{ SHIFT_F6,							F6 },
	{ SHIFT_F7,							F7 },
	{ SHIFT_F8,							F8 },
	{ SHIFT_F9,							F9 },
	{ SHIFT_F10,						F10 },
	{ SHIFT_F11,						F11 },
	{ SHIFT_F12,						F12 },

	{ CTRL_F1,							F1 },
	{ CTRL_F2,							F2 },
	{ CTRL_F3,							F3 },
	{ CTRL_F4,							F4 },
	{ CTRL_F5,							F5 },
	{ CTRL_F6,							F6 },
	{ CTRL_F7,							F7 },
	{ CTRL_F8,							F8 },
	{ CTRL_F9,							F9 },
	{ CTRL_F10,							F10 },
	{ CTRL_F11,							F11 },
	{ CTRL_F12,							F12 },

	{ ALT_ESCAPE,						ESCAPE },
	{ ALT_PERIOD,						'.' },
	{ ALT_SPACE,						SPACE },

	{ GRAY_CTRL_ENTER,	  			GRAY_ENTER },
	{ CTRL_GRAY_UP_ARROW,			GRAY_UP_ARROW },
	{ CTRL_GRAY_DOWN_ARROW,			GRAY_DOWN_ARROW },
	{ CTRL_GRAY_LEFT_ARROW,			GRAY_LEFT_ARROW },
	{ CTRL_GRAY_RIGHT_ARROW,		GRAY_RIGHT_ARROW },
	{ CTRL_GRAY_INSERT,				GRAY_INSERT },
	{ CTRL_GRAY_DELETE,				GRAY_DELETE },
	{ CTRL_GRAY_HOME,					GRAY_HOME },
	{ CTRL_GRAY_END,					GRAY_END },
	{ CTRL_GRAY_PGUP,					GRAY_PGUP },
	{ CTRL_GRAY_PGDN,					GRAY_PGDN },
	{ CTRL_GRAY_DIVIDE,				GRAY_DIVIDE },
	{ CTRL_GRAY_MULTIPLY,			GRAY_MULTIPLY },
	{ CTRL_GRAY_PLUS,					GRAY_PLUS },
	{ CTRL_GRAY_MINUS,				GRAY_MINUS },

	{ ALT_GRAY_UP_ARROW,				GRAY_UP_ARROW },
	{ ALT_GRAY_DOWN_ARROW,			GRAY_DOWN_ARROW },
	{ ALT_GRAY_LEFT_ARROW,			GRAY_LEFT_ARROW },
	{ ALT_GRAY_RIGHT_ARROW,			GRAY_RIGHT_ARROW },
	{ ALT_GRAY_INSERT,				GRAY_INSERT },
	{ ALT_GRAY_DELETE,				GRAY_DELETE },
	{ ALT_GRAY_HOME,					GRAY_HOME },
	{ ALT_GRAY_END,					GRAY_END },
	{ ALT_GRAY_PGUP,					GRAY_PGUP },
	{ ALT_GRAY_PGDN,					GRAY_PGDN },
	{ ALT_GRAY_DIVIDE,				GRAY_DIVIDE },
	{ ALT_GRAY_MULTIPLY,				GRAY_MULTIPLY },
	{ ALT_GRAY_PLUS,					GRAY_PLUS },
	{ ALT_GRAY_MINUS,					GRAY_MINUS },

	{ SHIFT_WHITE_UP_ARROW,			WHITE_UP_ARROW },
	{ SHIFT_WHITE_DOWN_ARROW,		WHITE_DOWN_ARROW },
	{ SHIFT_WHITE_LEFT_ARROW,		WHITE_LEFT_ARROW },
	{ SHIFT_WHITE_RIGHT_ARROW,		WHITE_RIGHT_ARROW },
	{ SHIFT_WHITE_INSERT,			WHITE_INSERT },
	{ SHIFT_WHITE_DELETE,			WHITE_DELETE },
	{ SHIFT_WHITE_HOME,				WHITE_HOME },
	{ SHIFT_WHITE_END,				WHITE_END },
	{ SHIFT_WHITE_PGUP,				WHITE_PGUP },
	{ SHIFT_WHITE_PGDN,				WHITE_PGDN },

	{ CTRL_WHITE_UP_ARROW,			WHITE_UP_ARROW },
	{ CTRL_WHITE_DOWN_ARROW,		WHITE_DOWN_ARROW },
	{ CTRL_WHITE_LEFT_ARROW,		WHITE_LEFT_ARROW },
	{ CTRL_WHITE_RIGHT_ARROW,		WHITE_RIGHT_ARROW },
	{ CTRL_WHITE_INSERT,				WHITE_INSERT },
	{ CTRL_WHITE_DELETE,				WHITE_DELETE },
	{ CTRL_WHITE_HOME,				WHITE_HOME },
	{ CTRL_WHITE_END,					WHITE_END },
	{ CTRL_WHITE_PGUP,				WHITE_PGUP },
	{ CTRL_WHITE_PGDN,				WHITE_PGDN },

	{ 0,									0}
};
#endif


struct ZafKeyMapStruct
{
	ZafRawCode unmappedCode;
	ZafIChar mappedChar;
};

#if !defined(USE_UGL_INPUT)
static ZAF_EXPORT ZafKeyMapStruct keyMap[] = 
{
	{ ALT_A,								'a' },
	{ ALT_B,								'b' },
	{ ALT_C,								'c' },
	{ ALT_D,								'd' },
	{ ALT_E,								'e' },
	{ ALT_F,								'f' },
	{ ALT_G,								'g' },
	{ ALT_H,								'h' },
	{ ALT_I,								'i' },
	{ ALT_J,								'j' },
	{ ALT_K,								'k' },
	{ ALT_L,								'l' },
	{ ALT_M,								'm' },
	{ ALT_N,								'n' },
	{ ALT_O,								'o' },
	{ ALT_P,								'p' },
	{ ALT_Q,								'q' },
	{ ALT_R,								'r' },
	{ ALT_S,								's' },
	{ ALT_T,								't' },
	{ ALT_U,								'u' },
	{ ALT_V,								'v' },
	{ ALT_W,								'w' },
	{ ALT_X,								'x' },
	{ ALT_Y,								'y' },
	{ ALT_Z,								'z' },
	{ ALT_1,								'1' },
	{ ALT_2,								'2' },
	{ ALT_3,								'3' },
	{ ALT_4,								'4' },
	{ ALT_5,								'5' },
	{ ALT_6,								'6' },
	{ ALT_7,								'7' },
	{ ALT_8,								'8' },
	{ ALT_9,								'9' },
	{ ALT_0,								'0' },

	{ ALT_PERIOD,						'.' },
	{ ALT_SPACE,						' ' },

	{ 0,									0}
};
#else
static ZAF_EXPORT ZafKeyMapStruct keyMap[] = 
{
	{ WHITE_INSERT,								0x2 },

	{ 0,									0}
};
#endif

static ZAF_EXPORT ZafKeyMapStruct keypadMap[] =
{
	{ SHIFT_WHITE_UP_ARROW,		0},
	{ SHIFT_WHITE_DOWN_ARROW, 	0},
	{ SHIFT_WHITE_LEFT_ARROW, 	0},
	{ SHIFT_WHITE_RIGHT_ARROW, 0},
	{ SHIFT_WHITE_INSERT, 		0},
	{ SHIFT_WHITE_DELETE, 		0},
	{ SHIFT_WHITE_HOME, 			0},
	{ SHIFT_WHITE_END, 			0},
	{ SHIFT_WHITE_PGUP, 			0},
	{ SHIFT_WHITE_PGDN, 			0},
	{ 0,								0}
};

void TranslateKeyEvent(ZafEventStruct &event)
{
	for (ZafKeyMapStruct *charMap = keyMap; charMap->unmappedCode; charMap++)
		if (event.rawCode == charMap->unmappedCode)
		{
			event.key.value = charMap->mappedChar;
			break;
		}

#if !defined(USE_UGL_INPUT)
	if (event.key.shiftState & S_NUM_LOCK)
		for (ZafKeyMapStruct *padMap = keypadMap; padMap->unmappedCode;
			padMap++)
			if (event.rawCode == padMap->unmappedCode)
			{
				ZafRawCode newCode = (event.rawCode & 0xff);
				newCode += ((newCode & 0x0f) << 8) + 0x100;
				event.rawCode = newCode;
				break;
			}
#endif

#if !defined(USE_UGL_INPUT)
	for (ZafRawKeyMapStruct *map = rawKeyMap; map->unmappedCode; map++)
		if (event.rawCode == map->unmappedCode)
		{
			event.rawCode = map->mappedCode;
			break;
		}
	if (event.rawCode >= 'a' && event.rawCode <= 'z')
		event.rawCode -= 'a' - 'A';	// shiftState should be enough.
#endif
}

