/***************************************************************************

  inptport.c

  Input ports handling

TODO:	remove the 1 analog device per port limitation
		support for inputports producing interrupts
		support for extra "real" hardware (PC throttle's, spinners etc)

***************************************************************************/

#include "driver.h"
#include <math.h>
#include "ui_text.h"

/* header identifying the version of the game.cfg file */
/* mame 0.36b11 */
#define MAMECFGSTRING_V5 "MAMECFG\5"
#define MAMEDEFSTRING_V5 "MAMEDEF\4"

/* mame 0.36b12 with multi key/joy extension */
#define MAMECFGSTRING_V6 "MAMECFG\6"
#define MAMEDEFSTRING_V6 "MAMEDEF\5"

/* mame 0.36b13 with and/or/not combination */
#define MAMECFGSTRING_V7 "MAMECFG\7"
#define MAMEDEFSTRING_V7 "MAMEDEF\6"

/* mame 0.36b16 with key/joy merge */
#define MAMECFGSTRING_V8 "MAMECFG\x8"
#define MAMEDEFSTRING_V8 "MAMEDEF\7"

extern void *record;
extern void *playback;
extern short cpu_clocks[];

extern unsigned int dispensed_tickets;
extern unsigned int coins[COIN_COUNTERS];
extern unsigned int lastcoin[COIN_COUNTERS];
extern unsigned int coinlockedout[COIN_COUNTERS];

static unsigned short input_port_value[MAX_INPUT_PORTS];
static unsigned short input_vblank[MAX_INPUT_PORTS];

/* Assuming a maxium of one analog input device per port BW 101297 */
static struct InputPort *input_analog[MAX_INPUT_PORTS];
static int input_analog_current_value[MAX_INPUT_PORTS],input_analog_previous_value[MAX_INPUT_PORTS];
static int input_analog_init[MAX_INPUT_PORTS];
static int input_analog_scale[MAX_INPUT_PORTS];

static InputCode analogjoy_input[OSD_MAX_JOY_ANALOG][MAX_ANALOG_AXES];	/* [player#][mame axis#] array */

static int mouse_delta_axis[OSD_MAX_JOY_ANALOG][MAX_ANALOG_AXES];
static int analog_current_axis[OSD_MAX_JOY_ANALOG][MAX_ANALOG_AXES];
static int analog_previous_axis[OSD_MAX_JOY_ANALOG][MAX_ANALOG_AXES];

static int pback;

#define MAX_INPUT	256
static int common_input_ports;
//static int neogeo_input_ports;
//static int cps_input_ports;

#define MAX_INPUT_BITS  1024
static int auto_pressed(InputSeq *seq, UINT32 type, int bit);
static UINT8  autopressed[MAX_INPUT_BITS];
static UINT32 autofire_enable;

#define MAX_BUTTON	6
static int playing_no = 0;
static UINT16 custom_port[2][MAX_BUTTON], custom_mask[2][MAX_BUTTON];

int show_input = 0;
UINT8 command_buf[COMMAND_LOG_BUFSIZE];
int command_counter = 0;

UINT16 custom_button[2][4];
int button_number = 0;

static void make_input_log(void);


/***************************************************************************

  Configuration load/save

***************************************************************************/

struct ipd inputport_common[] =
{
	{ IPT_UI_CONFIGURE,			portname(ConfigMenu),			SEQ_DEF_1(KEYCODE_TAB) },
	{ IPT_UI_ON_SCREEN_DISPLAY,	portname(OnScreenDisplay),		SEQ_DEF_1(KEYCODE_OPENBRACE) },
	{ IPT_UI_PAUSE,				portname(Pause),				SEQ_DEF_1(KEYCODE_P) },
	{ IPT_UI_SINGLE_STEP,		portname(SingleStep),			SEQ_DEF_1(KEYCODE_O) },
	{ IPT_UI_RESET_MACHINE,		portname(ResetGame),			SEQ_DEF_1(KEYCODE_F3) },
	{ IPT_UI_SHOW_GFX,			portname(ShowGfx),				SEQ_DEF_1(KEYCODE_F4) },
	{ IPT_UI_FRAMESKIP_DEC,		portname(FrameskipDec),			SEQ_DEF_1(KEYCODE_F8) },
	{ IPT_UI_FRAMESKIP_INC,		portname(FrameskipInc),			SEQ_DEF_1(KEYCODE_F9) },
	{ IPT_UI_THROTTLE,			portname(Throttole),			SEQ_DEF_1(KEYCODE_F10) },
	{ IPT_UI_SHOW_FPS,			portname(ShowFPS),				SEQ_DEF_5(KEYCODE_F11, CODE_NOT, KEYCODE_LCONTROL, CODE_NOT, KEYCODE_LSHIFT) },
	{ IPT_UI_SHOW_PROFILER,		portname(ShowProfiler),			SEQ_DEF_2(KEYCODE_F11, KEYCODE_LSHIFT) },
	{ IPT_UI_SNAPSHOT,			portname(SaveSnapshot),			SEQ_DEF_1(KEYCODE_F12) },
	{ IPT_UI_TOGGLE_CHEAT,		portname(ToggleCheat),			SEQ_DEF_1(KEYCODE_F6) },
	{ IPT_UI_SAVE_STATE,		portname(SaveState),			SEQ_DEF_2(KEYCODE_F7, KEYCODE_LSHIFT) },
	{ IPT_UI_LOAD_STATE,		portname(LoadState),			SEQ_DEF_3(KEYCODE_F7, CODE_NOT, KEYCODE_LSHIFT) },
	{ IPT_UI_ADD_CHEAT,			portname(AddCheat),				SEQ_DEF_1(KEYCODE_NONE) },
	{ IPT_UI_DELETE_CHEAT,		portname(DeleteCheat),			SEQ_DEF_1(KEYCODE_NONE) },
	{ IPT_UI_SAVE_CHEAT,		portname(SaveCheat),			SEQ_DEF_1(KEYCODE_NONE) },
	{ IPT_UI_WATCH_VALUE,		portname(WatchValue),			SEQ_DEF_1(KEYCODE_NONE) },
	{ IPT_UI_EDIT_CHEAT,		portname(EditCheat),			SEQ_DEF_1(KEYCODE_NONE) },
	{ IPT_UI_TOGGLE_DISPLAY,	portname(ChangeScreenMode),		SEQ_DEF_2(KEYCODE_LALT, KEYCODE_ENTER) },
	{ IPT_UI_TOGGLE_AUTOFIRE,	portname(ToggleAutofire),		SEQ_DEF_1(KEYCODE_COLON) },
	{ IPT_UI_TOGGLE_LOGWAVE,	portname(ToggleWaveRecording),	SEQ_DEF_1(KEYCODE_BACKSPACE) },
	{ IPT_UI_SHOW_INPUT_LOG,	portname(ShowInputLog),			SEQ_DEF_1(KEYCODE_DEL) },
	{ IPT_UI_OPERATION_OBJ,		portname(OperationObj),			SEQ_DEF_1(KEYCODE_HOME) },
	{ IPT_UI_COMMAND,			portname(ShowCommandList),		SEQ_DEF_1(KEYCODE_END) },
	{ IPT_UI_CHEAT,				portname(ShowCheatList),		SEQ_DEF_1(KEYCODE_RCONTROL) },
	{ IPT_UI_TIME,				portname(ShowTime),				SEQ_DEF_1(KEYCODE_CLOSEBRACE) },
	{ IPT_UI_UP,				portname(UIUp),					SEQ_DEF_3(KEYCODE_UP, CODE_OR, JOYCODE_1_UP) },
	{ IPT_UI_DOWN,				portname(UIDown),				SEQ_DEF_3(KEYCODE_DOWN, CODE_OR, JOYCODE_1_DOWN) },
	{ IPT_UI_LEFT,				portname(UILeft),				SEQ_DEF_3(KEYCODE_LEFT, CODE_OR, JOYCODE_1_LEFT) },
	{ IPT_UI_RIGHT,				portname(UIRight),				SEQ_DEF_3(KEYCODE_RIGHT, CODE_OR, JOYCODE_1_RIGHT) },
	{ IPT_UI_SELECT,			portname(UISelect),				SEQ_DEF_3(KEYCODE_ENTER, CODE_OR, JOYCODE_1_BUTTON1) },
	{ IPT_UI_CANCEL,			portname(UICancel),				SEQ_DEF_3(KEYCODE_ESC, CODE_NOT, KEYCODE_LSHIFT) },
	{ IPT_UI_CLOSE,				portname(UIClose),				SEQ_DEF_2(KEYCODE_ESC, KEYCODE_LSHIFT) },
	{ IPT_END,					0,								SEQ_DEF_0 }	/* returned when there is no match */
};

struct ipd inputport_neogeo[] =
{
	{ IPT_START1,	portname(P1Start),	SEQ_DEF_1(KEYCODE_1) },
	{ IPT_START2,	portname(P2Start),	SEQ_DEF_1(KEYCODE_2) },
	{ IPT_SELECT1,	portname(P1Select),	SEQ_DEF_1(KEYCODE_3) },
	{ IPT_SELECT2,	portname(P2Select),	SEQ_DEF_1(KEYCODE_4) },
	{ IPT_COIN1,	portname(Coin1),	SEQ_DEF_1(KEYCODE_5) },
	{ IPT_COIN2,	portname(Coin2),	SEQ_DEF_1(KEYCODE_6) },
	{ IPT_SERVICE1,	portname(Service),	SEQ_DEF_1(KEYCODE_9) },

	{ IPT_JOYSTICK_UP		| IPF_PLAYER1, portname(P1Up),		SEQ_DEF_3(KEYCODE_UP, CODE_OR, JOYCODE_1_UP)    },
	{ IPT_JOYSTICK_DOWN		| IPF_PLAYER1, portname(P1Down),	SEQ_DEF_3(KEYCODE_DOWN, CODE_OR, JOYCODE_1_DOWN)  },
	{ IPT_JOYSTICK_LEFT		| IPF_PLAYER1, portname(P1Left),	SEQ_DEF_3(KEYCODE_LEFT, CODE_OR, JOYCODE_1_LEFT)  },
	{ IPT_JOYSTICK_RIGHT	| IPF_PLAYER1, portname(P1Right),	SEQ_DEF_3(KEYCODE_RIGHT, CODE_OR, JOYCODE_1_RIGHT) },
	{ IPT_BUTTON1			| IPF_PLAYER1, portname(P1ButtonA),	SEQ_DEF_5(KEYCODE_A, CODE_OR, JOYCODE_1_BUTTON1, CODE_OR, JOYCODE_MOUSE_1_BUTTON1) },
	{ IPT_BUTTON2			| IPF_PLAYER1, portname(P1ButtonB),	SEQ_DEF_5(KEYCODE_S, CODE_OR, JOYCODE_1_BUTTON2, CODE_OR, JOYCODE_MOUSE_1_BUTTON3) },
	{ IPT_BUTTON3			| IPF_PLAYER1, portname(P1ButtonC),	SEQ_DEF_5(KEYCODE_D, CODE_OR, JOYCODE_1_BUTTON3, CODE_OR, JOYCODE_MOUSE_1_BUTTON2) },
	{ IPT_BUTTON4			| IPF_PLAYER1, portname(P1ButtonD),	SEQ_DEF_3(KEYCODE_F, CODE_OR, JOYCODE_1_BUTTON4) },
	{ IPT_CUSTOM1			| IPF_PLAYER1, portname(P1Custom1),	SEQ_DEF_3(KEYCODE_Z, CODE_OR, JOYCODE_1_BUTTON5) },
	{ IPT_CUSTOM2			| IPF_PLAYER1, portname(P1Custom2),	SEQ_DEF_3(KEYCODE_X, CODE_OR, JOYCODE_1_BUTTON6) },
	{ IPT_CUSTOM3			| IPF_PLAYER1, portname(P1Custom3),	SEQ_DEF_3(KEYCODE_C, CODE_OR, JOYCODE_1_BUTTON7) },
	{ IPT_CUSTOM4			| IPF_PLAYER1, portname(P1Custom4),	SEQ_DEF_3(KEYCODE_V, CODE_OR, JOYCODE_1_BUTTON8) },

	{ IPT_JOYSTICK_UP		| IPF_PLAYER2, portname(P2Up),		SEQ_DEF_3(KEYCODE_8_PAD, CODE_OR, JOYCODE_2_UP)    },
	{ IPT_JOYSTICK_DOWN		| IPF_PLAYER2, portname(P2Down),	SEQ_DEF_3(KEYCODE_2_PAD, CODE_OR, JOYCODE_2_DOWN)  },
	{ IPT_JOYSTICK_LEFT		| IPF_PLAYER2, portname(P2Left),	SEQ_DEF_3(KEYCODE_4_PAD, CODE_OR, JOYCODE_2_LEFT)  },
	{ IPT_JOYSTICK_RIGHT	| IPF_PLAYER2, portname(P2Right),	SEQ_DEF_3(KEYCODE_6_PAD, CODE_OR, JOYCODE_2_RIGHT) },
	{ IPT_BUTTON1			| IPF_PLAYER2, portname(P2ButtonA),	SEQ_DEF_3(KEYCODE_G, CODE_OR, JOYCODE_2_BUTTON1) },
	{ IPT_BUTTON2			| IPF_PLAYER2, portname(P2ButtonB),	SEQ_DEF_3(KEYCODE_H, CODE_OR, JOYCODE_2_BUTTON2) },
	{ IPT_BUTTON3			| IPF_PLAYER2, portname(P2ButtonC),	SEQ_DEF_3(KEYCODE_J, CODE_OR, JOYCODE_2_BUTTON3) },
	{ IPT_BUTTON4			| IPF_PLAYER2, portname(P2ButtonD),	SEQ_DEF_3(KEYCODE_K, CODE_OR, JOYCODE_2_BUTTON4) },
	{ IPT_CUSTOM1			| IPF_PLAYER2, portname(P2Custom1),	SEQ_DEF_3(KEYCODE_B, CODE_OR, JOYCODE_2_BUTTON5) },
	{ IPT_CUSTOM2			| IPF_PLAYER2, portname(P2Custom2),	SEQ_DEF_3(KEYCODE_N, CODE_OR, JOYCODE_2_BUTTON6) },
	{ IPT_CUSTOM3			| IPF_PLAYER2, portname(P2Custom3),	SEQ_DEF_3(KEYCODE_M, CODE_OR, JOYCODE_2_BUTTON7) },
	{ IPT_CUSTOM4			| IPF_PLAYER2, portname(P2Custom4),	SEQ_DEF_3(KEYCODE_COMMA, CODE_OR, JOYCODE_2_BUTTON8) },

	{ IPT_TRACKBALL_Y | IPF_PLAYER1,                 portname(P1TrackYUp), SEQ_DEF_3(KEYCODE_UP, CODE_OR, JOYCODE_1_UP) },
	{ (IPT_TRACKBALL_Y | IPF_PLAYER1)+IPT_EXTENSION, portname(P1TrackYDown), SEQ_DEF_3(KEYCODE_DOWN, CODE_OR, JOYCODE_1_DOWN) },
	{ IPT_TRACKBALL_X | IPF_PLAYER1,                 portname(P1TrackXLeft), SEQ_DEF_3(KEYCODE_LEFT, CODE_OR, JOYCODE_1_LEFT) },
	{ (IPT_TRACKBALL_X | IPF_PLAYER1)+IPT_EXTENSION, portname(P1TrackXRight), SEQ_DEF_3(KEYCODE_RIGHT, CODE_OR, JOYCODE_1_RIGHT) },

	{ IPT_TRACKBALL_Y | IPF_PLAYER2,                 portname(P2TrackYUp), SEQ_DEF_3(KEYCODE_8_PAD, CODE_OR, JOYCODE_2_UP) },
	{ (IPT_TRACKBALL_Y | IPF_PLAYER2)+IPT_EXTENSION, portname(P2TrackYDown), SEQ_DEF_3(KEYCODE_2_PAD, CODE_OR, JOYCODE_2_DOWN) },
	{ IPT_TRACKBALL_X | IPF_PLAYER2,                 portname(P2TrackXLeft), SEQ_DEF_3(KEYCODE_4_PAD, CODE_OR, JOYCODE_2_LEFT) },
	{ (IPT_TRACKBALL_X | IPF_PLAYER2)+IPT_EXTENSION, portname(P2TrackXRight), SEQ_DEF_3(KEYCODE_6_PAD, CODE_OR, JOYCODE_2_RIGHT) },

	{ IPT_UNKNOWN,             "UNKNOWN",         SEQ_DEF_0 },
	{ IPT_END,                 0,                 SEQ_DEF_0 }	/* returned when there is no match */
};

struct ipd inputport_cps[] =
{
	{ IPT_START1,	portname(P1Start),	SEQ_DEF_1(KEYCODE_1) },
	{ IPT_START2,	portname(P2Start),	SEQ_DEF_1(KEYCODE_2) },
	{ IPT_START3,	portname(P3Start),	SEQ_DEF_1(KEYCODE_3) },
	{ IPT_START4,	portname(P4Start),	SEQ_DEF_1(KEYCODE_4) },
	{ IPT_COIN1,	portname(Coin1),	SEQ_DEF_1(KEYCODE_5) },
	{ IPT_COIN2,	portname(Coin2),	SEQ_DEF_1(KEYCODE_6) },
	{ IPT_COIN3,	portname(Coin3),	SEQ_DEF_1(KEYCODE_7) },
	{ IPT_COIN4,	portname(Coin4),	SEQ_DEF_1(KEYCODE_8) },
	{ IPT_SERVICE1,	portname(Service),	SEQ_DEF_1(KEYCODE_9) },

	{ IPT_JOYSTICK_UP		| IPF_PLAYER1, portname(P1Up),		SEQ_DEF_3(KEYCODE_UP, CODE_OR, JOYCODE_1_UP)    },
	{ IPT_JOYSTICK_DOWN		| IPF_PLAYER1, portname(P1Down),	SEQ_DEF_3(KEYCODE_DOWN, CODE_OR, JOYCODE_1_DOWN)  },
	{ IPT_JOYSTICK_LEFT		| IPF_PLAYER1, portname(P1Left),	SEQ_DEF_3(KEYCODE_LEFT, CODE_OR, JOYCODE_1_LEFT)  },
	{ IPT_JOYSTICK_RIGHT	| IPF_PLAYER1, portname(P1Right),	SEQ_DEF_3(KEYCODE_RIGHT, CODE_OR, JOYCODE_1_RIGHT) },
	{ IPT_BUTTON1			| IPF_PLAYER1, portname(P1Button1),	SEQ_DEF_5(KEYCODE_A, CODE_OR, JOYCODE_1_BUTTON1, CODE_OR, JOYCODE_MOUSE_1_BUTTON1) },
	{ IPT_BUTTON2			| IPF_PLAYER1, portname(P1Button2),	SEQ_DEF_5(KEYCODE_S, CODE_OR, JOYCODE_1_BUTTON2, CODE_OR, JOYCODE_MOUSE_1_BUTTON3) },
	{ IPT_BUTTON3			| IPF_PLAYER1, portname(P1Button3),	SEQ_DEF_5(KEYCODE_D, CODE_OR, JOYCODE_1_BUTTON3, CODE_OR, JOYCODE_MOUSE_1_BUTTON2) },
	{ IPT_BUTTON4			| IPF_PLAYER1, portname(P1Button4),	SEQ_DEF_3(KEYCODE_Z, CODE_OR, JOYCODE_1_BUTTON4) },
	{ IPT_BUTTON5			| IPF_PLAYER1, portname(P1Button5),	SEQ_DEF_3(KEYCODE_X, CODE_OR, JOYCODE_1_BUTTON5) },
	{ IPT_BUTTON6			| IPF_PLAYER1, portname(P1Button6),	SEQ_DEF_3(KEYCODE_C, CODE_OR, JOYCODE_1_BUTTON6) },
	{ IPT_CUSTOM1			| IPF_PLAYER1, portname(P1Custom1),	SEQ_DEF_3(KEYCODE_Q, CODE_OR, JOYCODE_1_BUTTON7) },
	{ IPT_CUSTOM2			| IPF_PLAYER1, portname(P1Custom2),	SEQ_DEF_3(KEYCODE_W, CODE_OR, JOYCODE_1_BUTTON8) },
	{ IPT_CUSTOM3			| IPF_PLAYER1, portname(P1Custom3),	SEQ_DEF_3(KEYCODE_E, CODE_OR, JOYCODE_1_BUTTON9) },
	{ IPT_CUSTOM4			| IPF_PLAYER1, portname(P1Custom4),	SEQ_DEF_3(KEYCODE_R, CODE_OR, JOYCODE_1_BUTTON10) },

	{ IPT_JOYSTICK_UP		| IPF_PLAYER2, portname(P2Up),		SEQ_DEF_3(KEYCODE_8_PAD, CODE_OR, JOYCODE_2_UP)    },
	{ IPT_JOYSTICK_DOWN		| IPF_PLAYER2, portname(P2Down),	SEQ_DEF_3(KEYCODE_2_PAD, CODE_OR, JOYCODE_2_DOWN)  },
	{ IPT_JOYSTICK_LEFT		| IPF_PLAYER2, portname(P2Left),	SEQ_DEF_3(KEYCODE_4_PAD, CODE_OR, JOYCODE_2_LEFT)  },
	{ IPT_JOYSTICK_RIGHT	| IPF_PLAYER2, portname(P2Right),	SEQ_DEF_3(KEYCODE_6_PAD, CODE_OR, JOYCODE_2_RIGHT) },
	{ IPT_BUTTON1			| IPF_PLAYER2, portname(P2Button1),	SEQ_DEF_3(KEYCODE_G, CODE_OR, JOYCODE_2_BUTTON1) },
	{ IPT_BUTTON2			| IPF_PLAYER2, portname(P2Button2),	SEQ_DEF_3(KEYCODE_H, CODE_OR, JOYCODE_2_BUTTON2) },
	{ IPT_BUTTON3			| IPF_PLAYER2, portname(P2Button3),	SEQ_DEF_3(KEYCODE_J, CODE_OR, JOYCODE_2_BUTTON3) },
	{ IPT_BUTTON4			| IPF_PLAYER2, portname(P2Button4),	SEQ_DEF_3(KEYCODE_B, CODE_OR, JOYCODE_2_BUTTON4) },
	{ IPT_BUTTON5			| IPF_PLAYER2, portname(P2Button5),	SEQ_DEF_3(KEYCODE_N, CODE_OR, JOYCODE_2_BUTTON5) },
	{ IPT_BUTTON6			| IPF_PLAYER2, portname(P2Button6),	SEQ_DEF_3(KEYCODE_M, CODE_OR, JOYCODE_2_BUTTON6) },
	{ IPT_CUSTOM1			| IPF_PLAYER2, portname(P2Custom1),	SEQ_DEF_3(KEYCODE_T, CODE_OR, JOYCODE_2_BUTTON7) },
	{ IPT_CUSTOM2			| IPF_PLAYER2, portname(P2Custom2),	SEQ_DEF_3(KEYCODE_Y, CODE_OR, JOYCODE_2_BUTTON8) },
	{ IPT_CUSTOM3			| IPF_PLAYER2, portname(P2Custom3),	SEQ_DEF_3(KEYCODE_U, CODE_OR, JOYCODE_2_BUTTON9) },
	{ IPT_CUSTOM4			| IPF_PLAYER2, portname(P2Custom4),	SEQ_DEF_3(KEYCODE_I, CODE_OR, JOYCODE_2_BUTTON10) },

	{ IPT_JOYSTICK_UP		| IPF_PLAYER3, portname(P3Up),		SEQ_DEF_1(JOYCODE_3_UP)    },
	{ IPT_JOYSTICK_DOWN		| IPF_PLAYER3, portname(P3Down),	SEQ_DEF_1(JOYCODE_3_DOWN)  },
	{ IPT_JOYSTICK_LEFT		| IPF_PLAYER3, portname(P3Left),	SEQ_DEF_1(JOYCODE_3_LEFT)  },
	{ IPT_JOYSTICK_RIGHT	| IPF_PLAYER3, portname(P3Right),	SEQ_DEF_1(JOYCODE_3_RIGHT) },
	{ IPT_BUTTON1			| IPF_PLAYER3, portname(P3Button1),	SEQ_DEF_1(JOYCODE_3_BUTTON1) },
	{ IPT_BUTTON2			| IPF_PLAYER3, portname(P3Button2),	SEQ_DEF_1(JOYCODE_3_BUTTON2) },
	{ IPT_BUTTON3			| IPF_PLAYER3, portname(P3Button3),	SEQ_DEF_1(JOYCODE_3_BUTTON3) },
	{ IPT_BUTTON4			| IPF_PLAYER3, portname(P3Button4),	SEQ_DEF_1(JOYCODE_3_BUTTON4) },

	{ IPT_JOYSTICK_UP		| IPF_PLAYER4, portname(P4Up),		SEQ_DEF_1(JOYCODE_4_UP) },
	{ IPT_JOYSTICK_DOWN		| IPF_PLAYER4, portname(P4Down),	SEQ_DEF_1(JOYCODE_4_DOWN) },
	{ IPT_JOYSTICK_LEFT		| IPF_PLAYER4, portname(P4Left),	SEQ_DEF_1(JOYCODE_4_LEFT) },
	{ IPT_JOYSTICK_RIGHT	| IPF_PLAYER4, portname(P4Right),	SEQ_DEF_1(JOYCODE_4_RIGHT) },
	{ IPT_BUTTON1			| IPF_PLAYER4, portname(P4Button1),	SEQ_DEF_1(JOYCODE_4_BUTTON1) },
	{ IPT_BUTTON2			| IPF_PLAYER4, portname(P4Button2),	SEQ_DEF_1(JOYCODE_4_BUTTON2) },
	{ IPT_BUTTON3			| IPF_PLAYER4, portname(P4Button3),	SEQ_DEF_1(JOYCODE_4_BUTTON3) },
	{ IPT_BUTTON4			| IPF_PLAYER4, portname(P4Button4),	SEQ_DEF_1(JOYCODE_4_BUTTON4) },

	{ IPT_DIAL | IPF_PLAYER1,                 portname(P1DialDec), SEQ_DEF_3(KEYCODE_LEFT, CODE_OR, JOYCODE_1_LEFT) },
	{ (IPT_DIAL | IPF_PLAYER1)+IPT_EXTENSION, portname(P1DialInc), SEQ_DEF_3(KEYCODE_RIGHT, CODE_OR, JOYCODE_1_RIGHT) },
	{ IPT_DIAL | IPF_PLAYER2,                 portname(P2DialDec), SEQ_DEF_3(KEYCODE_4_PAD, CODE_OR, JOYCODE_2_LEFT) },
	{ (IPT_DIAL | IPF_PLAYER2)+IPT_EXTENSION, portname(P2DialInc), SEQ_DEF_3(KEYCODE_6_PAD, CODE_OR, JOYCODE_2_RIGHT) },

	{ IPT_UNKNOWN,             "UNKNOWN",         SEQ_DEF_0 },
	{ IPT_END,                 0,                 SEQ_DEF_0 }	/* returned when there is no match */
};

struct ipd inputport_terminate = { IPT_END, 0, SEQ_DEF_0 };

struct ipd inputport_defaults[MAX_INPUT];
struct ipd inputport_defaults_backup[MAX_INPUT];

char default_filename[][10] =
{
	"neogeo",
	"cps",
	"cps",
	"unknown"
};

struct ButtonSetting button_mask[] =
{
	/* NeoGeo */
	{ "neogeo",		{ { 0x00010, 0x00020, 0x00040, 0x00080, 0x00000, 0x00000 }, { 0x10010, 0x10020, 0x10040, 0x10080, 0x00000, 0x00000} } },
	{ "irrmaze",	{ { 0x00010, 0x00020, 0x00000, 0x00000, 0x00000, 0x00000 }, { 0x00040, 0x00080, 0x00000, 0x00000, 0x00000, 0x00000} } },

	/* CPS-1 */
	{ "forgottn",	{ { 0x40010, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000} } },
	{ "ghouls",		{ { 0x40010, 0x40020, 0x40040, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x00000, 0x00000, 0x00000} } },
	{ "strider",	{ { 0x40010, 0x40020, 0x40040, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x00000, 0x00000, 0x00000} } },
	{ "dwj",		{ { 0x40010, 0x40020, 0x40040, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x00000, 0x00000, 0x00000} } },
	{ "willow",		{ { 0x40010, 0x40020, 0x40040, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x00000, 0x00000, 0x00000} } },
	{ "unsquad",	{ { 0x40010, 0x40020, 0x40040, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x00000, 0x00000, 0x00000} } },
	{ "ffight",		{ { 0x40010, 0x40020, 0x40040, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x00000, 0x00000, 0x00000} } },
	{ "1941",		{ { 0x40010, 0x40020, 0x00000, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x00000, 0x00000, 0x00000, 0x00000} } },
	{ "mercs",		{ { 0x40010, 0x40020, 0x00000, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x00000, 0x00000, 0x00000, 0x00000} } },
	{ "mtwins",		{ { 0x40010, 0x40020, 0x40040, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x00000, 0x00000, 0x00000} } },
	{ "msword",		{ { 0x40010, 0x40020, 0x40040, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x00000, 0x00000, 0x00000} } },
	{ "cawing",		{ { 0x40010, 0x40020, 0x40040, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x00000, 0x00000, 0x00000} } },
	{ "nemo",		{ { 0x40010, 0x40020, 0x40040, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x00000, 0x00000, 0x00000} } },
	{ "sf2",		{ { 0x40010, 0x40020, 0x40040, 0x50001, 0x50002, 0x50004 }, { 0x41000, 0x42000, 0x44000, 0x50010, 0x50020, 0x50040} } },
	{ "sf2j",		{ { 0x40010, 0x40020, 0x40040, 0x50001, 0x50002, 0x50004 }, { 0x41000, 0x42000, 0x44000, 0x50010, 0x50020, 0x50040} } },
	{ "3wonders",	{ { 0x40010, 0x40020, 0x40040, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x00000, 0x00000, 0x00000} } },
	{ "kod",		{ { 0x40010, 0x40020, 0x40040, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x00000, 0x00000, 0x00000} } },
	{ "captcomm",	{ { 0x40010, 0x40020, 0x00000, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x00000, 0x00000, 0x00000, 0x00000} } },
	{ "knights",	{ { 0x40010, 0x40020, 0x00000, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x00000, 0x00000, 0x00000, 0x00000} } },
	{ "varth",		{ { 0x40010, 0x40020, 0x40040, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x00000, 0x00000, 0x00000} } },
	{ "cworld2j",	{ { 0x40010, 0x40020, 0x40040, 0x40080, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x48000, 0x00000, 0x00000} } },
	{ "wof",		{ { 0x40010, 0x40020, 0x00000, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x00000, 0x00000, 0x00000, 0x00000} } },
	{ "dino",		{ { 0x40010, 0x40020, 0x00000, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x00000, 0x00000, 0x00000, 0x00000} } },
	{ "punisher",	{ { 0x40010, 0x40020, 0x00000, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x00000, 0x00000, 0x00000, 0x00000} } },
	{ "slammast",	{ { 0x40010, 0x40020, 0x40040, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x00000, 0x00000, 0x00000} } },
	{ "pnickj",		{ { 0x40010, 0x40020, 0x40040, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x00000, 0x00000, 0x00000} } },
	{ "qad",		{ { 0x40010, 0x40020, 0x40040, 0x40080, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x48000, 0x00000, 0x00000} } },
	{ "qadj",		{ { 0x40010, 0x40020, 0x40040, 0x40080, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x48000, 0x00000, 0x00000} } },
	{ "qtono2",		{ { 0x40010, 0x40020, 0x40040, 0x40080, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x48000, 0x00000, 0x00000} } },
	{ "pang3",		{ { 0x40010, 0x40020, 0x40040, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x00000, 0x00000, 0x00000} } },
	{ "megaman",	{ { 0x40010, 0x40020, 0x40040, 0x00000, 0x00000, 0x00000 }, { 0x41000, 0x42000, 0x44000, 0x00000, 0x00000, 0x00000} } },
	{ "sfzch",		{ { 0x40010, 0x40020, 0x40040, 0x40080, 0x00001, 0x00040 }, { 0x41000, 0x42000, 0x44000, 0x48000, 0x00002, 0x00080} } },

	/* CPS-2 */
	{ "19xx",		{ { 0x00010, 0x00020, 0x00000, 0x00000, 0x00000, 0x00000 }, { 0x01000, 0x02000, 0x00000, 0x00000, 0x00000, 0x00000} } },
	{ "cybots",		{ { 0x00010, 0x00020, 0x00040, 0x10001, 0x00000, 0x00000 }, { 0x01000, 0x02000, 0x04000, 0x10010, 0x00000, 0x00000} } },
	{ "ssf2",		{ { 0x00010, 0x00020, 0x00040, 0x10001, 0x10002, 0x10004 }, { 0x01000, 0x02000, 0x04000, 0x10010, 0x10020, 0x24000} } },
	{ "ddtod",		{ { 0x00010, 0x00020, 0x00040, 0x00080, 0x00000, 0x00000 }, { 0x01000, 0x02000, 0x04000, 0x08000, 0x00000, 0x00000} } },
	{ "avsp",		{ { 0x00010, 0x00020, 0x00040, 0x00000, 0x00000, 0x00000 }, { 0x01000, 0x02000, 0x04000, 0x00000, 0x00000, 0x00000} } },
	{ "qndream",	{ { 0x00008, 0x00004, 0x00002, 0x00001, 0x00000, 0x00000 }, { 0x00800, 0x00400, 0x00200, 0x00100, 0x00000, 0x00000} } },
	{ "batcir",		{ { 0x00010, 0x00020, 0x00000, 0x00000, 0x00000, 0x00000 }, { 0x01000, 0x02000, 0x00000, 0x00000, 0x00000, 0x00000} } },
	{ "sgemf",		{ { 0x00010, 0x00020, 0x00040, 0x00000, 0x00000, 0x00000 }, { 0x01000, 0x02000, 0x04000, 0x00000, 0x00000, 0x00000} } },
	{ "cps2",		{ { 0x00010, 0x00020, 0x00040, 0x10001, 0x10002, 0x10004 }, { 0x01000, 0x02000, 0x04000, 0x10010, 0x10020, 0x24000} } },
};

static int num_buttonsetting = sizeof(button_mask) / sizeof(button_mask[0]);

struct ik *osd_input_keywords = NULL;

struct ik input_keywords[] =
{
	{ "KEYCODE_A",		   		IKT_STD,		KEYCODE_A },
	{ "KEYCODE_B",		   		IKT_STD,		KEYCODE_B },
	{ "KEYCODE_C",		   		IKT_STD,		KEYCODE_C },
	{ "KEYCODE_D",		   		IKT_STD,		KEYCODE_D },
	{ "KEYCODE_E",		   		IKT_STD,		KEYCODE_E },
	{ "KEYCODE_F",		   		IKT_STD,		KEYCODE_F },
	{ "KEYCODE_G",		   		IKT_STD,		KEYCODE_G },
	{ "KEYCODE_H",		   		IKT_STD,		KEYCODE_H },
	{ "KEYCODE_I",		   		IKT_STD,		KEYCODE_I },
	{ "KEYCODE_J",		   		IKT_STD,		KEYCODE_J },
	{ "KEYCODE_K",		   		IKT_STD,		KEYCODE_K },
	{ "KEYCODE_L",		   		IKT_STD,		KEYCODE_L },
	{ "KEYCODE_M",		   		IKT_STD,		KEYCODE_M },
	{ "KEYCODE_N",		   		IKT_STD,		KEYCODE_N },
	{ "KEYCODE_O",		   		IKT_STD,		KEYCODE_O },
	{ "KEYCODE_P",		   		IKT_STD,		KEYCODE_P },
	{ "KEYCODE_Q",		   		IKT_STD,		KEYCODE_Q },
	{ "KEYCODE_R",		   		IKT_STD,		KEYCODE_R },
	{ "KEYCODE_S",		   		IKT_STD,		KEYCODE_S },
	{ "KEYCODE_T",		   		IKT_STD,		KEYCODE_T },
	{ "KEYCODE_U",		   		IKT_STD,		KEYCODE_U },
	{ "KEYCODE_V",		   		IKT_STD,		KEYCODE_V },
	{ "KEYCODE_W",		   		IKT_STD,		KEYCODE_W },
	{ "KEYCODE_X",		   		IKT_STD,		KEYCODE_X },
	{ "KEYCODE_Y",		   		IKT_STD,		KEYCODE_Y },
	{ "KEYCODE_Z",		   		IKT_STD,		KEYCODE_Z },
	{ "KEYCODE_0",		   		IKT_STD,		KEYCODE_0 },
	{ "KEYCODE_1",		   		IKT_STD,		KEYCODE_1 },
	{ "KEYCODE_2",		   		IKT_STD,		KEYCODE_2 },
	{ "KEYCODE_3",		   		IKT_STD,		KEYCODE_3 },
	{ "KEYCODE_4",		   		IKT_STD,		KEYCODE_4 },
	{ "KEYCODE_5",		   		IKT_STD,		KEYCODE_5 },
	{ "KEYCODE_6",		   		IKT_STD,		KEYCODE_6 },
	{ "KEYCODE_7",		   		IKT_STD,		KEYCODE_7 },
	{ "KEYCODE_8",		   		IKT_STD,		KEYCODE_8 },
	{ "KEYCODE_9",		   		IKT_STD,		KEYCODE_9 },
	{ "KEYCODE_0_PAD",	   		IKT_STD,		KEYCODE_0_PAD },
	{ "KEYCODE_1_PAD",	   		IKT_STD,		KEYCODE_1_PAD },
	{ "KEYCODE_2_PAD",	   		IKT_STD,		KEYCODE_2_PAD },
	{ "KEYCODE_3_PAD",	   		IKT_STD,		KEYCODE_3_PAD },
	{ "KEYCODE_4_PAD",	   		IKT_STD,		KEYCODE_4_PAD },
	{ "KEYCODE_5_PAD",	   		IKT_STD,		KEYCODE_5_PAD },
	{ "KEYCODE_6_PAD",	   		IKT_STD,		KEYCODE_6_PAD },
	{ "KEYCODE_7_PAD",	   		IKT_STD,		KEYCODE_7_PAD },
	{ "KEYCODE_8_PAD",	      	IKT_STD,		KEYCODE_8_PAD },
	{ "KEYCODE_9_PAD",	      	IKT_STD,		KEYCODE_9_PAD },
	{ "KEYCODE_F1",		   		IKT_STD,		KEYCODE_F1 },
	{ "KEYCODE_F2",			  	IKT_STD,		KEYCODE_F2 },
	{ "KEYCODE_F3",			  	IKT_STD,		KEYCODE_F3 },
	{ "KEYCODE_F4",			  	IKT_STD,		KEYCODE_F4 },
	{ "KEYCODE_F5",			  	IKT_STD,		KEYCODE_F5 },
	{ "KEYCODE_F6",			  	IKT_STD,		KEYCODE_F6 },
	{ "KEYCODE_F7",			  	IKT_STD,		KEYCODE_F7 },
	{ "KEYCODE_F8",			  	IKT_STD,		KEYCODE_F8 },
	{ "KEYCODE_F9",			  	IKT_STD,		KEYCODE_F9 },
	{ "KEYCODE_F10",		  	IKT_STD,		KEYCODE_F10 },
	{ "KEYCODE_F11",		  	IKT_STD,		KEYCODE_F11 },
	{ "KEYCODE_F12",		  	IKT_STD,		KEYCODE_F12 },
	{ "KEYCODE_ESC",		  	IKT_STD,		KEYCODE_ESC },
	{ "KEYCODE_TILDE",		  	IKT_STD,		KEYCODE_TILDE },
	{ "KEYCODE_MINUS",		  	IKT_STD,		KEYCODE_MINUS },
	{ "KEYCODE_EQUALS",		  	IKT_STD,		KEYCODE_EQUALS },
	{ "KEYCODE_BACKSPACE",	  	IKT_STD,		KEYCODE_BACKSPACE },
	{ "KEYCODE_TAB",		  	IKT_STD,		KEYCODE_TAB },
	{ "KEYCODE_OPENBRACE",	  	IKT_STD,		KEYCODE_OPENBRACE },
	{ "KEYCODE_CLOSEBRACE",	  	IKT_STD,		KEYCODE_CLOSEBRACE },
	{ "KEYCODE_ENTER",		  	IKT_STD,		KEYCODE_ENTER },
	{ "KEYCODE_COLON",		  	IKT_STD,		KEYCODE_COLON },
	{ "KEYCODE_QUOTE",		  	IKT_STD,		KEYCODE_QUOTE },
	{ "KEYCODE_BACKSLASH",	  	IKT_STD,		KEYCODE_BACKSLASH },
	{ "KEYCODE_BACKSLASH2",	  	IKT_STD,		KEYCODE_BACKSLASH2 },
	{ "KEYCODE_COMMA",		  	IKT_STD,		KEYCODE_COMMA },
	{ "KEYCODE_STOP",		  	IKT_STD,		KEYCODE_STOP },
	{ "KEYCODE_SLASH",		  	IKT_STD,		KEYCODE_SLASH },
	{ "KEYCODE_SPACE",		  	IKT_STD,		KEYCODE_SPACE },
	{ "KEYCODE_INSERT",		  	IKT_STD,		KEYCODE_INSERT },
	{ "KEYCODE_DEL",		  	IKT_STD,		KEYCODE_DEL },
	{ "KEYCODE_HOME",		  	IKT_STD,		KEYCODE_HOME },
	{ "KEYCODE_END",		  	IKT_STD,		KEYCODE_END },
	{ "KEYCODE_PGUP",		  	IKT_STD,		KEYCODE_PGUP },
	{ "KEYCODE_PGDN",		  	IKT_STD,		KEYCODE_PGDN },
	{ "KEYCODE_LEFT",		  	IKT_STD,		KEYCODE_LEFT },
	{ "KEYCODE_RIGHT",		  	IKT_STD,		KEYCODE_RIGHT },
	{ "KEYCODE_UP",			  	IKT_STD,		KEYCODE_UP },
	{ "KEYCODE_DOWN",		  	IKT_STD,		KEYCODE_DOWN },
	{ "KEYCODE_SLASH_PAD",	  	IKT_STD,		KEYCODE_SLASH_PAD },
	{ "KEYCODE_ASTERISK",	  	IKT_STD,		KEYCODE_ASTERISK },
	{ "KEYCODE_MINUS_PAD",	  	IKT_STD,		KEYCODE_MINUS_PAD },
	{ "KEYCODE_PLUS_PAD",	  	IKT_STD,		KEYCODE_PLUS_PAD },
	{ "KEYCODE_DEL_PAD",	  	IKT_STD,		KEYCODE_DEL_PAD },
	{ "KEYCODE_ENTER_PAD",	  	IKT_STD,		KEYCODE_ENTER_PAD },
	{ "KEYCODE_PRTSCR",		  	IKT_STD,		KEYCODE_PRTSCR },
	{ "KEYCODE_PAUSE",		  	IKT_STD,		KEYCODE_PAUSE },
	{ "KEYCODE_LSHIFT",		  	IKT_STD,		KEYCODE_LSHIFT },
	{ "KEYCODE_RSHIFT",		  	IKT_STD,		KEYCODE_RSHIFT },
	{ "KEYCODE_LCONTROL",	  	IKT_STD,		KEYCODE_LCONTROL },
	{ "KEYCODE_RCONTROL",	  	IKT_STD,		KEYCODE_RCONTROL },
	{ "KEYCODE_LALT",		  	IKT_STD,		KEYCODE_LALT },
	{ "KEYCODE_RALT",		  	IKT_STD,		KEYCODE_RALT },
	{ "KEYCODE_SCRLOCK",	  	IKT_STD,		KEYCODE_SCRLOCK },
	{ "KEYCODE_NUMLOCK",	  	IKT_STD,		KEYCODE_NUMLOCK },
	{ "KEYCODE_CAPSLOCK",	  	IKT_STD,		KEYCODE_CAPSLOCK },
	{ "KEYCODE_LWIN",		  	IKT_STD,		KEYCODE_LWIN },
	{ "KEYCODE_RWIN",		  	IKT_STD,		KEYCODE_RWIN },
	{ "KEYCODE_MENU",		  	IKT_STD,		KEYCODE_MENU },

	{ "JOYCODE_1_LEFT",		  	IKT_STD,		JOYCODE_1_LEFT },
	{ "JOYCODE_1_RIGHT",	  	IKT_STD,		JOYCODE_1_RIGHT },
	{ "JOYCODE_1_UP",		  	IKT_STD,		JOYCODE_1_UP },
	{ "JOYCODE_1_DOWN",		  	IKT_STD,		JOYCODE_1_DOWN },
	{ "JOYCODE_1_BUTTON1",	  	IKT_STD,		JOYCODE_1_BUTTON1 },
	{ "JOYCODE_1_BUTTON2",	  	IKT_STD,		JOYCODE_1_BUTTON2 },
	{ "JOYCODE_1_BUTTON3",	  	IKT_STD,		JOYCODE_1_BUTTON3 },
	{ "JOYCODE_1_BUTTON4",	  	IKT_STD,		JOYCODE_1_BUTTON4 },
	{ "JOYCODE_1_BUTTON5",	  	IKT_STD,		JOYCODE_1_BUTTON5 },
	{ "JOYCODE_1_BUTTON6",	  	IKT_STD,		JOYCODE_1_BUTTON6 },
	{ "JOYCODE_1_BUTTON7",	  	IKT_STD,		JOYCODE_1_BUTTON7 },
	{ "JOYCODE_1_BUTTON8",	  	IKT_STD,		JOYCODE_1_BUTTON8 },
	{ "JOYCODE_1_BUTTON9",	  	IKT_STD,		JOYCODE_1_BUTTON9 },
	{ "JOYCODE_1_BUTTON10",	  	IKT_STD,		JOYCODE_1_BUTTON10 },
	{ "JOYCODE_1_BUTTON11",	  	IKT_STD,		JOYCODE_1_BUTTON11 },
	{ "JOYCODE_1_BUTTON12",	  	IKT_STD,		JOYCODE_1_BUTTON12 },
	{ "JOYCODE_1_BUTTON13",	  	IKT_STD,		JOYCODE_1_BUTTON13 },
	{ "JOYCODE_1_BUTTON14",	  	IKT_STD,		JOYCODE_1_BUTTON14 },
	{ "JOYCODE_1_BUTTON15",	  	IKT_STD,		JOYCODE_1_BUTTON15 },
	{ "JOYCODE_1_BUTTON16",	  	IKT_STD,		JOYCODE_1_BUTTON16 },
	{ "JOYCODE_1_START",	  	IKT_STD,		JOYCODE_1_START },
	{ "JOYCODE_1_SELECT",	  	IKT_STD,		JOYCODE_1_SELECT },
	{ "JOYCODE_2_LEFT",		  	IKT_STD,		JOYCODE_2_LEFT },
	{ "JOYCODE_2_RIGHT",	  	IKT_STD,		JOYCODE_2_RIGHT },
	{ "JOYCODE_2_UP",		  	IKT_STD,		JOYCODE_2_UP },
	{ "JOYCODE_2_DOWN",		  	IKT_STD,		JOYCODE_2_DOWN },
	{ "JOYCODE_2_BUTTON1",	  	IKT_STD,		JOYCODE_2_BUTTON1 },
	{ "JOYCODE_2_BUTTON2",	  	IKT_STD,		JOYCODE_2_BUTTON2 },
	{ "JOYCODE_2_BUTTON3",	  	IKT_STD,		JOYCODE_2_BUTTON3 },
	{ "JOYCODE_2_BUTTON4",	  	IKT_STD,		JOYCODE_2_BUTTON4 },
	{ "JOYCODE_2_BUTTON5",	  	IKT_STD,		JOYCODE_2_BUTTON5 },
	{ "JOYCODE_2_BUTTON6",	  	IKT_STD,		JOYCODE_2_BUTTON6 },
	{ "JOYCODE_2_BUTTON7",	  	IKT_STD,		JOYCODE_2_BUTTON7 },
	{ "JOYCODE_2_BUTTON8",	  	IKT_STD,		JOYCODE_2_BUTTON8 },
	{ "JOYCODE_2_BUTTON9",	  	IKT_STD,		JOYCODE_2_BUTTON9 },
	{ "JOYCODE_2_BUTTON10",	  	IKT_STD,		JOYCODE_2_BUTTON10 },
	{ "JOYCODE_2_BUTTON11",	  	IKT_STD,		JOYCODE_2_BUTTON11 },
	{ "JOYCODE_2_BUTTON12",	  	IKT_STD,		JOYCODE_2_BUTTON12 },
	{ "JOYCODE_2_BUTTON13",	  	IKT_STD,		JOYCODE_2_BUTTON13 },
	{ "JOYCODE_2_BUTTON14",	  	IKT_STD,		JOYCODE_2_BUTTON14 },
	{ "JOYCODE_2_BUTTON15",	  	IKT_STD,		JOYCODE_2_BUTTON15 },
	{ "JOYCODE_2_BUTTON16",	  	IKT_STD,		JOYCODE_2_BUTTON16 },
	{ "JOYCODE_2_START",	  	IKT_STD,		JOYCODE_2_START },
	{ "JOYCODE_2_SELECT",	  	IKT_STD,		JOYCODE_2_SELECT },
	{ "JOYCODE_3_LEFT",		  	IKT_STD,		JOYCODE_3_LEFT },
	{ "JOYCODE_3_RIGHT",	  	IKT_STD,		JOYCODE_3_RIGHT },
	{ "JOYCODE_3_UP",		  	IKT_STD,		JOYCODE_3_UP },
	{ "JOYCODE_3_DOWN",		  	IKT_STD,		JOYCODE_3_DOWN },
	{ "JOYCODE_3_BUTTON1",	  	IKT_STD,		JOYCODE_3_BUTTON1 },
	{ "JOYCODE_3_BUTTON2",	  	IKT_STD,		JOYCODE_3_BUTTON2 },
	{ "JOYCODE_3_BUTTON3",	  	IKT_STD,		JOYCODE_3_BUTTON3 },
	{ "JOYCODE_3_BUTTON4",	  	IKT_STD,		JOYCODE_3_BUTTON4 },
	{ "JOYCODE_3_BUTTON5",	  	IKT_STD,		JOYCODE_3_BUTTON5 },
	{ "JOYCODE_3_BUTTON6",	  	IKT_STD,		JOYCODE_3_BUTTON6 },
	{ "JOYCODE_3_BUTTON7",	  	IKT_STD,		JOYCODE_3_BUTTON7 },
	{ "JOYCODE_3_BUTTON8",	  	IKT_STD,		JOYCODE_3_BUTTON8 },
	{ "JOYCODE_3_BUTTON9",	  	IKT_STD,		JOYCODE_3_BUTTON9 },
	{ "JOYCODE_3_BUTTON10",	  	IKT_STD,		JOYCODE_3_BUTTON10 },
	{ "JOYCODE_3_BUTTON11",	  	IKT_STD,		JOYCODE_3_BUTTON11 },
	{ "JOYCODE_3_BUTTON12",	  	IKT_STD,		JOYCODE_3_BUTTON12 },
	{ "JOYCODE_3_BUTTON13",	  	IKT_STD,		JOYCODE_3_BUTTON13 },
	{ "JOYCODE_3_BUTTON14",	  	IKT_STD,		JOYCODE_3_BUTTON14 },
	{ "JOYCODE_3_BUTTON15",	  	IKT_STD,		JOYCODE_3_BUTTON15 },
	{ "JOYCODE_3_BUTTON16",	  	IKT_STD,		JOYCODE_3_BUTTON16 },
	{ "JOYCODE_3_START",	  	IKT_STD,		JOYCODE_3_START },
	{ "JOYCODE_3_SELECT",	  	IKT_STD,		JOYCODE_3_SELECT },
	{ "JOYCODE_4_LEFT",		  	IKT_STD,		JOYCODE_4_LEFT },
	{ "JOYCODE_4_RIGHT",	  	IKT_STD,		JOYCODE_4_RIGHT },
	{ "JOYCODE_4_UP",		  	IKT_STD,		JOYCODE_4_UP },
	{ "JOYCODE_4_DOWN",		  	IKT_STD,		JOYCODE_4_DOWN },
	{ "JOYCODE_4_BUTTON1",	  	IKT_STD,		JOYCODE_4_BUTTON1 },
	{ "JOYCODE_4_BUTTON2",	  	IKT_STD,		JOYCODE_4_BUTTON2 },
	{ "JOYCODE_4_BUTTON3",	  	IKT_STD,		JOYCODE_4_BUTTON3 },
	{ "JOYCODE_4_BUTTON4",	  	IKT_STD,		JOYCODE_4_BUTTON4 },
	{ "JOYCODE_4_BUTTON5",	  	IKT_STD,		JOYCODE_4_BUTTON5 },
	{ "JOYCODE_4_BUTTON6",	  	IKT_STD,		JOYCODE_4_BUTTON6 },
	{ "JOYCODE_4_BUTTON7",	  	IKT_STD,		JOYCODE_4_BUTTON7 },
	{ "JOYCODE_4_BUTTON8",	  	IKT_STD,		JOYCODE_4_BUTTON8 },
	{ "JOYCODE_4_BUTTON9",	  	IKT_STD,		JOYCODE_4_BUTTON9 },
	{ "JOYCODE_4_BUTTON10",	  	IKT_STD,		JOYCODE_4_BUTTON10 },
	{ "JOYCODE_4_BUTTON11",	  	IKT_STD,		JOYCODE_4_BUTTON11 },
	{ "JOYCODE_4_BUTTON12",	  	IKT_STD,		JOYCODE_4_BUTTON12 },
	{ "JOYCODE_4_BUTTON13",	  	IKT_STD,		JOYCODE_4_BUTTON13 },
	{ "JOYCODE_4_BUTTON14",	  	IKT_STD,		JOYCODE_4_BUTTON14 },
	{ "JOYCODE_4_BUTTON15",	  	IKT_STD,		JOYCODE_4_BUTTON15 },
	{ "JOYCODE_4_BUTTON16",	  	IKT_STD,		JOYCODE_4_BUTTON16 },
	{ "JOYCODE_4_START",	  	IKT_STD,		JOYCODE_4_START },
	{ "JOYCODE_4_SELECT",	  	IKT_STD,		JOYCODE_4_SELECT },

	{ "MOUSECODE_1_BUTTON1", 	IKT_STD,		JOYCODE_MOUSE_1_BUTTON1 },
	{ "MOUSECODE_1_BUTTON2", 	IKT_STD,		JOYCODE_MOUSE_1_BUTTON2 },
	{ "MOUSECODE_1_BUTTON3", 	IKT_STD,		JOYCODE_MOUSE_1_BUTTON3 },

	{ "KEYCODE_NONE",			IKT_STD,		CODE_NONE },
	{ "CODE_NONE",			  	IKT_STD,		CODE_NONE },
	{ "CODE_OTHER",				IKT_STD,		CODE_OTHER },
	{ "CODE_DEFAULT",			IKT_STD,		CODE_DEFAULT },
	{ "CODE_PREVIOUS",			IKT_STD,		CODE_PREVIOUS },
	{ "CODE_NOT",				IKT_STD,		CODE_NOT },
	{ "CODE_OR",			   	IKT_STD,		CODE_OR },
	{ "!",						IKT_STD,		CODE_NOT },
	{ "|",					   	IKT_STD,		CODE_OR },

	{ "UI_CONFIGURE", 			IKT_IPT,	 	IPT_UI_CONFIGURE },
	{ "UI_ON_SCREEN_DISPLAY",	IKT_IPT,		IPT_UI_ON_SCREEN_DISPLAY },
	{ "UI_PAUSE",				IKT_IPT,		IPT_UI_PAUSE },
	{ "UI_SINGLE_STEP",			IKT_IPT,		IPT_UI_SINGLE_STEP },
	{ "UI_RESET_MACHINE",		IKT_IPT,		IPT_UI_RESET_MACHINE },
	{ "UI_SHOW_GFX",			IKT_IPT,		IPT_UI_SHOW_GFX },
	{ "UI_FRAMESKIP_DEC",		IKT_IPT,		IPT_UI_FRAMESKIP_DEC },
	{ "UI_FRAMESKIP_INC",		IKT_IPT,		IPT_UI_FRAMESKIP_INC },
	{ "UI_THROTTLE",			IKT_IPT,		IPT_UI_THROTTLE },
	{ "UI_SHOW_FPS",			IKT_IPT,		IPT_UI_SHOW_FPS },
	{ "UI_SHOW_PROFILER",		IKT_IPT,		IPT_UI_SHOW_PROFILER },
	{ "UI_SNAPSHOT",			IKT_IPT,		IPT_UI_SNAPSHOT },
	{ "UI_TOGGLE_CHEAT",		IKT_IPT,		IPT_UI_TOGGLE_CHEAT },
	{ "UI_UP",					IKT_IPT,		IPT_UI_UP },
	{ "UI_DOWN",				IKT_IPT,		IPT_UI_DOWN },
	{ "UI_LEFT",				IKT_IPT,		IPT_UI_LEFT },
	{ "UI_RIGHT",				IKT_IPT,		IPT_UI_RIGHT },
	{ "UI_SELECT",				IKT_IPT,		IPT_UI_SELECT },
	{ "UI_CANCEL",				IKT_IPT,		IPT_UI_CANCEL },
	{ "UI_CLOSE",				IKT_IPT,		IPT_UI_CLOSE },
	{ "UI_SAVE_STATE",			IKT_IPT,		IPT_UI_SAVE_STATE },
	{ "UI_LOAD_STATE",			IKT_IPT,		IPT_UI_LOAD_STATE },
	{ "UI_ADD_CHEAT",			IKT_IPT,		IPT_UI_ADD_CHEAT },
	{ "UI_DELETE_CHEAT",		IKT_IPT,		IPT_UI_DELETE_CHEAT },
	{ "UI_SAVE_CHEAT",			IKT_IPT,		IPT_UI_SAVE_CHEAT },
	{ "UI_WATCH_VALUE",			IKT_IPT,		IPT_UI_WATCH_VALUE },
	{ "UI_EDIT_CHEAT",			IKT_IPT,		IPT_UI_EDIT_CHEAT },
	{ "UI_TOGGLE_DISPLAY",		IKT_IPT,		IPT_UI_TOGGLE_DISPLAY },
	{ "UI_TOGGLE_AUTOFIRE",		IKT_IPT,		IPT_UI_TOGGLE_AUTOFIRE },
	{ "UI_TOGGLE_LOGWAVE",		IKT_IPT,		IPT_UI_TOGGLE_LOGWAVE },
	{ "UI_SHOW_INPUT_LOG",		IKT_IPT,		IPT_UI_SHOW_INPUT_LOG },
	{ "UI_OPERATION_OBJ",		IKT_IPT,		IPT_UI_OPERATION_OBJ },
	{ "UI_COMMAND",				IKT_IPT,		IPT_UI_COMMAND },
	{ "UI_CHEAT",				IKT_IPT,		IPT_UI_CHEAT },
	{ "UI_TIME",				IKT_IPT,		IPT_UI_TIME },
	{ "START1",					IKT_IPT,		IPT_START1 },
	{ "START2",					IKT_IPT,		IPT_START2 },
	{ "START3",					IKT_IPT,		IPT_START3 },
	{ "START4",					IKT_IPT,		IPT_START4 },
	{ "COIN1",					IKT_IPT,		IPT_COIN1 },
	{ "COIN2",					IKT_IPT,		IPT_COIN2 },
	{ "COIN3",					IKT_IPT,		IPT_COIN3 },
	{ "COIN4",					IKT_IPT,		IPT_COIN4 },
	{ "SERVICE1",				IKT_IPT,		IPT_SERVICE1 },
	{ "SELECT1",				IKT_IPT,		IPT_SELECT1 },
	{ "SELECT2",				IKT_IPT,		IPT_SELECT2 },

	{ "P1_JOYSTICK_UP",			IKT_IPT,		IPF_PLAYER1 | IPT_JOYSTICK_UP },
	{ "P1_JOYSTICK_DOWN",		IKT_IPT,		IPF_PLAYER1 | IPT_JOYSTICK_DOWN },
	{ "P1_JOYSTICK_LEFT",		IKT_IPT,		IPF_PLAYER1 | IPT_JOYSTICK_LEFT },
	{ "P1_JOYSTICK_RIGHT",		IKT_IPT,		IPF_PLAYER1 | IPT_JOYSTICK_RIGHT },
	{ "P1_BUTTON1",				IKT_IPT,		IPF_PLAYER1 | IPT_BUTTON1 },
	{ "P1_BUTTON2",				IKT_IPT,		IPF_PLAYER1 | IPT_BUTTON2 },
	{ "P1_BUTTON3",				IKT_IPT,		IPF_PLAYER1 | IPT_BUTTON3 },
	{ "P1_BUTTON4",				IKT_IPT,		IPF_PLAYER1 | IPT_BUTTON4 },
	{ "P1_BUTTON5",				IKT_IPT,		IPF_PLAYER1 | IPT_BUTTON5 },
	{ "P1_BUTTON6",				IKT_IPT,		IPF_PLAYER1 | IPT_BUTTON6 },
	{ "P1_CUSTOM1",				IKT_IPT,		IPF_PLAYER1 | IPT_CUSTOM1 },
	{ "P1_CUSTOM2",				IKT_IPT,		IPF_PLAYER1 | IPT_CUSTOM2 },
	{ "P1_CUSTOM3",				IKT_IPT,		IPF_PLAYER1 | IPT_CUSTOM3 },
	{ "P1_CUSTOM4",				IKT_IPT,		IPF_PLAYER1 | IPT_CUSTOM4 },

	{ "P2_JOYSTICK_UP",			IKT_IPT,		IPF_PLAYER2 | IPT_JOYSTICK_UP },
	{ "P2_JOYSTICK_DOWN",		IKT_IPT,		IPF_PLAYER2 | IPT_JOYSTICK_DOWN },
	{ "P2_JOYSTICK_LEFT",		IKT_IPT,		IPF_PLAYER2 | IPT_JOYSTICK_LEFT },
	{ "P2_JOYSTICK_RIGHT",		IKT_IPT,		IPF_PLAYER2 | IPT_JOYSTICK_RIGHT },
	{ "P2_BUTTON1",				IKT_IPT,		IPF_PLAYER2 | IPT_BUTTON1 },
	{ "P2_BUTTON2",				IKT_IPT,		IPF_PLAYER2 | IPT_BUTTON2 },
	{ "P2_BUTTON3",				IKT_IPT,		IPF_PLAYER2 | IPT_BUTTON3 },
	{ "P2_BUTTON4",				IKT_IPT,		IPF_PLAYER2 | IPT_BUTTON4 },
	{ "P2_BUTTON5",				IKT_IPT,		IPF_PLAYER2 | IPT_BUTTON5 },
	{ "P2_BUTTON6",				IKT_IPT,		IPF_PLAYER2 | IPT_BUTTON6 },
	{ "P2_CUSTOM1",				IKT_IPT,		IPF_PLAYER2 | IPT_CUSTOM1 },
	{ "P2_CUSTOM2",				IKT_IPT,		IPF_PLAYER2 | IPT_CUSTOM2 },
	{ "P2_CUSTOM3",				IKT_IPT,		IPF_PLAYER2 | IPT_CUSTOM3 },
	{ "P2_CUSTOM4",				IKT_IPT,		IPF_PLAYER2 | IPT_CUSTOM4 },

	{ "P3_JOYSTICK_UP",			IKT_IPT,		IPF_PLAYER3 | IPT_JOYSTICK_UP },
	{ "P3_JOYSTICK_DOWN",		IKT_IPT,		IPF_PLAYER3 | IPT_JOYSTICK_DOWN },
	{ "P3_JOYSTICK_LEFT",		IKT_IPT,		IPF_PLAYER3 | IPT_JOYSTICK_LEFT },
	{ "P3_JOYSTICK_RIGHT",		IKT_IPT,		IPF_PLAYER3 | IPT_JOYSTICK_RIGHT },
	{ "P3_BUTTON1",				IKT_IPT,		IPF_PLAYER3 | IPT_BUTTON1 },
	{ "P3_BUTTON2",				IKT_IPT,		IPF_PLAYER3 | IPT_BUTTON2 },
	{ "P3_BUTTON3",				IKT_IPT,		IPF_PLAYER3 | IPT_BUTTON3 },
	{ "P3_BUTTON4",				IKT_IPT,		IPF_PLAYER3 | IPT_BUTTON4 },

	{ "P4_JOYSTICK_UP",			IKT_IPT,		IPF_PLAYER4 | IPT_JOYSTICK_UP },
	{ "P4_JOYSTICK_DOWN",		IKT_IPT,		IPF_PLAYER4 | IPT_JOYSTICK_DOWN },
	{ "P4_JOYSTICK_LEFT",		IKT_IPT,		IPF_PLAYER4 | IPT_JOYSTICK_LEFT },
	{ "P4_JOYSTICK_RIGHT",		IKT_IPT,		IPF_PLAYER4 | IPT_JOYSTICK_RIGHT },
	{ "P4_BUTTON1",				IKT_IPT,		IPF_PLAYER4 | IPT_BUTTON1 },
	{ "P4_BUTTON2",				IKT_IPT,		IPF_PLAYER4 | IPT_BUTTON2 },
	{ "P4_BUTTON3",				IKT_IPT,		IPF_PLAYER4 | IPT_BUTTON3 },
	{ "P4_BUTTON4",				IKT_IPT,		IPF_PLAYER4 | IPT_BUTTON4 },

	{ "P1_DIAL",				IKT_IPT,		IPF_PLAYER1 | IPT_DIAL },
	{ "P1_DIAL_EXT",			IKT_IPT_EXT,	IPF_PLAYER1 | IPT_DIAL },
	{ "P2_DIAL",				IKT_IPT,		IPF_PLAYER2 | IPT_DIAL },
	{ "P2_DIAL_EXT",			IKT_IPT_EXT,	IPF_PLAYER2 | IPT_DIAL },

	{ "P1_TRACKBALL_X",			IKT_IPT,		IPF_PLAYER1 | IPT_TRACKBALL_X },
	{ "P1_TRACKBALL_X_EXT",		IKT_IPT_EXT,	IPF_PLAYER1 | IPT_TRACKBALL_X },
	{ "P2_TRACKBALL_X",			IKT_IPT,		IPF_PLAYER2 | IPT_TRACKBALL_X },
	{ "P2_TRACKBALL_X_EXT",		IKT_IPT_EXT,	IPF_PLAYER2 | IPT_TRACKBALL_X },

	{ "P1_TRACKBALL_Y",			IKT_IPT,		IPF_PLAYER1 | IPT_TRACKBALL_Y },
	{ "P1_TRACKBALL_Y_EXT",		IKT_IPT_EXT,	IPF_PLAYER1 | IPT_TRACKBALL_Y },
	{ "P2_TRACKBALL_Y",			IKT_IPT,		IPF_PLAYER2 | IPT_TRACKBALL_Y },
	{ "P2_TRACKBALL_Y_EXT",		IKT_IPT_EXT,	IPF_PLAYER2 | IPT_TRACKBALL_Y },

	{ "UNKNOWN",				IKT_IPT,		IPT_UNKNOWN },
	{ "END",					IKT_IPT,		IPT_END },

	{ "",						0,	0 }
};

int num_ik = sizeof(input_keywords)/sizeof(struct ik);

/***************************************************************************/
/* Generic IO */

static int readint(void *f,UINT32 *num)
{
	unsigned i;

	*num = 0;
	for (i = 0;i < sizeof(UINT32);i++)
	{
		unsigned char c;


		*num <<= 8;
		if (osd_fread(f,&c,1) != 1)
			return -1;
		*num |= c;
	}

	return 0;
}

static void writeint(void *f,UINT32 num)
{
	unsigned i;

	for (i = 0;i < sizeof(UINT32);i++)
	{
		unsigned char c;


		c = (num >> 8 * (sizeof(UINT32)-1)) & 0xff;
		osd_fwrite(f,&c,1);
		num <<= 8;
	}
}

static int readword(void *f,UINT16 *num)
{
	unsigned i;
	int res;

	res = 0;
	for (i = 0;i < sizeof(UINT16);i++)
	{
		unsigned char c;


		res <<= 8;
		if (osd_fread(f,&c,1) != 1)
			return -1;
		res |= c;
	}

	*num = res;
	return 0;
}

static void writeword(void *f,UINT16 num)
{
	unsigned i;

	for (i = 0;i < sizeof(UINT16);i++)
	{
		unsigned char c;


		c = (num >> 8 * (sizeof(UINT16)-1)) & 0xff;
		osd_fwrite(f,&c,1);
		num <<= 8;
	}
}

#ifndef NOLEGACY
#include "legacy.h"
#endif

static int seq_read_ver_8(void* f, InputSeq* seq)
{
	int j,len;
	UINT32 i;
	UINT16 w;

	if (readword(f,&w) != 0)
		return -1;

	len = w;
	seq_set_0(seq);
	for(j=0;j<len;++j)
	{
		if (readint(f,&i) != 0)
 			return -1;
		(*seq)[j] = savecode_to_code(i);
 	}

 	return 0;
  }

static int seq_read(void* f, InputSeq* seq, int ver)
  {
#ifdef NOLEGACY
	if (ver==8)
		return seq_read_ver_8(f,seq);
#else
	switch (ver) {
		case 5 : return seq_read_ver_5(f,seq);
		case 6 : return seq_read_ver_6(f,seq);
		case 7 : return seq_read_ver_7(f,seq);
		case 8 : return seq_read_ver_8(f,seq);
	}
#endif
	return -1;
  }

static void seq_write(void* f, InputSeq* seq)
  {
	int j,len;
        for(len=0;len<SEQ_MAX;++len)
		if ((*seq)[len] == CODE_NONE)
			break;
	writeword(f,len);
	for(j=0;j<len;++j)
		writeint(f, code_to_savecode( (*seq)[j] ));
  }

/***************************************************************************/
/* Load */

static void load_default_keys(void)
{
	void *f;
	int i = 0;
	int j, k;

	memset(autopressed, 0, MAX_INPUT_BITS);
	autofire_enable = 0;

	if (options.autofiredelay <= 0)
		options.autofiredelay = 1;

	for (playing_no = 0; playing_no < num_buttonsetting; playing_no++)
	{
		if (!strcmp(Machine->gamedrv->input, button_mask[playing_no].name))
			break;
	}
	
	for (j = 0; j < 2; j++)
	{
		for (k = 0; k < MAX_BUTTON; k++)
		{
			custom_port[j][k] = button_mask[playing_no].code[j][k] >> 16;
			custom_mask[j][k] = button_mask[playing_no].code[j][k] & 0xffff;
			
			if (button_mask[playing_no].code[j][k])
				button_number++;
		}
	}

	button_number /= 2;

	while (inputport_common[i].type != IPT_END)
	{
		inputport_defaults[i] = inputport_common[i];
		i++;
	}
	common_input_ports = i;

	switch(Machine->gamedrv->system)
	{
	case SYSTEM_NEOGEO:
		while (inputport_neogeo[i - common_input_ports].type != IPT_END)
		{
			inputport_defaults[i] = inputport_neogeo[i - common_input_ports];
			i++;
		}
//		neogeo_input_ports = i - common_input_ports;

		break;

	case SYSTEM_CPS1:
	case SYSTEM_CPS2:
		while (inputport_cps[i - common_input_ports].type != IPT_END)
		{
			inputport_defaults[i] = inputport_cps[i - common_input_ports];
			i++;
		}
//		cps_input_ports = i - common_input_ports;

		break;
	}
	inputport_defaults[i] = inputport_terminate;

	osd_customize_inputport_defaults(inputport_defaults);
	memcpy(inputport_defaults_backup,inputport_defaults,sizeof(inputport_defaults));

	if ((f = osd_fopen("default",0,OSD_FILETYPE_CONFIG,0)) != 0)
	{
		char buf[8];
		int version;

		/* read header */
		if (osd_fread(f,buf,8) != 8)
			goto getout;

		if (memcmp(buf,MAMEDEFSTRING_V5,8) == 0)
			version = 5;
		else if (memcmp(buf,MAMEDEFSTRING_V6,8) == 0)
			version = 6;
		else if (memcmp(buf,MAMEDEFSTRING_V7,8) == 0)
			version = 7;
		else if (memcmp(buf,MAMEDEFSTRING_V8,8) == 0)
			version = 8;
		else
			goto getout;	/* header invalid */

		for (;;)
		{
			UINT32 type;
			InputSeq def_seq;
			InputSeq seq;

			if (readint(f,&type) != 0)
				goto getout;

			if (seq_read(f,&def_seq,version)!=0)
				goto getout;
			if (seq_read(f,&seq,version)!=0)
				goto getout;

			i = 0;
			while (i < common_input_ports)
			{
				if (inputport_defaults[i].type == type)
				{
					/* load stored settings only if the default hasn't changed */
					if (seq_cmp(&inputport_defaults[i].seq,&def_seq)==0)
						seq_copy(&inputport_defaults[i].seq,&seq);
				}

				i++;
			}
		}

getout:
		osd_fclose(f);
	}

	if ((f = osd_fopen(default_filename[Machine->gamedrv->system],0,OSD_FILETYPE_CONFIG,0)) != 0)
	{
		char buf[8];
		int version;

		/* read header */
		if (osd_fread(f,buf,8) != 8)
			goto getout2;

		if (memcmp(buf,MAMEDEFSTRING_V5,8) == 0)
			version = 5;
		else if (memcmp(buf,MAMEDEFSTRING_V6,8) == 0)
			version = 6;
		else if (memcmp(buf,MAMEDEFSTRING_V7,8) == 0)
			version = 7;
		else if (memcmp(buf,MAMEDEFSTRING_V8,8) == 0)
			version = 8;
		else
			goto getout2;	/* header invalid */

		for (;;)
		{
			UINT32 type;
			InputSeq def_seq;
			InputSeq seq;

			if (readint(f,&type) != 0)
				goto getout2;

			if (seq_read(f,&def_seq,version)!=0)
				goto getout2;
			if (seq_read(f,&seq,version)!=0)
				goto getout2;

			i = common_input_ports;
			while (inputport_defaults[i].type != IPT_END)
			{
				if (inputport_defaults[i].type == type)
				{
					/* load stored settings only if the default hasn't changed */
					if (seq_cmp(&inputport_defaults[i].seq,&def_seq)==0)
						seq_copy(&inputport_defaults[i].seq,&seq);
				}

				i++;
			}
		}

getout2:
		osd_fclose(f);
	}
}

static void save_default_keys(void)
{
	void *f;

	if ((f = osd_fopen("default",0,OSD_FILETYPE_CONFIG,1)) != 0)
	{
		int i;


		/* write header */
		osd_fwrite(f,MAMEDEFSTRING_V8,8);

		i = 0;
		while (i < common_input_ports)
		{
			writeint(f,inputport_defaults[i].type);

			seq_write(f,&inputport_defaults_backup[i].seq);
			seq_write(f,&inputport_defaults[i].seq);

			i++;
		}

		osd_fclose(f);
	}

	if ((f = osd_fopen(default_filename[Machine->gamedrv->system],0,OSD_FILETYPE_CONFIG,1)) != 0)
	{
		int i;


		/* write header */
		osd_fwrite(f,MAMEDEFSTRING_V8,8);

		i = common_input_ports;
		while (inputport_defaults[i].type != IPT_END)
		{
			writeint(f,inputport_defaults[i].type);

			seq_write(f,&inputport_defaults_backup[i].seq);
			seq_write(f,&inputport_defaults[i].seq);

			i++;
		}

		osd_fclose(f);
	}
	memcpy(inputport_defaults,inputport_defaults_backup,sizeof(inputport_defaults_backup));
}

static int input_port_read_ver_8(void *f,struct InputPort *in)
{
	UINT32 i;
	UINT16 w;
	if (readint(f,&i) != 0)
		return -1;
	in->type = i;

	if (readword(f,&w) != 0)
		return -1;
	in->mask = w;

	if (readword(f,&w) != 0)
		return -1;
	in->default_value = w;

	if (seq_read_ver_8(f,&in->seq) != 0)
		return -1;

	return 0;
}

static int input_port_read(void *f,struct InputPort *in, int ver)
{
#ifdef NOLEGACY
	if (ver==8)
		return input_port_read_ver_8(f,in);
#else
	switch (ver) {
		case 5 : return	input_port_read_ver_5(f,in);
		case 6 : return	input_port_read_ver_6(f,in);
		case 7 : return	input_port_read_ver_7(f,in);
		case 8 : return	input_port_read_ver_8(f,in);
	}
#endif
	return -1;
}

static void input_port_write(void *f,struct InputPort *in)
{
	writeint(f,in->type);
	writeword(f,in->mask);
	writeword(f,in->default_value);
	seq_write(f,&in->seq);
}


int load_input_port_settings(void)
{
	int cpu;
	void *f;

	for (cpu = 0; cpu < MAX_CPU; cpu++)
	{
		if (cpu == 0)
			cpu_clocks[0]   = set_overclock(Machine->gamedrv->name);
		else
			cpu_clocks[cpu] = 100;
	}

	load_default_keys();

	if ((f = osd_fopen(Machine->gamedrv->name,0,OSD_FILETYPE_CONFIG,0)) != 0)
	{
		struct InputPort *in;
		unsigned int total,savedtotal;
		char buf[8];
		UINT16 tmp_clock;
		int i, j;
		int version;

		in = Machine->input_ports_default;

		/* calculate the size of the array */
		total = 0;
		while (in->type != IPT_END)
		{
			total++;
			in++;
		}

		/* read header */
		if (osd_fread(f,buf,8) != 8)
			goto getout;

		if (memcmp(buf,MAMECFGSTRING_V5,8) == 0)
			version = 5;
		else if (memcmp(buf,MAMECFGSTRING_V6,8) == 0)
			version = 6;
		else if (memcmp(buf,MAMECFGSTRING_V7,8) == 0)
			version = 7;
		else if (memcmp(buf,MAMECFGSTRING_V8,8) == 0)
			version = 8;
		else
			goto getout;	/* header invalid */

		/* read array size */
		if (readint(f,&savedtotal) != 0)
			goto getout;
		if (total != savedtotal)
			goto getout;	/* different size */

		/* read the original settings and compare them with the ones defined in the driver */
		in = Machine->input_ports_default;
		while (in->type != IPT_END)
		{
			struct InputPort saved;

			if (input_port_read(f,&saved,version) != 0)
				goto getout;

			if (in->mask != saved.mask ||
				in->default_value != saved.default_value ||
				in->type != saved.type ||
				seq_cmp(&in->seq,&saved.seq) !=0 )
			goto getout;	/* the default values are different */

			in++;
		}

		/* read the current settings */
		in = Machine->input_ports;
		while (in->type != IPT_END)
		{
			if (input_port_read(f,in,version) != 0)
				goto getout;
			in++;
		}

		/* Clear the coin & ticket counters/flags - LBO 042898 */
		for (i = 0; i < COIN_COUNTERS; i ++)
			coins[i] = lastcoin[i] = coinlockedout[i] = 0;
		dispensed_tickets = 0;

		/* read in the coin/ticket counters */
		for (i = 0; i < COIN_COUNTERS; i ++)
		{
			if (readint(f,&coins[i]) != 0)
				goto getout;
		}
		if (readint(f,&dispensed_tickets) != 0)
			goto getout;
		if (readint(f,&options.autofiredelay) != 0)
			goto getout;
		
		memset( custom_button, 0, sizeof(custom_button) );

		for (i = 0; i < 2; i++)
		{
			for (j = 0; j < 4; j++)
			{
				if (readword(f, &custom_button[i][j]) != 0)
					goto getout;
			}
		}

		mixer_read_config(f);

		for (i = 0; i < MAX_CPU; i++)
		{
			if (!readword(f, &tmp_clock) && tmp_clock >= 50 && tmp_clock <= 300)
				cpu_clocks[i] = tmp_clock;
		}

getout:
		osd_fclose(f);
	}

	/* All analog ports need initialization */
	{
		int i;
		for (i = 0; i < MAX_INPUT_PORTS; i++)
			input_analog_init[i] = 1;
	}

	if(playback) pback = 1; else pback = 0;

	init_analog_seq();

	update_input_ports();

	/* if we didn't find a saved config, return 0 so the main core knows that it */
	/* is the first time the game is run and it should diplay the disclaimer. */
	if (f) return 1;
	else return 0;
}

/***************************************************************************/
/* Save */

void save_input_port_settings(void)
{
	void *f;

	save_default_keys();

	if ((f = osd_fopen(Machine->gamedrv->name,0,OSD_FILETYPE_CONFIG,1)) != 0)
	{
		struct InputPort *in;
		int total;
		int i, j;


		in = Machine->input_ports_default;

		/* calculate the size of the array */
		total = 0;
		while (in->type != IPT_END)
		{
			total++;
			in++;
		}

		/* write header */
		osd_fwrite(f,MAMECFGSTRING_V8,8);
		/* write array size */
		writeint(f,total);
		/* write the original settings as defined in the driver */
		in = Machine->input_ports_default;
		while (in->type != IPT_END)
		{
			input_port_write(f,in);
			in++;
		}
		/* write the current settings */
		in = Machine->input_ports;
		while (in->type != IPT_END)
		{
			input_port_write(f,in);
			in++;
		}

		/* write out the coin/ticket counters for this machine - LBO 042898 */
		for (i = 0; i < COIN_COUNTERS; i ++)
			writeint(f,coins[i]);
		writeint(f,dispensed_tickets);
		writeint(f,options.autofiredelay);
		
		for (i = 0; i < 2; i++)
		{
			for (j = 0; j < 4; j++)
			{
				writeword(f, custom_button[i][j]);
			}
		}

		mixer_write_config(f);

		writeword(f, cpu_clocks[0]);
		writeword(f, cpu_clocks[1]);

		cpu_clocks[0] = cpu_clocks[1] = 100;

		osd_fclose(f);
	}
}



/* Note that the following 3 routines have slightly different meanings with analog ports */
const char *input_port_name(const struct InputPort *in)
{
	int i;
	unsigned type;

	if (in->name != IP_NAME_DEFAULT) return in->name;

	i = 0;

	if ((in->type & ~IPF_MASK) == IPT_EXTENSION)
		type = (in-1)->type & (~IPF_MASK | IPF_PLAYERMASK);
	else
		type = in->type & (~IPF_MASK | IPF_PLAYERMASK);

	while (inputport_defaults[i].type != IPT_END &&
			inputport_defaults[i].type != type)
		i++;

	if ((in->type & ~IPF_MASK) == IPT_EXTENSION)
		return inputport_defaults[i+1].name;
	else
		return inputport_defaults[i].name;
}

InputSeq* input_port_type_seq(int type)
{
	unsigned i;

	i = 0;

	while (inputport_defaults[i].type != IPT_END &&
			inputport_defaults[i].type != type)
		i++;

	return &inputport_defaults[i].seq;
}

InputSeq* input_port_seq(const struct InputPort *in)
{
	int i,type;

	static InputSeq ip_none = SEQ_DEF_1(CODE_NONE);

	while (seq_get_1((InputSeq*)&in->seq) == CODE_PREVIOUS) in--;

	if ((in->type & ~IPF_MASK) == IPT_EXTENSION)
	{
		type = (in-1)->type & (~IPF_MASK | IPF_PLAYERMASK);
		/* if port is disabled, or cheat with cheats disabled, return no key */
		if (((in-1)->type & IPF_UNUSED) || (!options.cheat && ((in-1)->type & IPF_CHEAT)))
			return &ip_none;
	}
	else
	{
		type = in->type & (~IPF_MASK | IPF_PLAYERMASK);
		/* if port is disabled, or cheat with cheats disabled, return no key */
		if ((in->type & IPF_UNUSED) || (!options.cheat && (in->type & IPF_CHEAT)))
			return &ip_none;
	}

	if (seq_get_1((InputSeq*)&in->seq) != CODE_DEFAULT)
		return (InputSeq*)&in->seq;

	i = 0;

	while (inputport_defaults[i].type != IPT_END &&
			inputport_defaults[i].type != type)
		i++;

	if ((in->type & ~IPF_MASK) == IPT_EXTENSION)
		return &inputport_defaults[i+1].seq;
	else
		return &inputport_defaults[i].seq;
}

void update_analog_port(int port)
{
	struct InputPort *in;
	int current, delta, type, sensitivity, min, max, default_value;
	int axis, is_stick, check_bounds;
	InputSeq* incseq;
	InputSeq* decseq;
	int keydelta;
	int player;

	/* get input definition */
	in = input_analog[port];

	/* if we're not cheating and this is a cheat-only port, bail */
	if (!options.cheat && (in->type & IPF_CHEAT)) return;
	type=(in->type & ~IPF_MASK);

	decseq = input_port_seq(in);
	incseq = input_port_seq(in+1);

	keydelta = IP_GET_DELTA(in);

	switch (type)
	{
		case IPT_DIAL:
			axis = X_AXIS; is_stick = 0; check_bounds = 0; break;
		case IPT_TRACKBALL_X:
			axis = X_AXIS; is_stick = 0; check_bounds = 0; break;
		case IPT_TRACKBALL_Y:
			axis = Y_AXIS; is_stick = 0; check_bounds = 0; break;
		default:
			/* Use some defaults to prevent crash */
			axis = X_AXIS; is_stick = 0; check_bounds = 0;
			logerror("Oops, polling non analog device in update_analog_port()????\n");
	}


	sensitivity = IP_GET_SENSITIVITY(in);
	min = IP_GET_MIN(in);
	max = IP_GET_MAX(in);
	default_value = in->default_value * 100 / sensitivity;
	/* extremes can be either signed or unsigned */
	if (min > max)
	{
		if (in->mask > 0xff) min = min - 0x10000;
		else min = min - 0x100;
	}

	input_analog_previous_value[port] = input_analog_current_value[port];

	/* if IPF_CENTER go back to the default position */
	/* sticks are handled later... */
	if ((in->type & IPF_CENTER) && (!is_stick))
		input_analog_current_value[port] = in->default_value * 100 / sensitivity;

	current = input_analog_current_value[port];

	delta = 0;

	switch (in->type & IPF_PLAYERMASK)
	{
		case IPF_PLAYER2:          player = 1; break;
		case IPF_PLAYER3:          player = 2; break;
		case IPF_PLAYER4:          player = 3; break;
		case IPF_PLAYER1: default: player = 0; break;
	}

	delta = mouse_delta_axis[player][axis];

	if (seq_pressed(decseq)) delta -= keydelta;

	if (seq_pressed(incseq)) delta += keydelta;

	if (in->type & IPF_REVERSE) delta = -delta;

	if (is_stick)
	{
		int new, prev;

		/* center stick */
		if ((delta == 0) && (in->type & IPF_CENTER))
		{
			if (current > default_value)
			delta = -100 / sensitivity;
			if (current < default_value)
			delta = 100 / sensitivity;
		}

		/* An analog joystick which is not at zero position (or has just */
		/* moved there) takes precedence over all other computations */
		/* analog_x/y holds values from -128 to 128 (yes, 128, not 127) */

		new  = analog_current_axis[player][axis];
		prev = analog_previous_axis[player][axis];

		if ((new != 0) || (new-prev != 0))
		{
			delta=0;

			if (in->type & IPF_REVERSE)
			{
				new  = -new;
				prev = -prev;
			}

			/* apply sensitivity using a logarithmic scale */
			if (in->mask > 0xff)
			{
				if (new > 0)
				{
					current = (pow(new / 32768.0, 100.0 / sensitivity) * (max-in->default_value)
							+ in->default_value) * 100 / sensitivity;
				}
				else
				{
					current = (pow(-new / 32768.0, 100.0 / sensitivity) * (min-in->default_value)
							+ in->default_value) * 100 / sensitivity;
				}
			}
			else
			{
				if (new > 0)
				{
					current = (pow(new / 128.0, 100.0 / sensitivity) * (max-in->default_value)
							+ in->default_value) * 100 / sensitivity;
				}
				else
				{
					current = (pow(-new / 128.0, 100.0 / sensitivity) * (min-in->default_value)
							+ in->default_value) * 100 / sensitivity;
				}
			}
		}
	}

	current += delta;

	if (check_bounds)
	{
		int temp;

		if (current >= 0)
			temp = (current * sensitivity + 50) / 100;
		else
			temp = (-current * sensitivity + 50) / -100;

		if (temp < min)
		{
			if (min >= 0)
				current = (min * 100 + sensitivity/2) / sensitivity;
			else
				current = (-min * 100 + sensitivity/2) / -sensitivity;
		}
		if (temp > max)
		{
			if (max >= 0)
				current = (max * 100 + sensitivity/2) / sensitivity;
			else
				current = (-max * 100 + sensitivity/2) / -sensitivity;
		}
	}

	input_analog_current_value[port] = current;
}

static void scale_analog_port(int port)
{
	struct InputPort *in;
	int delta,current,sensitivity;

profiler_mark(PROFILER_INPUT);
	in = input_analog[port];
	sensitivity = IP_GET_SENSITIVITY(in);

	/* apply scaling fairly in both positive and negative directions */
	delta = input_analog_current_value[port] - input_analog_previous_value[port];
	if (delta >= 0)
		delta = cpu_scalebyfcount(delta);
	else
		delta = -cpu_scalebyfcount(-delta);

	current = input_analog_previous_value[port] + delta;

	/* An ugly hack to remove scaling on lightgun ports */
	if (input_analog_scale[port]) {
		/* apply scaling fairly in both positive and negative directions */
		if (current >= 0)
			current = (current * sensitivity + 50) / 100;
		else
			current = (-current * sensitivity + 50) / -100;
	}

	input_port_value[port] &= ~in->mask;
	input_port_value[port] |= current & in->mask;

	if (playback)
		readword(playback,&input_port_value[port]);
	if (record)
		writeword(record,input_port_value[port]);
profiler_mark(PROFILER_END);
}

#define MAX_JOYSTICKS 3
#define MAX_PLAYERS 4
static int mJoyCurrent[MAX_JOYSTICKS*MAX_PLAYERS];
static int mJoyPrevious[MAX_JOYSTICKS*MAX_PLAYERS];
static int mJoy4Way[MAX_JOYSTICKS*MAX_PLAYERS];
/*
The above "Joy" states contain packed bits:
	0001	up
	0010	down
	0100	left
	1000	right
*/

static void
ScanJoysticks( struct InputPort *in )
{
	int i;
	int port = 0;

	/* Save old Joystick state. */
	memcpy( mJoyPrevious, mJoyCurrent, sizeof(mJoyPrevious) );

	/* Initialize bits of mJoyCurrent to zero. */
	memset( mJoyCurrent, 0, sizeof(mJoyCurrent) );

	/* Now iterate over the input port structure to populate mJoyCurrent. */
	while( in->type != IPT_END && port < MAX_INPUT_PORTS )
	{
		while (in->type != IPT_END && in->type != IPT_PORT)
		{
			if ((in->type & ~IPF_MASK) >= IPT_JOYSTICK_UP &&
				(in->type & ~IPF_MASK) <= IPT_JOYSTICK_RIGHT)
			{
				InputSeq* seq;
				seq = input_port_seq(in);
				if( seq_pressed(seq) )
				{
					int joynum,joydir,player;
					player = 0;
					if ((in->type & IPF_PLAYERMASK) == IPF_PLAYER2)
						player = 1;
					else if ((in->type & IPF_PLAYERMASK) == IPF_PLAYER3)
						player = 2;
					else if ((in->type & IPF_PLAYERMASK) == IPF_PLAYER4)
						player = 3;

					joynum = player * MAX_JOYSTICKS +
							 ((in->type & ~IPF_MASK) - IPT_JOYSTICK_UP) / 4;
					joydir = ((in->type & ~IPF_MASK) - IPT_JOYSTICK_UP) % 4;

					mJoyCurrent[joynum] |= 1<<joydir;
				}
			}
			in++;
		}
		port++;
		if (in->type == IPT_PORT) in++;
	}

	/* Process the joystick states, to filter out illegal combinations of switches. */
	for( i=0; i<MAX_JOYSTICKS*MAX_PLAYERS; i++ )
	{
		if( (mJoyCurrent[i]&0x3)==0x3 ) /* both up and down are pressed */
		{
			mJoyCurrent[i]&=0xc; /* clear up and down */
		}
		if( (mJoyCurrent[i]&0xc)==0xc ) /* both left and right are pressed */
		{
			mJoyCurrent[i]&=0x3; /* clear left and right */
		}

		/* Only update mJoy4Way if the joystick has moved. */
		if( mJoyCurrent[i]!=mJoyPrevious[i] )
		{
			mJoy4Way[i] = mJoyCurrent[i];

			if( (mJoy4Way[i] & 0x3) && (mJoy4Way[i] & 0xc) )
			{
				/* If joystick is pointing at a diagonal, acknowledge that the player moved
				 * the joystick by favoring a direction change.  This minimizes frustration
				 * when using a keyboard for input, and maximizes responsiveness.
				 *
				 * For example, if you are holding "left" then switch to "up" (where both left
				 * and up are briefly pressed at the same time), we'll transition immediately
				 * to "up."
				 *
				 * Under the old "sticky" key implentation, "up" wouldn't be triggered until
				 * left was released.
				 *
				 * Zero any switches that didn't change from the previous to current state.
				 */
				mJoy4Way[i] ^= (mJoy4Way[i] & mJoyPrevious[i]);
			}

			if( (mJoy4Way[i] & 0x3) && (mJoy4Way[i] & 0xc) )
			{
				/* If we are still pointing at a diagonal, we are in an indeterminant state.
				 *
				 * This could happen if the player moved the joystick from the idle position directly
				 * to a diagonal, or from one diagonal directly to an extreme diagonal.
				 *
				 * The chances of this happening with a keyboard are slim, but we still need to
				 * constrain this case.
				 *
				 * For now, just resolve randomly.
				 */
				if( rand()&1 )
				{
					mJoy4Way[i] &= 0x3; /* eliminate horizontal component */
				}
				else
				{
					mJoy4Way[i] &= 0xc; /* eliminate vertical component */
				}
			}
		}
	}
} /* ScanJoysticks */

void update_input_ports(void)
{
	int port,ib;
	struct InputPort *in;

#define MAX_INPUT_BITS 1024
	static int impulsecount[MAX_INPUT_BITS];
	static int waspressed[MAX_INPUT_BITS];
	static int pbwaspressed[MAX_INPUT_BITS];


profiler_mark(PROFILER_INPUT);

	/* clear all the values before proceeding */
	for (port = 0;port < MAX_INPUT_PORTS;port++)
	{
		input_port_value[port] = 0;
		input_vblank[port] = 0;
		input_analog[port] = 0;
	}

	in = Machine->input_ports;
	if (in->type == IPT_END) return; 	/* nothing to do */

	/* make sure the InputPort definition is correct */
	if (in->type != IPT_PORT)
	{
		logerror("Error in InputPort definition: expecting PORT_START\n");
		return;
	}
	else
	{
		in++;
	}

	ScanJoysticks( in ); /* populates mJoyCurrent[] */

	/* scan all the input ports */
	port = 0;
	ib = 0;
	while (in->type != IPT_END && port < MAX_INPUT_PORTS)
	{
		struct InputPort *start;
		/* first of all, scan the whole input port definition and build the */
		/* default value. I must do it before checking for input because otherwise */
		/* multiple keys associated with the same input bit wouldn't work (the bit */
		/* would be reset to its default value by the second entry, regardless if */
		/* the key associated with the first entry was pressed) */
		start = in;
		while (in->type != IPT_END && in->type != IPT_PORT)
		{
			if ((in->type & ~IPF_MASK) != IPT_DIPSWITCH_SETTING &&	/* skip dipswitch definitions */
				(in->type & ~IPF_MASK) != IPT_EXTENSION)			/* skip analog extension fields */
			{
				input_port_value[port] =
						(input_port_value[port] & ~in->mask) | (in->default_value & in->mask);
			}

			in++;
		}

		/* now get back to the beginning of the input port and check the input bits. */
		for (in = start;
			 in->type != IPT_END && in->type != IPT_PORT;
			 in++, ib++)
		{
			if ((in->type & ~IPF_MASK) != IPT_DIPSWITCH_SETTING &&	/* skip dipswitch definitions */
					(in->type & ~IPF_MASK) != IPT_EXTENSION)		/* skip analog extension fields */
			{
				if ((in->type & ~IPF_MASK) == IPT_VBLANK)
				{
					input_vblank[port] ^= in->mask;
					input_port_value[port] ^= in->mask;
					if (Machine->drv->vblank_duration == 0)
						logerror("Warning: you are using IPT_VBLANK with vblank_duration = 0. You need to increase vblank_duration for IPT_VBLANK to work.\n");
				}
				/* If it's an analog control, handle it appropriately */
				else if (((in->type & ~IPF_MASK) > IPT_ANALOG_START)
					  && ((in->type & ~IPF_MASK) < IPT_ANALOG_END  )) /* LBO 120897 */
				{
					input_analog[port]=in;
					/* reset the analog port on first access */
					if (input_analog_init[port])
					{
						input_analog_init[port] = 0;
						input_analog_scale[port] = 1;
						input_analog_current_value[port] = input_analog_previous_value[port]
							= in->default_value * 100 / IP_GET_SENSITIVITY(in);
					}
				}
				else
				{
					InputSeq* seq;
					seq = input_port_seq(in);
					if (auto_pressed(seq, in->type, ib))
					{
						/* skip if coin input and it's locked out */
						if ((in->type & ~IPF_MASK) >= IPT_COIN1 &&
							(in->type & ~IPF_MASK) <= IPT_COIN4 &&
                            coinlockedout[(in->type & ~IPF_MASK) - IPT_COIN1])
						{
							continue;
						}

						/* if IPF_RESET set, reset the first CPU */
						if ((in->type & IPF_RESETCPU) && waspressed[ib] == 0 && !playback)
						{
							cpu_set_reset_line(0,PULSE_LINE);
						}

						if (in->type & IPF_IMPULSE)
						{
							if (IP_GET_IMPULSE(in) == 0)
								logerror("error in input port definition: IPF_IMPULSE with length = 0\n");
							if (waspressed[ib] == 0)
								impulsecount[ib] = IP_GET_IMPULSE(in);
								/* the input bit will be toggled later */
						}
						else if (in->type & IPF_TOGGLE)
						{
							if (waspressed[ib] == 0)
							{
								in->default_value ^= in->mask;
								input_port_value[port] ^= in->mask;
							}
						}
						else if ((in->type & ~IPF_MASK) >= IPT_JOYSTICK_UP &&
								(in->type & ~IPF_MASK) <= IPT_JOYSTICK_RIGHT)
						{
							int joynum,joydir,mask,player;


							player = 0;
							if ((in->type & IPF_PLAYERMASK) == IPF_PLAYER2) player = 1;
							else if ((in->type & IPF_PLAYERMASK) == IPF_PLAYER3) player = 2;
							else if ((in->type & IPF_PLAYERMASK) == IPF_PLAYER4) player = 3;
							joynum = player * MAX_JOYSTICKS +
									((in->type & ~IPF_MASK) - IPT_JOYSTICK_UP) / 4;

							joydir = ((in->type & ~IPF_MASK) - IPT_JOYSTICK_UP) % 4;

							mask = in->mask;

							if( in->type & IPF_4WAY )
							{
								/* apply 4-way joystick constraint */
								if( ((mJoy4Way[joynum]>>joydir)&1) == 0 )
								{
									mask = 0;
								}
							}
							else
							{
								/* filter up+down and left+right */
								if( ((mJoyCurrent[joynum]>>joydir)&1) == 0 )
								{
									mask = 0;
								}
							}

							input_port_value[port] ^= mask;
						} /* joystick */
						else if ((in->type & ~IPF_MASK) >= IPT_CUSTOM1 &&
							(in->type & ~IPF_MASK) <= IPT_CUSTOM4)
						{
							int i, n = 1;

							if ((in->type & IPF_PLAYERMASK) == IPF_PLAYER2)
							{
								for (i = 0; i < button_number; i++)
								{
									if (custom_button[1][(in->type & ~IPF_MASK) - IPT_CUSTOM1] & n)
										input_port_value[custom_port[1][i]] ^= custom_mask[1][i];

									n <<= 1;
								}
							}
							else
							{
								for (i = 0; i < button_number; i++)
								{
									if (custom_button[0][(in->type & ~IPF_MASK) - IPT_CUSTOM1] & n)
										input_port_value[custom_port[0][i]] ^= custom_mask[0][i];

									n <<= 1;
								}
							}
						}
						else
						{
							input_port_value[port] ^= in->mask;
						}
						waspressed[ib] = 1;
					}
					else
						waspressed[ib] = 0;

					if ((in->type & IPF_IMPULSE) && impulsecount[ib] > 0)
					{
						impulsecount[ib]--;
						waspressed[ib] = 1;
						input_port_value[port] ^= in->mask;
					}
				}
			}
		}

		port++;
		if (in->type == IPT_PORT) in++;
	}

	if (playback && pback)
	{
		int i;

		ib = 0;
		in = Machine->input_ports;
		in++;
		for (i = 0; i < MAX_INPUT_PORTS; i ++)
		{
			if (readword(playback,&input_port_value[i]))
			{
				pback = 0;
				usrintf_showmessage(ui_getstring(UI_playbackend));
				break;
			}

			/* check if the input port includes an IPF_RESETCPU bit
			   and reset the CPU on first "press", no need to check
			   the impulse count as this was done during recording */
			for (; in->type != IPT_END && in->type != IPT_PORT; in++, ib++)
			{
				if (in->type & IPF_RESETCPU)
				{
					if((input_port_value[i] ^ in->default_value) & in->mask)
					{
						if (pbwaspressed[ib] == 0)
							cpu_set_reset_line(0,PULSE_LINE);
						pbwaspressed[ib] = 1;
					}
					else
						pbwaspressed[ib] = 0;
				}
			}
			if (in->type == IPT_PORT) in++;
		}

		in = Machine->input_ports;
		in++;
		port = 0;
		while (in->type != IPT_END && port < MAX_INPUT_PORTS)
		{
			while (in->type != IPT_END && in->type != IPT_PORT)
			{
				if ((in->type & ~IPF_MASK) == IPT_DIPSWITCH_NAME)
				{
					in->default_value =
						(in->default_value & ~in->mask) | (input_port_value[port] & in->mask);
				}
				in++;
			}
			port++;
			if (in->type == IPT_PORT) in++;
		}
	}

	if (record)
	{
		int i;

		for (i = 0; i < MAX_INPUT_PORTS; i ++)
			writeword(record,input_port_value[i]);
	}

	if (show_input)
		make_input_log();

profiler_mark(PROFILER_END);
}



/* used the the CPU interface to notify that VBlank has ended, so we can update */
/* IPT_VBLANK input ports. */
void inputport_vblank_end(void)
{
	int port;
	int i;


profiler_mark(PROFILER_INPUT);
	for (port = 0;port < MAX_INPUT_PORTS;port++)
	{
		if (input_vblank[port])
		{
			input_port_value[port] ^= input_vblank[port];
			input_vblank[port] = 0;
		}
	}

	/* update the analog devices */
	for (i = 0;i < OSD_MAX_JOY_ANALOG;i++)
	{
		/* update the analog joystick position */
		int a;
		for (a=0; a<MAX_ANALOG_AXES ; a++)
		{
			analog_previous_axis[i][a] = analog_current_axis[i][a];
		}
		osd_analogjoy_read (i, analog_current_axis[i], analogjoy_input[i]);

		/* update mouse/trackball position */
		osd_trak_read (i, &(mouse_delta_axis[i])[X_AXIS], &(mouse_delta_axis[i])[Y_AXIS]);
	}

	for (i = 0;i < MAX_INPUT_PORTS;i++)
	{
		struct InputPort *in;

		in=input_analog[i];
		if (in)
		{
			update_analog_port(i);
		}
	}
profiler_mark(PROFILER_END);
}



int readinputport(int port)
{
	struct InputPort *in;

	/* Update analog ports on demand */
	in=input_analog[port];
	if (in)
	{
		scale_analog_port(port);
	}

	return input_port_value[port];
}

READ_HANDLER( input_port_0_r ) { return readinputport(0); }
READ_HANDLER( input_port_1_r ) { return readinputport(1); }
READ_HANDLER( input_port_2_r ) { return readinputport(2); }
READ_HANDLER( input_port_3_r ) { return readinputport(3); }
READ_HANDLER( input_port_4_r ) { return readinputport(4); }
READ_HANDLER( input_port_5_r ) { return readinputport(5); }
READ_HANDLER( input_port_6_r ) { return readinputport(6); }
READ_HANDLER( input_port_7_r ) { return readinputport(7); }
READ_HANDLER( input_port_8_r ) { return readinputport(8); }
READ_HANDLER( input_port_9_r ) { return readinputport(9); }
READ_HANDLER( input_port_10_r ) { return readinputport(10); }
READ_HANDLER( input_port_11_r ) { return readinputport(11); }
READ_HANDLER( input_port_12_r ) { return readinputport(12); }
READ_HANDLER( input_port_13_r ) { return readinputport(13); }
READ_HANDLER( input_port_14_r ) { return readinputport(14); }
READ_HANDLER( input_port_15_r ) { return readinputport(15); }
READ_HANDLER( input_port_16_r ) { return readinputport(16); }
READ_HANDLER( input_port_17_r ) { return readinputport(17); }
READ_HANDLER( input_port_18_r ) { return readinputport(18); }
READ_HANDLER( input_port_19_r ) { return readinputport(19); }

READ16_HANDLER( input_port_0_word_r ) { return readinputport(0); }
READ16_HANDLER( input_port_1_word_r ) { return readinputport(1); }
READ16_HANDLER( input_port_2_word_r ) { return readinputport(2); }
READ16_HANDLER( input_port_3_word_r ) { return readinputport(3); }
READ16_HANDLER( input_port_4_word_r ) { return readinputport(4); }
READ16_HANDLER( input_port_5_word_r ) { return readinputport(5); }
READ16_HANDLER( input_port_6_word_r ) { return readinputport(6); }
READ16_HANDLER( input_port_7_word_r ) { return readinputport(7); }
READ16_HANDLER( input_port_8_word_r ) { return readinputport(8); }
READ16_HANDLER( input_port_9_word_r ) { return readinputport(9); }
READ16_HANDLER( input_port_10_word_r ) { return readinputport(10); }
READ16_HANDLER( input_port_11_word_r ) { return readinputport(11); }
READ16_HANDLER( input_port_12_word_r ) { return readinputport(12); }
READ16_HANDLER( input_port_13_word_r ) { return readinputport(13); }
READ16_HANDLER( input_port_14_word_r ) { return readinputport(14); }
READ16_HANDLER( input_port_15_word_r ) { return readinputport(15); }
READ16_HANDLER( input_port_16_word_r ) { return readinputport(16); }
READ16_HANDLER( input_port_17_word_r ) { return readinputport(17); }
READ16_HANDLER( input_port_18_word_r ) { return readinputport(18); }
READ16_HANDLER( input_port_19_word_r ) { return readinputport(19); }

/***************************************************************************/
/* InputPort conversion */

static unsigned input_port_count(const struct InputPortTiny *src)
{
	unsigned total;

	total = 0;
	while (src->type != IPT_END)
	{
		int type = src->type & ~IPF_MASK;
		if (type > IPT_ANALOG_START && type < IPT_ANALOG_END)
			total += 2;
		else if (type != IPT_EXTENSION)
			++total;
		++src;
	}

	++total; /* for IPT_END */

	return total;
}

struct InputPort* input_port_allocate(const struct InputPortTiny *src)
{
	struct InputPort* dst;
	struct InputPort* base;
	unsigned total;

	total = input_port_count(src);

	base = (struct InputPort*)malloc(total * sizeof(struct InputPort));
	dst = base;

	while (src->type != IPT_END)
	{
		int type = src->type & ~IPF_MASK;
		const struct InputPortTiny *ext;
		const struct InputPortTiny *src_end;
		InputCode seq_default;

		if (type > IPT_ANALOG_START && type < IPT_ANALOG_END)
			src_end = src + 2;
		else
			src_end = src + 1;

		switch (type)
		{
			case IPT_END :
			case IPT_PORT :
			case IPT_DIPSWITCH_NAME :
			case IPT_DIPSWITCH_SETTING :
				seq_default = CODE_NONE;
			break;
			default:
				seq_default = CODE_DEFAULT;
		}

		ext = src_end;
		while (src != src_end)
		{
			dst->type = src->type;
			dst->mask = src->mask;
			dst->default_value = src->default_value;
			dst->name = src->name;

  			if (ext->type == IPT_EXTENSION)
  			{
				InputCode or1 =	IP_GET_CODE_OR1(ext);
				InputCode or2 =	IP_GET_CODE_OR2(ext);

				if (or1 < __code_max)
				{
					if (or2 < __code_max)
						seq_set_3(&dst->seq, or1, CODE_OR, or2);
					else
						seq_set_1(&dst->seq, or1);
				} else {
					if (or1 == CODE_NONE)
						seq_set_1(&dst->seq, or2);
					else
						seq_set_1(&dst->seq, or1);
				}

  				++ext;
  			} else {
				seq_set_1(&dst->seq,seq_default);
  			}

			++src;
			++dst;
		}

		src = ext;
	}

	dst->type = IPT_END;

	return base;
}

void input_port_free(struct InputPort* dst)
{
	free(dst);
}

UINT32 toggle_autofire(void)
{
	autofire_enable = autofire_enable ? 0 : 1;

	return autofire_enable;
}


static int auto_pressed(InputSeq *seq, UINT32 type, int bit)
{
	int pressed = seq_pressed(seq);

	if (pressed)
	{
		if ((type & IPF_AUTOFIRE_ON) || ((type & IPF_AUTOFIRE_TOGGLE) && autofire_enable))
		{
			if (autopressed[bit] >= options.autofiredelay)
			{
				pressed = 0;
				autopressed[bit] = 0;
			}
			else
				autopressed[bit]++;
		}
	}

	return pressed;
}

#define BT_U   0x01
#define BT_D   0x02
#define BT_L   0x04
#define BT_R   0x08
#define BT_UL  (BT_U | BT_L)
#define BT_UR  (BT_U | BT_R)
#define BT_DL  (BT_D | BT_L)
#define BT_DR  (BT_D | BT_R)
#define BT_1   0x10
#define BT_2   0x20
#define BT_3   0x40
#define BT_4   0x80
#define BT_5   0x100
#define BT_6   0x200
#define BT_S   0x400


INLINE void copy_command_buf(int button)
{
	int i, len;

	len = strlen((char *)command_buf);

	if (len >= MAX_COMMAND_LOG - 1)
	{
		for (i = 0; i < MAX_COMMAND_LOG - 2; i++)
			command_buf[i] = command_buf[i + 2];
	}

	command_buf[MAX_COMMAND_LOG - 2] = '\0';
	command_buf[MAX_COMMAND_LOG - 1] = '\0';

	len = strlen((char *)command_buf);

	switch(button)
	{
		case BT_U:
			command_buf[len]   = 0x81;
			command_buf[len+1] = 0xd8;
			break;
		case BT_D:
			command_buf[len]   = 0x81;
			command_buf[len+1] = 0xd2;
			break;
		case BT_L:
			command_buf[len]   = 0x81;
			command_buf[len+1] = 0xd4;
			break;
		case BT_R:
			command_buf[len]   = 0x81;
			command_buf[len+1] = 0xd6;
			break;
		case BT_UL:
			command_buf[len]   = 0x81;
			command_buf[len+1] = 0xd7;
			break;
		case BT_UR:
			command_buf[len]   = 0x81;
			command_buf[len+1] = 0xd9;
			break;
		case BT_DL:
			command_buf[len]   = 0x81;
			command_buf[len+1] = 0xd1;
			break;
		case BT_DR:
			command_buf[len]   = 0x81;
			command_buf[len+1] = 0xd3;
			break;

		case BT_1:
			if (Machine->gamedrv->system == SYSTEM_NEOGEO)
			{
				command_buf[len]   = 0x81;
				command_buf[len+1] = 0xc0;
			}
			else
			{
				command_buf[len]   = 0x81;
				command_buf[len+1] = 0xe9;
			}
			break;
		case BT_2:
			if (Machine->gamedrv->system == SYSTEM_NEOGEO)
			{
				command_buf[len]   = 0x81;
				command_buf[len+1] = 0xc1;
			}
			else
			{
				command_buf[len]   = 0x81;
				command_buf[len+1] = 0xea;
			}
			break;
		case BT_3:
			if (Machine->gamedrv->system == SYSTEM_NEOGEO)
			{
				command_buf[len]   = 0x81;
				command_buf[len+1] = 0xc2;
			}
			else
			{
				command_buf[len]   = 0x81;
				command_buf[len+1] = 0xeb;
			}
			break;
		case BT_4:
			if (Machine->gamedrv->system == SYSTEM_NEOGEO)
			{
				command_buf[len]   = 0x81;
				command_buf[len+1] = 0xc3;
			}
			else
			{
				command_buf[len]   = 0x81;
				command_buf[len+1] = 0xec;
			}
			break;
		case BT_5:
			command_buf[len]   = 0x81;
			command_buf[len+1] = 0xed;
			break;
		case BT_6:
			command_buf[len]   = 0x81;
			command_buf[len+1] = 0xee;
			break;
		case BT_S:
			command_buf[len]   = 0x81;
			command_buf[len+1] = 0xef;
			break;

		default:
			break;
	}
}

static void make_input_log(void)
{
	static int old_dir  = 0;
	static int old_btn  = 0;
	int now_dir, now_btn;

	now_dir = 0;
	if (Machine->gamedrv->system == SYSTEM_NEOGEO)
	{
		if (strcmp(Machine->gamedrv->input, "irrmaze"))
		{
			if (!(input_port_value[0] & 0x01)) now_dir |= BT_U;
			if (!(input_port_value[0] & 0x02)) now_dir |= BT_D;
			if (!(input_port_value[0] & 0x04)) now_dir |= BT_L;
			if (!(input_port_value[0] & 0x08)) now_dir |= BT_R;
		}
	}
	else if (Machine->gamedrv->system == SYSTEM_CPS1)
	{
		if (!(input_port_value[4] & 0x08)) now_dir |= BT_U;
		if (!(input_port_value[4] & 0x04)) now_dir |= BT_D;
		if (!(input_port_value[4] & 0x02)) now_dir |= BT_L;
		if (!(input_port_value[4] & 0x01)) now_dir |= BT_R;
	}
	else	// SYSTEM_CPS2
	{
		if (strcmp(Machine->gamedrv->input, "qndream"))
		{
			if (!(input_port_value[0] & 0x08)) now_dir |= BT_U;
			if (!(input_port_value[0] & 0x04)) now_dir |= BT_D;
			if (!(input_port_value[0] & 0x02)) now_dir |= BT_L;
			if (!(input_port_value[0] & 0x01)) now_dir |= BT_R;
		}
	}

	if ((now_dir & BT_UL) == BT_UL)      now_dir = BT_UL;
	else if ((now_dir & BT_UR) == BT_UR) now_dir = BT_UR;
	else if ((now_dir & BT_DL) == BT_DL) now_dir = BT_DL;
	else if ((now_dir & BT_DR) == BT_DR) now_dir = BT_DR;
	else if (now_dir & BT_U)             now_dir = BT_U;
	else if (now_dir & BT_D)             now_dir = BT_D;
	else if (now_dir & BT_L)             now_dir = BT_L;
	else if (now_dir & BT_R)             now_dir = BT_R;

	if (old_dir != now_dir)
	{
		if (now_dir != 0)
			copy_command_buf(now_dir);
		old_dir = now_dir;
	}

	now_btn = 0;
	if (Machine->gamedrv->system == SYSTEM_NEOGEO)
	{
		if (!strcmp(Machine->gamedrv->input, "irrmaze"))
		{
			if (!(input_port_value[1] & 0x10)) now_btn |= BT_1;
			if (!(input_port_value[1] & 0x20)) now_btn |= BT_2;
		}
		else
		{
			if (!(input_port_value[0] & 0x10)) now_btn |= BT_1;
			if (!(input_port_value[0] & 0x20)) now_btn |= BT_2;
			if (!(input_port_value[0] & 0x40)) now_btn |= BT_3;
			if (!(input_port_value[0] & 0x80)) now_btn |= BT_4;
		}
		
		if (!(input_port_value[2] & 0x01)) now_btn |= BT_S;
	}
	else if (Machine->gamedrv->system == SYSTEM_CPS1)
	{
		if (!strcmp(Machine->gamedrv->input, "sf2") ||
			!strcmp(Machine->gamedrv->input, "sf2j"))
		{
			if (!(input_port_value[4] & 0x10)) now_btn |= BT_1;
			if (!(input_port_value[4] & 0x20)) now_btn |= BT_2;
			if (!(input_port_value[4] & 0x40)) now_btn |= BT_3;
			if (!(input_port_value[5] & 0x01)) now_btn |= BT_4;
			if (!(input_port_value[5] & 0x02)) now_btn |= BT_5;
			if (!(input_port_value[5] & 0x04)) now_btn |= BT_6;
		}
		else if (!strcmp(Machine->gamedrv->input, "sfzch"))
		{
			if (!(input_port_value[4] & 0x10)) now_btn |= BT_1;
			if (!(input_port_value[4] & 0x20)) now_btn |= BT_2;
			if (!(input_port_value[4] & 0x40)) now_btn |= BT_3;
			if (!(input_port_value[4] & 0x80)) now_btn |= BT_4;
			if (!(input_port_value[0] & 0x01)) now_btn |= BT_5;
			if (!(input_port_value[0] & 0x40)) now_btn |= BT_6;
		}
		else if (!strcmp(Machine->gamedrv->input, "cworld2j") ||
				 !strcmp(Machine->gamedrv->input, "qad")      ||
				 !strcmp(Machine->gamedrv->input, "qadj")     ||
				 !strcmp(Machine->gamedrv->input, "qtono2"))
		{
			if (!(input_port_value[4] & 0x10)) now_btn |= BT_1;
			if (!(input_port_value[4] & 0x20)) now_btn |= BT_2;
			if (!(input_port_value[4] & 0x40)) now_btn |= BT_3;
			if (!(input_port_value[4] & 0x80)) now_btn |= BT_4;
		}
		else
		{
			if (!(input_port_value[4] & 0x10)) now_btn |= BT_1;
			if (!(input_port_value[4] & 0x20)) now_btn |= BT_2;
			if (!(input_port_value[4] & 0x40)) now_btn |= BT_3;
		}
		
		if (!(input_port_value[0] & 0x10)) now_btn |= BT_S;
	}
	else	// SYSTEM_CPS2
	{
		if (!strcmp(Machine->gamedrv->input, "ddtod"))
		{
			if (!(input_port_value[0] & 0x10)) now_btn |= BT_1;
			if (!(input_port_value[0] & 0x20)) now_btn |= BT_2;
			if (!(input_port_value[0] & 0x40)) now_btn |= BT_3;
			if (!(input_port_value[0] & 0x80)) now_btn |= BT_4;
		}
		else if (!strcmp(Machine->gamedrv->input, "qndream"))
		{
			if (!(input_port_value[0] & 0x08)) now_btn |= BT_1;
			if (!(input_port_value[0] & 0x04)) now_btn |= BT_2;
			if (!(input_port_value[0] & 0x02)) now_btn |= BT_3;
			if (!(input_port_value[0] & 0x01)) now_btn |= BT_4;
		}
		else
		{
			if (!(input_port_value[0] & 0x10)) now_btn |= BT_1;
			if (!(input_port_value[0] & 0x20)) now_btn |= BT_2;
			if (!(input_port_value[0] & 0x40)) now_btn |= BT_3;
			if (!(input_port_value[1] & 0x01)) now_btn |= BT_4;
			if (!(input_port_value[1] & 0x02)) now_btn |= BT_5;
			if (!(input_port_value[1] & 0x04)) now_btn |= BT_6;
		}
		
		if (!(input_port_value[2] & 0x100)) now_btn |= BT_S;
	}

	if ((now_btn & BT_1) != 0 && (old_btn & BT_1) == 0)
		copy_command_buf(BT_1);
	if ((now_btn & BT_2) != 0 && (old_btn & BT_2) == 0)
		copy_command_buf(BT_2);
	if ((now_btn & BT_3) != 0 && (old_btn & BT_3) == 0)
		copy_command_buf(BT_3);
	if ((now_btn & BT_4) != 0 && (old_btn & BT_4) == 0)
		copy_command_buf(BT_4);
	if ((now_btn & BT_5) != 0 && (old_btn & BT_5) == 0)
		copy_command_buf(BT_5);
	if ((now_btn & BT_6) != 0 && (old_btn & BT_6) == 0)
		copy_command_buf(BT_6);
	if ((now_btn & BT_S) != 0 && (old_btn & BT_S) == 0)
		copy_command_buf(BT_S);

	old_btn = now_btn;

	if (now_dir || now_btn)
		command_counter = 60;
}


void seq_set_string(InputSeq* a, const char *buf)
{
	char *lbuf;
	char *arg = NULL;
	int j;
	struct ik *pik;
	int found;

	// create a locale buffer to be parsed by strtok
	lbuf = malloc (strlen(buf)+1);

	// copy the input string
	strcpy (lbuf, buf);

	for(j=0;j<SEQ_MAX;++j)
		(*a)[j] = CODE_NONE;

	arg = strtok(lbuf, " \t\r\n");
	j = 0;
	while( arg != NULL )
	{
		found = 0;

		pik = input_keywords;

		while (!found && pik->name && pik->name[0] != 0)
		{
			if (strcmp(pik->name,arg) == 0)
			{
				// this entry is only valid if it is a KEYCODE
				if (pik->type == IKT_STD)
				{
					(*a)[j] = pik->val;
					j++;
					found = 1;
				}
			}
			pik++;
		}

		pik = osd_input_keywords;

		if (pik)
		{
			while (!found && pik->name && pik->name[0] != 0)
			{
				if (strcmp(pik->name,arg) == 0)
				{
					switch (pik->type)
					{
						case IKT_STD:
							(*a)[j] = pik->val;
							j++;
							found = 1;
						break;

						case IKT_OSD_KEY:
							(*a)[j] = keyoscode_to_code(pik->val);
							j++;
							found = 1;
						break;

						case IKT_OSD_JOY:
							(*a)[j] = joyoscode_to_code(pik->val);
							j++;
							found = 1;
						break;
					}
				}
				pik++;
			}
		}

		arg = strtok(NULL, " \t\r\n");
	}
	free (lbuf);
}

void init_analog_seq()
{
	struct InputPort *in;
	int player, axis;

/* init analogjoy_input array */
	for (player=0; player<OSD_MAX_JOY_ANALOG; player++)
	{
		for (axis=0; axis<MAX_ANALOG_AXES; axis++)
		{
			analogjoy_input[player][axis] = CODE_NONE;
		}
	}

	in = Machine->input_ports;
	if (in->type == IPT_END) return; 	/* nothing to do */

	/* make sure the InputPort definition is correct */
	if (in->type != IPT_PORT)
	{
		logerror("Error in InputPort definition: expecting PORT_START\n");
		return;
	}
	else
	{
		in++;
	}

	while (in->type != IPT_END)
	{
		if (in->type != IPT_PORT && ((in->type & ~IPF_MASK) > IPT_ANALOG_START)
			&& ((in->type & ~IPF_MASK) < IPT_ANALOG_END))
		{
			int j, invert;
			InputSeq *seq;
			InputCode analog_seq;

			seq = input_port_seq(in);
			invert = 0;
			analog_seq = CODE_NONE;

			for(j=0; j<SEQ_MAX && analog_seq == CODE_NONE; ++j)
			{
				switch ((*seq)[j])
				{
					case CODE_NONE :
						continue;
					case CODE_NOT :
						invert = !invert;
						break;
					case CODE_OR :
						invert = 0;
						break;
					default:
						if (!invert && is_joystick_axis_code((*seq)[j]) )
						{
							analog_seq = return_os_joycode((*seq)[j]);
						}
						invert = 0;
						break;
				}
			}
			if (analog_seq != CODE_NONE)
			{
				switch (in->type & IPF_PLAYERMASK)
				{
					case IPF_PLAYER2:          player = 1; break;
					case IPF_PLAYER3:          player = 2; break;
					case IPF_PLAYER4:          player = 3; break;
					case IPF_PLAYER1: default: player = 0; break;
				}

				switch (in->type & ~IPF_MASK)
				{
					case IPT_DIAL:
					case IPT_TRACKBALL_X:
						axis = X_AXIS;
						break;
					case IPT_TRACKBALL_Y:
						axis = Y_AXIS;
						break;
					default:
						axis = 0;
						break;
				}

				analogjoy_input[player][axis] = analog_seq;
			}
		}

		in++;
	}

	return;
}
