/*
    Sample Linux ZiNc keyboard plugin v1.2

    Public domain: use and enjoy!

 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>

// these files will get modified for newer versions of ZiNc
#include "controller_defines.h"
#include "game_defines.h"

// callback for GPU plugin to get keys
//void GPUkeypressed(int keycode);
extern void (*GPU_keypressed)(int keycode);

typedef struct
{
    unsigned char key;
    unsigned long bit;
} ipc_keystate;

typedef struct
{
	int				count;
	ipc_keystate	player1[16];
	ipc_keystate	player2[16];
	ipc_keystate	player3[16];
	ipc_keystate	player4[16];
} ipc_keystates_t;

// This is an ugly hack to quickly port the Win32 version.  Sorry to those offended ;)
#define DIK_RIGHT 0x53
#define DIK_LEFT  0x51
#define DIK_DOWN  0x54
#define DIK_UP    0x52
#define DIK_1	'1'
#define DIK_2	'2'
#define DIK_3	'3'
#define DIK_4	'4'
#define DIK_5	'5'
#define DIK_6	'6'
#define DIK_7	'7'
#define DIK_8	'8'
#define DIK_9	'9'
#define DIK_0	'0'
#define DIK_Q	'q'
#define DIK_W	'w'
#define DIK_E	'e'
#define DIK_R	'r'
#define DIK_T	't'
#define DIK_Y   'y'
#define DIK_U	'u'
#define DIK_I	'i'
#define DIK_O	'o'
#define DIK_P	'p'
#define DIK_A	'a'
#define DIK_S	's'
#define DIK_D	'd'
#define DIK_F	'f'
#define DIK_G	'g'
#define DIK_H	'h'
#define DIK_J	'j'
#define DIK_K	'k'
#define DIK_L	'l'
#define DIK_Z	'z'
#define DIK_X	'x'
#define DIK_C	'c'
#define DIK_B	'b'
#define DIK_N	'n'
#define DIK_M	'm'
#define DIK_V	'v'

ipc_keystates_t s11_pad_states =
{
	16,
	{	// player 1 keys
		{DIK_RIGHT, 8},
		{DIK_LEFT, 9},
		{DIK_DOWN, 10},
		{DIK_UP, 11},
		{DIK_R, 0},
		{DIK_Q, 1},
		{DIK_W, 2},
		{DIK_E, 3},
		{DIK_F, 4},
		{DIK_Z, 5},
		{DIK_X, 6},
		{DIK_C, 7},
		{DIK_A, 12},
		{DIK_S, 13},
		{DIK_D, 14},
		{DIK_1, 15},		// start
	},
	{	// player 2 keys
		{DIK_U, 8},
		{DIK_U, 9},
		{DIK_U, 10},
		{DIK_U, 11},
		{DIK_U, 0},
		{DIK_U, 1},
		{DIK_U, 2},
		{DIK_U, 3},
		{DIK_U, 4},
		{DIK_U, 5},
		{DIK_U, 6},
		{DIK_U, 7},
		{DIK_U, 12},
		{DIK_U, 13},
		{DIK_U, 14},
		{DIK_2, 15},		// start
	},
	{	// player 3 keys
		{DIK_I, 8},
		{DIK_I, 9},
		{DIK_I, 10},
		{DIK_I, 11},
		{DIK_I, 0},
		{DIK_I, 1},
		{DIK_I, 2},
		{DIK_I, 3},
		{DIK_I, 4},
		{DIK_I, 5},
		{DIK_I, 6},
		{DIK_I, 7},
		{DIK_Z, 12},		// tekken 2 kick1
		{DIK_X, 13},		// tekken 2 kick2, souledge block
		{DIK_I, 14},
		{DIK_3, 15},		// start
	},
	{	// player 4 keys
		{DIK_O, 8},
		{DIK_O, 9},
		{DIK_O, 10},
		{DIK_O, 11},
		{DIK_O, 0},
		{DIK_O, 1},
		{DIK_O, 2},
		{DIK_O, 3},
		{DIK_O, 4},
		{DIK_O, 5},
		{DIK_O, 6},
		{DIK_O, 7},
		{DIK_O, 12},
		{DIK_O, 13},
		{DIK_O, 14},
		{DIK_4, 15},		// start
	},

};

ipc_keystates_t s12_pad_states =
{
	16,
	{	// player 1 keys
		{DIK_R, 0},	// unused
		{DIK_Z, 1},	// p1 b4   
		{DIK_X, 2},	// p1 b5
		{DIK_C, 3},	// p1 b6
		{DIK_R, 4},	// unused
		{DIK_J, 5},	// p2 b4
		{DIK_K, 6},	// p2 b5
		{DIK_L, 7},	// p2 b6   
		{DIK_RIGHT, 8}, // p1 right 
		{DIK_LEFT, 9},  // p1 left  
		{DIK_DOWN, 10}, // p1 down  
		{DIK_UP, 11}, 	// p1 up    
		{DIK_A, 12},	// p1 b1       
		{DIK_S, 13},	// p1 b2       
		{DIK_D, 14},
	// p1 b3    
		{DIK_1, 15},	// p1 start    
	},
	{	// player 2 keys
		{DIK_R, 0},  // unused
		{DIK_R, 1},  // unused
		{DIK_R, 2},  // unused
		{DIK_R, 3},  // unused
		{DIK_6, 4},  // coin 2
		{DIK_5, 5},  // coin 1
		{DIK_4, 6},  // test
		{DIK_7, 7},  // service
		{DIK_M, 8},  // p2 right
		{DIK_B, 9},  // p2 left
		{DIK_N, 10}, // p2 down
		{DIK_H, 11}, // p2 up
		{DIK_U, 12}, // p2 b1
		{DIK_I, 13}, // p2 b2
		{DIK_O, 14}, // p2 b3
		{DIK_2, 15}, // p2 start
	},
	{	// player 3 keys
		{DIK_I, 8},
		{DIK_I, 9},
		{DIK_I, 10},
		{DIK_I, 11},
		{DIK_I, 0},
		{DIK_I, 1},
		{DIK_I, 2},
		{DIK_I, 3},
		{DIK_I, 4},
		{DIK_I, 5},
		{DIK_I, 6},
		{DIK_I, 7},
		{DIK_Z, 12},		// tekken 2 kick1
		{DIK_X, 13},		// tekken 2 kick2, souledge block
		{DIK_I, 14},
		{DIK_3, 15},		// start
	},
	{	// player 4 keys
		{DIK_O, 8},
		{DIK_O, 9},
		{DIK_O, 10},
		{DIK_O, 11},
		{DIK_O, 0},
		{DIK_O, 1},
		{DIK_O, 2},
		{DIK_O, 3},
		{DIK_O, 4},
		{DIK_O, 5},
		{DIK_O, 6},
		{DIK_O, 7},
		{DIK_O, 12},
		{DIK_O, 13},
		{DIK_O, 14},
		{DIK_4, 15},		// start
	},

};

ipc_keystates_t zn1_pad_states =
{
	11,
	{
		{DIK_RIGHT, 3},
		{DIK_LEFT, 2},
		{DIK_DOWN, 1},
		{DIK_UP, 0},
		{DIK_A, 4},
		{DIK_S, 5},
		{DIK_D, 6},
	        {DIK_1, 8},  
		{DIK_Z, 12},
		{DIK_X, 13},
		{DIK_C, 14},
	},
	{
		{DIK_M, 3},
		{DIK_B, 2},
		{DIK_N, 1},
		{DIK_H, 0},
		{DIK_J, 4},
		{DIK_K, 5},
		{DIK_L, 6},
 	    	{DIK_2, 8}, 
		{DIK_U, 12},
		{DIK_I, 13},
		{DIK_O, 14},
	}
};

ipc_keystates_t gv_pad_states =
{
	11,
	{
		{DIK_LEFT, 0},
		{DIK_RIGHT, 1},
		{DIK_UP, 2},
		{DIK_DOWN, 3},
		{DIK_A, 4},
		{DIK_S, 5},
		{DIK_D, 6},
	    	{DIK_1, 7},  
	},
	{
		{DIK_B, 0},	// p2 left
		{DIK_M, 1},	// p2 right
		{DIK_H, 2},	// p2 up
		{DIK_N, 3},	// p2 down
		{DIK_U, 4},
		{DIK_I, 5},
		{DIK_O, 6},
	    	{DIK_2, 7},  
	}
};

ipc_keystates_t null_pad_states =
{
	0
};

ipc_keystates_t *j_pad_states;



ipc_keystate j_coinslot_states[] =
{
    {'5',       JAMMA_CTRL_COIN1},	// coin for player 1
    {'6',       JAMMA_CTRL_COIN2},	// coin for player 2
    {'4',	JAMMA_CTRL_TEST},	// test switch
    {'7',	JAMMA_CTRL_SERVICE},	// service switch
};

unsigned char keys[256];

static Display *display;

long ZN_JammaOpen(unsigned long disp, vendor_id_t vendor_id, game_id_t game, char *cfg)
{
	switch(vendor_id)
	{
	case MACHINE_NAMCO_S12:
		j_pad_states = &s12_pad_states;
		break;
	case MACHINE_NAMCO_S11:
	case MACHINE_KONAMI_SYS573:
		j_pad_states = &s11_pad_states;
		break;
	case MACHINE_CAPCOM_ZN1:
	case MACHINE_TAITO_FX1A:
	case MACHINE_TAITO_FX1A2:
	case MACHINE_TAITO_FX1A3:
	case MACHINE_TECMO_TPS:
	case MACHINE_ATARI_ZN:
	case MACHINE_RAIZING_ZN:
	case MACHINE_BANPRESTO_KN1:
		j_pad_states = &zn1_pad_states;
		break;
	case MACHINE_KONAMI_GV:
		j_pad_states = &gv_pad_states;
		break;
	case MACHINE_UNKNOWN:
	default:
		printf("ERROR: System not yet supported by keyboard plugin\n");
		j_pad_states = &null_pad_states;
		break;
	}

	display = (Display *)disp;

	return 0;
}

long ZN_JammaClose(void)
{
	return 0;
}

long ZN_JammaRead(jamma_t *jamma)
{
	unsigned short i;
	XEvent E;
	int keycode;
	int retval = 0;

	while ( XPending(display) )
	{
		XNextEvent(display,&E);

		switch (E.type)
		{
		case DestroyNotify:
			retval = -1;
			break;

		case KeyPress:
			keycode = XLookupKeysym ((XKeyEvent *) &E, 0);
			keys[keycode & 0xff] = 0x80;
			break;
			
		case KeyRelease:
			keycode = XLookupKeysym ((XKeyEvent *) &E, 0);
			keys[keycode & 0xff] = 0;

			retval = keycode;
			break;
		}
	}

	// LINUX: non-zero means "quit"
	if (keys[27] == 0x80)
	{	
		retval = -1;
	}

	jamma->controls = 0;
	for (i=0;i<4;i++)
	if (keys[j_coinslot_states[i].key] &0x80)
	        jamma->controls |= j_coinslot_states[i].bit;

	jamma->players[0] = jamma->players[1] = jamma->players[2] = jamma->players[3] = 0;
	for (i=0;i<j_pad_states->count;i++)
	{
		if (keys[j_pad_states->player1[i].key] &0x80)
		{
			jamma->players[0] |= 1 << j_pad_states->player1[i].bit;
		}
	
		if (keys[j_pad_states->player2[i].key] &0x80)
		{
			jamma->players[1] |= 1 << j_pad_states->player2[i].bit;
		}
	
		if (keys[j_pad_states->player3[i].key] &0x80)
		{
			jamma->players[2] |= 1 << j_pad_states->player3[i].bit;
		}
	
		if (keys[j_pad_states->player4[i].key] &0x80)
		{
			jamma->players[3] |= 1 << j_pad_states->player4[i].bit;
		}
	}

	return retval;
}

