TOP MAP UP

HAUMAME

HAUMAMEについて

HAUMAMEとは、もともとカリスマプログラマのはぅさんによって作られた派生MAMEの事を指す。
v0.36あたりのNEOGEO/CPS2等が盛んにサポートされたあたりに特に活発にリリースされていた。
機能も多岐に渡りステートセーブ等を実装していた

この頃エミュ厨の跋扈がかなり酷く(まぁ今もだが・・・)GPL関連のいざこざによりHAUMAMEはあっさりと一般公開を終了(この件についての是非はここでは議論しない)

しかしV-Syncに同期したシンクロ連射、通称「はぅ連」とエミュレータ上のボタンに複数の実際のボタンを割り当てる通称「Exキー」は一部のお願いちゃんにより非常に継続を望まれたために何故かAZUCOがせっせとMAMEの新バージョンが出るたびに実装したいた(はぅさん本人はPSOをしていた模様・・・・)

しかしMAMEが様々なゲームをサポートするにあたり、旧来のアーキテクチャでは無理があると判断したのか、v0.97辺りまでMAMEコアその物に大きく修正が入った事、気が付くとAZUCOも何故かPSOをプレイしているという状態であった為に、とある時期から実装が中断していた。

今回、お願いちゃんが再度熱望した事、AZUCOのPSOの垢がBANされた事、必死の決断によりPSUはプレイしない事に決定した事、などにより再度実装の運びとなった

自分で実装しよう!

AZUCOも他に色々やる事があるので、なるべく自分で実装して欲しいのである。技術的問題により齟齬が発生するかもしれない。でも聞いて(長門)
基本的に移植すべき部分には「HAUMAME」というキーワードが出てくる。これを手がかりに、どこからどこまでを移植するのかを以下に解説する

mame/makefile

###########################################################################
#################   BEGIN USER-CONFIGURABLE OPTIONS   #####################
###########################################################################

HAUMAME = 1
メイクファイルの先頭辺り。メイクファイル内のディレクティブとしてHAUMAMEを定義(Cのディレクティブとは別物なので混同しないように)

#-------------------------------------------------
# compile-time definitions
#-------------------------------------------------

DEFS = -DX86_ASM -DLSB_FIRST -DINLINE="static __inline__" -Dasm=__asm__ -DCRLF=3

ifdef HAUMAME
DEFS += -DHAUMAME
endif
+=は追加であるので、順番は特に規定されないと思うが、まぁ一番最後が良いのではないか。ちなみにここで、CのディレクティブとなるHAUMAMEを規定している

mame/src/haumame.h

このファイルはそもそもMAMEには無い物なので、そのまま上書きでOK。

mame/src/inputport.c

一番複雑な事をしている部分。
/***************************************************************************
    DEFAULT INPUT PORTS
***************************************************************************/

		:
		略
		:

	INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, SELECT,				"P1 Select",			SEQ_DEF_3(KEYCODE_5, CODE_OR, JOYCODE_1_SELECT) )

#ifdef	HAUMAME
	INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1,	RAPID_JOYSTICK_UP,	"P1 RAPID Up",		SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1,	RAPID_JOYSTICK_DOWN,	"P1 RAPID Down",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1,	RAPID_JOYSTICK_LEFT,	"P1 RAPID Left",    	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1,	RAPID_JOYSTICK_RIGHT,	"P1 RAPID Right",   	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1,	RAPID_BUTTON1,		"P1 RAPID Button 1",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1,	RAPID_BUTTON2,		"P1 RAPID Button 2",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1,	RAPID_BUTTON3,		"P1 RAPID Button 3",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1,	RAPID_BUTTON4,		"P1 RAPID Button 4",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1,	RAPID_BUTTON5,		"P1 RAPID Button 5",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1,	RAPID_BUTTON6,		"P1 RAPID Button 6",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1,	RAPID_BUTTON7,		"P1 RAPID Button 7",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1,	RAPID_BUTTON8,		"P1 RAPID Button 8",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1,	RAPID_BUTTON9,		"P1 RAPID Button 9",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1,	RAPID_BUTTON10,		"P1 RAPID Button 10",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, RAPID_START,		"P1 RAPID Start",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1, RAPID_SELECT,		"P1 RAPID Select",	SEQ_DEF_0 )
#endif

	INPUT_PORT_DIGITAL_DEF( 1, IPG_PLAYER1,	MAHJONG_A,          "P1 Mahjong A",			SEQ_DEF_1(KEYCODE_A) )

		:
		略
		:

	INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, SELECT,				"P2 Select",			SEQ_DEF_3(KEYCODE_6, CODE_OR, JOYCODE_2_SELECT) )

#ifdef	HAUMAME
	INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2,	RAPID_JOYSTICK_UP,	"P2 RAPID Up",		SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2,	RAPID_JOYSTICK_DOWN,	"P2 RAPID Down",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2,	RAPID_JOYSTICK_LEFT,	"P2 RAPID Left",    	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2,	RAPID_JOYSTICK_RIGHT,	"P2 RAPID Right",   	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2,	RAPID_BUTTON1,		"P2 RAPID Button 1",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2,	RAPID_BUTTON2,		"P2 RAPID Button 2",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2,	RAPID_BUTTON3,		"P2 RAPID Button 3",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2,	RAPID_BUTTON4,		"P2 RAPID Button 4",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2,	RAPID_BUTTON5,		"P2 RAPID Button 5",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2,	RAPID_BUTTON6,		"P2 RAPID Button 6",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2,	RAPID_BUTTON7,		"P2 RAPID Button 7",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2,	RAPID_BUTTON8,		"P2 RAPID Button 8",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2,	RAPID_BUTTON9,		"P2 RAPID Button 9",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2,	RAPID_BUTTON10,		"P2 RAPID Button 10",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, RAPID_START,		"P2 RAPID Start",	SEQ_DEF_0 )
	INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2, RAPID_SELECT,		"P2 RAPID Select",	SEQ_DEF_0 )
#endif

	INPUT_PORT_DIGITAL_DEF( 2, IPG_PLAYER2,	MAHJONG_A,          "P2 Mahjong A",			SEQ_DEF_0 )
最初のコメント欄にあるように、デフォルトのインプットポートを定義している。

/***************************************************************************
    CORE IMPLEMENTATION
***************************************************************************/

#ifdef	HAUMAME
#include	"haumame.h"
static input_port_entry *hau_ipa[HAU_RAPID_MAX][2];
extern int		hau_rc[HAU_RAPID_MAX][2];

static int rapid_pressed(input_port_entry *in)
{
	int i;
	int press0 = 0;
	int press1 = 0;
	int result2 = 0;

					press0 = seq_pressed(input_port_seq(in,SEQ_TYPE_STANDARD));
	for(i=0;i< HAU_RAPID_MAX;i++){
		if(	(hau_ipa[i][0]==in)&&
			(hau_ipa[i][1]!=0)	){
					press1 = seq_pressed(input_port_seq(hau_ipa[i][1],SEQ_TYPE_STANDARD));
			if(press1){
				if(hau_rc[i][1]==0){
					result2=1;
					hau_rc[i][1]=hau_rc[i][0];
				}else{	result2=0;
					hau_rc[i][1]--;
				}
			}else{		result2=0;
					hau_rc[i][1]=0;
			}

			if(result2)	return(press1);
			else		return(press0);
		}
	}

	return(press0);
}
#endif
連射の処理をしている部分。
hau_ipaはインプットポートのエイリアスでポインタが格納される(つまりそれを通して実体にアクセスするのだが、いちいち探すのが手間なので、最初にこのエイリアスに突っ込んでおくのだ)
最初の配列はボタンを表す(haumame.h内でmaxは32と定義してある)次の配列は、0=リダイレクトする先(つまりエミュ上で実体のあるボタン)、1=Exキーのインプットポートになっている。
処理的にはリダイレクトされる先のボタンのサーチが来れば、Exキーのステータスをチェックし(この時連射処理も行う)それをリダイレクト先に反映させる
連射処理は、キーを押してない時は常にカウンターをゼロセットする(ここが重要)押した時は、カウンターがゼロであるならば「押している」と判定し、カウンターを設定されたカウント値に設定する。カウンターがゼロでない場合はデクリメントし、押してないという判定を行う。これにより「押した時にすぐ発射」が可能となる。
ちなみに一番最後でExキーとおおもとのキーの論理値をorしているので、連射ボタンは押しっぱなしだが、おおもとのキーも押しっぱなしとすることで、溜めショット等も打つ事が可能(R-TYPEとか必須)

/*************************************
 *
 *  Input port initialize
 *
 *************************************/

int input_port_init(running_machine *machine, void (*construct_ipt)(input_port_init_params *))
{

		:
		略
		:

		input_port_entry *port;
#ifdef	HAUMAME
		input_port_entry *pend;
#endif
		int portnum;

		:
		略
		:

		/* identify all the tagged ports up front so the memory system can access them */
		portnum = 0;
		for (port = Machine->input_ports; port->type != IPT_END; port++)
			if (port->type == IPT_PORT)
				port_info[portnum++].tag = port->start.tag;

#ifdef	HAUMAME
for (	pend = Machine->input_ports;
	pend->type != IPT_END;)
	pend++;

for (	port = Machine->input_ports;
	port->type != IPT_END;
	port++){

	switch(	((port->player+1)<<16)|
		(port->type)		){

		case	(IPG_PLAYER1<<16)|IPT_JOYSTICK_UP:
			hau_ipa[ 0][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_JOYSTICK_UP;
			hau_ipa[ 0][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER1<<16)|IPT_JOYSTICK_DOWN:
			hau_ipa[ 1][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_JOYSTICK_DOWN;
			hau_ipa[ 1][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER1<<16)|IPT_JOYSTICK_LEFT:
			hau_ipa[ 2][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_JOYSTICK_LEFT;
			hau_ipa[ 2][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER1<<16)|IPT_JOYSTICK_RIGHT:
			hau_ipa[ 3][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_JOYSTICK_RIGHT;
			hau_ipa[ 3][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER1<<16)|IPT_BUTTON1:
			hau_ipa[ 4][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON1;
			hau_ipa[ 4][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER1<<16)|IPT_BUTTON2:
			hau_ipa[ 5][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON2;
			hau_ipa[ 5][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER1<<16)|IPT_BUTTON3:
			hau_ipa[ 6][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON3;
			hau_ipa[ 6][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER1<<16)|IPT_BUTTON4:
			hau_ipa[ 7][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON4;
			hau_ipa[ 7][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER1<<16)|IPT_BUTTON5:
			hau_ipa[ 8][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON5;
			hau_ipa[ 8][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER1<<16)|IPT_BUTTON6:
			hau_ipa[ 9][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON6;
			hau_ipa[ 9][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER1<<16)|IPT_BUTTON7:
			hau_ipa[10][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON7;
			hau_ipa[10][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER1<<16)|IPT_BUTTON8:
			hau_ipa[11][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON8;
			hau_ipa[11][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER1<<16)|IPT_BUTTON9:
			hau_ipa[12][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON9;
			hau_ipa[12][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER1<<16)|IPT_BUTTON10:
			hau_ipa[13][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON10;
			hau_ipa[13][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER1<<16)|IPT_START1:
			hau_ipa[14][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_START;
			hau_ipa[14][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER1<<16)|IPT_SELECT:
			hau_ipa[15][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_SELECT;
			hau_ipa[15][1]=pend;
			pend++;
			break;


		case	(IPG_PLAYER2<<16)|IPT_JOYSTICK_UP:
			hau_ipa[16][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_JOYSTICK_UP;
			hau_ipa[16][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER2<<16)|IPT_JOYSTICK_DOWN:
			hau_ipa[17][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_JOYSTICK_DOWN;
			hau_ipa[17][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER2<<16)|IPT_JOYSTICK_LEFT:
			hau_ipa[18][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_JOYSTICK_LEFT;
			hau_ipa[18][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER2<<16)|IPT_JOYSTICK_RIGHT:
			hau_ipa[19][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_JOYSTICK_RIGHT;
			hau_ipa[19][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER2<<16)|IPT_BUTTON1:
			hau_ipa[20][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON1;
			hau_ipa[20][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER2<<16)|IPT_BUTTON2:
			hau_ipa[21][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON2;
			hau_ipa[21][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER2<<16)|IPT_BUTTON3:
			hau_ipa[22][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON3;
			hau_ipa[22][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER2<<16)|IPT_BUTTON4:
			hau_ipa[23][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON4;
			hau_ipa[23][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER2<<16)|IPT_BUTTON5:
			hau_ipa[24][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON5;
			hau_ipa[24][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER2<<16)|IPT_BUTTON6:
			hau_ipa[25][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON6;
			hau_ipa[25][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER2<<16)|IPT_BUTTON7:
			hau_ipa[26][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON7;
			hau_ipa[26][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER2<<16)|IPT_BUTTON8:
			hau_ipa[27][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON8;
			hau_ipa[27][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER2<<16)|IPT_BUTTON9:
			hau_ipa[28][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON9;
			hau_ipa[28][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER2<<16)|IPT_BUTTON10:
			hau_ipa[29][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_BUTTON10;
			hau_ipa[29][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER2<<16)|IPT_START2:
			hau_ipa[30][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_START;
			hau_ipa[30][1]=pend;
			pend++;
			break;

		case	(IPG_PLAYER2<<16)|IPT_SELECT:
			hau_ipa[31][0]=port;
			memcpy(pend+1,pend,sizeof(input_port_entry));
			memcpy(pend,port,sizeof(input_port_entry));
			pend->mask=0;
			pend->type=IPT_RAPID_SELECT;
			hau_ipa[31][1]=pend;
			pend++;
			break;
	}
}
#endif
portには現在のゲームで使用されるボタンがドライバ上で定義され格納されている
そのportをスキャンしExキーが割り当てられる予定のおおもとのキーを発見した場合、hau_ipaに格納する(hau_ipa[?][0]=port;の部分)
memcpyを2回行い、現在のゲームで使用されるボタンの配列を無理矢理拡張する(pendというポインタがボタン定義の終端、IPT_ENDを指すようになっている)
拡張して空いた部分にExキーの情報を埋め込む。この際、Exキーはエミュレータ上では実体のないキーであるのでマスク値はゼロとなる。
最後にhau_ipaにExキーを登録し、pendを進めて次の処理へ進む

/*************************************
 *
 *  VBLANK start routine
 *
 *************************************/

void input_port_vblank_start(void)
{

		:
		略
		:


				/* handle non-analog types, but only when the UI isn't visible */
				if (port->type != IPT_VBLANK && !IS_ANALOG(port) && !ui_visible)
				{
					/* if the sequence for this port is currently pressed.... */
#ifdef	HAUMAME
					if (rapid_pressed(port))
#else
					if (seq_pressed(input_port_seq(port, SEQ_TYPE_STANDARD)))
#endif
					{
シンクロ連射のシンクロする所以たる部分

mame/src/inputport.h

	IPT_BUTTON10,

#ifdef	HAUMAME
	IPT_RAPID_JOYSTICK_UP,
	IPT_RAPID_JOYSTICK_DOWN,
	IPT_RAPID_JOYSTICK_LEFT,
	IPT_RAPID_JOYSTICK_RIGHT,

	IPT_RAPID_BUTTON1,
	IPT_RAPID_BUTTON2,
	IPT_RAPID_BUTTON3,
	IPT_RAPID_BUTTON4,
	IPT_RAPID_BUTTON5,
	IPT_RAPID_BUTTON6,
	IPT_RAPID_BUTTON7,
	IPT_RAPID_BUTTON8,
	IPT_RAPID_BUTTON9,
	IPT_RAPID_BUTTON10,

	IPT_RAPID_START,
	IPT_RAPID_SELECT,
#endif

	/* mahjong inputs */
実は場所はあまり関係ないのだが(単にユニークな値を列挙するだけなので)MAME側で「なんとかの値からなんとかの値までをメニューに列挙」という処理をやっているっぽいので、この位置に入れておくとまぁ便利かな?と

mame/src/uimenu.c

/***************************************************************************
    GLOBAL VARIABLES
***************************************************************************/

#ifdef	HAUMAME
#include	"haumame.h"
static UINT32	hau_menu(UINT32 state);
int		hau_rc[HAU_RAPID_MAX][2];
#endif
これも場所は特に問われないはず

#ifdef	HAUMAME
static UINT32 hau_menu(UINT32 state)
{	char		menutext[HAU_RAPID_MAX][0x100];
	int		menu_items;
	ui_menu_item	item_list[HAU_RAPID_MAX+2];

	/* reset the menu */
	memset(item_list, 0, sizeof(item_list));

	/* build up the menu */
	for(menu_items=0;menu_items< HAU_RAPID_MAX;menu_items++){
		sprintf(menutext[menu_items],"%s %02d",ui_getstring(UI_hau+1+menu_items),hau_rc[menu_items][0]);
		item_list[menu_items].text = menutext[menu_items];
	}

	/* add an item for the return */
	item_list[menu_items++].text = ui_getstring(UI_returntomain);

	/* draw the menu */
	ui_menu_draw(item_list, menu_items, state);

	/* handle the keys */
	if (ui_menu_generic_keys(&state, menu_items))
		return state;

	/* handle left/right arrows */
	if (input_ui_pressed(IPT_UI_LEFT))
		if(hau_rc[state][0]!=0 )	hau_rc[state][0]--;
	if (input_ui_pressed(IPT_UI_RIGHT))
		if(hau_rc[state][0]!=59)	hau_rc[state][0]++;

	return state;
}
#endif

/***************************************************************************
    MENU HANDLERS
***************************************************************************/
menu handlersの前あたりに入れるとよろし(これも別に何処でも良いのだが)
ここでは具体的には連射速度を決めている。
この数値はこの数値分だけボタンを押したという判定をスキップする。つまり数値を大きくすればするほど、連射が遅くなる。
ちなみにゼロでは押した時は常に押したと判定されるので、連射にはならない

static UINT32 menu_main(UINT32 state)
{

		:
		略
		:

	/* add input menu items */
	ADD_MENU(UI_inputgeneral, menu_input_groups, 0);
	ADD_MENU(UI_inputspecific, menu_input, 1000 << 16);

#ifdef	HAUMAME
	ADD_MENU(UI_hau,hau_menu,0);
#endif
こいつは場所が重要。ここに入れましょう。

mame/src/uitext.c

	"Flip Y",

#ifdef	HAUMAME
	"HAUMAME",
	"1P RAPID     UP",
	"1P RAPID   DOWN",
	"1P RAPID   LEFT",
	"1P RAPID  RIGHT",
	"1P RAPID BUTN01",
	"1P RAPID BUTN02",
	"1P RAPID BUTN03",
	"1P RAPID BUTN04",
	"1P RAPID BUTN05",
	"1P RAPID BUTN06",
	"1P RAPID BUTN07",
	"1P RAPID BUTN08",
	"1P RAPID BUTN09",
	"1P RAPID BUTN10",
	"1P RAPID  START",
	"1P RAPID SELECT",
	"2P RAPID     UP",
	"2P RAPID   DOWN",
	"2P RAPID   LEFT",
	"2P RAPID  RIGHT",
	"2P RAPID BUTN01",
	"2P RAPID BUTN02",
	"2P RAPID BUTN03",
	"2P RAPID BUTN04",
	"2P RAPID BUTN05",
	"2P RAPID BUTN06",
	"2P RAPID BUTN07",
	"2P RAPID BUTN08",
	"2P RAPID BUTN09",
	"2P RAPID BUTN10",
	"2P RAPID  START",
	"2P RAPID SELECT",
#endif

	NULL
これも何処でも良いと言えば良いのだが、順序が大事なのでここに入れましょう

mame/src/uitext.h

	UI_flip_y,

#ifdef	HAUMAME
	UI_hau,
	UI_hau_dummy00,
	UI_hau_dummy01,
	UI_hau_dummy02,
	UI_hau_dummy03,
	UI_hau_dummy04,
	UI_hau_dummy05,
	UI_hau_dummy06,
	UI_hau_dummy07,
	UI_hau_dummy08,
	UI_hau_dummy09,
	UI_hau_dummy10,
	UI_hau_dummy11,
	UI_hau_dummy12,
	UI_hau_dummy13,
	UI_hau_dummy14,
	UI_hau_dummy15,
	UI_hau_dummy16,
	UI_hau_dummy17,
	UI_hau_dummy18,
	UI_hau_dummy19,
	UI_hau_dummy20,
	UI_hau_dummy21,
	UI_hau_dummy22,
	UI_hau_dummy23,
	UI_hau_dummy24,
	UI_hau_dummy25,
	UI_hau_dummy26,
	UI_hau_dummy27,
	UI_hau_dummy28,
	UI_hau_dummy29,
	UI_hau_dummy30,
	UI_hau_dummy31,
#endif

	UI_last_mame_entry
上記部分の順序があってないとダメな部分。

その他注意点・わかっている問題点など

方向キーのEx/連射がうまく行かない
これは以前のHAUMAMEでも課題点ではあったが、今回も同じ。気合が入れば調査するかも

デバッグビルドで挙動不審
これも方向キーがらみの問題点だと思われる

キーアサイン等は記憶されない
一部されてるように見えるが、基本的に気の迷い

今回このソースは名前こそHAUMAMEであるが、ほとんどAZUCOのスクラッチなので、質問等はAZUCOの方にするように!
リスペクトは、はぅさんとAZUCOにするように!www