input: merge buttons and axes
Default mappings for arcade and console Default mappings for arcade stick/hitbox Proper handling of inverted axes ggpo: automatic analog setting for arcade games
This commit is contained in:
parent
50a67dbd3e
commit
65956dbc8d
|
@ -762,8 +762,6 @@ if(NOT LIBRETRO)
|
|||
core/linux-dist/evdev.cpp
|
||||
core/linux-dist/evdev.h
|
||||
core/linux-dist/icon.h
|
||||
core/linux-dist/joystick.cpp
|
||||
core/linux-dist/joystick.h
|
||||
core/linux-dist/x11.cpp
|
||||
core/linux-dist/x11.h
|
||||
core/linux-dist/x11_keyboard.h)
|
||||
|
|
|
@ -13,7 +13,7 @@ static u8 GetBtFromSgn(s8 val)
|
|||
}
|
||||
|
||||
u32 awave_button_mapping[32] = {
|
||||
AWAVE_SERVICE_KEY, // DC_BTN_C
|
||||
AWAVE_BTN2_KEY, // DC_BTN_C
|
||||
AWAVE_BTN1_KEY, // DC_BTN_B
|
||||
AWAVE_BTN0_KEY, // DC_BTN_A
|
||||
AWAVE_START_KEY, // DC_BTN_START
|
||||
|
@ -21,18 +21,18 @@ u32 awave_button_mapping[32] = {
|
|||
AWAVE_DOWN_KEY, // DC_DPAD_DOWN
|
||||
AWAVE_LEFT_KEY, // DC_DPAD_LEFT
|
||||
AWAVE_RIGHT_KEY, // DC_DPAD_RIGHT
|
||||
AWAVE_TEST_KEY, // DC_BTN_Z
|
||||
AWAVE_BTN3_KEY, // DC_BTN_Y
|
||||
AWAVE_BTN2_KEY, // DC_BTN_X
|
||||
AWAVE_BTN4_KEY, // DC_BTN_Z (duplicated)
|
||||
AWAVE_BTN4_KEY, // DC_BTN_Y
|
||||
AWAVE_BTN3_KEY, // DC_BTN_X
|
||||
AWAVE_COIN_KEY, // DC_BTN_D
|
||||
AWAVE_BTN4_KEY, // DC_DPAD2_UP
|
||||
0, // DC_DPAD2_DOWN
|
||||
AWAVE_SERVICE_KEY, // DC_DPAD2_UP
|
||||
AWAVE_TEST_KEY, // DC_DPAD2_DOWN
|
||||
0, // DC_DPAD2_LEFT
|
||||
0, // DC_DPAD2_RIGHT
|
||||
};
|
||||
|
||||
u32 awavelg_button_mapping[32] = {
|
||||
AWAVE_SERVICE_KEY, // DC_BTN_C
|
||||
AWAVE_BTN1_KEY, // DC_BTN_C
|
||||
AWAVE_BTN0_KEY, // DC_BTN_B
|
||||
AWAVE_TRIGGER_KEY, // DC_BTN_A
|
||||
AWAVE_START_KEY, // DC_BTN_START
|
||||
|
@ -40,12 +40,12 @@ u32 awavelg_button_mapping[32] = {
|
|||
AWAVE_DOWN_KEY, // DC_DPAD_DOWN
|
||||
AWAVE_LEFT_KEY, // DC_DPAD_LEFT
|
||||
AWAVE_RIGHT_KEY, // DC_DPAD_RIGHT
|
||||
AWAVE_TEST_KEY, // DC_BTN_Z
|
||||
AWAVE_BTN2_KEY, // DC_BTN_Y
|
||||
AWAVE_BTN1_KEY, // DC_BTN_X
|
||||
AWAVE_BTN4_KEY, // DC_BTN_Z
|
||||
AWAVE_BTN3_KEY, // DC_BTN_Y
|
||||
AWAVE_BTN2_KEY, // DC_BTN_X
|
||||
AWAVE_COIN_KEY, // DC_BTN_D
|
||||
AWAVE_BTN3_KEY, // DC_DPAD2_UP
|
||||
AWAVE_BTN4_KEY, // DC_DPAD2_DOWN
|
||||
AWAVE_SERVICE_KEY, // DC_DPAD2_UP
|
||||
AWAVE_TEST_KEY, // DC_DPAD2_DOWN
|
||||
0, // DC_DPAD2_LEFT
|
||||
0, // DC_DPAD2_RIGHT
|
||||
|
||||
|
@ -64,8 +64,7 @@ void MapleConfigMap::SetVibration(float power, float inclination, u32 duration_m
|
|||
|
||||
void MapleConfigMap::GetInput(PlainJoystickState* pjs)
|
||||
{
|
||||
u32 player_num = playerNum();
|
||||
const MapleInputState& inputState = mapleInputState[player_num];
|
||||
const MapleInputState& inputState = mapleInputState[playerNum()];
|
||||
|
||||
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
||||
{
|
||||
|
@ -126,7 +125,7 @@ void MapleConfigMap::GetInput(PlainJoystickState* pjs)
|
|||
pjs->joy[axis] = inputState.halfAxes[PJTI_L];
|
||||
break;
|
||||
default:
|
||||
pjs->joy[axis] = 0x80;
|
||||
pjs->joy[axis] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ void load_naomi_eeprom()
|
|||
}
|
||||
|
||||
const u32 naomi_button_mapping[32] = {
|
||||
NAOMI_SERVICE_KEY, // DC_BTN_C
|
||||
NAOMI_BTN2_KEY, // DC_BTN_C
|
||||
NAOMI_BTN1_KEY, // DC_BTN_B
|
||||
NAOMI_BTN0_KEY, // DC_BTN_A
|
||||
NAOMI_START_KEY, // DC_BTN_START
|
||||
|
@ -62,12 +62,12 @@ const u32 naomi_button_mapping[32] = {
|
|||
NAOMI_DOWN_KEY, // DC_DPAD_DOWN
|
||||
NAOMI_LEFT_KEY, // DC_DPAD_LEFT
|
||||
NAOMI_RIGHT_KEY, // DC_DPAD_RIGHT
|
||||
NAOMI_TEST_KEY, // DC_BTN_Z
|
||||
NAOMI_BTN3_KEY, // DC_BTN_Y
|
||||
NAOMI_BTN2_KEY, // DC_BTN_X
|
||||
NAOMI_BTN5_KEY, // DC_BTN_Z
|
||||
NAOMI_BTN4_KEY, // DC_BTN_Y
|
||||
NAOMI_BTN3_KEY, // DC_BTN_X
|
||||
NAOMI_COIN_KEY, // DC_BTN_D
|
||||
NAOMI_BTN4_KEY, // DC_DPAD2_UP
|
||||
NAOMI_BTN5_KEY, // DC_DPAD2_DOWN
|
||||
NAOMI_SERVICE_KEY, // DC_DPAD2_UP
|
||||
NAOMI_TEST_KEY, // DC_DPAD2_DOWN
|
||||
NAOMI_BTN6_KEY, // DC_DPAD2_LEFT
|
||||
NAOMI_BTN7_KEY, // DC_DPAD2_RIGHT
|
||||
|
||||
|
@ -79,7 +79,7 @@ extern u32 awavelg_button_mapping[32];
|
|||
|
||||
const char *GetCurrentGameButtonName(DreamcastKey key)
|
||||
{
|
||||
if (NaomiGameInputs == nullptr || key == EMU_BTN_NONE)
|
||||
if (NaomiGameInputs == nullptr || key == EMU_BTN_NONE || key > DC_BTN_RELOAD)
|
||||
return nullptr;
|
||||
u32 pos = 0;
|
||||
u32 val = (u32)key;
|
||||
|
@ -116,33 +116,36 @@ const char *GetCurrentGameAxisName(DreamcastKey axis)
|
|||
|
||||
for (int i = 0; NaomiGameInputs->axes[i].name != nullptr; i++)
|
||||
{
|
||||
DreamcastKey cur_axis;
|
||||
switch (NaomiGameInputs->axes[i].axis)
|
||||
{
|
||||
case 0:
|
||||
cur_axis = DC_AXIS_X;
|
||||
if (axis != DC_AXIS_LEFT && axis != DC_AXIS_RIGHT)
|
||||
continue;
|
||||
break;
|
||||
case 1:
|
||||
cur_axis = DC_AXIS_Y;
|
||||
if (axis != DC_AXIS_UP && axis != DC_AXIS_DOWN)
|
||||
continue;
|
||||
break;
|
||||
case 2:
|
||||
cur_axis = DC_AXIS_X2;
|
||||
if (axis != DC_AXIS2_LEFT && axis != DC_AXIS2_RIGHT)
|
||||
continue;
|
||||
break;
|
||||
case 3:
|
||||
cur_axis = DC_AXIS_Y2;
|
||||
if (axis != DC_AXIS2_UP && axis != DC_AXIS2_DOWN)
|
||||
continue;
|
||||
break;
|
||||
case 4:
|
||||
cur_axis = DC_AXIS_RT;
|
||||
if (axis != DC_AXIS_RT)
|
||||
continue;
|
||||
break;
|
||||
case 5:
|
||||
cur_axis = DC_AXIS_LT;
|
||||
if (axis != DC_AXIS_LT)
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
cur_axis = EMU_BTN_NONE;
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (cur_axis == axis)
|
||||
return NaomiGameInputs->axes[i].name;
|
||||
return NaomiGameInputs->axes[i].name;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
|
|
@ -206,8 +206,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
nullptr,
|
||||
// ATACK, HOLD, THROW, MOVE
|
||||
// same as ggram2
|
||||
&giant_gram_inputs,
|
||||
},
|
||||
// Kick '4' Cash (Export)
|
||||
{
|
||||
|
@ -959,7 +958,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
NULL,
|
||||
&capsnk_inputs
|
||||
&capcom_4btn_inputs
|
||||
},
|
||||
// Capcom Vs. SNK Millennium Fight 2000 (Rev A)
|
||||
{
|
||||
|
@ -984,7 +983,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
NULL,
|
||||
&capsnk_inputs
|
||||
&capcom_4btn_inputs
|
||||
},
|
||||
// Capcom Vs. SNK Millennium Fight 2000
|
||||
{
|
||||
|
@ -1009,7 +1008,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
NULL,
|
||||
&capsnk_inputs
|
||||
&capcom_4btn_inputs
|
||||
},
|
||||
// Crackin' DJ
|
||||
{
|
||||
|
@ -1810,8 +1809,9 @@ Game Games[] =
|
|||
{ "mpr-21830.ic10", 0x5000000, 0x0800000 },
|
||||
{ "mpr-21831.ic11", 0x5800000, 0x0800000 },
|
||||
{ NULL, 0, 0 },
|
||||
}
|
||||
// same as gram2000
|
||||
},
|
||||
nullptr,
|
||||
&giant_gram_inputs,
|
||||
},
|
||||
// Guilty Gear X (JPN)
|
||||
{
|
||||
|
@ -1988,7 +1988,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
NULL,
|
||||
&shot1234_inputs,
|
||||
&hmgeo_input,
|
||||
hmgeo_eeprom_dump
|
||||
},
|
||||
// House of the Dead 2
|
||||
|
@ -2596,7 +2596,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
nullptr,
|
||||
&pjustic_inputs,
|
||||
&capcom_4btn_inputs,
|
||||
},
|
||||
// Power Stone
|
||||
{
|
||||
|
@ -2623,7 +2623,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
nullptr,
|
||||
&shot123_inputs,
|
||||
&pstone_inputs,
|
||||
},
|
||||
// Power Stone 2
|
||||
{
|
||||
|
@ -2650,7 +2650,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
nullptr,
|
||||
&shot123_inputs,
|
||||
&pstone2_inputs,
|
||||
pstone2_eeprom_dump
|
||||
},
|
||||
// Power Stone 2 (bootleg)
|
||||
|
@ -2678,7 +2678,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
nullptr,
|
||||
&shot123_inputs,
|
||||
&pstone2_inputs,
|
||||
pstone2_eeprom_dump
|
||||
},
|
||||
// Puyo Puyo Da! (Japan)
|
||||
|
@ -3588,7 +3588,9 @@ Game Games[] =
|
|||
{ "trf1ma14.6m", 0xe000000, 0x1000000 },
|
||||
{ "trf1ma15.6l", 0xf000000, 0x1000000 },
|
||||
{ NULL, 0, 0 },
|
||||
}
|
||||
},
|
||||
nullptr,
|
||||
&toukon4_input,
|
||||
},
|
||||
// Toy Fighter
|
||||
{
|
||||
|
@ -4360,8 +4362,9 @@ Game Games[] =
|
|||
{ "ic13.bin", 0x14000000, 0x4000000 },
|
||||
{ "317-5133-jpn.ic3", 0, 0x800, 0x0000000, Key }, // pic_readout
|
||||
{ NULL, 0, 0 },
|
||||
}
|
||||
// BUTTON A/B/C/D/E
|
||||
},
|
||||
nullptr,
|
||||
&meltyb_input,
|
||||
},
|
||||
// Melty Blood Actress Again (Japan) (Clone)
|
||||
{
|
||||
|
@ -4383,7 +4386,9 @@ Game Games[] =
|
|||
{ "ic13.bin", 0x14000000, 0x4000000 },
|
||||
{ "317-5133-jpn.ic3", 0, 0x800, 0x0000000, Key }, // pic_readout
|
||||
{ NULL, 0, 0 },
|
||||
}
|
||||
},
|
||||
nullptr,
|
||||
&meltyb_input,
|
||||
},
|
||||
// Mushiking The King Of Beetles - Mushiking II / III / III+ (Ver. 1.001) (World)
|
||||
{
|
||||
|
@ -4704,7 +4709,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
"gdl-0004",
|
||||
// SHOT1/2/na/4/5
|
||||
&capcom_4btn_inputs,
|
||||
},
|
||||
// Capcom Vs. SNK 2 Mark Of The Millennium 2001 (GDL-0008)
|
||||
// ver 010804
|
||||
|
@ -4724,7 +4729,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
"gdl-0008",
|
||||
&cvs2_inputs,
|
||||
&capcom_6btn_inputs,
|
||||
},
|
||||
// Capcom Vs. SNK 2 Millionaire Fighting 2001 (Rev A) (GDL-0007A)
|
||||
// ver 010705
|
||||
|
@ -4743,7 +4748,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
"gdl-0007a",
|
||||
&cvs2_inputs,
|
||||
&capcom_6btn_inputs,
|
||||
},
|
||||
// Dragon Treasure (Rev B) (GDS-0030B)
|
||||
{
|
||||
|
@ -4850,7 +4855,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
"gdl-0011",
|
||||
// KICK, SLASH, HIGH SLASH, PUNCH, DUST ATTACK
|
||||
&guilty_gear_input,
|
||||
},
|
||||
// Guilty Gear XX Accent Core (Japan) (GDL-0041)
|
||||
{
|
||||
|
@ -4868,7 +4873,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
"gdl-0041",
|
||||
// same KICK, SLASH, HIGH SLASH, PUNCH, DUST ATTACK
|
||||
&guilty_gear_input,
|
||||
},
|
||||
// Guilty Gear XX #Reload (Japan, Rev A) (GDL-0019A)
|
||||
{
|
||||
|
@ -4886,7 +4891,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
"gdl-0019a",
|
||||
// same KICK, SLASH, HIGH SLASH, PUNCH, DUST ATTACK
|
||||
&guilty_gear_input,
|
||||
},
|
||||
// Guilty Gear XX #Reload (Japan) (GDL-0019)
|
||||
{
|
||||
|
@ -4904,6 +4909,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
"gdl-0019",
|
||||
&guilty_gear_input,
|
||||
},
|
||||
// Guilty Gear XX Slash (Japan, Rev A) (GDL-0033A)
|
||||
{
|
||||
|
@ -4921,7 +4927,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
"gdl-0033a",
|
||||
// same KICK, SLASH, HIGH SLASH, PUNCH, DUST ATTACK
|
||||
&guilty_gear_input,
|
||||
},
|
||||
// Mobile Suit Gundam: Federation Vs. Zeon (GDL-0001)
|
||||
{
|
||||
|
@ -5120,7 +5126,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
"gdl-0039a",
|
||||
// BUTTON A/B/C/D/E
|
||||
&meltyb_input,
|
||||
},
|
||||
// Melty Blood Act Cadenza Ver. A (Japan) (GDL-0028C)
|
||||
{
|
||||
|
@ -5138,6 +5144,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
"gdl-0028c",
|
||||
&meltyb_input,
|
||||
},
|
||||
// Melty Blood Act Cadenza (Japan) (GDL-0028)
|
||||
{
|
||||
|
@ -5155,6 +5162,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
"gdl-0028",
|
||||
&meltyb_input,
|
||||
},
|
||||
// Melty Blood Act Cadenza Version B (Japan) (GDL-0039)
|
||||
{
|
||||
|
@ -5172,6 +5180,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
"gdl-0039",
|
||||
&meltyb_input,
|
||||
},
|
||||
// Moeru Casinyo (Japan) (GDL-0013)
|
||||
{
|
||||
|
@ -5427,6 +5436,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
"gdl-0038",
|
||||
&senkosp_input,
|
||||
},
|
||||
// Street Fighter Zero 3 Upper (Japan) (GDL-0002)
|
||||
{
|
||||
|
@ -5445,7 +5455,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
"gdl-0002",
|
||||
&sfz3ugd_inputs
|
||||
&capcom_6btn_inputs,
|
||||
},
|
||||
// Shakatto Tambourine (Rev B) (GDS-0002B)
|
||||
{
|
||||
|
@ -6063,7 +6073,9 @@ Game Games[] =
|
|||
{ "ax1906m01.ic16", 0x6000000, 0x1000000 },
|
||||
{ "ax1907m01.ic17", 0x7000000, 0x1000000 },
|
||||
{ NULL, 0, 0 },
|
||||
}
|
||||
},
|
||||
nullptr,
|
||||
&fotns_input,
|
||||
},
|
||||
// Faster Than Speed
|
||||
{
|
||||
|
@ -6111,7 +6123,9 @@ Game Games[] =
|
|||
{ "ax1207m01.ic16", 0x6000000, 0x1000000 },
|
||||
{ "ax1208m01.ic17", 0x7000000, 0x1000000 },
|
||||
{ NULL, 0, 0 },
|
||||
}
|
||||
},
|
||||
nullptr,
|
||||
&guilty_gear_aw_input,
|
||||
},
|
||||
// Guilty Gear X ver. 1.5
|
||||
{
|
||||
|
@ -6158,7 +6172,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
NULL,
|
||||
&kofnw_inputs
|
||||
&kofnw_input,
|
||||
},
|
||||
// The King of Fighters Neowave (Japan)
|
||||
{
|
||||
|
@ -6183,7 +6197,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
NULL,
|
||||
&kofnw_inputs
|
||||
&kofnw_input,
|
||||
},
|
||||
// The King of Fighters XI
|
||||
{
|
||||
|
@ -6208,7 +6222,7 @@ Game Games[] =
|
|||
{ NULL, 0, 0 },
|
||||
},
|
||||
NULL,
|
||||
&kofxi_inputs
|
||||
&kofxi_input,
|
||||
},
|
||||
// Knights of Valour - The Seven Spirits
|
||||
{
|
||||
|
@ -6274,7 +6288,9 @@ Game Games[] =
|
|||
{ "ax3003m01.mrom3", 0x6000000, 0x2000000 },
|
||||
{ "ax3004m01.mrom4", 0xa000000, 0x2000000 },
|
||||
{ NULL, 0, 0 },
|
||||
}
|
||||
},
|
||||
nullptr,
|
||||
&mslug6_input,
|
||||
},
|
||||
// NeoGeo Battle Coliseum
|
||||
{
|
||||
|
@ -6368,7 +6384,9 @@ Game Games[] =
|
|||
{ "ax1806m01.ic16", 0x6000000, 0x1000000 },
|
||||
{ "ax1807m01.ic17", 0x7000000, 0x1000000 },
|
||||
{ NULL, 0, 0 },
|
||||
}
|
||||
},
|
||||
nullptr,
|
||||
&rumblef_input,
|
||||
},
|
||||
// The Rumble Fish (prototype)
|
||||
{
|
||||
|
@ -6399,7 +6417,9 @@ Game Games[] =
|
|||
{ "ic26", 0x07000000, 0x00800000 },
|
||||
// IC27 populated, empty
|
||||
{ NULL, 0, 0 },
|
||||
}
|
||||
},
|
||||
nullptr,
|
||||
&rumblef_input,
|
||||
},
|
||||
// The Rumble Fish 2
|
||||
{
|
||||
|
@ -6420,7 +6440,9 @@ Game Games[] =
|
|||
{ "ax3404m01.mrom4", 0xa000000, 0x2000000 },
|
||||
{ "ax3405m01.mrom5", 0xc000000, 0x2000000 },
|
||||
{ NULL, 0, 0 },
|
||||
}
|
||||
},
|
||||
nullptr,
|
||||
&rumblef_input,
|
||||
},
|
||||
// The Rumble Fish 2 (prototype)
|
||||
{
|
||||
|
@ -6451,7 +6473,9 @@ Game Games[] =
|
|||
{ "ic26", 0x07000000, 0x00800000 },
|
||||
// IC27 populated, empty
|
||||
{ NULL, 0, 0 },
|
||||
}
|
||||
},
|
||||
nullptr,
|
||||
&rumblef_input,
|
||||
},
|
||||
// Net Select: Salaryman Kintaro
|
||||
{
|
||||
|
|
|
@ -35,47 +35,91 @@
|
|||
{ \
|
||||
{ NAOMI_BTN0_KEY, btn0 }, \
|
||||
{ NAOMI_BTN1_KEY, btn1 }, \
|
||||
{ NAOMI_UP_KEY, "" }, \
|
||||
{ NAOMI_DOWN_KEY, "" }, \
|
||||
{ NAOMI_LEFT_KEY, "" }, \
|
||||
{ NAOMI_RIGHT_KEY, "" }, \
|
||||
NAO_START_DESC \
|
||||
NAO_BASE_BTN_DESC \
|
||||
{ 0 }, \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
#define INPUT_3_BUTTONS(btn0, btn1, btn2) { \
|
||||
{ \
|
||||
{ NAOMI_BTN0_KEY, btn0 }, \
|
||||
{ NAOMI_BTN1_KEY, btn1 }, \
|
||||
{ NAOMI_BTN2_KEY, btn2 }, \
|
||||
{ NAOMI_UP_KEY, "" }, \
|
||||
{ NAOMI_DOWN_KEY, "" }, \
|
||||
{ NAOMI_LEFT_KEY, "" }, \
|
||||
{ NAOMI_RIGHT_KEY, "" }, \
|
||||
NAO_START_DESC \
|
||||
NAO_BASE_BTN_DESC \
|
||||
} \
|
||||
}
|
||||
|
||||
#define INPUT_4_BUTTONS(btn0, btn1, btn2, btn3) { \
|
||||
{ \
|
||||
{ NAOMI_BTN0_KEY, btn0 }, \
|
||||
{ NAOMI_BTN1_KEY, btn1 }, \
|
||||
{ NAOMI_BTN2_KEY, btn2 }, \
|
||||
{ NAOMI_BTN3_KEY, btn3 }, \
|
||||
{ NAOMI_UP_KEY, "" }, \
|
||||
{ NAOMI_DOWN_KEY, "" }, \
|
||||
{ NAOMI_LEFT_KEY, "" }, \
|
||||
{ NAOMI_RIGHT_KEY, "" }, \
|
||||
NAO_START_DESC \
|
||||
NAO_BASE_BTN_DESC \
|
||||
} \
|
||||
}
|
||||
|
||||
#define INPUT_5_BUTTONS(btn0, btn1, btn2, btn3, btn4) { \
|
||||
{ \
|
||||
{ NAOMI_BTN0_KEY, btn0 }, \
|
||||
{ NAOMI_BTN1_KEY, btn1 }, \
|
||||
{ NAOMI_BTN2_KEY, btn2 }, \
|
||||
{ NAOMI_BTN3_KEY, btn3 }, \
|
||||
{ NAOMI_BTN5_KEY, btn4, NAOMI_BTN4_KEY }, \
|
||||
{ NAOMI_UP_KEY, "" }, \
|
||||
{ NAOMI_DOWN_KEY, "" }, \
|
||||
{ NAOMI_LEFT_KEY, "" }, \
|
||||
{ NAOMI_RIGHT_KEY, "" }, \
|
||||
NAO_START_DESC \
|
||||
NAO_BASE_BTN_DESC \
|
||||
} \
|
||||
}
|
||||
|
||||
static InputDescriptors _18wheelr_inputs = {
|
||||
{
|
||||
{ NAOMI_BTN0_KEY, "HORN" },
|
||||
{ NAOMI_DOWN_KEY, "VIEW" },
|
||||
{ NAOMI_BTN1_KEY, "SHIFT L", 0, NAOMI_DOWN_KEY }, // This button uses P2 inputs for P1
|
||||
{ NAOMI_BTN2_KEY, "SHIFT H", 0, NAOMI_UP_KEY }, // This button uses P2 inputs for P1
|
||||
{ NAOMI_BTN2_KEY, "SHIFT L", 0, NAOMI_DOWN_KEY }, // This button uses P2 inputs for P1
|
||||
{ NAOMI_BTN1_KEY, "SHIFT H", 0, NAOMI_UP_KEY }, // This button uses P2 inputs for P1
|
||||
{ NAOMI_BTN3_KEY, "SHIFT R", 0, NAOMI_LEFT_KEY | NAOMI_DOWN_KEY },
|
||||
// This button uses P2 inputs for P1
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ "HANDLE", Full, 0 },
|
||||
{ "ACCEL", Half, 4 },
|
||||
{ "BRAKE", Half, 5 },
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors alienfnt_inputs = {
|
||||
{
|
||||
{ NAOMI_BTN0_KEY, "LEFT SHOT" },
|
||||
{ NAOMI_BTN3_KEY, "ROTATION R", NAOMI_BTN1_KEY },
|
||||
{ NAOMI_BTN5_KEY, "ROTATION R", NAOMI_BTN1_KEY },
|
||||
{ NAOMI_BTN1_KEY, "RIGHT SHOT", NAOMI_BTN2_KEY },
|
||||
{ NAOMI_BTN2_KEY, "ROTATION L", NAOMI_BTN3_KEY },
|
||||
{ NAOMI_BTN4_KEY, "ROTATION L", NAOMI_BTN3_KEY },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ "WHEEL", Full, 0 },
|
||||
{ "RIGHT PEDAL", Half, 4 },
|
||||
{ "LEFT PEDAL", Half, 5 },
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -86,7 +130,6 @@ static InputDescriptors alpilot_inputs = {
|
|||
{ NAOMI_BTN2_KEY, "FLAP SWITCH" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ "ELEVATOR", Full, 1 },
|
||||
|
@ -95,26 +138,38 @@ static InputDescriptors alpilot_inputs = {
|
|||
{ "RUDDER PEDAL", Full, 2 },
|
||||
{ "THRUST LEVER L", Half, 5 },
|
||||
{ "THRUST LEVER R", Half, 4 },
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors capsnk_inputs = {
|
||||
static InputDescriptors capcom_4btn_inputs = {
|
||||
{
|
||||
{ NAOMI_BTN0_KEY, "LIGHT PUNCH" },
|
||||
{ NAOMI_BTN1_KEY, "STRONG PUNCH" },
|
||||
{ NAOMI_BTN1_KEY, "HEAVY PUNCH" },
|
||||
{ NAOMI_BTN3_KEY, "LIGHT KICK" },
|
||||
{ NAOMI_BTN4_KEY, "STRONG KICK" },
|
||||
{ NAOMI_UP_KEY, "UP" },
|
||||
{ NAOMI_DOWN_KEY, "DOWN" },
|
||||
{ NAOMI_LEFT_KEY, "LEFT" },
|
||||
{ NAOMI_RIGHT_KEY, "RIGHT" },
|
||||
{ NAOMI_BTN4_KEY, "HEAVY KICK" },
|
||||
{ NAOMI_UP_KEY, "" },
|
||||
{ NAOMI_DOWN_KEY, "" },
|
||||
{ NAOMI_LEFT_KEY, "" },
|
||||
{ NAOMI_RIGHT_KEY, "" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors capcom_6btn_inputs = {
|
||||
{
|
||||
{ NULL },
|
||||
{ NAOMI_BTN0_KEY, "LIGHT PUNCH" },
|
||||
{ NAOMI_BTN1_KEY, "MEDIUM PUNCH" },
|
||||
{ NAOMI_BTN2_KEY, "HEAVY PUNCH" },
|
||||
{ NAOMI_BTN3_KEY, "LIGHT KICK" },
|
||||
{ NAOMI_BTN4_KEY, "MEDIUM KICK" },
|
||||
{ NAOMI_BTN5_KEY, "HEAVY KICK" },
|
||||
{ NAOMI_UP_KEY, "" },
|
||||
{ NAOMI_DOWN_KEY, "" },
|
||||
{ NAOMI_LEFT_KEY, "" },
|
||||
{ NAOMI_RIGHT_KEY, "" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -124,47 +179,26 @@ static InputDescriptors crzytaxi_inputs = {
|
|||
{ NAOMI_DOWN_KEY, "REVERSE GEAR" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ "HANDLE", Full, 0 },
|
||||
{ "ACCEL", Half, 4 },
|
||||
{ "BRAKE", Half, 5 },
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors cspike_inputs = {
|
||||
{
|
||||
{ NAOMI_BTN0_KEY, "SHOT1" },
|
||||
{ NAOMI_BTN1_KEY, "SHOT2" },
|
||||
{ NAOMI_BTN2_KEY, "SHOT3" },
|
||||
{ NAOMI_BTN3_KEY, "SHOT4" },
|
||||
{ NAOMI_UP_KEY, "UP" },
|
||||
{ NAOMI_DOWN_KEY, "DOWN" },
|
||||
{ NAOMI_LEFT_KEY, "LEFT" },
|
||||
{ NAOMI_RIGHT_KEY, "RIGHT" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
static InputDescriptors cspike_inputs = INPUT_3_BUTTONS("Shoot", "Attack", "Mark");
|
||||
|
||||
static InputDescriptors trigger_inputs = {
|
||||
{
|
||||
{ NAOMI_BTN0_KEY, "TRIGGER" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors giant_gram_inputs = INPUT_4_BUTTONS("Attack", "Hold", "Throw", "Move");
|
||||
|
||||
static InputDescriptors gunsur2_inputs = {
|
||||
{
|
||||
{ NAOMI_BTN0_KEY, "GUN BUTTON" },
|
||||
|
@ -173,13 +207,11 @@ static InputDescriptors gunsur2_inputs = {
|
|||
{ NAOMI_DOWN_KEY, "SELECT DOWN" },
|
||||
{ NAOMI_START_KEY, "ENTER" },
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ "PITCH", Full, 1 },
|
||||
{ "ROLL", Full, 2, true },
|
||||
{ "YAW", Full, 0 },
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -189,13 +221,11 @@ static InputDescriptors jambo_inputs = {
|
|||
{ NAOMI_BTN0_KEY, "LEVER DOWN", 0, NAOMI_UP_KEY }, // This button uses P2 inputs for P1
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ "HANDLE", Full, 0 },
|
||||
{ "ACCEL", Half, 4 },
|
||||
{ "BRAKE", Half, 5 },
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -207,37 +237,12 @@ static InputDescriptors mvsc2_inputs = {
|
|||
{ NAOMI_BTN3_KEY, "LIGHT KICK" },
|
||||
{ NAOMI_BTN4_KEY, "STRONG KICK" },
|
||||
{ NAOMI_BTN5_KEY, "ASSIST B" },
|
||||
{ NAOMI_UP_KEY, "UP" },
|
||||
{ NAOMI_DOWN_KEY, "DOWN" },
|
||||
{ NAOMI_LEFT_KEY, "LEFT" },
|
||||
{ NAOMI_RIGHT_KEY, "RIGHT" },
|
||||
{ NAOMI_UP_KEY, "" },
|
||||
{ NAOMI_DOWN_KEY, "" },
|
||||
{ NAOMI_LEFT_KEY, "" },
|
||||
{ NAOMI_RIGHT_KEY, "" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors sfz3ugd_inputs = {
|
||||
{
|
||||
{ NAOMI_BTN0_KEY, "LIGHT PUNCH" },
|
||||
{ NAOMI_BTN1_KEY, "MEDIUM PUNCH" },
|
||||
{ NAOMI_BTN2_KEY, "STRONG PUNCH" },
|
||||
{ NAOMI_BTN3_KEY, "LIGHT KICK" },
|
||||
{ NAOMI_BTN4_KEY, "MEDIUM KICK" },
|
||||
{ NAOMI_BTN5_KEY, "STRONG KICK" },
|
||||
{ NAOMI_UP_KEY, "UP" },
|
||||
{ NAOMI_DOWN_KEY, "DOWN" },
|
||||
{ NAOMI_LEFT_KEY, "LEFT" },
|
||||
{ NAOMI_RIGHT_KEY, "RIGHT" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -249,10 +254,6 @@ static InputDescriptors ninjaslt_inputs = {
|
|||
{ NAOMI_UP_KEY, "SELECT UP" },
|
||||
{ NAOMI_DOWN_KEY, "SELECT DOWN" },
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -275,118 +276,29 @@ static InputDescriptors vonot_inputs = {
|
|||
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors shot12_inputs = {
|
||||
{
|
||||
{ NAOMI_BTN0_KEY, "SHOT1" },
|
||||
{ NAOMI_BTN1_KEY, "SHOT2" },
|
||||
{ NAOMI_UP_KEY, "UP" },
|
||||
{ NAOMI_DOWN_KEY, "DOWN" },
|
||||
{ NAOMI_LEFT_KEY, "LEFT" },
|
||||
{ NAOMI_RIGHT_KEY, "RIGHT" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
},
|
||||
};
|
||||
static InputDescriptors shot12_inputs = INPUT_2_BUTTONS("SHOT1", "SHOT2");
|
||||
|
||||
static InputDescriptors shot123_inputs = {
|
||||
{
|
||||
{ NAOMI_BTN0_KEY, "SHOT1" },
|
||||
{ NAOMI_BTN1_KEY, "SHOT2" },
|
||||
{ NAOMI_BTN2_KEY, "SHOT3" },
|
||||
{ NAOMI_UP_KEY, "UP" },
|
||||
{ NAOMI_DOWN_KEY, "DOWN" },
|
||||
{ NAOMI_LEFT_KEY, "LEFT" },
|
||||
{ NAOMI_RIGHT_KEY, "RIGHT" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
},
|
||||
};
|
||||
static InputDescriptors pstone_inputs = INPUT_3_BUTTONS("Punch", "Kick", "Jump");
|
||||
|
||||
static InputDescriptors shot1234_inputs = {
|
||||
{
|
||||
{ NAOMI_BTN0_KEY, "SHOT1" },
|
||||
{ NAOMI_BTN1_KEY, "SHOT2" },
|
||||
{ NAOMI_BTN2_KEY, "SHOT3" },
|
||||
{ NAOMI_BTN3_KEY, "SHOT4" },
|
||||
{ NAOMI_UP_KEY, "UP" },
|
||||
{ NAOMI_DOWN_KEY, "DOWN" },
|
||||
{ NAOMI_LEFT_KEY, "LEFT" },
|
||||
{ NAOMI_RIGHT_KEY, "RIGHT" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
},
|
||||
};
|
||||
static InputDescriptors pstone2_inputs = INPUT_3_BUTTONS("Punch", "Jump", "Attack");
|
||||
|
||||
static InputDescriptors shot1234_inputs = INPUT_4_BUTTONS("SHOT1", "SHOT2", "SHOT3", "SHOT4");
|
||||
|
||||
static InputDescriptors monkeyba_inputs = {
|
||||
{
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ "STICK V", Full, 1 },
|
||||
{ "STICK H", Full, 0 },
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors cvs2_inputs = {
|
||||
{
|
||||
{ NAOMI_BTN0_KEY, "LIGHT PUNCH" },
|
||||
{ NAOMI_BTN1_KEY, "MEDIUM PUNCH" },
|
||||
{ NAOMI_BTN2_KEY, "STRONG PUNCH" },
|
||||
{ NAOMI_BTN3_KEY, "LIGHT KICK" },
|
||||
{ NAOMI_BTN4_KEY, "MEDIUM KICK" },
|
||||
{ NAOMI_BTN5_KEY, "STRONG KICK" },
|
||||
{ NAOMI_UP_KEY, "UP" },
|
||||
{ NAOMI_DOWN_KEY, "DOWN" },
|
||||
{ NAOMI_LEFT_KEY, "LEFT" },
|
||||
{ NAOMI_RIGHT_KEY, "RIGHT" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors pjustic_inputs = {
|
||||
{
|
||||
{ NAOMI_BTN0_KEY, "SHOT1" },
|
||||
{ NAOMI_BTN1_KEY, "SHOT2" },
|
||||
{ NAOMI_BTN2_KEY, "SHOT3", NAOMI_BTN3_KEY },
|
||||
{ NAOMI_BTN3_KEY, "SHOT4", NAOMI_BTN4_KEY },
|
||||
{ NAOMI_UP_KEY, "UP" },
|
||||
{ NAOMI_DOWN_KEY, "DOWN" },
|
||||
{ NAOMI_LEFT_KEY, "LEFT" },
|
||||
{ NAOMI_RIGHT_KEY, "RIGHT" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors slashout_inputs = {
|
||||
{
|
||||
{ NAOMI_BTN0_KEY, "BLADE" },
|
||||
{ NAOMI_BTN1_KEY, "CHARGE" },
|
||||
{ NAOMI_BTN2_KEY, "JUMP" },
|
||||
{ NAOMI_BTN3_KEY, "SHIFT" },
|
||||
{ NAOMI_UP_KEY, "UP" },
|
||||
{ NAOMI_DOWN_KEY, "DOWN" },
|
||||
{ NAOMI_LEFT_KEY, "LEFT" },
|
||||
{ NAOMI_RIGHT_KEY, "RIGHT" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
},
|
||||
};
|
||||
static InputDescriptors slashout_inputs = INPUT_4_BUTTONS("Blade", "Charge", "Jump", "Shift");
|
||||
|
||||
static InputDescriptors tokyobus_inputs = {
|
||||
{
|
||||
|
@ -395,19 +307,17 @@ static InputDescriptors tokyobus_inputs = {
|
|||
{ NAOMI_LEFT_KEY, "ANNOUNCE" },
|
||||
{ NAOMI_RIGHT_KEY, "DOOR CLOSE" },
|
||||
// These buttons uses P2 inputs for P1
|
||||
{ NAOMI_BTN1_KEY, "WINKER RIGHT", 0, NAOMI_BTN0_KEY },
|
||||
{ NAOMI_BTN2_KEY, "WINKER LEFT", 0, NAOMI_BTN1_KEY },
|
||||
{ NAOMI_BTN3_KEY, "SHIFT FRONT", 0, NAOMI_UP_KEY },
|
||||
{ NAOMI_BTN4_KEY, "SHIFT REVERSE", 0, NAOMI_DOWN_KEY },
|
||||
{ NAOMI_BTN5_KEY, "WINKER RIGHT", 0, NAOMI_BTN0_KEY },
|
||||
{ NAOMI_BTN4_KEY, "WINKER LEFT", 0, NAOMI_BTN1_KEY },
|
||||
{ NAOMI_BTN2_KEY, "SHIFT FRONT", 0, NAOMI_UP_KEY },
|
||||
{ NAOMI_BTN1_KEY, "SHIFT REVERSE", 0, NAOMI_DOWN_KEY },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ "HANDLE", Full, 0 },
|
||||
{ "ACCEL", Half, 4 },
|
||||
{ "BRAKE", Half, 5 },
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -416,14 +326,12 @@ static InputDescriptors wrungp_inputs = {
|
|||
{ NAOMI_UP_KEY, "VIEW" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ "HANDLE BAR", Full, 0 },
|
||||
{ "THROTTLE LEVER", Half, 4, true },
|
||||
{ "ROLL", Full, 2 },
|
||||
{ "PITCH", Full, 3 },
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -433,7 +341,6 @@ static InputDescriptors marine_fishing_inputs = {
|
|||
{ NAOMI_START_KEY, "CAST" },
|
||||
{ NAOMI_UP_KEY, "LURE" },
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ "ROD Y", Full, 1 },
|
||||
|
@ -441,7 +348,6 @@ static InputDescriptors marine_fishing_inputs = {
|
|||
{ "STICK X", Full, 2 },
|
||||
{ "STICK Y", Full, 3 },
|
||||
{ "REEL SPEED", Half, 4 },
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -466,7 +372,6 @@ static InputDescriptors f355_inputs = {
|
|||
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ "ACCEL", Half, 4 },
|
||||
|
@ -474,23 +379,24 @@ static InputDescriptors f355_inputs = {
|
|||
{ "CLUTCH", Full, 2 }, // Deluxe only
|
||||
{ "unused", Full, 4 },
|
||||
{ "HANDLE", Full, 0 },
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors zombie_inputs = {
|
||||
{
|
||||
{ NAOMI_BTN0_KEY, "BTN0" },
|
||||
{ NAOMI_BTN1_KEY, "BTN1" },
|
||||
{ NAOMI_BTN2_KEY, "BTN2" },
|
||||
{ NAOMI_BTN0_KEY, "L" },
|
||||
{ NAOMI_BTN1_KEY, "R" },
|
||||
{ NAOMI_BTN2_KEY, "G" },
|
||||
{ NAOMI_UP_KEY, "" },
|
||||
{ NAOMI_DOWN_KEY, "" },
|
||||
{ NAOMI_LEFT_KEY, "" },
|
||||
{ NAOMI_RIGHT_KEY, "" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ "UP - DOWN", Full, 1, true },
|
||||
{ "LEFT - RIGHT", Full, 0, true },
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -502,14 +408,12 @@ static InputDescriptors wsbb_inputs = {
|
|||
{ NAOMI_BTN1_KEY, "BTN B" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ "STICK Y", Full, 1, true },
|
||||
{ "STICK X", Full, 0, true },
|
||||
{ "BAT", Half, 4, true },
|
||||
{ "", Half, 5 }, // unused but P2 starts at axis 4
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -519,12 +423,10 @@ static InputDescriptors ringout_inputs = {
|
|||
{ NAOMI_BTN1_KEY, "BACK" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ "STEER", Full, 0 },
|
||||
{ "ACCEL", Half, 4 },
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -536,16 +438,38 @@ static InputDescriptors sstrkfgt_inputs = {
|
|||
{ NAOMI_BTN3_KEY, "VIEW CHANGE" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ "ELEVATOR", Full, 1 },
|
||||
{ "AILERON", Full, 0 },
|
||||
{ "THRUST LEVER", Half, 4 },
|
||||
{ "RUDDER PEDAL", Full, 2 },
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors guilty_gear_input = INPUT_5_BUTTONS("KICK", "SLASH", "HSLASH", "PUNCH", "DUST ATTACK");
|
||||
|
||||
static InputDescriptors senkosp_input = INPUT_5_BUTTONS("MAIN", "SUB", "MAIN+SUB", "ACTION", "OVER DRIVE");
|
||||
|
||||
static InputDescriptors meltyb_input = INPUT_5_BUTTONS("LAttack", "MAttack", "HAttack", "Guard", "Quick Action");
|
||||
|
||||
static InputDescriptors toukon4_input = INPUT_5_BUTTONS("X", "Y", "R", "A", "B");
|
||||
|
||||
static InputDescriptors hmgeo_input = {
|
||||
{
|
||||
{ NAOMI_BTN0_KEY, "Fire" },
|
||||
{ NAOMI_BTN1_KEY, "Attack" },
|
||||
{ NAOMI_BTN3_KEY, "Jump" },
|
||||
{ NAOMI_BTN4_KEY, "Target" },
|
||||
{ NAOMI_UP_KEY, "" },
|
||||
{ NAOMI_DOWN_KEY, "" },
|
||||
{ NAOMI_LEFT_KEY, "" },
|
||||
{ NAOMI_RIGHT_KEY, "" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
},
|
||||
};
|
||||
|
||||
//
|
||||
// AtomisWave games
|
||||
//
|
||||
|
@ -555,6 +479,24 @@ static InputDescriptors sstrkfgt_inputs = {
|
|||
{ AWAVE_SERVICE_KEY, "SERVICE" },
|
||||
#define AW_START_DESC { AWAVE_START_KEY, "START" },
|
||||
|
||||
#define AW_5_BUTTONS(btn0, btn1, btn2, btn3, btn4) { \
|
||||
{ \
|
||||
{ AWAVE_BTN0_KEY, btn0 }, \
|
||||
{ AWAVE_BTN1_KEY, btn1 }, \
|
||||
{ AWAVE_BTN2_KEY, btn2 }, \
|
||||
{ AWAVE_BTN3_KEY, btn3 }, \
|
||||
{ AWAVE_BTN4_KEY, btn4 }, \
|
||||
{ AWAVE_UP_KEY, "" }, \
|
||||
{ AWAVE_DOWN_KEY, "" }, \
|
||||
{ AWAVE_LEFT_KEY, "" }, \
|
||||
{ AWAVE_RIGHT_KEY, "" }, \
|
||||
AW_START_DESC \
|
||||
AW_BASE_BTN_DESC \
|
||||
} \
|
||||
}
|
||||
|
||||
static InputDescriptors guilty_gear_aw_input = AW_5_BUTTONS("KICK", "SLASH", "HSLASH", "PUNCH", "DUST ATTACK");
|
||||
|
||||
static InputDescriptors ftspeed_inputs = {
|
||||
{
|
||||
{ AWAVE_BTN0_KEY, "BOOST" },
|
||||
|
@ -562,49 +504,17 @@ static InputDescriptors ftspeed_inputs = {
|
|||
{ AWAVE_DOWN_KEY, "LOW GEAR" },
|
||||
AW_START_DESC
|
||||
AW_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ "STEERING WHEEL", Full, 0 },
|
||||
{ "GAS PEDAL", Half, 4 },
|
||||
{ "BRAKE PEDAL", Half, 5 },
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors kofnw_inputs = {
|
||||
{
|
||||
{ AWAVE_BTN0_KEY, "LIGHT PUNCH" },
|
||||
{ AWAVE_BTN1_KEY, "STRONG PUNCH" },
|
||||
{ AWAVE_BTN2_KEY, "HEAT MODE" },
|
||||
{ AWAVE_BTN3_KEY, "LIGHT KICK" },
|
||||
{ AWAVE_BTN4_KEY, "STRONG KICK" },
|
||||
{ AWAVE_UP_KEY, "UP" },
|
||||
{ AWAVE_DOWN_KEY, "DOWN" },
|
||||
{ AWAVE_LEFT_KEY, "LEFT" },
|
||||
{ AWAVE_RIGHT_KEY, "RIGHT" },
|
||||
AW_START_DESC
|
||||
AW_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
}
|
||||
};
|
||||
static InputDescriptors kofnw_input = AW_5_BUTTONS("LP", "SP", "Heat mode", "LK", "SK");
|
||||
|
||||
static InputDescriptors kofxi_inputs = {
|
||||
{
|
||||
{ AWAVE_BTN0_KEY, "LIGHT PUNCH" },
|
||||
{ AWAVE_BTN1_KEY, "STRONG PUNCH" },
|
||||
{ AWAVE_BTN2_KEY, "SPECIAL ATTACK" },
|
||||
{ AWAVE_BTN3_KEY, "LIGHT KICK" },
|
||||
{ AWAVE_BTN4_KEY, "STRONG KICK" },
|
||||
{ AWAVE_UP_KEY, "UP" },
|
||||
{ AWAVE_DOWN_KEY, "DOWN" },
|
||||
{ AWAVE_LEFT_KEY, "LEFT" },
|
||||
{ AWAVE_RIGHT_KEY, "RIGHT" },
|
||||
AW_START_DESC
|
||||
AW_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
}
|
||||
};
|
||||
static InputDescriptors kofxi_input = AW_5_BUTTONS("LP", "SP", "Blow-off", "LK", "SK");
|
||||
|
||||
static InputDescriptors maxspeed_inputs = {
|
||||
{
|
||||
|
@ -612,61 +522,33 @@ static InputDescriptors maxspeed_inputs = {
|
|||
{ AWAVE_DOWN_KEY, "LOW SHIFT" },
|
||||
AW_START_DESC
|
||||
AW_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ "STEERING", Full, 0 },
|
||||
{ "ACCELERATOR", Half, 4 },
|
||||
{ "BRAKE", Half, 5 },
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors ngbc_inputs = {
|
||||
{
|
||||
{ AWAVE_BTN0_KEY, "LIGHT PUNCH" },
|
||||
{ AWAVE_BTN1_KEY, "STRONG PUNCH" },
|
||||
{ AWAVE_BTN2_KEY, "SWAP CHARACTERS" },
|
||||
{ AWAVE_BTN3_KEY, "LIGHT KICK" },
|
||||
{ AWAVE_BTN4_KEY, "STRONG KICK" },
|
||||
{ AWAVE_UP_KEY, "UP" },
|
||||
{ AWAVE_DOWN_KEY, "DOWN" },
|
||||
{ AWAVE_LEFT_KEY, "LEFT" },
|
||||
{ AWAVE_RIGHT_KEY, "RIGHT" },
|
||||
AW_START_DESC
|
||||
AW_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
}
|
||||
};
|
||||
static InputDescriptors ngbc_inputs = AW_5_BUTTONS("LP", "SP", "SWAP", "LK", "SK");
|
||||
|
||||
static InputDescriptors samsptk_inputs = {
|
||||
{
|
||||
{ AWAVE_BTN0_KEY, "LIGHT SLASH" },
|
||||
{ AWAVE_BTN1_KEY, "MEDIUM SLASH" },
|
||||
{ AWAVE_BTN2_KEY, "STRONG SLASH" },
|
||||
{ AWAVE_BTN3_KEY, "KICK" },
|
||||
{ AWAVE_BTN4_KEY, "SPECIAL EVASION" },
|
||||
{ AWAVE_UP_KEY, "UP" },
|
||||
{ AWAVE_DOWN_KEY, "DOWN" },
|
||||
{ AWAVE_LEFT_KEY, "LEFT" },
|
||||
{ AWAVE_RIGHT_KEY, "RIGHT" },
|
||||
AW_START_DESC
|
||||
AW_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
}
|
||||
};
|
||||
static InputDescriptors samsptk_inputs = AW_5_BUTTONS("LIGHT SLASH", "MEDIUM SLASH", "STRONG SLASH", "KICK", "SPECIAL EVASION");
|
||||
|
||||
static InputDescriptors blockpong_inputs = {
|
||||
{
|
||||
AW_START_DESC
|
||||
AW_BASE_BTN_DESC
|
||||
{ 0 },
|
||||
},
|
||||
{
|
||||
{ "ANALOG X", Full, 0, true },
|
||||
{ "ANALOG Y", Full, 1 },
|
||||
{ "ANALOG X", Full, 0 }, // for P2
|
||||
{ "ANALOG Y", Full, 1 }, // for P2
|
||||
{ NULL },
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors fotns_input = AW_5_BUTTONS("LP", "HP", "BOOST", "LK", "HK");
|
||||
|
||||
static InputDescriptors mslug6_input = AW_5_BUTTONS("Shoot", "Jump", "Switch", "Grenade", "Mslug Attack");
|
||||
|
||||
static InputDescriptors rumblef_input = AW_5_BUTTONS("LP", "SP", "Dodge", "LK", "SK");
|
||||
|
|
|
@ -39,44 +39,28 @@ enum DreamcastKey
|
|||
|
||||
// System buttons
|
||||
EMU_BTN_NONE = 0,
|
||||
EMU_BTN_TRIGGER_LEFT = 1 << 17,
|
||||
EMU_BTN_TRIGGER_RIGHT = 1 << 18,
|
||||
EMU_BTN_MENU = 1 << 19,
|
||||
EMU_BTN_FFORWARD = 1 << 20,
|
||||
EMU_BTN_ANA_UP = 1 << 21,
|
||||
EMU_BTN_ANA_DOWN = 1 << 22,
|
||||
EMU_BTN_ANA_LEFT = 1 << 23,
|
||||
EMU_BTN_ANA_RIGHT = 1 << 24,
|
||||
EMU_BTN_ESCAPE = 1 << 25,
|
||||
|
||||
DC_BTN_GROUP_MASK = 0xF000000,
|
||||
|
||||
EMU_BUTTONS = 0x3000000,
|
||||
EMU_BTN_MENU,
|
||||
EMU_BTN_FFORWARD,
|
||||
EMU_BTN_ESCAPE,
|
||||
|
||||
// Real axes
|
||||
DC_AXIS_LT = 0x10000,
|
||||
DC_AXIS_RT = 0x10001,
|
||||
DC_AXIS_X = 0x20000,
|
||||
DC_AXIS_Y = 0x20001,
|
||||
DC_AXIS_X2 = 0x20002,
|
||||
DC_AXIS_Y2 = 0x20003,
|
||||
DC_AXIS_TRIGGERS = 0x1000000,
|
||||
DC_AXIS_LT,
|
||||
DC_AXIS_RT,
|
||||
DC_AXIS_STICKS = 0x2000000,
|
||||
DC_AXIS_LEFT,
|
||||
DC_AXIS_RIGHT,
|
||||
DC_AXIS_UP,
|
||||
DC_AXIS_DOWN,
|
||||
DC_AXIS2_LEFT,
|
||||
DC_AXIS2_RIGHT,
|
||||
DC_AXIS2_UP,
|
||||
DC_AXIS2_DOWN,
|
||||
|
||||
// System axes
|
||||
EMU_AXIS_NONE = 0x00000,
|
||||
EMU_AXIS_DPAD1_X = DC_DPAD_LEFT,
|
||||
EMU_AXIS_DPAD1_Y = DC_DPAD_UP,
|
||||
EMU_AXIS_DPAD2_X = DC_DPAD2_LEFT,
|
||||
EMU_AXIS_DPAD2_Y = DC_DPAD2_UP,
|
||||
EMU_AXIS_BTN_A = 0x40000 | DC_BTN_A,
|
||||
EMU_AXIS_BTN_B = 0x40000 | DC_BTN_B,
|
||||
EMU_AXIS_BTN_C = 0x40000 | DC_BTN_C,
|
||||
EMU_AXIS_BTN_D = 0x40000 | DC_BTN_D,
|
||||
EMU_AXIS_BTN_X = 0x40000 | DC_BTN_X,
|
||||
EMU_AXIS_BTN_Y = 0x40000 | DC_BTN_Y,
|
||||
EMU_AXIS_BTN_Z = 0x40000 | DC_BTN_Z,
|
||||
EMU_AXIS_BTN_START = 0x40000 | DC_BTN_START,
|
||||
EMU_AXIS_DPAD_UP = 0x40000 | DC_DPAD_UP,
|
||||
EMU_AXIS_DPAD_DOWN = 0x40000 | DC_DPAD_DOWN,
|
||||
EMU_AXIS_DPAD_LEFT = 0x40000 | DC_DPAD_LEFT,
|
||||
EMU_AXIS_DPAD_RIGHT = 0x40000 | DC_DPAD_RIGHT,
|
||||
EMU_AXIS_DPAD2_UP = 0x40000 | DC_DPAD2_UP,
|
||||
EMU_AXIS_DPAD2_DOWN = 0x40000 | DC_DPAD2_DOWN,
|
||||
EMU_AXIS_DPAD2_LEFT = 0x40000 | DC_DPAD2_LEFT,
|
||||
EMU_AXIS_DPAD2_RIGHT = 0x40000 | DC_DPAD2_RIGHT,
|
||||
EMU_AXIS_NONE = 0,
|
||||
};
|
||||
|
|
|
@ -53,7 +53,7 @@ bool GamepadDevice::gamepad_btn_input(u32 code, bool pressed)
|
|||
if (_input_detected != nullptr && _detecting_button
|
||||
&& os_GetSeconds() >= _detection_start_time && pressed)
|
||||
{
|
||||
_input_detected(code);
|
||||
_input_detected(code, false, false);
|
||||
_input_detected = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
@ -92,44 +92,30 @@ bool GamepadDevice::gamepad_btn_input(u32 code, bool pressed)
|
|||
if (pressed && !gui_is_open())
|
||||
settings.input.fastForwardMode = !settings.input.fastForwardMode && !settings.online;
|
||||
break;
|
||||
case EMU_BTN_TRIGGER_LEFT:
|
||||
case DC_AXIS_LT:
|
||||
lt[port] = pressed ? 255 : 0;
|
||||
break;
|
||||
case EMU_BTN_TRIGGER_RIGHT:
|
||||
case DC_AXIS_RT:
|
||||
rt[port] = pressed ? 255 : 0;
|
||||
break;
|
||||
case EMU_BTN_ANA_UP:
|
||||
case EMU_BTN_ANA_DOWN:
|
||||
{
|
||||
if (pressed)
|
||||
digitalToAnalogState[port] |= key;
|
||||
else
|
||||
digitalToAnalogState[port] &= ~key;
|
||||
const u32 upDown = digitalToAnalogState[port] & (EMU_BTN_ANA_UP | EMU_BTN_ANA_DOWN);
|
||||
if (upDown == 0 || upDown == (EMU_BTN_ANA_UP | EMU_BTN_ANA_DOWN))
|
||||
joyy[port] = 0;
|
||||
else if (upDown == EMU_BTN_ANA_UP)
|
||||
joyy[port] = -128;
|
||||
else
|
||||
joyy[port] = 127;
|
||||
}
|
||||
|
||||
case DC_AXIS_UP:
|
||||
case DC_AXIS_DOWN:
|
||||
buttonToAnalogInput<DC_AXIS_UP, DIGANA_UP, DIGANA_DOWN>(port, key, pressed, joyy[port]);
|
||||
break;
|
||||
case EMU_BTN_ANA_LEFT:
|
||||
case EMU_BTN_ANA_RIGHT:
|
||||
{
|
||||
if (pressed)
|
||||
digitalToAnalogState[port] |= key;
|
||||
else
|
||||
digitalToAnalogState[port] &= ~key;
|
||||
const u32 leftRight = digitalToAnalogState[port] & (EMU_BTN_ANA_LEFT | EMU_BTN_ANA_RIGHT);
|
||||
if (leftRight == 0 || leftRight == (EMU_BTN_ANA_LEFT | EMU_BTN_ANA_RIGHT))
|
||||
joyx[port] = 0;
|
||||
else if (leftRight == EMU_BTN_ANA_LEFT)
|
||||
joyx[port] = -128;
|
||||
else
|
||||
joyx[port] = 127;
|
||||
}
|
||||
case DC_AXIS_LEFT:
|
||||
case DC_AXIS_RIGHT:
|
||||
buttonToAnalogInput<DC_AXIS_LEFT, DIGANA_LEFT, DIGANA_RIGHT>(port, key, pressed, joyx[port]);
|
||||
break;
|
||||
case DC_AXIS2_UP:
|
||||
case DC_AXIS2_DOWN:
|
||||
buttonToAnalogInput<DC_AXIS2_UP, DIGANA2_UP, DIGANA2_DOWN>(port, key, pressed, joyry[port]);
|
||||
break;
|
||||
case DC_AXIS2_LEFT:
|
||||
case DC_AXIS2_RIGHT:
|
||||
buttonToAnalogInput<DC_AXIS2_LEFT, DIGANA2_LEFT, DIGANA2_RIGHT>(port, key, pressed, joyrx[port]);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -158,70 +144,71 @@ bool GamepadDevice::gamepad_btn_input(u32 code, bool pressed)
|
|||
return rc;
|
||||
}
|
||||
|
||||
//
|
||||
// value must be >= -32768 and <= 32767 for full axes
|
||||
// and 0 to 32767 for half axes/triggers
|
||||
//
|
||||
bool GamepadDevice::gamepad_axis_input(u32 code, int value)
|
||||
{
|
||||
s32 v;
|
||||
if (input_mapper->get_axis_inverted(0, code))
|
||||
v = (get_axis_min_value(code) + get_axis_range(code) - value) * 255 / get_axis_range(code) - 128;
|
||||
else
|
||||
v = (value - get_axis_min_value(code)) * 255 / get_axis_range(code) - 128; //-128 ... +127 range
|
||||
if (_input_detected != NULL && !_detecting_button
|
||||
&& os_GetSeconds() >= _detection_start_time && (v >= 64 || v <= -64))
|
||||
bool positive = value >= 0;
|
||||
if (_input_detected != NULL && _detecting_axis
|
||||
&& os_GetSeconds() >= _detection_start_time && std::abs(value) >= 16384)
|
||||
{
|
||||
_input_detected(code);
|
||||
_input_detected = NULL;
|
||||
_input_detected(code, true, positive);
|
||||
_input_detected = nullptr;
|
||||
return true;
|
||||
}
|
||||
if (!input_mapper || _maple_port < 0 || _maple_port > 4)
|
||||
return false;
|
||||
|
||||
auto handle_axis = [&](u32 port, DreamcastKey key)
|
||||
auto handle_axis = [&](u32 port, DreamcastKey key, int v)
|
||||
{
|
||||
|
||||
if ((int)key < 0x10000)
|
||||
if ((key & DC_BTN_GROUP_MASK) == DC_AXIS_TRIGGERS) // Triggers
|
||||
{
|
||||
kcode[port] |= key | (key << 1);
|
||||
if (v <= -64)
|
||||
kcode[port] &= ~key;
|
||||
else if (v >= 64)
|
||||
kcode[port] &= ~(key << 1);
|
||||
|
||||
// printf("Mapped to %d %d %d\n",mo,kcode[port]&mo,kcode[port]&(mo*2));
|
||||
}
|
||||
else if (((int)key >> 16) == 1) // Triggers
|
||||
{
|
||||
//printf("T-AXIS %d Mapped to %d -> %d\n",key, value, v + 128);
|
||||
|
||||
//printf("T-AXIS %d Mapped to %d -> %d\n", key, value, std::min(std::abs(v) >> 7, 255));
|
||||
if (key == DC_AXIS_LT)
|
||||
lt[port] = (u8)(v + 128);
|
||||
lt[port] = std::min(std::abs(v) >> 7, 255);
|
||||
else if (key == DC_AXIS_RT)
|
||||
rt[port] = (u8)(v + 128);
|
||||
rt[port] = std::min(std::abs(v) >> 7, 255);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (((int)key >> 16) == 2) // Analog axes
|
||||
else if ((key & DC_BTN_GROUP_MASK) == DC_AXIS_STICKS) // Analog axes
|
||||
{
|
||||
//printf("AXIS %d Mapped to %d -> %d\n", key, value, v);
|
||||
s8 *this_axis;
|
||||
s8 *other_axis;
|
||||
int axisDirection = -1;
|
||||
switch (key)
|
||||
{
|
||||
case DC_AXIS_X:
|
||||
case DC_AXIS_RIGHT:
|
||||
axisDirection = 1;
|
||||
//no break
|
||||
case DC_AXIS_LEFT:
|
||||
this_axis = &joyx[port];
|
||||
other_axis = &joyy[port];
|
||||
break;
|
||||
|
||||
case DC_AXIS_Y:
|
||||
case DC_AXIS_DOWN:
|
||||
axisDirection = 1;
|
||||
//no break
|
||||
case DC_AXIS_UP:
|
||||
this_axis = &joyy[port];
|
||||
other_axis = &joyx[port];
|
||||
break;
|
||||
|
||||
case DC_AXIS_X2:
|
||||
case DC_AXIS2_RIGHT:
|
||||
axisDirection = 1;
|
||||
//no break
|
||||
case DC_AXIS2_LEFT:
|
||||
this_axis = &joyrx[port];
|
||||
other_axis = &joyry[port];
|
||||
break;
|
||||
|
||||
case DC_AXIS_Y2:
|
||||
case DC_AXIS2_DOWN:
|
||||
axisDirection = 1;
|
||||
//no break
|
||||
case DC_AXIS2_UP:
|
||||
this_axis = &joyry[port];
|
||||
other_axis = &joyrx[port];
|
||||
break;
|
||||
|
@ -231,20 +218,31 @@ bool GamepadDevice::gamepad_axis_input(u32 code, int value)
|
|||
}
|
||||
// Radial dead zone
|
||||
// FIXME compute both axes at the same time
|
||||
v = std::min(127, std::abs(v >> 8));
|
||||
if ((float)(v * v + *other_axis * *other_axis) < input_mapper->dead_zone * input_mapper->dead_zone * 128.f * 128.f)
|
||||
{
|
||||
*this_axis = 0;
|
||||
*other_axis = 0;
|
||||
}
|
||||
else
|
||||
*this_axis = (s8)v;
|
||||
*this_axis = v * axisDirection;
|
||||
}
|
||||
else if (((int)key >> 16) == 4) // Map triggers to digital buttons
|
||||
else if (key != EMU_BTN_NONE && key <= DC_BTN_RELOAD) // Map triggers to digital buttons
|
||||
{
|
||||
if (v <= -64)
|
||||
kcode[port] |= (key & ~0x40000); // button released
|
||||
else if (v >= 64)
|
||||
kcode[port] &= ~(key & ~0x40000); // button pressed
|
||||
//printf("B-AXIS %d Mapped to %d -> %d\n", key, value, v);
|
||||
// TODO hysteresis?
|
||||
if (std::abs(v) < 16384)
|
||||
kcode[port] |= key; // button released
|
||||
else
|
||||
kcode[port] &= ~key; // button pressed
|
||||
}
|
||||
else if ((key & DC_BTN_GROUP_MASK) == EMU_BUTTONS) // Map triggers to emu buttons
|
||||
{
|
||||
// TODO hysteresis?
|
||||
if (std::abs(v) < 16384)
|
||||
gamepad_btn_input(key, false); // button released
|
||||
else
|
||||
gamepad_btn_input(key, true); // button pressed
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
@ -257,41 +255,24 @@ bool GamepadDevice::gamepad_axis_input(u32 code, int value)
|
|||
{
|
||||
for (u32 port = 0; port < 4; port++)
|
||||
{
|
||||
DreamcastKey key = input_mapper->get_axis_id(port, code);
|
||||
rc = handle_axis(port, key) || rc;
|
||||
DreamcastKey key = input_mapper->get_axis_id(port, code, !positive);
|
||||
handle_axis(port, key, 0);
|
||||
key = input_mapper->get_axis_id(port, code, positive);
|
||||
rc = handle_axis(port, key, value) || rc;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DreamcastKey key = input_mapper->get_axis_id(0, code);
|
||||
rc = handle_axis(_maple_port, key);
|
||||
DreamcastKey key = input_mapper->get_axis_id(0, code, !positive);
|
||||
// Reset opposite axis to 0
|
||||
handle_axis(_maple_port, key, 0);
|
||||
key = input_mapper->get_axis_id(0, code, positive);
|
||||
rc = handle_axis(_maple_port, key, value);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int GamepadDevice::get_axis_min_value(u32 axis) {
|
||||
auto it = axis_min_values.find(axis);
|
||||
if (it == axis_min_values.end()) {
|
||||
load_axis_min_max(axis);
|
||||
it = axis_min_values.find(axis);
|
||||
if (it == axis_min_values.end())
|
||||
return INT_MIN;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
unsigned int GamepadDevice::get_axis_range(u32 axis) {
|
||||
auto it = axis_ranges.find(axis);
|
||||
if (it == axis_ranges.end()) {
|
||||
load_axis_min_max(axis);
|
||||
it = axis_ranges.find(axis);
|
||||
if (it == axis_ranges.end())
|
||||
return UINT_MAX;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::string GamepadDevice::make_mapping_filename(bool instance)
|
||||
{
|
||||
std::string mapping_file = api_name() + "_" + name();
|
||||
|
@ -321,11 +302,13 @@ void GamepadDevice::verify_or_create_system_mappings()
|
|||
|
||||
if (!file_exists(arcade_path))
|
||||
{
|
||||
resetMappingToDefault(true, true);
|
||||
save_mapping(2);
|
||||
input_mapper->ClearMappings();
|
||||
}
|
||||
if (!file_exists(dc_path))
|
||||
{
|
||||
resetMappingToDefault(false, false);
|
||||
save_mapping(0);
|
||||
input_mapper->ClearMappings();
|
||||
}
|
||||
|
@ -454,6 +437,7 @@ void GamepadDevice::detect_btn_input(input_detected_cb button_pressed)
|
|||
{
|
||||
_input_detected = button_pressed;
|
||||
_detecting_button = true;
|
||||
_detecting_axis = false;
|
||||
_detection_start_time = os_GetSeconds() + 0.2;
|
||||
}
|
||||
|
||||
|
@ -461,6 +445,15 @@ void GamepadDevice::detect_axis_input(input_detected_cb axis_moved)
|
|||
{
|
||||
_input_detected = axis_moved;
|
||||
_detecting_button = false;
|
||||
_detecting_axis = true;
|
||||
_detection_start_time = os_GetSeconds() + 0.2;
|
||||
}
|
||||
|
||||
void GamepadDevice::detectButtonOrAxisInput(input_detected_cb input_changed)
|
||||
{
|
||||
_input_detected = input_changed;
|
||||
_detecting_button = true;
|
||||
_detecting_axis = true;
|
||||
_detection_start_time = os_GetSeconds() + 0.2;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
class GamepadDevice
|
||||
{
|
||||
public:
|
||||
typedef void (*input_detected_cb)(u32 code);
|
||||
typedef void (*input_detected_cb)(u32 code, bool analog, bool positive);
|
||||
|
||||
const std::string& api_name() { return _api_name; }
|
||||
const std::string& name() { return _name; }
|
||||
|
@ -37,13 +37,13 @@ public:
|
|||
virtual void set_maple_port(int port) { _maple_port = port; }
|
||||
const std::string& unique_id() { return _unique_id; }
|
||||
virtual bool gamepad_btn_input(u32 code, bool pressed);
|
||||
bool gamepad_axis_input(u32 code, int value);
|
||||
virtual bool gamepad_axis_input(u32 code, int value);
|
||||
virtual ~GamepadDevice() = default;
|
||||
|
||||
virtual void detect_btn_input(input_detected_cb button_pressed);
|
||||
void detect_btn_input(input_detected_cb button_pressed);
|
||||
void detect_axis_input(input_detected_cb axis_moved);
|
||||
virtual void cancel_detect_input()
|
||||
{
|
||||
void detectButtonOrAxisInput(input_detected_cb input_changed);
|
||||
void cancel_detect_input() {
|
||||
_input_detected = nullptr;
|
||||
}
|
||||
std::shared_ptr<InputMapping> get_input_mapping() { return input_mapper; }
|
||||
|
@ -71,6 +71,10 @@ public:
|
|||
|
||||
static void load_system_mappings(int system = settings.platform.system);
|
||||
bool find_mapping(int system);
|
||||
virtual void resetMappingToDefault(bool arcade, bool gamepad) {
|
||||
input_mapper = getDefaultMapping();
|
||||
}
|
||||
|
||||
protected:
|
||||
GamepadDevice(int maple_port, const char *api_name, bool remappable = true)
|
||||
: _api_name(api_name), _maple_port(maple_port), _input_detected(nullptr), _remappable(remappable),
|
||||
|
@ -87,25 +91,50 @@ protected:
|
|||
return std::make_shared<IdentityInputMapping>();
|
||||
}
|
||||
|
||||
virtual void load_axis_min_max(u32 axis) {}
|
||||
bool is_detecting_input() { return _input_detected != nullptr; }
|
||||
|
||||
std::string _name;
|
||||
std::string _unique_id;
|
||||
std::shared_ptr<InputMapping> input_mapper;
|
||||
std::map<u32, int> axis_min_values;
|
||||
std::map<u32, unsigned int> axis_ranges;
|
||||
bool _rumble_enabled = true;
|
||||
|
||||
private:
|
||||
int get_axis_min_value(u32 axis);
|
||||
unsigned int get_axis_range(u32 axis);
|
||||
std::string make_mapping_filename(bool instance = false);
|
||||
std::string make_mapping_filename(bool instance, int system);
|
||||
|
||||
enum DigAnalog {
|
||||
DIGANA_LEFT = 1 << 0,
|
||||
DIGANA_RIGHT = 1 << 1,
|
||||
DIGANA_UP = 1 << 2,
|
||||
DIGANA_DOWN = 1 << 3,
|
||||
DIGANA2_LEFT = 1 << 4,
|
||||
DIGANA2_RIGHT = 1 << 5,
|
||||
DIGANA2_UP = 1 << 6,
|
||||
DIGANA2_DOWN = 1 << 7,
|
||||
};
|
||||
|
||||
template<DreamcastKey DcNegDir, DigAnalog NegDir, DigAnalog PosDir>
|
||||
void buttonToAnalogInput(u32 port, DreamcastKey key, bool pressed, s8& joystick)
|
||||
{
|
||||
DigAnalog axis = key == DcNegDir ? NegDir : PosDir;
|
||||
if (pressed)
|
||||
digitalToAnalogState[port] |= axis;
|
||||
else
|
||||
digitalToAnalogState[port] &= ~axis;
|
||||
const u32 socd = digitalToAnalogState[port] & (NegDir | PosDir);
|
||||
if (socd == 0 || socd == (NegDir | PosDir))
|
||||
joystick = 0;
|
||||
else if (socd == NegDir)
|
||||
joystick = -128;
|
||||
else
|
||||
joystick = 127;
|
||||
|
||||
}
|
||||
|
||||
std::string _api_name;
|
||||
int _maple_port;
|
||||
bool _detecting_button = false;
|
||||
bool _detecting_axis = false;
|
||||
double _detection_start_time = 0.0;
|
||||
input_detected_cb _input_detected;
|
||||
bool _remappable;
|
||||
|
|
|
@ -37,8 +37,8 @@ public:
|
|||
set_button(DC_DPAD_LEFT, 80);
|
||||
set_button(DC_DPAD_RIGHT, 79);
|
||||
set_button(DC_BTN_START, 40); // Return
|
||||
set_button(EMU_BTN_TRIGGER_LEFT, 9); // F
|
||||
set_button(EMU_BTN_TRIGGER_RIGHT, 25); // V
|
||||
set_button(DC_AXIS_LT, 9); // F
|
||||
set_button(DC_AXIS_RT, 25); // V
|
||||
set_button(EMU_BTN_MENU, 43); // TAB
|
||||
set_button(EMU_BTN_FFORWARD, 44); // Space
|
||||
|
||||
|
|
|
@ -48,12 +48,12 @@ button_list[] =
|
|||
{ EMU_BTN_ESCAPE, "emulator", "btn_escape" },
|
||||
{ EMU_BTN_MENU, "emulator", "btn_menu" },
|
||||
{ EMU_BTN_FFORWARD, "emulator", "btn_fforward" },
|
||||
{ EMU_BTN_TRIGGER_LEFT, "compat", "btn_trigger_left" },
|
||||
{ EMU_BTN_TRIGGER_RIGHT, "compat", "btn_trigger_right" },
|
||||
{ EMU_BTN_ANA_UP, "compat", "btn_analog_up" },
|
||||
{ EMU_BTN_ANA_DOWN, "compat", "btn_analog_down" },
|
||||
{ EMU_BTN_ANA_LEFT, "compat", "btn_analog_left" },
|
||||
{ EMU_BTN_ANA_RIGHT, "compat", "btn_analog_right" },
|
||||
{ DC_AXIS_LT, "compat", "btn_trigger_left" },
|
||||
{ DC_AXIS_RT, "compat", "btn_trigger_right" },
|
||||
{ DC_AXIS_UP, "compat", "btn_analog_up" },
|
||||
{ DC_AXIS_DOWN, "compat", "btn_analog_down" },
|
||||
{ DC_AXIS_LEFT, "compat", "btn_analog_left" },
|
||||
{ DC_AXIS_RIGHT, "compat", "btn_analog_right" },
|
||||
{ DC_BTN_RELOAD, "dreamcast", "reload" },
|
||||
};
|
||||
|
||||
|
@ -67,37 +67,49 @@ static struct
|
|||
}
|
||||
axis_list[] =
|
||||
{
|
||||
{ DC_AXIS_X, "dreamcast", "axis_x", "compat", "axis_x_inverted" },
|
||||
{ DC_AXIS_Y, "dreamcast", "axis_y", "compat", "axis_y_inverted" },
|
||||
// v3
|
||||
{ DC_AXIS_LEFT, "", "axis_left", "", "" },
|
||||
{ DC_AXIS_RIGHT, "", "axis_right", "", "" },
|
||||
{ DC_AXIS_UP, "", "axis_up", "", "" },
|
||||
{ DC_AXIS_DOWN, "", "axis_down", "", "" },
|
||||
{ DC_AXIS2_LEFT, "", "axis2_left", "", "" },
|
||||
{ DC_AXIS2_RIGHT, "", "axis2_right", "", "" },
|
||||
{ DC_AXIS2_UP, "", "axis2_up", "", "" },
|
||||
{ DC_AXIS2_DOWN, "", "axis2_down", "", "" },
|
||||
{ DC_AXIS_LT, "dreamcast", "axis_trigger_left", "compat", "axis_trigger_left_inverted" },
|
||||
{ DC_AXIS_RT, "dreamcast", "axis_trigger_right", "compat", "axis_trigger_right_inverted" },
|
||||
{ DC_AXIS_X2, "dreamcast", "axis_right_x", "compat", "axis_right_x_inverted" },
|
||||
{ DC_AXIS_Y2, "dreamcast", "axis_right_y", "compat", "axis_right_y_inverted" },
|
||||
{ EMU_AXIS_DPAD1_X, "compat", "axis_dpad1_x", "compat", "axis_dpad1_x_inverted" },
|
||||
{ EMU_AXIS_DPAD1_Y, "compat", "axis_dpad1_y", "compat", "axis_dpad1_y_inverted" },
|
||||
{ EMU_AXIS_DPAD2_X, "compat", "axis_dpad2_x", "compat", "axis_dpad2_x_inverted" },
|
||||
{ EMU_AXIS_DPAD2_Y, "compat", "axis_dpad2_y", "compat", "axis_dpad2_y_inverted" },
|
||||
{ EMU_AXIS_BTN_A, "compat", "axis_btn_a", "compat", "axis_btn_a_inverted" },
|
||||
{ EMU_AXIS_BTN_B, "compat", "axis_btn_b", "compat", "axis_btn_b_inverted" },
|
||||
{ EMU_AXIS_BTN_C, "compat", "axis_btn_c", "compat", "axis_btn_c_inverted" },
|
||||
{ EMU_AXIS_BTN_D, "compat", "axis_btn_d", "compat", "axis_btn_d_inverted" },
|
||||
{ EMU_AXIS_BTN_X, "compat", "axis_btn_x", "compat", "axis_btn_x_inverted" },
|
||||
{ EMU_AXIS_BTN_Y, "compat", "axis_btn_y", "compat", "axis_btn_y_inverted" },
|
||||
{ EMU_AXIS_BTN_Z, "compat", "axis_btn_z", "compat", "axis_btn_z_inverted" },
|
||||
{ EMU_AXIS_BTN_START, "compat", "axis_btn_start", "compat", "axis_btn_start_inverted" },
|
||||
{ EMU_AXIS_DPAD_LEFT, "compat", "axis_dpad1_left", "compat", "axis_dpad1_left_inverted" },
|
||||
{ EMU_AXIS_DPAD_RIGHT, "compat", "axis_dpad1_right", "compat", "axis_dpad1_right_inverted" },
|
||||
{ EMU_AXIS_DPAD_UP, "compat", "axis_dpad1_up", "compat", "axis_dpad1_up_inverted" },
|
||||
{ EMU_AXIS_DPAD_DOWN, "compat", "axis_dpad1_down", "compat", "axis_dpad1_down_inverted" },
|
||||
{ EMU_AXIS_DPAD2_LEFT, "compat", "axis_dpad2_left", "compat", "axis_dpad2_left_inverted" },
|
||||
{ EMU_AXIS_DPAD2_RIGHT, "compat", "axis_dpad2_right", "compat", "axis_dpad2_right_inverted" },
|
||||
{ EMU_AXIS_DPAD2_UP, "compat", "axis_dpad2_up", "compat", "axis_dpad2_up_inverted" },
|
||||
{ EMU_AXIS_DPAD2_DOWN, "compat", "axis_dpad2_down", "compat", "axis_dpad2_down_inverted" }
|
||||
|
||||
// legacy (v2)
|
||||
{ DC_AXIS_RIGHT, "dreamcast", "axis_x", "compat", "axis_x_inverted" },
|
||||
{ DC_AXIS_DOWN, "dreamcast", "axis_y", "compat", "axis_y_inverted" },
|
||||
{ DC_AXIS2_RIGHT, "dreamcast", "axis_right_x", "compat", "axis_right_x_inverted" },
|
||||
{ DC_AXIS2_DOWN, "dreamcast", "axis_right_y", "compat", "axis_right_y_inverted" },
|
||||
{ DC_DPAD_LEFT, "compat", "axis_dpad1_x", "compat", "axis_dpad1_x_inverted" },
|
||||
{ DC_DPAD_UP, "compat", "axis_dpad1_y", "compat", "axis_dpad1_y_inverted" },
|
||||
{ DC_DPAD2_LEFT, "compat", "axis_dpad2_x", "compat", "axis_dpad2_x_inverted" },
|
||||
{ DC_DPAD2_UP, "compat", "axis_dpad2_y", "compat", "axis_dpad2_y_inverted" },
|
||||
{ DC_BTN_A, "compat", "axis_btn_a", "compat", "axis_btn_a_inverted" },
|
||||
{ DC_BTN_B, "compat", "axis_btn_b", "compat", "axis_btn_b_inverted" },
|
||||
{ DC_BTN_C, "compat", "axis_btn_c", "compat", "axis_btn_c_inverted" },
|
||||
{ DC_BTN_D, "compat", "axis_btn_d", "compat", "axis_btn_d_inverted" },
|
||||
{ DC_BTN_X, "compat", "axis_btn_x", "compat", "axis_btn_x_inverted" },
|
||||
{ DC_BTN_Y, "compat", "axis_btn_y", "compat", "axis_btn_y_inverted" },
|
||||
{ DC_BTN_Z, "compat", "axis_btn_z", "compat", "axis_btn_z_inverted" },
|
||||
{ DC_BTN_START, "compat", "axis_btn_start", "compat", "axis_btn_start_inverted" },
|
||||
{ DC_DPAD_LEFT, "compat", "axis_dpad1_left", "compat", "axis_dpad1_left_inverted" },
|
||||
{ DC_DPAD_RIGHT, "compat", "axis_dpad1_right", "compat", "axis_dpad1_right_inverted" },
|
||||
{ DC_DPAD_UP, "compat", "axis_dpad1_up", "compat", "axis_dpad1_up_inverted" },
|
||||
{ DC_DPAD_DOWN, "compat", "axis_dpad1_down", "compat", "axis_dpad1_down_inverted" },
|
||||
{ DC_DPAD2_LEFT, "compat", "axis_dpad2_left", "compat", "axis_dpad2_left_inverted" },
|
||||
{ DC_DPAD2_RIGHT, "compat", "axis_dpad2_right", "compat", "axis_dpad2_right_inverted" },
|
||||
{ DC_DPAD2_UP, "compat", "axis_dpad2_up", "compat", "axis_dpad2_up_inverted" },
|
||||
{ DC_DPAD2_DOWN, "compat", "axis_dpad2_down", "compat", "axis_dpad2_down_inverted" },
|
||||
|
||||
};
|
||||
|
||||
std::map<std::string, std::shared_ptr<InputMapping>> InputMapping::loaded_mappings;
|
||||
|
||||
void InputMapping::clear_button(u32 port, DreamcastKey id, u32 code)
|
||||
void InputMapping::clear_button(u32 port, DreamcastKey id)
|
||||
{
|
||||
if (id != EMU_BTN_NONE)
|
||||
{
|
||||
|
@ -107,8 +119,8 @@ void InputMapping::clear_button(u32 port, DreamcastKey id, u32 code)
|
|||
if (code == (u32)-1)
|
||||
break;
|
||||
buttons[port][code] = EMU_BTN_NONE;
|
||||
dirty = true;
|
||||
}
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,52 +128,52 @@ void InputMapping::set_button(u32 port, DreamcastKey id, u32 code)
|
|||
{
|
||||
if (id != EMU_BTN_NONE)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
u32 code = get_button_code(port, id);
|
||||
if (code == (u32)-1)
|
||||
break;
|
||||
buttons[port][code] = EMU_BTN_NONE;
|
||||
}
|
||||
clear_button(port, id);
|
||||
buttons[port][code] = id;
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void InputMapping::clear_axis(u32 port, DreamcastKey id, u32 code)
|
||||
void InputMapping::clear_axis(u32 port, DreamcastKey id)
|
||||
{
|
||||
if (id != EMU_AXIS_NONE)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
u32 code = get_axis_code(port, id);
|
||||
if (code == (u32)-1)
|
||||
std::pair<u32, bool> code = get_axis_code(port, id);
|
||||
if (code.first == (u32)-1)
|
||||
break;
|
||||
axes[port][code] = EMU_AXIS_NONE;
|
||||
dirty = true;
|
||||
}
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void InputMapping::set_axis(u32 port, DreamcastKey id, u32 code, bool is_inverted)
|
||||
void InputMapping::set_axis(u32 port, DreamcastKey id, u32 code, bool positive)
|
||||
{
|
||||
if (id != EMU_AXIS_NONE)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
u32 code = get_axis_code(port, id);
|
||||
if (code == (u32)-1)
|
||||
break;
|
||||
axes[port][code] = EMU_AXIS_NONE;
|
||||
}
|
||||
axes[port][code] = id;
|
||||
axes_inverted[port][code] = is_inverted;
|
||||
clear_axis(port, id);
|
||||
axes[port][std::make_pair(code, positive)] = id;
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace emucfg;
|
||||
|
||||
static DreamcastKey getKeyId(const std::string& name)
|
||||
{
|
||||
for (u32 i = 0; i < ARRAY_SIZE(button_list); i++)
|
||||
if (name == button_list[i].option)
|
||||
return button_list[i].id;
|
||||
for (u32 i = 0; i < ARRAY_SIZE(axis_list); i++)
|
||||
if (name == axis_list[i].option)
|
||||
return axis_list[i].id;
|
||||
|
||||
WARN_LOG(INPUT, "Unknown key/axis: %s", name.c_str());
|
||||
return EMU_BTN_NONE;
|
||||
}
|
||||
|
||||
void InputMapping::load(FILE* fp)
|
||||
{
|
||||
ConfigFile mf;
|
||||
|
@ -172,10 +184,76 @@ void InputMapping::load(FILE* fp)
|
|||
int dz = mf.get_int("emulator", "dead_zone", 10);
|
||||
dz = std::min(dz, 100);
|
||||
dz = std::max(dz, 0);
|
||||
version = mf.get_int("emulator", "version", 1);
|
||||
|
||||
this->dead_zone = (float)dz / 100.f;
|
||||
|
||||
version = mf.get_int("emulator", "version", 1);
|
||||
if (version < 3)
|
||||
{
|
||||
loadv1(mf);
|
||||
return;
|
||||
}
|
||||
int bindIndex = 0;
|
||||
while (true)
|
||||
{
|
||||
std::string s = mf.get("digital", "bind" + std::to_string(bindIndex++), "");
|
||||
if (s.empty())
|
||||
break;
|
||||
size_t colon = s.find(':');
|
||||
if (colon == std::string::npos || colon == 0)
|
||||
{
|
||||
WARN_LOG(INPUT, "Invalid bind entry: %s", s.c_str());
|
||||
break;
|
||||
}
|
||||
u32 code = atoi(s.substr(0, colon).c_str());
|
||||
std::string key = s.substr(colon + 1);
|
||||
if (key.empty())
|
||||
{
|
||||
WARN_LOG(INPUT, "Invalid bind entry: %s", s.c_str());
|
||||
break;
|
||||
}
|
||||
int port = 0;
|
||||
if (key[key.size() - 1] >= '1' && key[key.size() - 1] <= '3')
|
||||
{
|
||||
port = key[key.size() - 1] - '0';
|
||||
key = key.substr(0, key.size() - 1);
|
||||
}
|
||||
DreamcastKey id = getKeyId(key);
|
||||
set_button(port, id, code);
|
||||
}
|
||||
bindIndex = 0;
|
||||
while (true)
|
||||
{
|
||||
std::string s = mf.get("analog", "bind" + std::to_string(bindIndex++), "");
|
||||
if (s.empty())
|
||||
break;
|
||||
size_t colon = s.find(':');
|
||||
if (colon == std::string::npos || colon < 2)
|
||||
{
|
||||
WARN_LOG(INPUT, "Invalid bind entry: %s", s.c_str());
|
||||
break;
|
||||
}
|
||||
bool positive = s[colon - 1] == '+';
|
||||
u32 code = atoi(s.substr(0, colon - 1).c_str());
|
||||
std::string key = s.substr(colon + 1);
|
||||
if (key.empty())
|
||||
{
|
||||
WARN_LOG(INPUT, "Invalid bind entry: %s", s.c_str());
|
||||
break;
|
||||
}
|
||||
int port = 0;
|
||||
if (key[key.size() - 1] >= '1' && key[key.size() - 1] <= '3')
|
||||
{
|
||||
port = key[key.size() - 1] - '0';
|
||||
key = key.substr(0, key.size() - 1);
|
||||
}
|
||||
DreamcastKey id = getKeyId(key);
|
||||
set_axis(port, id, code, positive);
|
||||
}
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
void InputMapping::loadv1(ConfigFile& mf)
|
||||
{
|
||||
for (int port = 0; port < 4; port++)
|
||||
{
|
||||
for (u32 i = 0; i < ARRAY_SIZE(button_list); i++)
|
||||
|
@ -187,7 +265,15 @@ void InputMapping::load(FILE* fp)
|
|||
option = button_list[i].option + std::to_string(port);
|
||||
int button_code = mf.get_int(button_list[i].section, option, -1);
|
||||
if (button_code >= 0)
|
||||
this->set_button(port, button_list[i].id, button_code);
|
||||
{
|
||||
DreamcastKey id = button_list[i].id;
|
||||
// remap service and test buttons to their new aliases
|
||||
if (id == DC_BTN_C)
|
||||
id = DC_DPAD2_UP;
|
||||
else if (id == DC_BTN_Z)
|
||||
id = DC_DPAD2_DOWN;
|
||||
this->set_button(port, id, button_code);
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < ARRAY_SIZE(axis_list); i++)
|
||||
|
@ -204,11 +290,22 @@ void InputMapping::load(FILE* fp)
|
|||
option = axis_list[i].option_inverted;
|
||||
else
|
||||
option = axis_list[i].option_inverted + std::to_string(port);
|
||||
this->set_axis(port, axis_list[i].id, axis_code, mf.get_bool(axis_list[i].section_inverted, option, false));
|
||||
bool inverted = mf.get_bool(axis_list[i].section_inverted, option, false);
|
||||
|
||||
this->set_axis(port, axis_list[i].id, axis_code, !inverted);
|
||||
|
||||
if (axis_list[i].id == DC_AXIS_RIGHT)
|
||||
this->set_axis(port, DC_AXIS_LEFT, axis_code, inverted);
|
||||
else if (axis_list[i].id == DC_AXIS_DOWN)
|
||||
this->set_axis(port, DC_AXIS_UP, axis_code, inverted);
|
||||
else if (axis_list[i].id == DC_AXIS2_RIGHT)
|
||||
this->set_axis(port, DC_AXIS2_LEFT, axis_code, inverted);
|
||||
else if (axis_list[i].id == DC_AXIS2_DOWN)
|
||||
this->set_axis(port, DC_AXIS2_UP, axis_code, inverted);
|
||||
}
|
||||
}
|
||||
}
|
||||
dirty = false;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
u32 InputMapping::get_button_code(u32 port, DreamcastKey key)
|
||||
|
@ -221,14 +318,14 @@ u32 InputMapping::get_button_code(u32 port, DreamcastKey key)
|
|||
return -1;
|
||||
}
|
||||
|
||||
u32 InputMapping::get_axis_code(u32 port, DreamcastKey key)
|
||||
std::pair<u32, bool> InputMapping::get_axis_code(u32 port, DreamcastKey key)
|
||||
{
|
||||
for (auto& it : axes[port])
|
||||
{
|
||||
if (it.second == key)
|
||||
return it.first;
|
||||
}
|
||||
return -1;
|
||||
return std::make_pair((u32)-1, false);
|
||||
}
|
||||
|
||||
void InputMapping::ClearMappings()
|
||||
|
@ -251,6 +348,31 @@ std::shared_ptr<InputMapping> InputMapping::LoadMapping(const char *name)
|
|||
std::fclose(fp);
|
||||
loaded_mappings[name] = mapping;
|
||||
|
||||
if (mapping->is_dirty())
|
||||
{
|
||||
// Make a backup of the current mapping file
|
||||
FILE *out = nowide::fopen((path + ".save").c_str(), "w");
|
||||
if (out == nullptr)
|
||||
WARN_LOG(INPUT, "Can't backup controller mapping file %s", path.c_str());
|
||||
else
|
||||
{
|
||||
fp = nowide::fopen(path.c_str(), "r");
|
||||
if (fp != nullptr)
|
||||
{
|
||||
u8 buf[4096];
|
||||
while (true)
|
||||
{
|
||||
size_t n = fread(buf, 1, sizeof(buf), fp);
|
||||
if (n <= 0)
|
||||
break;
|
||||
fwrite(buf, 1, n, out);
|
||||
}
|
||||
std::fclose(fp);
|
||||
}
|
||||
std::fclose(out);
|
||||
}
|
||||
}
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
|
@ -259,6 +381,19 @@ void InputMapping::set_dirty()
|
|||
dirty = true;
|
||||
}
|
||||
|
||||
static const char *getKeyName(DreamcastKey key)
|
||||
{
|
||||
for (u32 i = 0; i < ARRAY_SIZE(button_list); i++)
|
||||
if (key == button_list[i].id)
|
||||
return button_list[i].option.c_str();
|
||||
for (u32 i = 0; i < ARRAY_SIZE(axis_list); i++)
|
||||
if (key == axis_list[i].id)
|
||||
return axis_list[i].option.c_str();
|
||||
ERROR_LOG(INPUT, "Invalid key %x", key);
|
||||
die("Invalid key");
|
||||
return "?";
|
||||
}
|
||||
|
||||
bool InputMapping::save(const char *name)
|
||||
{
|
||||
if (!dirty)
|
||||
|
@ -277,46 +412,41 @@ bool InputMapping::save(const char *name)
|
|||
|
||||
mf.set("emulator", "mapping_name", this->name);
|
||||
mf.set_int("emulator", "dead_zone", (int)std::round(this->dead_zone * 100.f));
|
||||
mf.set_int("emulator", "version", version);
|
||||
mf.set_int("emulator", "version", 3);
|
||||
|
||||
int bindIndex = 0;
|
||||
for (int port = 0; port < 4; port++)
|
||||
{
|
||||
for (u32 i = 0; i < ARRAY_SIZE(button_list); i++)
|
||||
for (const auto& pair : buttons[port])
|
||||
{
|
||||
if (pair.second == EMU_BTN_NONE)
|
||||
continue;
|
||||
const char *keyName = getKeyName(pair.second);
|
||||
std::string option;
|
||||
if (port == 0)
|
||||
option = button_list[i].option;
|
||||
option = keyName;
|
||||
else
|
||||
option = button_list[i].option + std::to_string(port);
|
||||
|
||||
for (auto& it : buttons[port])
|
||||
{
|
||||
if (it.second == button_list[i].id)
|
||||
mf.set_int(button_list[i].section, option, (int)it.first);
|
||||
}
|
||||
option = keyName + std::to_string(port);
|
||||
mf.set("digital", "bind" + std::to_string(bindIndex), std::to_string(pair.first) + ":" + option);
|
||||
bindIndex++;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < ARRAY_SIZE(axis_list); i++)
|
||||
}
|
||||
bindIndex = 0;
|
||||
for (int port = 0; port < 4; port++)
|
||||
{
|
||||
for (const auto& pair : axes[port])
|
||||
{
|
||||
if (pair.second == EMU_BTN_NONE)
|
||||
continue;
|
||||
const char *keyName = getKeyName(pair.second);
|
||||
std::string option;
|
||||
if (port == 0)
|
||||
option = axis_list[i].option;
|
||||
option = keyName;
|
||||
else
|
||||
option = axis_list[i].option + std::to_string(port);
|
||||
std::string option_inverted;
|
||||
if (port == 0)
|
||||
option_inverted = axis_list[i].option_inverted;
|
||||
else
|
||||
option_inverted = axis_list[i].option_inverted + std::to_string(port);
|
||||
|
||||
for (auto& it : axes[port])
|
||||
{
|
||||
if (it.second == axis_list[i].id)
|
||||
{
|
||||
mf.set_int(axis_list[i].section, option, (int)it.first);
|
||||
mf.set_bool(axis_list[i].section_inverted, option_inverted, axes_inverted[port][it.first]);
|
||||
}
|
||||
}
|
||||
option = keyName + std::to_string(port);
|
||||
mf.set("analog", "bind" + std::to_string(bindIndex),
|
||||
std::to_string(pair.first.first) + (pair.first.second ? "+" : "-") + ":" + option);
|
||||
bindIndex++;
|
||||
}
|
||||
}
|
||||
mf.save(fp);
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace emucfg {
|
||||
struct ConfigFile;
|
||||
}
|
||||
|
||||
class InputMapping
|
||||
{
|
||||
public:
|
||||
|
@ -35,13 +39,12 @@ public:
|
|||
{
|
||||
buttons[port] = other.buttons[port];
|
||||
axes[port] = other.axes[port];
|
||||
axes_inverted[port] = other.axes_inverted[port];
|
||||
}
|
||||
}
|
||||
|
||||
std::string name;
|
||||
float dead_zone = 0.1f;
|
||||
int version = 2;
|
||||
int version = 3;
|
||||
|
||||
DreamcastKey get_button_id(u32 port, u32 code)
|
||||
{
|
||||
|
@ -51,31 +54,24 @@ public:
|
|||
else
|
||||
return EMU_BTN_NONE;
|
||||
}
|
||||
void clear_button(u32 port, DreamcastKey id, u32 code);
|
||||
void clear_button(u32 port, DreamcastKey id);
|
||||
void set_button(u32 port, DreamcastKey id, u32 code);
|
||||
void set_button(DreamcastKey id, u32 code) { set_button(0, id, code); }
|
||||
u32 get_button_code(u32 port, DreamcastKey key);
|
||||
|
||||
DreamcastKey get_axis_id(u32 port, u32 code)
|
||||
DreamcastKey get_axis_id(u32 port, u32 code, bool pos)
|
||||
{
|
||||
auto it = axes[port].find(code);
|
||||
auto it = axes[port].find(std::make_pair(code, pos));
|
||||
if (it != axes[port].end())
|
||||
return it->second;
|
||||
else
|
||||
return EMU_AXIS_NONE;
|
||||
}
|
||||
bool get_axis_inverted(u32 port, u32 code)
|
||||
{
|
||||
auto it = axes_inverted[port].find(code);
|
||||
if (it != axes_inverted[port].end())
|
||||
return it->second;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
u32 get_axis_code(u32 port, DreamcastKey key);
|
||||
void clear_axis(u32 port, DreamcastKey id, u32 code);
|
||||
void set_axis(u32 port, DreamcastKey id, u32 code, bool inverted);
|
||||
void set_axis(DreamcastKey id, u32 code, bool inverted) { set_axis(0, id, code, inverted); }
|
||||
std::pair<u32, bool> get_axis_code(u32 port, DreamcastKey key);
|
||||
|
||||
void clear_axis(u32 port, DreamcastKey id);
|
||||
void set_axis(u32 port, DreamcastKey id, u32 code, bool positive);
|
||||
void set_axis(DreamcastKey id, u32 code, bool positive) { set_axis(0, id, code, positive); }
|
||||
|
||||
void load(FILE* fp);
|
||||
bool save(const char *name);
|
||||
|
@ -92,9 +88,10 @@ protected:
|
|||
bool dirty = false;
|
||||
|
||||
private:
|
||||
void loadv1(emucfg::ConfigFile& mf);
|
||||
|
||||
std::map<u32, DreamcastKey> buttons[4];
|
||||
std::map<u32, DreamcastKey> axes[4];
|
||||
std::map<u32, bool> axes_inverted[4];
|
||||
std::map<std::pair<u32, bool>, DreamcastKey> axes[4];
|
||||
|
||||
static std::map<std::string, std::shared_ptr<InputMapping>> loaded_mappings;
|
||||
};
|
||||
|
@ -108,11 +105,15 @@ public:
|
|||
|
||||
for (int i = 0; i < 32; i++)
|
||||
set_button(0, (DreamcastKey)(1 << i), 1 << i);
|
||||
set_axis(0, DC_AXIS_X, DC_AXIS_X, false);
|
||||
set_axis(0, DC_AXIS_Y, DC_AXIS_Y, false);
|
||||
set_axis(0, DC_AXIS_LT, DC_AXIS_LT, false);
|
||||
set_axis(0, DC_AXIS_RT, DC_AXIS_RT, false);
|
||||
set_axis(0, DC_AXIS_X2, DC_AXIS_X2, false);
|
||||
set_axis(0, DC_AXIS_Y2, DC_AXIS_Y2, false);
|
||||
set_axis(0, DC_AXIS_LEFT, DC_AXIS_LEFT, true);
|
||||
set_axis(0, DC_AXIS_RIGHT, DC_AXIS_RIGHT, true);
|
||||
set_axis(0, DC_AXIS_UP, DC_AXIS_UP, true);
|
||||
set_axis(0, DC_AXIS_DOWN, DC_AXIS_DOWN, true);
|
||||
set_axis(0, DC_AXIS_LT, DC_AXIS_LT, true);
|
||||
set_axis(0, DC_AXIS_RT, DC_AXIS_RT, true);
|
||||
set_axis(0, DC_AXIS2_LEFT, DC_AXIS2_LEFT, true);
|
||||
set_axis(0, DC_AXIS2_RIGHT, DC_AXIS2_RIGHT, true);
|
||||
set_axis(0, DC_AXIS2_UP, DC_AXIS2_UP, true);
|
||||
set_axis(0, DC_AXIS2_DOWN, DC_AXIS2_DOWN, true);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <fcntl.h>
|
||||
#include <linux/input.h>
|
||||
#include <unistd.h>
|
||||
#include <climits>
|
||||
|
||||
class DefaultEvdevInputMapping : public InputMapping
|
||||
{
|
||||
|
@ -24,12 +25,16 @@ public:
|
|||
set_button(DC_DPAD_RIGHT, BTN_DPAD_RIGHT);
|
||||
set_button(EMU_BTN_MENU, BTN_SELECT);
|
||||
|
||||
set_axis(DC_AXIS_X, ABS_X, false);
|
||||
set_axis(DC_AXIS_Y, ABS_Y, false);
|
||||
set_axis(DC_AXIS_LT, ABS_Z, false);
|
||||
set_axis(DC_AXIS_RT, ABS_RZ, false);
|
||||
set_axis(DC_AXIS_X2, ABS_RX, false);
|
||||
set_axis(DC_AXIS_Y2, ABS_RY, false);
|
||||
set_axis(DC_AXIS_LEFT, ABS_X, false);
|
||||
set_axis(DC_AXIS_RIGHT, ABS_X, true);
|
||||
set_axis(DC_AXIS_UP, ABS_Y, false);
|
||||
set_axis(DC_AXIS_DOWN, ABS_Y, true);
|
||||
set_axis(DC_AXIS_LT, ABS_Z, true);
|
||||
set_axis(DC_AXIS_RT, ABS_RZ, true);
|
||||
set_axis(DC_AXIS2_LEFT, ABS_RX, false);
|
||||
set_axis(DC_AXIS2_RIGHT, ABS_RX, true);
|
||||
set_axis(DC_AXIS_UP, ABS_RY, false);
|
||||
set_axis(DC_AXIS_DOWN, ABS_RY, true);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -225,8 +230,32 @@ public:
|
|||
GamepadDevice::Unregister(gamepad);
|
||||
}
|
||||
|
||||
protected:
|
||||
void load_axis_min_max(u32 axis) override
|
||||
private:
|
||||
int get_axis_min_value(u32 axis)
|
||||
{
|
||||
auto it = axis_min_values.find(axis);
|
||||
if (it == axis_min_values.end()) {
|
||||
load_axis_min_max(axis);
|
||||
it = axis_min_values.find(axis);
|
||||
if (it == axis_min_values.end())
|
||||
return INT_MIN;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
unsigned int get_axis_range(u32 axis)
|
||||
{
|
||||
auto it = axis_ranges.find(axis);
|
||||
if (it == axis_ranges.end()) {
|
||||
load_axis_min_max(axis);
|
||||
it = axis_ranges.find(axis);
|
||||
if (it == axis_ranges.end())
|
||||
return UINT_MAX;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void load_axis_min_max(u32 axis)
|
||||
{
|
||||
struct input_absinfo abs;
|
||||
if (ioctl(_fd, EVIOCGABS(axis), &abs))
|
||||
|
@ -241,7 +270,6 @@ protected:
|
|||
DEBUG_LOG(INPUT, "evdev: range of axis %d is from %d to %d", axis, axis_min_values[axis], axis_min_values[axis] + axis_ranges[axis]);
|
||||
}
|
||||
|
||||
private:
|
||||
void read_input()
|
||||
{
|
||||
update_rumble();
|
||||
|
@ -256,7 +284,12 @@ private:
|
|||
break;
|
||||
|
||||
case EV_ABS:
|
||||
gamepad_axis_input(ie.code, ie.value);
|
||||
{
|
||||
// TODO no way to distinguish between half and full axes
|
||||
int min = get_axis_min_value(ie.code);
|
||||
unsigned range = get_axis_range(ie.code);
|
||||
gamepad_axis_input(ie.code, (ie.value - min) * 65535 / range - 32768);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -303,6 +336,8 @@ private:
|
|||
int _rumble_effect_id = -1;
|
||||
float vib_inclination = 0;
|
||||
double vib_stop_time = 0;
|
||||
std::map<u32, int> axis_min_values;
|
||||
std::map<u32, unsigned int> axis_ranges;
|
||||
static std::map<std::string, std::shared_ptr<EvdevGamepadDevice>> evdev_gamepads;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,159 +0,0 @@
|
|||
#include "joystick.h"
|
||||
|
||||
#if defined(USE_JOYSTICK)
|
||||
#include <fcntl.h>
|
||||
#include <linux/joystick.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
const u32 joystick_map_btn_usb[JOYSTICK_MAP_SIZE] = { DC_BTN_Y, DC_BTN_B, DC_BTN_A, DC_BTN_X, 0, 0, 0, 0, 0, DC_BTN_START };
|
||||
const u32 joystick_map_axis_usb[JOYSTICK_MAP_SIZE] = { DC_AXIS_X, DC_AXIS_Y, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
const u32 joystick_map_btn_xbox360[JOYSTICK_MAP_SIZE] = { DC_BTN_A, DC_BTN_B, DC_BTN_X, DC_BTN_Y, 0, 0, 0, DC_BTN_START, 0, 0 };
|
||||
const u32 joystick_map_axis_xbox360[JOYSTICK_MAP_SIZE] = { DC_AXIS_X, DC_AXIS_Y, DC_AXIS_LT, 0, 0, DC_AXIS_RT, DC_DPAD_LEFT, DC_DPAD_UP, 0, 0 };
|
||||
|
||||
const u32* joystick_map_btn = joystick_map_btn_usb;
|
||||
const u32* joystick_map_axis = joystick_map_axis_usb;
|
||||
|
||||
int input_joystick_init(const char* device)
|
||||
{
|
||||
int axis_count = 0;
|
||||
int button_count = 0;
|
||||
char name[128] = "Unknown";
|
||||
|
||||
printf("joystick: Trying to open device at '%s'\n", device);
|
||||
|
||||
int fd = open(device, O_RDONLY);
|
||||
|
||||
if(fd >= 0)
|
||||
{
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
ioctl(fd, JSIOCGAXES, &axis_count);
|
||||
ioctl(fd, JSIOCGBUTTONS, &button_count);
|
||||
ioctl(fd, JSIOCGNAME(sizeof(name)), &name);
|
||||
|
||||
printf("joystick: Found '%s' with %d axis and %d buttons at '%s'.\n", name, axis_count, button_count, device);
|
||||
|
||||
if (strcmp(name, "Microsoft X-Box 360 pad") == 0 ||
|
||||
strcmp(name, "Xbox Gamepad (userspace driver)") == 0 ||
|
||||
strcmp(name, "Xbox 360 Wireless Receiver (XBOX)") == 0)
|
||||
{
|
||||
joystick_map_btn = joystick_map_btn_xbox360;
|
||||
joystick_map_axis = joystick_map_axis_xbox360;
|
||||
printf("joystick: Using Xbox 360 map\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("joystick open");
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
bool input_joystick_handle(int fd, u32 port)
|
||||
{
|
||||
// Joystick must be connected
|
||||
if(fd < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct js_event JE;
|
||||
while(read(fd, &JE, sizeof(JE)) == sizeof(JE))
|
||||
if (JE.number < JOYSTICK_MAP_SIZE)
|
||||
{
|
||||
switch(JE.type & ~JS_EVENT_INIT)
|
||||
{
|
||||
case JS_EVENT_AXIS:
|
||||
{
|
||||
u32 mt = joystick_map_axis[JE.number] >> 16;
|
||||
u32 mo = joystick_map_axis[JE.number] & 0xFFFF;
|
||||
|
||||
//printf("AXIS %d,%d\n",JE.number,JE.value);
|
||||
s8 v=(s8)(JE.value/256); //-127 ... + 127 range
|
||||
|
||||
if (mt == 0)
|
||||
{
|
||||
kcode[port] |= mo;
|
||||
kcode[port] |= mo*2;
|
||||
if (v<-64)
|
||||
{
|
||||
kcode[port] &= ~mo;
|
||||
}
|
||||
else if (v>64)
|
||||
{
|
||||
kcode[port] &= ~(mo*2);
|
||||
}
|
||||
|
||||
//printf("Mapped to %d %d %d\n",mo,kcode[port]&mo,kcode[port]&(mo*2));
|
||||
}
|
||||
else if (mt == 1)
|
||||
{
|
||||
if (v >= 0)
|
||||
{
|
||||
v++; //up to 255
|
||||
}
|
||||
//printf("AXIS %d,%d Mapped to %d %d %d\n",JE.number,JE.value,mo,v,v+127);
|
||||
if (mo == 0)
|
||||
{
|
||||
lt[port] = (v + 127);
|
||||
}
|
||||
else if (mo == 1)
|
||||
{
|
||||
rt[port] = (v + 127);
|
||||
}
|
||||
}
|
||||
else if (mt == 2)
|
||||
{
|
||||
// printf("AXIS %d,%d Mapped to %d %d [%d]",JE.number,JE.value,mo,v);
|
||||
if (mo == 0)
|
||||
{
|
||||
joyx[port] = v;
|
||||
}
|
||||
else if (mo == 1)
|
||||
{
|
||||
joyy[port] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case JS_EVENT_BUTTON:
|
||||
{
|
||||
u32 mt = joystick_map_btn[JE.number] >> 16;
|
||||
u32 mo = joystick_map_btn[JE.number] & 0xFFFF;
|
||||
|
||||
// printf("BUTTON %d,%d\n",JE.number,JE.value);
|
||||
|
||||
if (mt == 0)
|
||||
{
|
||||
// printf("Mapped to %d\n",mo);
|
||||
if (JE.value)
|
||||
{
|
||||
kcode[port] &= ~mo;
|
||||
}
|
||||
else
|
||||
{
|
||||
kcode[port] |= mo;
|
||||
}
|
||||
}
|
||||
else if (mt == 1)
|
||||
{
|
||||
// printf("Mapped to %d %d\n",mo,JE.value?255:0);
|
||||
if (mo==0)
|
||||
{
|
||||
lt[port] = JE.value ? 255 : 0;
|
||||
}
|
||||
else if (mo==1)
|
||||
{
|
||||
rt[port] = JE.value ? 255 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
|
@ -1,10 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define JOYSTICK_DEVICE_STRING "/dev/input/js%d"
|
||||
#define JOYSTICK_DEFAULT_DEVICE_ID -1
|
||||
#define JOYSTICK_MAP_SIZE 32
|
||||
|
||||
extern int input_joystick_init(const char* device);
|
||||
extern bool input_joystick_handle(int fd, u32 port);
|
|
@ -35,16 +35,6 @@
|
|||
#include "evdev.h"
|
||||
#endif
|
||||
|
||||
#if defined(USE_JOYSTICK)
|
||||
#include "cfg/cfg.h"
|
||||
#include "joystick.h"
|
||||
#endif
|
||||
|
||||
#if defined(USE_JOYSTICK)
|
||||
/* legacy joystick input */
|
||||
static int joystick_fd = -1; // Joystick file descriptor
|
||||
#endif
|
||||
|
||||
#ifdef USE_BREAKPAD
|
||||
#include "client/linux/handler/exception_handler.h"
|
||||
#endif
|
||||
|
@ -55,21 +45,6 @@ void os_SetupInput()
|
|||
input_evdev_init();
|
||||
#endif
|
||||
|
||||
#if defined(USE_JOYSTICK)
|
||||
int joystick_device_id = cfgLoadInt("input", "joystick_device_id", JOYSTICK_DEFAULT_DEVICE_ID);
|
||||
if (joystick_device_id < 0) {
|
||||
INFO_LOG(INPUT, "Legacy Joystick input disabled by config.");
|
||||
}
|
||||
else
|
||||
{
|
||||
int joystick_device_length = snprintf(NULL, 0, JOYSTICK_DEVICE_STRING, joystick_device_id);
|
||||
char* joystick_device = (char*)malloc(joystick_device_length + 1);
|
||||
sprintf(joystick_device, JOYSTICK_DEVICE_STRING, joystick_device_id);
|
||||
joystick_fd = input_joystick_init(joystick_device);
|
||||
free(joystick_device);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(SUPPORT_X11)
|
||||
input_x11_init();
|
||||
#endif
|
||||
|
@ -81,10 +56,6 @@ void os_SetupInput()
|
|||
|
||||
void UpdateInputState()
|
||||
{
|
||||
#if defined(USE_JOYSTICK)
|
||||
input_joystick_handle(joystick_fd, 0);
|
||||
#endif
|
||||
|
||||
#if defined(USE_EVDEV)
|
||||
input_evdev_handle();
|
||||
#endif
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
namespace ggpo
|
||||
{
|
||||
|
||||
constexpr u32 BTN_TRIGGER_LEFT = DC_BTN_RELOAD << 1;
|
||||
constexpr u32 BTN_TRIGGER_RIGHT = DC_BTN_RELOAD << 2;
|
||||
|
||||
static void getLocalInput(MapleInputState inputState[4])
|
||||
{
|
||||
for (int player = 0; player < 4; player++)
|
||||
|
@ -55,6 +58,7 @@ static void getLocalInput(MapleInputState inputState[4])
|
|||
#include <xxhash.h>
|
||||
#include "imgui/imgui.h"
|
||||
#include "miniupnp.h"
|
||||
#include "hw/naomi/naomi_cart.h"
|
||||
|
||||
//#define SYNC_TEST 1
|
||||
|
||||
|
@ -77,6 +81,7 @@ static time_point<steady_clock> lastFrameTime;
|
|||
static int msPerFrameAvg;
|
||||
static bool _endOfFrame;
|
||||
static MiniUPnP miniupnp;
|
||||
static int analogAxes;
|
||||
|
||||
struct MemPages
|
||||
{
|
||||
|
@ -367,9 +372,27 @@ void startSession(int localPort, int localPlayerNum)
|
|||
player.player_num = (1 - localPlayerNum) + 1;
|
||||
result = ggpo_add_player(ggpoSession, &player, &remotePlayer);
|
||||
synchronized = true;
|
||||
analogAxes = 0;
|
||||
NOTICE_LOG(NETWORK, "GGPO synctest session started");
|
||||
#else
|
||||
u32 inputSize = sizeof(kcode[0]) + config::GGPOAnalogAxes;
|
||||
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
||||
analogAxes = config::GGPOAnalogAxes;
|
||||
else
|
||||
{
|
||||
analogAxes = 0;
|
||||
if (NaomiGameInputs != nullptr)
|
||||
{
|
||||
for (const auto& axis : NaomiGameInputs->axes)
|
||||
{
|
||||
if (axis.name == nullptr)
|
||||
break;
|
||||
if (axis.type == Full)
|
||||
analogAxes = std::max(analogAxes, (int)axis.axis + 1);
|
||||
}
|
||||
}
|
||||
NOTICE_LOG(NETWORK, "GGPO: Using %d full analog axes", analogAxes);
|
||||
}
|
||||
u32 inputSize = sizeof(kcode[0]) + analogAxes;
|
||||
GGPOErrorCode result = ggpo_start_session(&ggpoSession, &cb, config::Settings::instance().getGameId().c_str(), MAX_PLAYERS, inputSize, localPort);
|
||||
if (result != GGPO_OK)
|
||||
{
|
||||
|
@ -447,7 +470,7 @@ void getInput(MapleInputState inputState[4])
|
|||
for (int player = 0; player < 4; player++)
|
||||
inputState[player] = {};
|
||||
|
||||
u32 inputSize = sizeof(u32) + config::GGPOAnalogAxes;
|
||||
u32 inputSize = sizeof(u32) + analogAxes;
|
||||
std::vector<u8> inputs(inputSize * MAX_PLAYERS);
|
||||
// should not call any callback
|
||||
GGPOErrorCode error = ggpo_synchronize_input(ggpoSession, (void *)&inputs[0], inputs.size(), nullptr);
|
||||
|
@ -461,14 +484,14 @@ void getInput(MapleInputState inputState[4])
|
|||
{
|
||||
MapleInputState& state = inputState[player];
|
||||
state.kcode = ~(*(u32 *)&inputs[player * inputSize]);
|
||||
if (config::GGPOAnalogAxes > 0)
|
||||
if (analogAxes > 0)
|
||||
{
|
||||
state.fullAxes[PJAI_X1] = inputs[player * inputSize + 4];
|
||||
if (config::GGPOAnalogAxes == 2)
|
||||
if (analogAxes >= 2)
|
||||
state.fullAxes[PJAI_Y1] = inputs[player * inputSize + 5];
|
||||
}
|
||||
state.halfAxes[PJTI_R] = (state.kcode & EMU_BTN_TRIGGER_RIGHT) == 0 ? 255 : 0;
|
||||
state.halfAxes[PJTI_L] = (state.kcode & EMU_BTN_TRIGGER_LEFT) == 0 ? 255 : 0;
|
||||
state.halfAxes[PJTI_R] = (state.kcode & BTN_TRIGGER_RIGHT) == 0 ? 255 : 0;
|
||||
state.halfAxes[PJTI_L] = (state.kcode & BTN_TRIGGER_LEFT) == 0 ? 255 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -508,24 +531,21 @@ bool nextFrame()
|
|||
// may call save_game_state
|
||||
do {
|
||||
u32 input = ~kcode[localPlayerNum];
|
||||
if (settings.platform.system != DC_PLATFORM_NAOMI)
|
||||
{
|
||||
if (rt[localPlayerNum] >= 64)
|
||||
input |= EMU_BTN_TRIGGER_RIGHT;
|
||||
else
|
||||
input &= ~EMU_BTN_TRIGGER_RIGHT;
|
||||
if (lt[localPlayerNum] >= 64)
|
||||
input |= EMU_BTN_TRIGGER_LEFT;
|
||||
else
|
||||
input &= ~EMU_BTN_TRIGGER_LEFT;
|
||||
}
|
||||
u32 inputSize = sizeof(input) + config::GGPOAnalogAxes;
|
||||
if (rt[localPlayerNum] >= 64)
|
||||
input |= BTN_TRIGGER_RIGHT;
|
||||
else
|
||||
input &= ~BTN_TRIGGER_RIGHT;
|
||||
if (lt[localPlayerNum] >= 64)
|
||||
input |= BTN_TRIGGER_LEFT;
|
||||
else
|
||||
input &= ~BTN_TRIGGER_LEFT;
|
||||
u32 inputSize = sizeof(input) + analogAxes;
|
||||
std::vector<u8> allInput(inputSize);
|
||||
*(u32 *)&allInput[0] = input;
|
||||
if (config::GGPOAnalogAxes > 0)
|
||||
if (analogAxes > 0)
|
||||
{
|
||||
allInput[4] = joyx[localPlayerNum];
|
||||
if (config::GGPOAnalogAxes == 2)
|
||||
if (analogAxes >= 2)
|
||||
allInput[5] = joyy[localPlayerNum];
|
||||
}
|
||||
GGPOErrorCode result = ggpo_add_local_input(ggpoSession, localPlayer, &allInput[0], inputSize);
|
||||
|
|
|
@ -566,6 +566,13 @@ static void gui_display_commands()
|
|||
ImGui::End();
|
||||
}
|
||||
|
||||
inline static void header(const char *title)
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.f, 0.5f)); // Left
|
||||
ImGui::ButtonEx(title, ImVec2(-1, 0), ImGuiButtonFlags_Disabled);
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
const char *maple_device_types[] = { "None", "Sega Controller", "Light Gun", "Keyboard", "Mouse", "Twin Stick", "Ascii Stick" };
|
||||
const char *maple_expansion_device_types[] = { "None", "Sega VMU", "Purupuru", "Microphone" };
|
||||
|
||||
|
@ -630,46 +637,100 @@ static const char *maple_expansion_device_name(MapleDeviceType type)
|
|||
}
|
||||
|
||||
const char *maple_ports[] = { "None", "A", "B", "C", "D", "All" };
|
||||
const DreamcastKey button_keys[] = {
|
||||
DC_BTN_START, DC_BTN_A, DC_BTN_B, DC_BTN_X, DC_BTN_Y, DC_DPAD_UP, DC_DPAD_DOWN, DC_DPAD_LEFT, DC_DPAD_RIGHT,
|
||||
EMU_BTN_MENU, EMU_BTN_ESCAPE, EMU_BTN_FFORWARD, EMU_BTN_TRIGGER_LEFT, EMU_BTN_TRIGGER_RIGHT,
|
||||
DC_BTN_C, DC_BTN_D, DC_BTN_Z, DC_DPAD2_UP, DC_DPAD2_DOWN, DC_DPAD2_LEFT, DC_DPAD2_RIGHT,
|
||||
DC_BTN_RELOAD,
|
||||
EMU_BTN_ANA_UP, EMU_BTN_ANA_DOWN, EMU_BTN_ANA_LEFT, EMU_BTN_ANA_RIGHT
|
||||
|
||||
struct Mapping {
|
||||
DreamcastKey key;
|
||||
const char *name;
|
||||
};
|
||||
const char *button_names[] = {
|
||||
"Start", "A", "B", "X", "Y", "DPad Up", "DPad Down", "DPad Left", "DPad Right",
|
||||
"Menu", "Exit", "Fast-forward", "Left Trigger", "Right Trigger",
|
||||
"C", "D", "Z", "Right Dpad Up", "Right DPad Down", "Right DPad Left", "Right DPad Right",
|
||||
"Reload",
|
||||
"Left Stick Up", "Left Stick Down", "Left Stick Left", "Left Stick Right"
|
||||
|
||||
const Mapping dcButtons[] = {
|
||||
{ EMU_BTN_NONE, "Directions" },
|
||||
{ DC_DPAD_UP, "Up" },
|
||||
{ DC_DPAD_DOWN, "Down" },
|
||||
{ DC_DPAD_LEFT, "Left" },
|
||||
{ DC_DPAD_RIGHT, "Right" },
|
||||
|
||||
{ DC_AXIS_UP, "Thumbstick Up" },
|
||||
{ DC_AXIS_DOWN, "Thumbstick Down" },
|
||||
{ DC_AXIS_LEFT, "Thumbstick Left" },
|
||||
{ DC_AXIS_RIGHT, "Thumbstick Right" },
|
||||
|
||||
{ DC_DPAD2_UP, "DPad2 Up" },
|
||||
{ DC_DPAD2_DOWN, "DPad2 Down" },
|
||||
{ DC_DPAD2_LEFT, "DPad2 Left" },
|
||||
{ DC_DPAD2_RIGHT, "DPad2 Right" },
|
||||
|
||||
{ EMU_BTN_NONE, "Buttons" },
|
||||
{ DC_BTN_A, "A" },
|
||||
{ DC_BTN_B, "B" },
|
||||
{ DC_BTN_X, "X" },
|
||||
{ DC_BTN_Y, "Y" },
|
||||
{ DC_BTN_C, "C" },
|
||||
{ DC_BTN_D, "D" },
|
||||
{ DC_BTN_Z, "Z" },
|
||||
|
||||
{ EMU_BTN_NONE, "Triggers" },
|
||||
{ DC_AXIS_LT, "Left Trigger" },
|
||||
{ DC_AXIS_RT, "Right Trigger" },
|
||||
|
||||
{ EMU_BTN_NONE, "System Buttons" },
|
||||
{ DC_BTN_START, "Start" },
|
||||
{ DC_BTN_RELOAD, "Reload" },
|
||||
|
||||
{ EMU_BTN_NONE, "Emulator" },
|
||||
{ EMU_BTN_MENU, "Menu" },
|
||||
{ EMU_BTN_ESCAPE, "Exit" },
|
||||
{ EMU_BTN_FFORWARD, "Fast-forward" },
|
||||
|
||||
{ EMU_BTN_NONE, nullptr }
|
||||
};
|
||||
const char *arcade_button_names[] = {
|
||||
"Start", "Button 1", "Button 2", "Button 3", "Button 4", "Up", "Down", "Left", "Right",
|
||||
"Menu", "Exit", "Fast-forward", "N/A", "N/A",
|
||||
"Service", "Coin", "Test", "Button 5", "Button 6", "Button 7", "Button 8",
|
||||
"Reload",
|
||||
"N/A", "N/A", "N/A", "N/A"
|
||||
|
||||
const Mapping arcadeButtons[] = {
|
||||
{ EMU_BTN_NONE, "Directions" },
|
||||
{ DC_DPAD_UP, "Up" },
|
||||
{ DC_DPAD_DOWN, "Down" },
|
||||
{ DC_DPAD_LEFT, "Left" },
|
||||
{ DC_DPAD_RIGHT, "Right" },
|
||||
|
||||
{ DC_AXIS_UP, "Thumbstick Up" },
|
||||
{ DC_AXIS_DOWN, "Thumbstick Down" },
|
||||
{ DC_AXIS_LEFT, "Thumbstick Left" },
|
||||
{ DC_AXIS_RIGHT, "Thumbstick Right" },
|
||||
|
||||
{ DC_AXIS2_UP, "R.Thumbstick Up" },
|
||||
{ DC_AXIS2_DOWN, "R.Thumbstick Down" },
|
||||
{ DC_AXIS2_LEFT, "R.Thumbstick Left" },
|
||||
{ DC_AXIS2_RIGHT, "R.Thumbstick Right" },
|
||||
|
||||
{ EMU_BTN_NONE, "Buttons" },
|
||||
{ DC_BTN_A, "Button 1" },
|
||||
{ DC_BTN_B, "Button 2" },
|
||||
{ DC_BTN_C, "Button 3" },
|
||||
{ DC_BTN_X, "Button 4" },
|
||||
{ DC_BTN_Y, "Button 5" },
|
||||
{ DC_BTN_Z, "Button 6" },
|
||||
{ DC_DPAD2_LEFT, "Button 7" },
|
||||
{ DC_DPAD2_RIGHT, "Button 8" },
|
||||
// { DC_DPAD2_RIGHT, "Button 9" }, // TODO
|
||||
|
||||
{ EMU_BTN_NONE, "Triggers" },
|
||||
{ DC_AXIS_LT, "Left Trigger" },
|
||||
{ DC_AXIS_RT, "Right Trigger" },
|
||||
|
||||
{ EMU_BTN_NONE, "System Buttons" },
|
||||
{ DC_BTN_START, "Start" },
|
||||
{ DC_BTN_RELOAD, "Reload" },
|
||||
{ DC_BTN_D, "Coin" },
|
||||
{ DC_DPAD2_UP, "Service" },
|
||||
{ DC_DPAD2_DOWN, "Test" },
|
||||
|
||||
{ EMU_BTN_NONE, "Emulator" },
|
||||
{ EMU_BTN_MENU, "Menu" },
|
||||
{ EMU_BTN_ESCAPE, "Exit" },
|
||||
{ EMU_BTN_FFORWARD, "Fast-forward" },
|
||||
|
||||
{ EMU_BTN_NONE, nullptr }
|
||||
};
|
||||
const DreamcastKey axis_keys[] = {
|
||||
DC_AXIS_X, DC_AXIS_Y, DC_AXIS_LT, DC_AXIS_RT, DC_AXIS_X2, DC_AXIS_Y2, EMU_AXIS_DPAD1_X, EMU_AXIS_DPAD1_Y,
|
||||
EMU_AXIS_DPAD2_X, EMU_AXIS_DPAD2_Y, EMU_AXIS_BTN_START, EMU_AXIS_BTN_A, EMU_AXIS_BTN_B, EMU_AXIS_BTN_X, EMU_AXIS_BTN_Y,
|
||||
EMU_AXIS_BTN_C, EMU_AXIS_BTN_D, EMU_AXIS_BTN_Z, EMU_AXIS_DPAD2_UP, EMU_AXIS_DPAD2_DOWN, EMU_AXIS_DPAD2_LEFT, EMU_AXIS_DPAD2_RIGHT
|
||||
};
|
||||
const char *axis_names[] = {
|
||||
"Left Stick X", "Left Stick Y", "Left Trigger", "Right Trigger", "Right Stick X", "Right Stick Y", "DPad X", "DPad Y",
|
||||
"Right DPad X", "Right DPad Y", "Start", "A", "B", "X", "Y",
|
||||
"C", "D", "Z", "N/A", "N/A", "N/A", "N/A"
|
||||
};
|
||||
const char *arcade_axis_names[] = {
|
||||
"Left Stick X", "Left Stick Y", "Left Trigger", "Right Trigger", "Right Stick X", "Right Stick Y", "DPad X", "DPad Y",
|
||||
"Right DPad X", "Right DPad Y", "Start", "Button 1", "Button 2", "Button 3", "Button 4",
|
||||
"Service", "Coin", "Test", "Button 5", "Button 6", "Button 7", "Button 8"
|
||||
};
|
||||
static_assert(ARRAY_SIZE(button_keys) == ARRAY_SIZE(button_names), "invalid size");
|
||||
static_assert(ARRAY_SIZE(button_keys) == ARRAY_SIZE(arcade_button_names), "invalid size");
|
||||
static_assert(ARRAY_SIZE(axis_keys) == ARRAY_SIZE(axis_names), "invalid size");
|
||||
static_assert(ARRAY_SIZE(axis_keys) == ARRAY_SIZE(arcade_axis_names), "invalid size");
|
||||
|
||||
static MapleDeviceType maple_expansion_device_type_from_index(int idx)
|
||||
{
|
||||
|
@ -689,20 +750,66 @@ static MapleDeviceType maple_expansion_device_type_from_index(int idx)
|
|||
|
||||
static std::shared_ptr<GamepadDevice> mapped_device;
|
||||
static u32 mapped_code;
|
||||
static bool analogAxis;
|
||||
static bool positiveDirection;
|
||||
static double map_start_time;
|
||||
static bool arcade_button_mode;
|
||||
static u32 gamepad_port;
|
||||
|
||||
static void detect_input_popup(int index, bool analog)
|
||||
static void unmapControl(const std::shared_ptr<InputMapping>& mapping, u32 gamepad_port, DreamcastKey key)
|
||||
{
|
||||
mapping->clear_button(gamepad_port, key);
|
||||
mapping->clear_axis(gamepad_port, key);
|
||||
}
|
||||
|
||||
static DreamcastKey getOppositeDirectionKey(DreamcastKey key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case DC_DPAD_UP:
|
||||
return DC_DPAD_DOWN;
|
||||
case DC_DPAD_DOWN:
|
||||
return DC_DPAD_UP;
|
||||
case DC_DPAD_LEFT:
|
||||
return DC_DPAD_RIGHT;
|
||||
case DC_DPAD_RIGHT:
|
||||
return DC_DPAD_LEFT;
|
||||
case DC_DPAD2_UP:
|
||||
return DC_DPAD2_DOWN;
|
||||
case DC_DPAD2_DOWN:
|
||||
return DC_DPAD2_UP;
|
||||
case DC_DPAD2_LEFT:
|
||||
return DC_DPAD2_RIGHT;
|
||||
case DC_DPAD2_RIGHT:
|
||||
return DC_DPAD2_LEFT;
|
||||
case DC_AXIS_UP:
|
||||
return DC_AXIS_DOWN;
|
||||
case DC_AXIS_DOWN:
|
||||
return DC_AXIS_UP;
|
||||
case DC_AXIS_LEFT:
|
||||
return DC_AXIS_RIGHT;
|
||||
case DC_AXIS_RIGHT:
|
||||
return DC_AXIS_LEFT;
|
||||
case DC_AXIS2_UP:
|
||||
return DC_AXIS2_DOWN;
|
||||
case DC_AXIS2_DOWN:
|
||||
return DC_AXIS2_UP;
|
||||
case DC_AXIS2_LEFT:
|
||||
return DC_AXIS2_RIGHT;
|
||||
case DC_AXIS2_RIGHT:
|
||||
return DC_AXIS2_LEFT;
|
||||
default:
|
||||
return EMU_BTN_NONE;
|
||||
}
|
||||
}
|
||||
static void detect_input_popup(const Mapping *mapping)
|
||||
{
|
||||
ImVec2 padding = ImVec2(20 * scaling, 20 * scaling);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, padding);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, padding);
|
||||
if (ImGui::BeginPopupModal(analog ? "Map Axis" : "Map Button", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove))
|
||||
if (ImGui::BeginPopupModal("Map Control", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove))
|
||||
{
|
||||
ImGui::Text("Waiting for %s '%s'...", analog ? "axis" : "button",
|
||||
analog ? arcade_button_mode ? arcade_axis_names[index] : axis_names[index]
|
||||
: arcade_button_mode ? arcade_button_names[index] : button_names[index]);
|
||||
ImGui::Text("Waiting for control '%s'...", mapping->name);
|
||||
double now = os_GetSeconds();
|
||||
ImGui::Text("Time out in %d s", (int)(5 - (now - map_start_time)));
|
||||
if (mapped_code != (u32)-1)
|
||||
|
@ -710,17 +817,21 @@ static void detect_input_popup(int index, bool analog)
|
|||
std::shared_ptr<InputMapping> input_mapping = mapped_device->get_input_mapping();
|
||||
if (input_mapping != NULL)
|
||||
{
|
||||
if (analog)
|
||||
unmapControl(input_mapping, gamepad_port, mapping->key);
|
||||
if (analogAxis)
|
||||
{
|
||||
u32 previous_mapping = input_mapping->get_axis_code(gamepad_port, axis_keys[index]);
|
||||
bool inverted = false;
|
||||
if (previous_mapping != (u32)-1)
|
||||
inverted = input_mapping->get_axis_inverted(gamepad_port, previous_mapping);
|
||||
// FIXME Allow inverted to be set
|
||||
input_mapping->set_axis(gamepad_port, axis_keys[index], mapped_code, inverted);
|
||||
input_mapping->set_axis(gamepad_port, mapping->key, mapped_code, positiveDirection);
|
||||
DreamcastKey opposite = getOppositeDirectionKey(mapping->key);
|
||||
// Map the axis opposite direction to the corresponding opposite dc button or axis,
|
||||
// but only if the opposite direction axis isn't used and the dc button or axis isn't mapped.
|
||||
if (opposite != EMU_BTN_NONE
|
||||
&& input_mapping->get_axis_id(gamepad_port, mapped_code, !positiveDirection) == EMU_BTN_NONE
|
||||
&& input_mapping->get_axis_code(gamepad_port, opposite).first == (u32)-1
|
||||
&& input_mapping->get_button_code(gamepad_port, opposite) == (u32)-1)
|
||||
input_mapping->set_axis(gamepad_port, opposite, mapped_code, !positiveDirection);
|
||||
}
|
||||
else
|
||||
input_mapping->set_button(gamepad_port, button_keys[index], mapped_code);
|
||||
input_mapping->set_button(gamepad_port, mapping->key, mapped_code);
|
||||
}
|
||||
mapped_device = NULL;
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
@ -735,6 +846,32 @@ static void detect_input_popup(int index, bool analog)
|
|||
ImGui::PopStyleVar(2);
|
||||
}
|
||||
|
||||
static void displayLabelOrCode(const char *label, u32 code, const char *suffix = "")
|
||||
{
|
||||
if (label != nullptr)
|
||||
ImGui::Text("%s%s", label, suffix);
|
||||
else
|
||||
ImGui::Text("[%d]%s", code, suffix);
|
||||
}
|
||||
|
||||
static void displayMappedControl(const std::shared_ptr<GamepadDevice>& gamepad, DreamcastKey key)
|
||||
{
|
||||
std::shared_ptr<InputMapping> input_mapping = gamepad->get_input_mapping();
|
||||
u32 code = input_mapping->get_button_code(gamepad_port, key);
|
||||
if (code != (u32)-1)
|
||||
{
|
||||
displayLabelOrCode(gamepad->get_button_name(code), code);
|
||||
return;
|
||||
}
|
||||
std::pair<u32, bool> pair = input_mapping->get_axis_code(gamepad_port, key);
|
||||
code = pair.first;
|
||||
if (code != (u32)-1)
|
||||
{
|
||||
displayLabelOrCode(gamepad->get_axis_name(code), code, pair.second ? "+" : "-");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void controller_mapping_popup(const std::shared_ptr<GamepadDevice>& gamepad)
|
||||
{
|
||||
fullScreenWindow(true);
|
||||
|
@ -742,7 +879,7 @@ static void controller_mapping_popup(const std::shared_ptr<GamepadDevice>& gamep
|
|||
if (ImGui::BeginPopupModal("Controller Mapping", NULL, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove))
|
||||
{
|
||||
const ImGuiStyle& style = ImGui::GetStyle();
|
||||
const float width = (ImGui::GetIO().DisplaySize.x - insetLeft - insetRight - style.ItemSpacing.x) / 2 - style.WindowBorderSize - style.WindowPadding.x;
|
||||
const float width = ImGui::GetIO().DisplaySize.x - insetLeft - insetRight - (style.WindowBorderSize + style.WindowPadding.x) * 2;
|
||||
const float col_width = (width - style.GrabMinSize - style.ItemSpacing.x
|
||||
- (ImGui::CalcTextSize("Map").x + style.FramePadding.x * 2.0f + style.ItemSpacing.x)
|
||||
- (ImGui::CalcTextSize("Unmap").x + style.FramePadding.x * 2.0f + style.ItemSpacing.x)) / 2;
|
||||
|
@ -774,35 +911,76 @@ static void controller_mapping_popup(const std::shared_ptr<GamepadDevice>& gamep
|
|||
}
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize("Dreamcast Controls").x
|
||||
- ImGui::GetStyle().FramePadding.x * 3.0f - ImGui::GetStyle().ItemSpacing.x * 3.0f);
|
||||
float comboWidth = ImGui::CalcTextSize("Dreamcast Controls").x + ImGui::GetStyle().ItemSpacing.x * 3.0f + ImGui::GetFontSize();
|
||||
ImGui::SameLine(0, ImGui::GetContentRegionAvail().x - comboWidth - ImGui::GetStyle().ItemSpacing.x - 100 * scaling * 2);
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
|
||||
if (ImGui::Button("Reset...", ImVec2(100 * scaling, 30 * scaling)))
|
||||
ImGui::OpenPopup("Confirm Reset");
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20 * scaling, 20 * scaling));
|
||||
if (ImGui::BeginPopupModal("Confirm Reset", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove))
|
||||
{
|
||||
ImGui::Text("Are you sure you want to reset the mappings to default?");
|
||||
static bool hitbox;
|
||||
if (arcade_button_mode)
|
||||
{
|
||||
ImGui::Text("Controller Type:");
|
||||
if (ImGui::RadioButton("Gamepad", !hitbox))
|
||||
hitbox = false;
|
||||
ImGui::SameLine();
|
||||
if (ImGui::RadioButton("Arcade / Hit Box", hitbox))
|
||||
hitbox = true;
|
||||
}
|
||||
ImGui::NewLine();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(20 * scaling, ImGui::GetStyle().ItemSpacing.y));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10 * scaling, 10 * scaling));
|
||||
if (ImGui::Button("Yes"))
|
||||
{
|
||||
gamepad->resetMappingToDefault(arcade_button_mode, !hitbox);
|
||||
gamepad->save_mapping(map_system);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("No"))
|
||||
ImGui::CloseCurrentPopup();
|
||||
ImGui::PopStyleVar(2);;
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
ImGui::PopStyleVar(1);;
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
const char* items[] = { "Dreamcast Controls", "Arcade Controls" };
|
||||
static int item_current_map_idx = 0;
|
||||
static int last_item_current_map_idx = 2;
|
||||
|
||||
// Here our selection data is an index.
|
||||
|
||||
ImGui::PushItemWidth(ImGui::CalcTextSize("Dreamcast Controls").x + ImGui::GetStyle().ItemSpacing.x * 2.0f * 3);
|
||||
|
||||
ImGui::Combo("", &item_current_map_idx, items, IM_ARRAYSIZE(items));
|
||||
|
||||
ImGui::PushItemWidth(comboWidth);
|
||||
// Make the combo height the same as the Done and Reset buttons
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(ImGui::GetStyle().FramePadding.x, (30 * scaling - ImGui::GetFontSize()) / 2));
|
||||
ImGui::Combo("##arcadeMode", &item_current_map_idx, items, IM_ARRAYSIZE(items));
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::PopItemWidth();
|
||||
if (item_current_map_idx != last_item_current_map_idx)
|
||||
{
|
||||
gamepad->save_mapping(map_system);
|
||||
}
|
||||
|
||||
const Mapping *systemMapping = dcButtons;
|
||||
if (item_current_map_idx == 0)
|
||||
{
|
||||
arcade_button_mode = false;
|
||||
map_system = DC_PLATFORM_DREAMCAST;
|
||||
systemMapping = dcButtons;
|
||||
}
|
||||
else if (item_current_map_idx == 1)
|
||||
{
|
||||
arcade_button_mode = true;
|
||||
map_system = DC_PLATFORM_NAOMI;
|
||||
systemMapping = arcadeButtons;
|
||||
}
|
||||
|
||||
if (item_current_map_idx != last_item_current_map_idx)
|
||||
|
@ -814,55 +992,55 @@ static void controller_mapping_popup(const std::shared_ptr<GamepadDevice>& gamep
|
|||
}
|
||||
|
||||
char key_id[32];
|
||||
ImGui::BeginGroup();
|
||||
ImGui::Text(" Buttons ");
|
||||
|
||||
ImGui::BeginChildFrame(ImGui::GetID("buttons"), ImVec2(width, 0), ImGuiWindowFlags_None);
|
||||
ImGui::Columns(3, "bindings", false);
|
||||
ImGui::SetColumnWidth(0, col_width);
|
||||
ImGui::SetColumnWidth(1, col_width);
|
||||
ImGui::BeginChildFrame(ImGui::GetID("buttons"), ImVec2(0, 0), ImGuiWindowFlags_None);
|
||||
|
||||
gamepad->find_mapping(map_system);
|
||||
for (u32 j = 0; j < ARRAY_SIZE(button_keys); j++)
|
||||
for (; systemMapping->name != nullptr; systemMapping++)
|
||||
{
|
||||
sprintf(key_id, "key_id%d", j);
|
||||
if (systemMapping->key == EMU_BTN_NONE)
|
||||
{
|
||||
ImGui::Columns(1, nullptr, false);
|
||||
header(systemMapping->name);
|
||||
ImGui::Columns(3, "bindings", false);
|
||||
ImGui::SetColumnWidth(0, col_width);
|
||||
ImGui::SetColumnWidth(1, col_width);
|
||||
continue;
|
||||
}
|
||||
sprintf(key_id, "key_id%d", systemMapping->key);
|
||||
ImGui::PushID(key_id);
|
||||
|
||||
const char *btn_name = arcade_button_mode ? arcade_button_names[j] : button_names[j];
|
||||
const char *game_btn_name = GetCurrentGameButtonName(button_keys[j]);
|
||||
if (game_btn_name != nullptr)
|
||||
ImGui::Text("%s - %s", btn_name, game_btn_name);
|
||||
const char *game_btn_name = GetCurrentGameButtonName(systemMapping->key);
|
||||
if (game_btn_name == nullptr)
|
||||
game_btn_name = GetCurrentGameAxisName(systemMapping->key);
|
||||
if (game_btn_name != nullptr && game_btn_name[0] != '\0')
|
||||
ImGui::Text("%s - %s", systemMapping->name, game_btn_name);
|
||||
else
|
||||
ImGui::Text("%s", btn_name);
|
||||
ImGui::Text("%s", systemMapping->name);
|
||||
|
||||
ImGui::NextColumn();
|
||||
u32 code = input_mapping->get_button_code(gamepad_port, button_keys[j]);
|
||||
if (code != (u32)-1)
|
||||
{
|
||||
const char *label = gamepad->get_button_name(code);
|
||||
if (label != nullptr)
|
||||
ImGui::Text("%s", label);
|
||||
else
|
||||
ImGui::Text("[%d]", code);
|
||||
}
|
||||
displayMappedControl(gamepad, systemMapping->key);
|
||||
|
||||
ImGui::NextColumn();
|
||||
if (ImGui::Button("Map"))
|
||||
{
|
||||
map_start_time = os_GetSeconds();
|
||||
ImGui::OpenPopup("Map Button");
|
||||
ImGui::OpenPopup("Map Control");
|
||||
mapped_device = gamepad;
|
||||
mapped_code = -1;
|
||||
gamepad->detect_btn_input([](u32 code)
|
||||
gamepad->detectButtonOrAxisInput([](u32 code, bool analog, bool positive)
|
||||
{
|
||||
mapped_code = code;
|
||||
analogAxis = analog;
|
||||
positiveDirection = positive;
|
||||
});
|
||||
}
|
||||
detect_input_popup(j, false);
|
||||
detect_input_popup(systemMapping);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Unmap"))
|
||||
{
|
||||
input_mapping = gamepad->get_input_mapping();
|
||||
input_mapping->clear_button(gamepad_port, button_keys[j], j);
|
||||
unmapControl(input_mapping, gamepad_port, systemMapping->key);
|
||||
}
|
||||
ImGui::NextColumn();
|
||||
ImGui::PopID();
|
||||
|
@ -872,66 +1050,6 @@ static void controller_mapping_popup(const std::shared_ptr<GamepadDevice>& gamep
|
|||
windowDragScroll();
|
||||
|
||||
ImGui::EndChildFrame();
|
||||
ImGui::EndGroup();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::BeginGroup();
|
||||
ImGui::Text(" Analog Axes ");
|
||||
ImGui::BeginChildFrame(ImGui::GetID("analog"), ImVec2(width, 0), ImGuiWindowFlags_None);
|
||||
ImGui::Columns(3, "anabindings", false);
|
||||
ImGui::SetColumnWidth(0, col_width);
|
||||
ImGui::SetColumnWidth(1, col_width);
|
||||
|
||||
for (u32 j = 0; j < ARRAY_SIZE(axis_keys); j++)
|
||||
{
|
||||
sprintf(key_id, "axis_id%d", j);
|
||||
ImGui::PushID(key_id);
|
||||
|
||||
const char *axis_name = arcade_button_mode ? arcade_axis_names[j] : axis_names[j];
|
||||
const char *game_axis_name = GetCurrentGameAxisName(axis_keys[j]);
|
||||
if (game_axis_name != nullptr)
|
||||
ImGui::Text("%s - %s", axis_name, game_axis_name);
|
||||
else
|
||||
ImGui::Text("%s", axis_name);
|
||||
|
||||
ImGui::NextColumn();
|
||||
u32 code = input_mapping->get_axis_code(gamepad_port, axis_keys[j]);
|
||||
if (code != (u32)-1)
|
||||
{
|
||||
const char *label = gamepad->get_axis_name(code);
|
||||
if (label != nullptr)
|
||||
ImGui::Text("%s", label);
|
||||
else
|
||||
ImGui::Text("[%d]", code);
|
||||
}
|
||||
ImGui::NextColumn();
|
||||
if (ImGui::Button("Map"))
|
||||
{
|
||||
map_start_time = os_GetSeconds();
|
||||
ImGui::OpenPopup("Map Axis");
|
||||
mapped_device = gamepad;
|
||||
mapped_code = -1;
|
||||
gamepad->detect_axis_input([](u32 code)
|
||||
{
|
||||
mapped_code = code;
|
||||
});
|
||||
}
|
||||
detect_input_popup(j, true);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Unmap"))
|
||||
{
|
||||
input_mapping = gamepad->get_input_mapping();
|
||||
input_mapping->clear_axis(gamepad_port, axis_keys[j], j);
|
||||
}
|
||||
ImGui::NextColumn();
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::Columns(1, nullptr, false);
|
||||
scrollWhenDraggingOnVoid();
|
||||
windowDragScroll();
|
||||
ImGui::EndChildFrame();
|
||||
ImGui::EndGroup();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
|
@ -1019,13 +1137,6 @@ static void contentpath_warning_popup()
|
|||
}
|
||||
}
|
||||
|
||||
inline static void header(const char *title)
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.f, 0.5f)); // Left
|
||||
ImGui::ButtonEx(title, ImVec2(-1, 0), ImGuiButtonFlags_Disabled);
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
static void gui_display_settings()
|
||||
{
|
||||
static bool maple_devices_changed;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "sdl.h"
|
||||
#include "rend/gui.h"
|
||||
|
||||
template<bool Arcade = false, bool Gamepad = false>
|
||||
class DefaultInputMapping : public InputMapping
|
||||
{
|
||||
public:
|
||||
|
@ -15,23 +16,26 @@ public:
|
|||
set_button(DC_BTN_X, 3);
|
||||
set_button(DC_BTN_START, 9);
|
||||
|
||||
set_axis(DC_AXIS_X, 0, false);
|
||||
set_axis(DC_AXIS_Y, 1, false);
|
||||
set_axis(DC_AXIS_X2, 2, false);
|
||||
set_axis(DC_AXIS_Y2, 3, false);
|
||||
set_axis(0, DC_AXIS_LEFT, 0, false);
|
||||
set_axis(0, DC_AXIS_RIGHT, 0, true);
|
||||
set_axis(0, DC_AXIS_UP, 1, false);
|
||||
set_axis(0, DC_AXIS_DOWN, 1, true);
|
||||
set_axis(0, DC_AXIS2_LEFT, 2, false);
|
||||
set_axis(0, DC_AXIS2_RIGHT, 2, true);
|
||||
set_axis(0, DC_AXIS2_UP, 3, false);
|
||||
set_axis(0, DC_AXIS2_DOWN, 3, true);
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
DefaultInputMapping(int joystick_idx) : DefaultInputMapping()
|
||||
DefaultInputMapping(SDL_GameController *sdlController) : DefaultInputMapping()
|
||||
{
|
||||
if (SDL_IsGameController(joystick_idx))
|
||||
if (sdlController != nullptr)
|
||||
{
|
||||
SDL_GameController *sdl_controller = SDL_GameControllerOpen(joystick_idx);
|
||||
name = SDL_GameControllerName(sdl_controller);
|
||||
name = SDL_GameControllerName(sdlController);
|
||||
INFO_LOG(INPUT, "SDL: using SDL game controller mappings for '%s'", name.c_str());
|
||||
|
||||
auto map_button = [&](SDL_GameControllerButton sdl_btn, DreamcastKey dc_btn) {
|
||||
SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton(sdl_controller, sdl_btn);
|
||||
SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton(sdlController, sdl_btn);
|
||||
if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON)
|
||||
set_button(dc_btn, bind.value.button);
|
||||
else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT)
|
||||
|
@ -57,21 +61,8 @@ public:
|
|||
set_button(dc_btn, ((bind.value.hat.hat + 1) << 8) | dir);
|
||||
}
|
||||
};
|
||||
map_button(SDL_CONTROLLER_BUTTON_A, DC_BTN_A);
|
||||
map_button(SDL_CONTROLLER_BUTTON_B, DC_BTN_B);
|
||||
map_button(SDL_CONTROLLER_BUTTON_X, DC_BTN_X);
|
||||
map_button(SDL_CONTROLLER_BUTTON_Y, DC_BTN_Y);
|
||||
map_button(SDL_CONTROLLER_BUTTON_START, DC_BTN_START);
|
||||
map_button(SDL_CONTROLLER_BUTTON_DPAD_UP, DC_DPAD_UP);
|
||||
map_button(SDL_CONTROLLER_BUTTON_DPAD_DOWN, DC_DPAD_DOWN);
|
||||
map_button(SDL_CONTROLLER_BUTTON_DPAD_LEFT, DC_DPAD_LEFT);
|
||||
map_button(SDL_CONTROLLER_BUTTON_DPAD_RIGHT, DC_DPAD_RIGHT);
|
||||
map_button(SDL_CONTROLLER_BUTTON_BACK, EMU_BTN_MENU);
|
||||
map_button(SDL_CONTROLLER_BUTTON_LEFTSHOULDER, DC_BTN_C); // service
|
||||
map_button(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, DC_BTN_Z); // test
|
||||
|
||||
auto map_axis = [&](SDL_GameControllerAxis sdl_axis, DreamcastKey dc_axis) {
|
||||
SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(sdl_controller, sdl_axis);
|
||||
auto map_axis = [&](SDL_GameControllerAxis sdl_axis, DreamcastKey dc_axis, bool positive) {
|
||||
SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(sdlController, sdl_axis);
|
||||
if (bind.bindType != SDL_CONTROLLER_BINDTYPE_AXIS)
|
||||
return false;
|
||||
|
||||
|
@ -79,19 +70,76 @@ public:
|
|||
const char *s = SDL_GameControllerGetStringForAxis(sdl_axis);
|
||||
if (s != nullptr && s[strlen(s) - 1] == '~')
|
||||
invert_axis = true;
|
||||
set_axis(dc_axis, bind.value.axis, invert_axis);
|
||||
set_axis(dc_axis, bind.value.axis, invert_axis ^ positive);
|
||||
return true;
|
||||
};
|
||||
map_axis(SDL_CONTROLLER_AXIS_LEFTX, DC_AXIS_X);
|
||||
map_axis(SDL_CONTROLLER_AXIS_LEFTY, DC_AXIS_Y);
|
||||
map_axis(SDL_CONTROLLER_AXIS_RIGHTX, DC_AXIS_X2);
|
||||
map_axis(SDL_CONTROLLER_AXIS_RIGHTY, DC_AXIS_Y2);
|
||||
if (!map_axis(SDL_CONTROLLER_AXIS_TRIGGERLEFT, DC_AXIS_LT))
|
||||
map_button(SDL_CONTROLLER_BUTTON_LEFTSHOULDER, EMU_BTN_TRIGGER_LEFT);
|
||||
if (!map_axis(SDL_CONTROLLER_AXIS_TRIGGERRIGHT, DC_AXIS_RT))
|
||||
map_button(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, EMU_BTN_TRIGGER_RIGHT);
|
||||
|
||||
SDL_GameControllerClose(sdl_controller);
|
||||
if (Arcade)
|
||||
{
|
||||
if (Gamepad)
|
||||
{
|
||||
// 1 2 3 4 5 6
|
||||
// A B X Y L R
|
||||
map_button(SDL_CONTROLLER_BUTTON_A, DC_BTN_A);
|
||||
map_button(SDL_CONTROLLER_BUTTON_B, DC_BTN_B);
|
||||
map_button(SDL_CONTROLLER_BUTTON_X, DC_BTN_C);
|
||||
map_button(SDL_CONTROLLER_BUTTON_Y, DC_BTN_X);
|
||||
|
||||
if (!map_axis(SDL_CONTROLLER_AXIS_TRIGGERLEFT, DC_AXIS_LT, true))
|
||||
map_button(SDL_CONTROLLER_BUTTON_LEFTSHOULDER, DC_AXIS_LT);
|
||||
else
|
||||
map_button(SDL_CONTROLLER_BUTTON_LEFTSHOULDER, DC_BTN_Y);
|
||||
if (!map_axis(SDL_CONTROLLER_AXIS_TRIGGERRIGHT, DC_AXIS_RT, true))
|
||||
map_button(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, DC_AXIS_RT);
|
||||
else
|
||||
map_button(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, DC_BTN_Z);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hitbox
|
||||
// 1 2 3 4 5 6 7 8
|
||||
// X Y R1 A B R2 L1 L2
|
||||
map_button(SDL_CONTROLLER_BUTTON_X, DC_BTN_A);
|
||||
map_button(SDL_CONTROLLER_BUTTON_Y, DC_BTN_B);
|
||||
map_button(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, DC_BTN_C); // R1
|
||||
map_button(SDL_CONTROLLER_BUTTON_A, DC_BTN_X);
|
||||
map_button(SDL_CONTROLLER_BUTTON_B, DC_BTN_Y);
|
||||
map_axis(SDL_CONTROLLER_AXIS_TRIGGERRIGHT, DC_BTN_Z, true); // R2
|
||||
map_button(SDL_CONTROLLER_BUTTON_LEFTSHOULDER, DC_DPAD2_LEFT); // L1 (Naomi button 7)
|
||||
map_axis(SDL_CONTROLLER_AXIS_TRIGGERLEFT, DC_DPAD2_RIGHT, true); // L2 (Naomi button 8)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
map_button(SDL_CONTROLLER_BUTTON_A, DC_BTN_A);
|
||||
map_button(SDL_CONTROLLER_BUTTON_B, DC_BTN_B);
|
||||
map_button(SDL_CONTROLLER_BUTTON_X, DC_BTN_X);
|
||||
map_button(SDL_CONTROLLER_BUTTON_Y, DC_BTN_Y);
|
||||
if (!map_axis(SDL_CONTROLLER_AXIS_TRIGGERLEFT, DC_AXIS_LT, true))
|
||||
map_button(SDL_CONTROLLER_BUTTON_LEFTSHOULDER, DC_AXIS_LT);
|
||||
else
|
||||
map_button(SDL_CONTROLLER_BUTTON_LEFTSHOULDER, DC_BTN_Z);
|
||||
if (!map_axis(SDL_CONTROLLER_AXIS_TRIGGERRIGHT, DC_AXIS_RT, true))
|
||||
map_button(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, DC_AXIS_RT);
|
||||
else
|
||||
map_button(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, DC_BTN_C);
|
||||
}
|
||||
map_button(SDL_CONTROLLER_BUTTON_START, DC_BTN_START);
|
||||
map_button(SDL_CONTROLLER_BUTTON_DPAD_UP, DC_DPAD_UP);
|
||||
map_button(SDL_CONTROLLER_BUTTON_DPAD_DOWN, DC_DPAD_DOWN);
|
||||
map_button(SDL_CONTROLLER_BUTTON_DPAD_LEFT, DC_DPAD_LEFT);
|
||||
map_button(SDL_CONTROLLER_BUTTON_DPAD_RIGHT, DC_DPAD_RIGHT);
|
||||
map_button(SDL_CONTROLLER_BUTTON_BACK, EMU_BTN_MENU);
|
||||
|
||||
map_axis(SDL_CONTROLLER_AXIS_LEFTX, DC_AXIS_LEFT, false);
|
||||
map_axis(SDL_CONTROLLER_AXIS_LEFTX, DC_AXIS_RIGHT, true);
|
||||
map_axis(SDL_CONTROLLER_AXIS_LEFTY, DC_AXIS_UP, false);
|
||||
map_axis(SDL_CONTROLLER_AXIS_LEFTY, DC_AXIS_DOWN, true);
|
||||
map_axis(SDL_CONTROLLER_AXIS_RIGHTX, DC_AXIS2_LEFT, false);
|
||||
map_axis(SDL_CONTROLLER_AXIS_RIGHTX, DC_AXIS2_RIGHT, true);
|
||||
map_axis(SDL_CONTROLLER_AXIS_RIGHTY, DC_AXIS2_UP, false);
|
||||
map_axis(SDL_CONTROLLER_AXIS_RIGHTY, DC_AXIS2_DOWN, true);
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
else
|
||||
|
@ -110,8 +158,19 @@ public:
|
|||
_unique_id = "sdl_joystick_" + std::to_string(sdl_joystick_instance);
|
||||
INFO_LOG(INPUT, "SDL: Opened joystick %d on port %d: '%s' unique_id=%s", sdl_joystick_instance, maple_port, _name.c_str(), _unique_id.c_str());
|
||||
|
||||
if (SDL_IsGameController(joystick_idx))
|
||||
{
|
||||
sdl_controller = SDL_GameControllerOpen(joystick_idx);
|
||||
SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(sdl_controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT);
|
||||
if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS)
|
||||
leftTrigger = bind.value.axis;
|
||||
bind = SDL_GameControllerGetBindForAxis(sdl_controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
|
||||
if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS)
|
||||
rightTrigger = bind.value.axis;
|
||||
}
|
||||
|
||||
if (!find_mapping())
|
||||
input_mapper = std::make_shared<DefaultInputMapping>(joystick_idx);
|
||||
input_mapper = std::make_shared<DefaultInputMapping<>>(sdl_controller);
|
||||
else
|
||||
INFO_LOG(INPUT, "using custom mapping '%s'", input_mapper->name.c_str());
|
||||
sdl_haptic = SDL_HapticOpenFromJoystick(sdl_joystick);
|
||||
|
@ -122,6 +181,13 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
bool gamepad_axis_input(u32 code, int value) override
|
||||
{
|
||||
if (code == leftTrigger || code == rightTrigger)
|
||||
value = (u16)(value + 32768) / 2;
|
||||
return GamepadDevice::gamepad_axis_input(code, value);
|
||||
}
|
||||
|
||||
void rumble(float power, float inclination, u32 duration_ms) override
|
||||
{
|
||||
if (sdl_haptic != NULL)
|
||||
|
@ -149,13 +215,126 @@ public:
|
|||
void close()
|
||||
{
|
||||
INFO_LOG(INPUT, "SDL: Joystick '%s' on port %d disconnected", _name.c_str(), maple_port());
|
||||
if (sdl_haptic != NULL)
|
||||
if (sdl_haptic != nullptr)
|
||||
SDL_HapticClose(sdl_haptic);
|
||||
if (sdl_controller != nullptr)
|
||||
SDL_GameControllerClose(sdl_controller);
|
||||
SDL_JoystickClose(sdl_joystick);
|
||||
GamepadDevice::Unregister(sdl_gamepads[sdl_joystick_instance]);
|
||||
sdl_gamepads.erase(sdl_joystick_instance);
|
||||
}
|
||||
|
||||
const char *get_button_name(u32 code) override
|
||||
{
|
||||
static struct
|
||||
{
|
||||
const char *sdlButton;
|
||||
const char *label;
|
||||
} buttonsTable[] =
|
||||
{
|
||||
{ "a", "A" },
|
||||
{ "b", "B" },
|
||||
{ "x", "X" },
|
||||
{ "y", "Y" },
|
||||
{ "back", "Back" },
|
||||
{ "guide", "Guide" },
|
||||
{ "start", "Start" },
|
||||
{ "leftstick", "L3" },
|
||||
{ "rightstick", "R3" },
|
||||
{ "leftshoulder", "L1" },
|
||||
{ "rightshoulder", "R1" },
|
||||
{ "dpup", "DPad Up" },
|
||||
{ "dpdown", "DPad Down" },
|
||||
{ "dpleft", "DPad Left" },
|
||||
{ "dpright", "DPad Right" },
|
||||
{ "misc1", "Misc" },
|
||||
{ "paddle1", "Paddle 1" },
|
||||
{ "paddle2", "Paddle 2" },
|
||||
{ "paddle3", "Paddle 3" },
|
||||
{ "paddle4", "Paddle 4" },
|
||||
{ "touchpad", "Touchpad" },
|
||||
};
|
||||
for (SDL_GameControllerButton button = SDL_CONTROLLER_BUTTON_A; button < SDL_CONTROLLER_BUTTON_MAX; button = (SDL_GameControllerButton)(button + 1))
|
||||
{
|
||||
SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton(sdl_controller, button);
|
||||
if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON && bind.value.button == (int)code)
|
||||
{
|
||||
const char *sdlButton = SDL_GameControllerGetStringForButton(button);
|
||||
if (sdlButton == nullptr)
|
||||
return nullptr;
|
||||
for (const auto& button : buttonsTable)
|
||||
if (!strcmp(button.sdlButton, sdlButton))
|
||||
return button.label;
|
||||
return sdlButton;
|
||||
}
|
||||
if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT && (code >> 8) - 1 == (u32)bind.value.hat.hat)
|
||||
{
|
||||
switch (bind.value.hat.hat_mask)
|
||||
{
|
||||
case SDL_HAT_UP:
|
||||
return "DPad Up";
|
||||
case SDL_HAT_DOWN:
|
||||
return "DPad Down";
|
||||
case SDL_HAT_LEFT:
|
||||
return "DPad Left";
|
||||
case SDL_HAT_RIGHT:
|
||||
return "DPad Right";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *get_axis_name(u32 code) override
|
||||
{
|
||||
static struct
|
||||
{
|
||||
const char *sdlAxis;
|
||||
const char *label;
|
||||
} axesTable[] =
|
||||
{
|
||||
{ "leftx", "Left Stick X" },
|
||||
{ "lefty", "Left Stick Y" },
|
||||
{ "rightx", "Right Stick X" },
|
||||
{ "righty", "Right Stick Y" },
|
||||
{ "lefttrigger", "L2" },
|
||||
{ "righttrigger", "R2" },
|
||||
};
|
||||
|
||||
for (SDL_GameControllerAxis axis = SDL_CONTROLLER_AXIS_LEFTX; axis < SDL_CONTROLLER_AXIS_MAX; axis = (SDL_GameControllerAxis)(axis + 1))
|
||||
{
|
||||
SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(sdl_controller, axis);
|
||||
if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS && bind.value.axis == (int)code)
|
||||
{
|
||||
const char *sdlAxis = SDL_GameControllerGetStringForAxis(axis);
|
||||
if (sdlAxis == nullptr)
|
||||
return nullptr;
|
||||
for (const auto& axis : axesTable)
|
||||
if (!strcmp(axis.sdlAxis, sdlAxis))
|
||||
return axis.label;
|
||||
return sdlAxis;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void resetMappingToDefault(bool arcade, bool gamepad) override
|
||||
{
|
||||
NOTICE_LOG(INPUT, "Resetting SDL gamepad to default: %d %d", arcade, gamepad);
|
||||
if (arcade)
|
||||
{
|
||||
if (gamepad)
|
||||
input_mapper = std::make_shared<DefaultInputMapping<true, true>>(sdl_controller);
|
||||
else
|
||||
input_mapper = std::make_shared<DefaultInputMapping<true, false>>(sdl_controller);
|
||||
}
|
||||
else
|
||||
input_mapper = std::make_shared<DefaultInputMapping<false, false>>(sdl_controller);
|
||||
}
|
||||
|
||||
|
||||
static void AddSDLGamepad(std::shared_ptr<SDLGamepad> gamepad)
|
||||
{
|
||||
sdl_gamepads[gamepad->sdl_joystick_instance] = gamepad;
|
||||
|
@ -175,19 +354,15 @@ public:
|
|||
pair.second->update_rumble();
|
||||
}
|
||||
|
||||
protected:
|
||||
void load_axis_min_max(u32 axis) override
|
||||
{
|
||||
axis_min_values[axis] = -32768;
|
||||
axis_ranges[axis] = 65535;
|
||||
}
|
||||
|
||||
private:
|
||||
SDL_Joystick* sdl_joystick;
|
||||
SDL_JoystickID sdl_joystick_instance;
|
||||
SDL_Haptic *sdl_haptic;
|
||||
float vib_inclination = 0;
|
||||
double vib_stop_time = 0;
|
||||
SDL_GameController *sdl_controller;
|
||||
u32 leftTrigger = ~0;
|
||||
u32 rightTrigger = ~0;
|
||||
static std::map<SDL_JoystickID, std::shared_ptr<SDLGamepad>> sdl_gamepads;
|
||||
};
|
||||
|
||||
|
|
|
@ -19,15 +19,19 @@ public:
|
|||
set_button(DC_DPAD_LEFT, XINPUT_GAMEPAD_DPAD_LEFT);
|
||||
set_button(DC_DPAD_RIGHT, XINPUT_GAMEPAD_DPAD_RIGHT);
|
||||
set_button(DC_BTN_START, XINPUT_GAMEPAD_START);
|
||||
set_button(EMU_BTN_TRIGGER_LEFT, XINPUT_GAMEPAD_LEFT_SHOULDER);
|
||||
set_button(EMU_BTN_TRIGGER_RIGHT, XINPUT_GAMEPAD_RIGHT_SHOULDER);
|
||||
set_button(DC_AXIS_LT, XINPUT_GAMEPAD_LEFT_SHOULDER);
|
||||
set_button(DC_AXIS_RT, XINPUT_GAMEPAD_RIGHT_SHOULDER);
|
||||
set_button(EMU_BTN_MENU, XINPUT_GAMEPAD_BACK);
|
||||
set_axis(DC_AXIS_LT, 0, false);
|
||||
set_axis(DC_AXIS_RT, 1, false);
|
||||
set_axis(DC_AXIS_X, 2, false);
|
||||
set_axis(DC_AXIS_Y, 3, true);
|
||||
set_axis(DC_AXIS_X2, 4, false);
|
||||
set_axis(DC_AXIS_Y2, 5, true);
|
||||
set_axis(DC_AXIS_LEFT, 2, false);
|
||||
set_axis(DC_AXIS_RIGHT, 2, true);
|
||||
set_axis(DC_AXIS_UP, 3, true);
|
||||
set_axis(DC_AXIS_DOWN, 3, false);
|
||||
set_axis(DC_AXIS2_LEFT, 4, false);
|
||||
set_axis(DC_AXIS2_RIGHT, 4, true);
|
||||
set_axis(DC_AXIS2_UP, 5, true);
|
||||
set_axis(DC_AXIS2_DOWN, 5, false);
|
||||
dirty = false;
|
||||
}
|
||||
};
|
||||
|
@ -67,12 +71,12 @@ public:
|
|||
|
||||
if (state.Gamepad.bLeftTrigger != last_left_trigger)
|
||||
{
|
||||
gamepad_axis_input(0, state.Gamepad.bLeftTrigger);
|
||||
gamepad_axis_input(0, (state.Gamepad.bLeftTrigger << 7) + (state.Gamepad.bLeftTrigger >> 1));
|
||||
last_left_trigger = state.Gamepad.bLeftTrigger;
|
||||
}
|
||||
if (state.Gamepad.bRightTrigger != last_right_trigger)
|
||||
{
|
||||
gamepad_axis_input(1, state.Gamepad.bRightTrigger);
|
||||
gamepad_axis_input(1, (state.Gamepad.bRightTrigger << 7) + (state.Gamepad.bRightTrigger >> 1));
|
||||
last_right_trigger = state.Gamepad.bRightTrigger;
|
||||
}
|
||||
if (state.Gamepad.sThumbLX != last_left_thumb_x)
|
||||
|
|
|
@ -64,32 +64,13 @@ enum {
|
|||
KEYCODE_BUTTON_MODE = 110,
|
||||
};
|
||||
|
||||
class AndroidGamepadDevice;
|
||||
|
||||
template<bool Arcade = false, bool Gamepad = false>
|
||||
class DefaultInputMapping : public InputMapping
|
||||
{
|
||||
public:
|
||||
DefaultInputMapping()
|
||||
{
|
||||
name = "Default";
|
||||
set_button(DC_BTN_Y, KEYCODE_BUTTON_Y);
|
||||
set_button(DC_BTN_B, KEYCODE_BUTTON_B);
|
||||
set_button(DC_BTN_A, KEYCODE_BUTTON_A);
|
||||
set_button(DC_BTN_X, KEYCODE_BUTTON_X);
|
||||
set_button(DC_BTN_START, KEYCODE_BUTTON_START);
|
||||
set_button(DC_DPAD_UP, KEYCODE_DPAD_UP);
|
||||
set_button(DC_DPAD_DOWN, KEYCODE_DPAD_DOWN);
|
||||
set_button(DC_DPAD_LEFT, KEYCODE_DPAD_LEFT);
|
||||
set_button(DC_DPAD_RIGHT, KEYCODE_DPAD_RIGHT);
|
||||
set_button(EMU_BTN_MENU, KEYCODE_BACK);
|
||||
|
||||
set_axis(DC_AXIS_X, AXIS_X, false);
|
||||
set_axis(DC_AXIS_Y, AXIS_Y, false);
|
||||
set_axis(DC_AXIS_LT, AXIS_LTRIGGER, false);
|
||||
set_axis(DC_AXIS_RT, AXIS_RTRIGGER, false);
|
||||
set_axis(DC_AXIS_X2, AXIS_Z, false);
|
||||
set_axis(DC_AXIS_Y2, AXIS_RZ, false);
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
DefaultInputMapping(const AndroidGamepadDevice& gamepad);
|
||||
};
|
||||
|
||||
class ShieldRemoteInputMapping : public InputMapping
|
||||
|
@ -123,14 +104,6 @@ public:
|
|||
if (id == VIRTUAL_GAMEPAD_ID)
|
||||
{
|
||||
input_mapper = std::make_shared<IdentityInputMapping>();
|
||||
axis_min_values[DC_AXIS_X] = -128;
|
||||
axis_ranges[DC_AXIS_X] = 255;
|
||||
axis_min_values[DC_AXIS_Y] = -128;
|
||||
axis_ranges[DC_AXIS_Y] = 255;
|
||||
axis_min_values[DC_AXIS_LT] = 0;
|
||||
axis_ranges[DC_AXIS_LT] = 255;
|
||||
axis_min_values[DC_AXIS_RT] = 0;
|
||||
axis_ranges[DC_AXIS_RT] = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -146,34 +119,8 @@ public:
|
|||
virtual std::shared_ptr<InputMapping> getDefaultMapping() override {
|
||||
if (_name == "SHIELD Remote")
|
||||
return std::make_shared<ShieldRemoteInputMapping>();
|
||||
std::shared_ptr<InputMapping> mapping = std::make_shared<DefaultInputMapping>();
|
||||
auto ltAxis = std::find(halfAxes.begin(), halfAxes.end(), AXIS_LTRIGGER);
|
||||
auto rtAxis = std::find(halfAxes.begin(), halfAxes.end(), AXIS_RTRIGGER);
|
||||
if (ltAxis != halfAxes.end() && rtAxis != halfAxes.end())
|
||||
{
|
||||
mapping->set_axis(DC_AXIS_LT, *ltAxis, false);
|
||||
mapping->set_axis(DC_AXIS_RT, *rtAxis, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ltAxis = std::find(halfAxes.begin(), halfAxes.end(), AXIS_BRAKE);
|
||||
rtAxis = std::find(halfAxes.begin(), halfAxes.end(), AXIS_GAS);
|
||||
if (ltAxis != halfAxes.end() && rtAxis != halfAxes.end())
|
||||
{
|
||||
mapping->set_axis(DC_AXIS_LT, *ltAxis, false);
|
||||
mapping->set_axis(DC_AXIS_RT, *rtAxis, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Xbox controller?
|
||||
mapping->set_axis(DC_AXIS_LT, AXIS_Z, false);
|
||||
mapping->set_axis(DC_AXIS_RT, AXIS_RZ, false);
|
||||
mapping->set_axis(DC_AXIS_X2, AXIS_RX, false);
|
||||
mapping->set_axis(DC_AXIS_Y2, AXIS_RY, false);
|
||||
|
||||
}
|
||||
}
|
||||
return mapping;
|
||||
return std::make_shared<DefaultInputMapping<>>(*this);
|
||||
}
|
||||
|
||||
virtual const char *get_button_name(u32 code) override
|
||||
|
@ -304,20 +251,26 @@ public:
|
|||
// RT + A -> D (coin)
|
||||
kcode &= ~DC_BTN_D;
|
||||
if ((kcode & DC_BTN_B) == 0)
|
||||
// RT + B -> C (service)
|
||||
kcode &= ~DC_BTN_C;
|
||||
// RT + B -> Service
|
||||
kcode &= ~DC_DPAD2_UP;
|
||||
if ((kcode & DC_BTN_X) == 0)
|
||||
// RT + X -> Z (test)
|
||||
kcode &= ~DC_BTN_Z;
|
||||
// RT + X -> Test
|
||||
kcode &= ~DC_DPAD2_DOWN;
|
||||
}
|
||||
u32 changes = kcode ^ previous_kcode;
|
||||
for (int i = 0; i < 32; i++)
|
||||
if (changes & (1 << i))
|
||||
gamepad_btn_input(1 << i, (kcode & (1 << i)) == 0);
|
||||
gamepad_axis_input(DC_AXIS_X, joyx);
|
||||
gamepad_axis_input(DC_AXIS_Y, joyy);
|
||||
gamepad_axis_input(DC_AXIS_LT, lt);
|
||||
gamepad_axis_input(DC_AXIS_RT, rt);
|
||||
if (joyx >= 0)
|
||||
gamepad_axis_input(DC_AXIS_RIGHT, joyx | (joyx << 8));
|
||||
else
|
||||
gamepad_axis_input(DC_AXIS_LEFT, -joyx | (-joyx << 8));
|
||||
if (joyy >= 0)
|
||||
gamepad_axis_input(DC_AXIS_DOWN, joyy | (joyy << 8));
|
||||
else
|
||||
gamepad_axis_input(DC_AXIS_UP, -joyy | (-joyy << 8));
|
||||
gamepad_axis_input(DC_AXIS_LT, lt == 0 ? 0 : 0x7fff);
|
||||
gamepad_axis_input(DC_AXIS_RT, rt == 0 ? 0 : 0x7fff);
|
||||
previous_kcode = kcode;
|
||||
}
|
||||
|
||||
|
@ -328,24 +281,25 @@ public:
|
|||
}
|
||||
bool is_virtual_gamepad() override { return android_id == VIRTUAL_GAMEPAD_ID; }
|
||||
|
||||
static const int VIRTUAL_GAMEPAD_ID = 0x12345678; // must match the Java definition
|
||||
bool hasHalfAxis(int axis) const { return std::find(halfAxes.begin(), halfAxes.end(), axis) != halfAxes.end(); }
|
||||
bool hasFullAxis(int axis) const { return std::find(fullAxes.begin(), fullAxes.end(), axis) != fullAxes.end(); }
|
||||
|
||||
protected:
|
||||
virtual void load_axis_min_max(u32 axis) override
|
||||
void resetMappingToDefault(bool arcade, bool gamepad) override
|
||||
{
|
||||
auto axisIt = std::find(halfAxes.begin(), halfAxes.end(), axis);
|
||||
if (axisIt != halfAxes.end())
|
||||
NOTICE_LOG(INPUT, "Resetting Android gamepad to default: %d %d", arcade, gamepad);
|
||||
if (arcade)
|
||||
{
|
||||
axis_min_values[axis] = 0;
|
||||
axis_ranges[axis] = 32767;
|
||||
if (gamepad)
|
||||
input_mapper = std::make_shared<DefaultInputMapping<true, true>>(*this);
|
||||
else
|
||||
input_mapper = std::make_shared<DefaultInputMapping<true, false>>(*this);
|
||||
}
|
||||
else
|
||||
{
|
||||
axis_min_values[axis] = -32768;
|
||||
axis_ranges[axis] = 65535;
|
||||
}
|
||||
input_mapper = std::make_shared<DefaultInputMapping<false, false>>(*this);
|
||||
}
|
||||
|
||||
static const int VIRTUAL_GAMEPAD_ID = 0x12345678; // must match the Java definition
|
||||
|
||||
private:
|
||||
int android_id;
|
||||
static std::map<int, std::shared_ptr<AndroidGamepadDevice>> android_gamepads;
|
||||
|
@ -356,6 +310,126 @@ private:
|
|||
|
||||
std::map<int, std::shared_ptr<AndroidGamepadDevice>> AndroidGamepadDevice::android_gamepads;
|
||||
|
||||
template<bool Arcade, bool Gamepad>
|
||||
inline DefaultInputMapping<Arcade, Gamepad>::DefaultInputMapping(const AndroidGamepadDevice& gamepad)
|
||||
{
|
||||
name = Arcade ? Gamepad ? "Arcade Gamepad" : "Arcade Hitbox" : "Default";
|
||||
int ltAxis = AXIS_LTRIGGER;
|
||||
int rtAxis = AXIS_RTRIGGER;
|
||||
int rightStickX = AXIS_Z;
|
||||
int rightStickY = AXIS_RZ;
|
||||
if (!gamepad.hasHalfAxis(AXIS_LTRIGGER) || !gamepad.hasHalfAxis(AXIS_RTRIGGER))
|
||||
{
|
||||
if (gamepad.hasHalfAxis(AXIS_BRAKE) && gamepad.hasHalfAxis(AXIS_GAS))
|
||||
{
|
||||
ltAxis = AXIS_BRAKE;
|
||||
rtAxis = AXIS_GAS;
|
||||
}
|
||||
else if (gamepad.hasHalfAxis(AXIS_Z) && gamepad.hasHalfAxis(AXIS_RZ))
|
||||
{
|
||||
ltAxis = AXIS_Z;
|
||||
rtAxis = AXIS_RZ;
|
||||
rightStickX = AXIS_RX;
|
||||
rightStickY = AXIS_RY;
|
||||
}
|
||||
else
|
||||
{
|
||||
ltAxis = -1;
|
||||
rtAxis = -1;
|
||||
}
|
||||
}
|
||||
if (!gamepad.hasFullAxis(rightStickX) || !gamepad.hasFullAxis(rightStickY))
|
||||
{
|
||||
rightStickX = -1;
|
||||
rightStickY = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
set_axis(DC_AXIS2_LEFT, rightStickX, false);
|
||||
set_axis(DC_AXIS2_RIGHT, rightStickX, true);
|
||||
set_axis(DC_AXIS2_UP, rightStickY, false);
|
||||
set_axis(DC_AXIS2_DOWN, rightStickY, true);
|
||||
}
|
||||
|
||||
if (Arcade)
|
||||
{
|
||||
if (Gamepad)
|
||||
{
|
||||
// 1 2 3 4 5 6
|
||||
// A B X Y L R
|
||||
set_button(DC_BTN_A, KEYCODE_BUTTON_A);
|
||||
set_button(DC_BTN_B, KEYCODE_BUTTON_B);
|
||||
set_button(DC_BTN_C, KEYCODE_BUTTON_X);
|
||||
set_button(DC_BTN_X, KEYCODE_BUTTON_Y);
|
||||
if (ltAxis != -1)
|
||||
{
|
||||
set_axis(DC_AXIS_LT, ltAxis, true);
|
||||
set_button(DC_BTN_Y, KEYCODE_BUTTON_L1);
|
||||
}
|
||||
else
|
||||
set_button(DC_AXIS_LT, KEYCODE_BUTTON_L1);
|
||||
if (rtAxis != -1)
|
||||
{
|
||||
set_axis(DC_AXIS_RT, rtAxis, true);
|
||||
set_button(DC_BTN_Z, KEYCODE_BUTTON_R1);
|
||||
}
|
||||
else
|
||||
set_button(DC_AXIS_RT, KEYCODE_BUTTON_R1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hitbox
|
||||
// 1 2 3 4 5 6 7 8
|
||||
// X Y R1 A B R2 L1 L2
|
||||
set_button(DC_BTN_A, KEYCODE_BUTTON_X);
|
||||
set_button(DC_BTN_B, KEYCODE_BUTTON_Y);
|
||||
set_button(DC_BTN_C, KEYCODE_BUTTON_R1);
|
||||
set_button(DC_BTN_X, KEYCODE_BUTTON_A);
|
||||
set_button(DC_BTN_Y, KEYCODE_BUTTON_B);
|
||||
if (rtAxis != -1)
|
||||
set_axis(DC_BTN_Z, rtAxis, true);
|
||||
set_button(DC_DPAD2_LEFT, KEYCODE_BUTTON_L1); // L1 (Naomi button 7)
|
||||
if (ltAxis != -1)
|
||||
set_axis(DC_DPAD2_RIGHT, ltAxis, true); // L2 (Naomi button 8)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
set_button(DC_BTN_A, KEYCODE_BUTTON_A);
|
||||
set_button(DC_BTN_B, KEYCODE_BUTTON_B);
|
||||
set_button(DC_BTN_X, KEYCODE_BUTTON_X);
|
||||
set_button(DC_BTN_Y, KEYCODE_BUTTON_Y);
|
||||
if (rtAxis != -1)
|
||||
{
|
||||
set_axis(DC_AXIS_RT, rtAxis, true);
|
||||
set_button(DC_BTN_C, KEYCODE_BUTTON_R1);
|
||||
}
|
||||
else
|
||||
set_button(DC_AXIS_RT, KEYCODE_BUTTON_R1);
|
||||
if (ltAxis != -1)
|
||||
{
|
||||
set_axis(DC_AXIS_LT, ltAxis, true);
|
||||
set_button(DC_BTN_Z, KEYCODE_BUTTON_L1);
|
||||
}
|
||||
else
|
||||
set_button(DC_AXIS_LT, KEYCODE_BUTTON_L1);
|
||||
|
||||
}
|
||||
set_button(DC_BTN_START, KEYCODE_BUTTON_START);
|
||||
set_button(DC_DPAD_UP, KEYCODE_DPAD_UP);
|
||||
set_button(DC_DPAD_DOWN, KEYCODE_DPAD_DOWN);
|
||||
set_button(DC_DPAD_LEFT, KEYCODE_DPAD_LEFT);
|
||||
set_button(DC_DPAD_RIGHT, KEYCODE_DPAD_RIGHT);
|
||||
set_button(EMU_BTN_MENU, KEYCODE_BUTTON_SELECT);
|
||||
|
||||
set_axis(DC_AXIS_LEFT, AXIS_X, false);
|
||||
set_axis(DC_AXIS_RIGHT, AXIS_X, true);
|
||||
set_axis(DC_AXIS_UP, AXIS_Y, false);
|
||||
set_axis(DC_AXIS_DOWN, AXIS_Y, true);
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
class AndroidMouse : public SystemMouse
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -116,8 +116,8 @@
|
|||
pos.y = std::max<CGFloat>(std::min<CGFloat>(25.0, pos.y), -25.0);
|
||||
self.joyXConstraint.constant = pos.x;
|
||||
self.joyYConstraint.constant = pos.y;
|
||||
virtualGamepad->gamepad_axis_input(IOS_AXIS_LX, (s8)std::round(pos.x * 127.0 / 25.0));
|
||||
virtualGamepad->gamepad_axis_input(IOS_AXIS_LY, (s8)std::round(pos.y * 127.0 / 25.0));
|
||||
virtualGamepad->gamepad_axis_input(IOS_AXIS_LX, (s8)std::round(pos.x * 32767.0 / 25.0));
|
||||
virtualGamepad->gamepad_axis_input(IOS_AXIS_LY, (s8)std::round(pos.y * 32767.0 / 25.0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,16 +64,54 @@ enum IOSAxis {
|
|||
|
||||
static NSString *GCInputXboxShareButton = @"Button Share";
|
||||
|
||||
template<bool Arcade = false, bool Gamepad = false>
|
||||
class DefaultIOSMapping : public InputMapping
|
||||
{
|
||||
public:
|
||||
DefaultIOSMapping()
|
||||
{
|
||||
name = "Default";
|
||||
set_button(DC_BTN_A, IOS_BTN_A);
|
||||
set_button(DC_BTN_B, IOS_BTN_B);
|
||||
set_button(DC_BTN_X, IOS_BTN_X);
|
||||
set_button(DC_BTN_Y, IOS_BTN_Y);
|
||||
name = Arcade ? Gamepad ? "Arcade Gamepad" : "Arcade Hitbox" : "Default";
|
||||
if (Arcade)
|
||||
{
|
||||
if (Gamepad)
|
||||
{
|
||||
// 1 2 3 4 5 6
|
||||
// A B X Y L R
|
||||
set_button(DC_BTN_A, IOS_BTN_A);
|
||||
set_button(DC_BTN_B, IOS_BTN_B);
|
||||
set_button(DC_BTN_C, IOS_BTN_X);
|
||||
set_button(DC_BTN_X, IOS_BTN_Y);
|
||||
set_button(DC_BTN_Y, IOS_BTN_L1);
|
||||
set_button(DC_BTN_Z, IOS_BTN_R1);
|
||||
set_axis(DC_AXIS_LT, IOS_AXIS_L2, true);
|
||||
set_axis(DC_AXIS_RT, IOS_AXIS_R2, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hitbox
|
||||
// 1 2 3 4 5 6 7 8
|
||||
// X Y R1 A B R2 L1 L2
|
||||
set_button(DC_BTN_A, IOS_BTN_X);
|
||||
set_button(DC_BTN_B, IOS_BTN_Y);
|
||||
set_button(DC_BTN_C, IOS_BTN_R1);
|
||||
set_button(DC_BTN_X, IOS_BTN_A);
|
||||
set_button(DC_BTN_Y, IOS_BTN_B);
|
||||
set_axis(DC_BTN_Z, IOS_AXIS_R2, true);
|
||||
set_button(DC_DPAD2_LEFT, KEYCODE_BUTTON_L1); // L1 (Naomi button 7)
|
||||
set_axis(DC_DPAD2_RIGHT, IOS_AXIS_L2, true); // L2 (Naomi button 8)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
set_button(DC_BTN_A, IOS_BTN_A);
|
||||
set_button(DC_BTN_B, IOS_BTN_B);
|
||||
set_button(DC_BTN_X, IOS_BTN_X);
|
||||
set_button(DC_BTN_Y, IOS_BTN_Y);
|
||||
set_axis(DC_AXIS_RT, IOS_AXIS_R2, true);
|
||||
set_button(DC_BTN_C, KEYCODE_BUTTON_R1);
|
||||
set_axis(DC_AXIS_LT, IOS_AXIS_L2, true);
|
||||
set_button(DC_BTN_Z, KEYCODE_BUTTON_L1);
|
||||
}
|
||||
set_button(DC_DPAD_UP, IOS_BTN_UP);
|
||||
set_button(DC_DPAD_DOWN, IOS_BTN_DOWN);
|
||||
set_button(DC_DPAD_LEFT, IOS_BTN_LEFT);
|
||||
|
@ -81,12 +119,14 @@ public:
|
|||
set_button(DC_BTN_START, IOS_BTN_MENU);
|
||||
set_button(EMU_BTN_MENU, IOS_BTN_OPTIONS);
|
||||
|
||||
set_axis(DC_AXIS_X, IOS_AXIS_LX, false);
|
||||
set_axis(DC_AXIS_Y, IOS_AXIS_LY, false);
|
||||
set_axis(DC_AXIS_X2, IOS_AXIS_RX, false);
|
||||
set_axis(DC_AXIS_Y2, IOS_AXIS_RY, false);
|
||||
set_axis(DC_AXIS_LT, IOS_AXIS_L2, false);
|
||||
set_axis(DC_AXIS_RT, IOS_AXIS_R2, false);
|
||||
set_axis(DC_AXIS_LEFT, IOS_AXIS_LX, false);
|
||||
set_axis(DC_AXIS_RIGHT, IOS_AXIS_LX, true);
|
||||
set_axis(DC_AXIS_UP, IOS_AXIS_LY, false);
|
||||
set_axis(DC_AXIS_DOWN, IOS_AXIS_LY, true);
|
||||
set_axis(DC_AXIS2_LEFT, IOS_AXIS_RX, false);
|
||||
set_axis(DC_AXIS2_RIGHT, IOS_AXIS_RX, true);
|
||||
set_axis(DC_AXIS2_UP, IOS_AXIS_RY, false);
|
||||
set_axis(DC_AXIS2_DOWN, IOS_AXIS_RY, true);
|
||||
dirty = false;
|
||||
}
|
||||
};
|
||||
|
@ -166,23 +206,23 @@ public:
|
|||
|
||||
[gcController.extendedGamepad.rightTrigger setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
||||
gamepad_btn_input(IOS_BTN_R2, pressed);
|
||||
gamepad_axis_input(IOS_AXIS_R2, (int)std::roundf(255.f * value));
|
||||
gamepad_axis_input(IOS_AXIS_R2, (int)std::roundf(32767.f * value));
|
||||
}];
|
||||
[gcController.extendedGamepad.leftTrigger setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
||||
gamepad_btn_input(IOS_BTN_L2, pressed);
|
||||
gamepad_axis_input(IOS_AXIS_L2, (int)std::roundf(255.f * value));
|
||||
gamepad_axis_input(IOS_AXIS_L2, (int)std::roundf(32767.f * value));
|
||||
}];
|
||||
[gcController.extendedGamepad.leftThumbstick.xAxis setValueChangedHandler:^(GCControllerAxisInput *axis, float value) {
|
||||
gamepad_axis_input(IOS_AXIS_LX, (int)std::roundf(127.f * value));
|
||||
gamepad_axis_input(IOS_AXIS_LX, (int)std::roundf(32767.f * value));
|
||||
}];
|
||||
[gcController.extendedGamepad.leftThumbstick.yAxis setValueChangedHandler:^(GCControllerAxisInput *axis, float value) {
|
||||
gamepad_axis_input(IOS_AXIS_LY, (int)std::roundf(-127.f * value));
|
||||
gamepad_axis_input(IOS_AXIS_LY, (int)std::roundf(-32767.f * value));
|
||||
}];
|
||||
[gcController.extendedGamepad.rightThumbstick.xAxis setValueChangedHandler:^(GCControllerAxisInput *axis, float value) {
|
||||
gamepad_axis_input(IOS_AXIS_RX, (int)std::roundf(127.f * value));
|
||||
gamepad_axis_input(IOS_AXIS_RX, (int)std::roundf(32767.f * value));
|
||||
}];
|
||||
[gcController.extendedGamepad.rightThumbstick.yAxis setValueChangedHandler:^(GCControllerAxisInput *axis, float value) {
|
||||
gamepad_axis_input(IOS_AXIS_RY, (int)std::roundf(-127.f * value));
|
||||
gamepad_axis_input(IOS_AXIS_RY, (int)std::roundf(-32767.f * value));
|
||||
}];
|
||||
|
||||
}
|
||||
|
@ -369,7 +409,7 @@ public:
|
|||
}
|
||||
|
||||
std::shared_ptr<InputMapping> getDefaultMapping() override {
|
||||
return std::make_shared<DefaultIOSMapping>();
|
||||
return std::make_shared<DefaultIOSMapping<>>();
|
||||
}
|
||||
|
||||
void rumble(float power, float inclination, u32 duration_ms) override
|
||||
|
@ -394,6 +434,20 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void resetMappingToDefault(bool arcade, bool gamepad) override
|
||||
{
|
||||
NOTICE_LOG(INPUT, "Resetting iOS gamepad to default: %d %d", arcade, gamepad);
|
||||
if (arcade)
|
||||
{
|
||||
if (gamepad)
|
||||
input_mapper = std::make_shared<DefaultIOSMapping<true, true>>();
|
||||
else
|
||||
input_mapper = std::make_shared<DefaultIOSMapping<true, false>>();
|
||||
}
|
||||
else
|
||||
input_mapper = std::make_shared<DefaultIOSMapping<false, false>>();
|
||||
}
|
||||
|
||||
static void addController(GCController *controller)
|
||||
{
|
||||
if (controllers.count(controller) > 0)
|
||||
|
@ -418,21 +472,6 @@ public:
|
|||
return !controllers.empty();
|
||||
}
|
||||
|
||||
protected:
|
||||
void load_axis_min_max(u32 axis) override
|
||||
{
|
||||
if (axis == IOS_AXIS_L1 || axis == IOS_AXIS_R1 || axis == IOS_AXIS_L2 || axis == IOS_AXIS_R2)
|
||||
{
|
||||
axis_min_values[axis] = 0;
|
||||
axis_ranges[axis] = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
axis_min_values[axis] = -127;
|
||||
axis_ranges[axis] = 254;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
GCController * __weak gcController = nullptr;
|
||||
CHHapticEngine *hapticEngine = nullptr;
|
||||
|
@ -452,7 +491,7 @@ public:
|
|||
bool is_virtual_gamepad() override { return true; }
|
||||
|
||||
std::shared_ptr<InputMapping> getDefaultMapping() override {
|
||||
return std::make_shared<DefaultIOSMapping>();
|
||||
return std::make_shared<DefaultIOSMapping<>>();
|
||||
}
|
||||
|
||||
bool gamepad_btn_input(u32 code, bool pressed) override
|
||||
|
@ -464,12 +503,12 @@ public:
|
|||
switch (code)
|
||||
{
|
||||
case IOS_BTN_L2:
|
||||
gamepad_axis_input(IOS_AXIS_L2, pressed ? 0xff : 0);
|
||||
gamepad_axis_input(IOS_AXIS_L2, pressed ? 0x7fff : 0);
|
||||
return true;
|
||||
case IOS_BTN_R2:
|
||||
if (!pressed && maple_port() >= 0 && maple_port() <= 3)
|
||||
kcode[maple_port()] |= DC_BTN_C | DC_BTN_D | DC_BTN_Z;
|
||||
gamepad_axis_input(IOS_AXIS_R2, pressed ? 0xff : 0);
|
||||
gamepad_axis_input(IOS_AXIS_R2, pressed ? 0x7fff : 0);
|
||||
return true;
|
||||
default:
|
||||
if ((buttonState & ((1 << IOS_BTN_UP) | (1 << IOS_BTN_DOWN))) == ((1 << IOS_BTN_UP) | (1 << IOS_BTN_DOWN))
|
||||
|
@ -493,12 +532,12 @@ public:
|
|||
keycode = pressed ? keycode & ~DC_BTN_D : keycode | DC_BTN_D;
|
||||
break;
|
||||
case IOS_BTN_B:
|
||||
// RT + B -> C (service)
|
||||
keycode = pressed ? keycode & ~DC_BTN_C : keycode | DC_BTN_C;
|
||||
// RT + B -> Service
|
||||
keycode = pressed ? keycode & ~DC_DPAD2_UP : keycode | DC_DPAD2_UP;
|
||||
break;
|
||||
case IOS_BTN_X:
|
||||
// RT + X -> Z (test)
|
||||
keycode = pressed ? keycode & ~DC_BTN_Z : keycode | DC_BTN_Z;
|
||||
// RT + X -> Test
|
||||
keycode = pressed ? keycode & ~DC_DPAD2_DOWN : keycode | DC_DPAD2_DOWN;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -508,20 +547,6 @@ public:
|
|||
return GamepadDevice::gamepad_btn_input(code, pressed);
|
||||
}
|
||||
}
|
||||
protected:
|
||||
void load_axis_min_max(u32 axis) override
|
||||
{
|
||||
if (axis == IOS_AXIS_L1 || axis == IOS_AXIS_R1 || axis == IOS_AXIS_L2 || axis == IOS_AXIS_R2)
|
||||
{
|
||||
axis_min_values[axis] = 0;
|
||||
axis_ranges[axis] = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
axis_min_values[axis] = -127;
|
||||
axis_ranges[axis] = 254;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
u32 buttonState = 0;
|
||||
|
|
Loading…
Reference in New Issue