
//#include <stdio.h>
#include "keycode.h"

#define NULL 0

#define PREFIX_E0 0x100

static const struct EncodeTable {
	unsigned char number;
	unsigned short code;
} encodetable[] = {
	1,    0x0e,
	2,    0x16,
	3,    0x1e,
	4,    0x26,
	5,    0x25,
	6,    0x2e,
	7,    0x36,
	8,    0x3d,
	9,    0x3e,
	10,   0x46,
	11,   0x45,
	12,   0x4e,
	13,   0x55,
	14,   0x6a,
	15,   0x66,
	16,   0x0d,
	17,   0x15,
	18,   0x1d,
	19,   0x24,
	20,   0x2d,
	21,   0x2c,
	22,   0x35,
	23,   0x3c,
	24,   0x43,
	25,   0x44,
	26,   0x4d,
	27,   0x54,
	28,   0x5b,
	29,   0x5d,
	30,   0x58,
	31,   0x1c,
	32,   0x1b,
	33,   0x23,
	34,   0x2b,
	35,   0x34,
	36,   0x33,
	37,   0x3b,
	38,   0x42,
	39,   0x4b,
	40,   0x4c,
	41,   0x52,
	42,   0x5d,
	43,   0x5a,
	44,   0x12,
	45,   0x61,
	46,   0x1a,
	47,   0x22,
	48,   0x21,
	49,   0x2a,
	50,   0x32,
	51,   0x31,
	52,   0x3a,
	53,   0x41,
	54,   0x49,
	55,   0x4a,
	56,   0x51,
	57,   0x59,
	58,   0x14,
	60,   0x11,
	61,   0x29,
	62,   0x11 | PREFIX_E0,
	64,   0x14 | PREFIX_E0,
	75,   0x70 | PREFIX_E0,
	76,   0x71 | PREFIX_E0,
	79,   0x6b | PREFIX_E0,
	80,   0x6c | PREFIX_E0,
	81,   0x69 | PREFIX_E0,
	83,   0x75 | PREFIX_E0,
	84,   0x72 | PREFIX_E0,
	85,   0x7d | PREFIX_E0,
	86,   0x7a | PREFIX_E0,
	89,   0x74 | PREFIX_E0,
	90,   0x77,
	91,   0x6c,
	92,   0x6b,
	93,   0x69,
	95,   0x4a | PREFIX_E0,
	96,   0x75,
	97,   0x73,
	98,   0x72,
	99,   0x70,
	100,  0x7c,
	101,  0x7d,
	102,  0x74,
	103,  0x7a,
	104,  0x71,
	105,  0x7b,
	106,  0x79,
	108,  0x5a | PREFIX_E0,
	110,  0x76,
	112,  0x05,
	113,  0x06,
	114,  0x04,
	115,  0x0c,
	116,  0x03,
	117,  0x0b,
	118,  0x83,
	119,  0x0a,
	120,  0x01,
	121,  0x09,
	122,  0x78,
	123,  0x07,
	125,  0x7e,
	131,  0x67,
	132,  0x64,
	133,  0x13,
};
enum {
	encodetablecount = sizeof(encodetable) / sizeof(struct EncodeTable),
};



static const unsigned char decodetable[] = {
	  0, 120,   0, 116, 114, 112, 113, 123,   0, 121, 119, 117, 115,  16,   1,   0,
	  0,  60,  44, 133,  58,  17,   2,   0,   0,   0,  46,  32,  31,  18,   3,   0,
	  0,  48,  47,  33,  19,   5,   4,   0,   0,  61,  49,  34,  21,  20,   6,   0,
	  0,  51,  50,  36,  35,  22,   7,   0,   0,   0,  52,  37,  23,   8,   9,   0,
	  0,  53,  38,  24,  25,  11,  10,   0,   0,  54,  55,  39,  40,  26,  12,   0,
	  0,  56,  41,   0,  27,  13,   0,   0,  30,  57,  43,  28,   0,  42,   0,   0,
	  0,  45,   0,   0, 132,   0,  15, 131,   0,  93,  14,  92,  91,   0,   0,   0,
	 99, 104,  98,  97, 102,  96, 110,  90, 122, 106, 103, 105, 100, 101, 125,   0,
	  0,   0,   0, 118, 124,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
	  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
	  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
	  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
	  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
	  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
	  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
	  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
};



unsigned short DecodeKeyCode(unsigned short *state, int c)
{
	enum {
		_PREFIX_E0 = 0x01,
		_PREFIX_E1 = 0x02,
		_KEYBREAK = 0x80,
		_IGNORE_90 = 0x100,
	};

	unsigned short code;

	code = 0;
	if (c == 0xf0) {
		*state |= _KEYBREAK;
	} else if (c == 0xe0) {
		*state = _PREFIX_E0;
	} else if (c == 0xe1) {
		*state = _PREFIX_E1;
	} else if (c < 0xe0) {
		switch (*state & 0x03) {
		case 0:
			code = decodetable[c];
			break;
		case _PREFIX_E0:
			switch (c) {
			case 0x11:	code = 62;		break;
			case 0x14:	code = 64;		break;
			case 0x70:	code = 75;		break;
			case 0x71:	code = 76;		break;
			case 0x6b:	code = 79;		break;
			case 0x6c:	code = 80;		break;
			case 0x69:	code = 81;		break;
			case 0x75:	code = 83;		break;
			case 0x72:	code = 84;		break;
			case 0x7d:	code = 85;		break;
			case 0x7a:	code = 86;		break;
			case 0x74:	code = 89;		break;
			case 0x4a:	code = 95;		break;
			case 0x5a:	code = 108;		break;
			case 0x7c:	code = 124;		break;
			case 0x7e:	code = 126;		break;
			}
			break;
		case _PREFIX_E1:
			switch (c) {
			case 0x14:	code = 126;		break;
			}
			break;
		}

		{
			unsigned short newstate = 0;
			if (code > 0) {
				if (code == 90 && (*state & _IGNORE_90)) {
					code = 0;
				} else {
					if (code == 126) newstate |= _IGNORE_90;
					if (*state & _KEYBREAK) code |= 0x8000;
				}
			}
			*state = newstate;
		}
	}
	return code;
}

int EncodeKeyCode(int number, unsigned short keyflag, void (*output)(int c, void *cookie), void *cookie)
{
	static const unsigned char _make124_default[] =
		"\xe0\x12\xe0\x7c";
	static const unsigned char _make124_shift_ctrl[] =
		"\xe0\x7c";
	static const unsigned char _make124_alt[] =
		"\x84";
	static const unsigned char _break124_default[] =
		"\xe0\xf0\x7c\xe0\xf0\x12";
	static const unsigned char _break124_shift_ctrl[] =
		"\xe0\xf0\x7c";
	static const unsigned char _break124_alt[] =
		"\xf0\x84";
	static const unsigned char _make126_default[] =
		"\xe1\x14\x77\xe1\xf0\x14\xf0\x77";
	static const unsigned char _make126_ctrl[] =
		"\xe0\x7e\xe0\xf0\x7e";

	int i, pos, len, key;
	const unsigned char *stream, *prefix, *suffix;
	unsigned char _stream[10];

	stream = prefix = suffix = NULL;

	if (number == 124) {
		if (keyflag & KEYFLAG_MAKE) {
			if (keyflag & (KEYFLAG_SHIFT | KEYFLAG_CTRL)) {
				stream = _make124_shift_ctrl;
			} else if (keyflag & KEYFLAG_ALT) {
				stream = _make124_alt;
			} else {
				stream = _make124_default;
			}
		} else {
			if (keyflag & (KEYFLAG_SHIFT | KEYFLAG_CTRL)) {
				stream = _break124_shift_ctrl;
			} else if (keyflag & KEYFLAG_ALT) {
				stream = _break124_alt;
			} else {
				stream = _break124_default;
			}
		}
	} else if (number == 126) {
		if (keyflag & KEYFLAG_MAKE) {
			if (keyflag & KEYFLAG_CTRL) {
				stream = _make126_ctrl;
			} else {
				stream = _make126_default;
			}
		} else {
			// nothing
		}
	} else {
		pos = 0;
		len = encodetablecount;
		key = number;

		while (len > 0) {
			i = encodetable[pos + len / 2].number - key;
			if (!i) {
				unsigned short code = encodetable[pos + len / 2].code;
				i = 0;
				if (code & PREFIX_E0) _stream[i++] = 0xe0;
				if (!(keyflag & KEYFLAG_MAKE)) {
					_stream[i++] = 0xf0;
				}
				_stream[i++] = code;
				_stream[i] = 0;
				stream = _stream;
				break;
			}
			if (i < 0) {
				pos = pos + len / 2 + 1;
				len--;
			}
			len /= 2;
		}
	}
	if (!stream) return -1;

	if (number >= 75 && number <= 89) {
		if (keyflag & KEYFLAG_MAKE) {
			if (keyflag & KEYFLAG_SHIFT) {
				prefix = "\xe0\xf0\x12";
			} else if (keyflag & KEYFLAG_NUMLOCK) {
				prefix = "\xe0\x12";
			}
		} else {
			if (keyflag & KEYFLAG_SHIFT) {
				suffix = "\xe0\x12";
			} else if (keyflag & KEYFLAG_NUMLOCK) {
				suffix = "\xe0\xf0\x12";
			}
		}
	}
	if (prefix) {
		for (i = 0; prefix[i]; i++) {
			output(prefix[i], cookie);
		}
	}
	for (i = 0; stream[i]; i++) {
		output(stream[i], cookie);
	}
	if (suffix) {
		for (i = 0; suffix[i]; i++) {
			output(suffix[i], cookie);
		}
	}

	return 0;
}



#if 0

void _output(int c, void *cookie)
{
	printf(" %02x", c);
}



int main(int ac, char **av)
{
	int c, i, j, t;
	unsigned short state = 0;

#if 0
	for (i = 1; i < ac; i++) {
		sscanf(av[i], "%x", &c);
		t = DecodeKeyCode(&state, c);
		if (t > 0) printf("[%d]\n", t);
	}
#elif 01
	for (i = 1; i < ac; i++) {
		sscanf(av[i], "%d", &c);
		EncodeKeyCode(c, 0, _output, NULL);
		putchar('\n');
	}
#elif 1
	for (i = 1; i < ac; i++) {
		sscanf(av[i], "%x", &c);
		t = _decode(c);
		if (t > 0) printf("[%d]\n", t);
	}
#endif
	return 0;
}

#endif

