Support for Maracas & Pop'n Music controllers, WIP for others (#1035)

Racing controller, fishing controller and Densha de Go controller

Co-authored-by: Ricardo <ric.ce.br@gmail.com>
Co-authored-by: Flyinghead <raphael.jean@gmail.com>
This commit is contained in:
Ricardo Mendonça Ferreira 2023-05-29 07:45:34 -03:00 committed by GitHub
parent f95c7212bf
commit 885714e883
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 661 additions and 74 deletions

6
.gitignore vendored
View File

@ -1,4 +1,5 @@
build/
artifact/
# macOS
.DS_Store
@ -6,8 +7,13 @@ shell/apple/emulator-ios/OpenMP/OpenMP.xcframework
# Visual Studio
.vs/
.vscode/
out/
# JetBrains IDES
.idea/
cmake-build-*/
# Dependencies from .gitmodules
core/deps/breakpad/
core/deps/glslang/

View File

@ -76,8 +76,14 @@ void MapleConfigMap::GetInput(PlainJoystickState* pjs)
pjs->kcode = inputState.kcode;
pjs->joy[PJAI_X1] = GetBtFromSgn(inputState.fullAxes[PJAI_X1]);
pjs->joy[PJAI_Y1] = GetBtFromSgn(inputState.fullAxes[PJAI_Y1]);
pjs->joy[PJAI_X2] = GetBtFromSgn(inputState.fullAxes[PJAI_X2]);
pjs->joy[PJAI_Y2] = GetBtFromSgn(inputState.fullAxes[PJAI_Y2]);
pjs->joy[PJAI_X3] = GetBtFromSgn(inputState.fullAxes[PJAI_X3]);
pjs->joy[PJAI_Y3] = GetBtFromSgn(inputState.fullAxes[PJAI_Y3]);
pjs->trigger[PJTI_R] = inputState.halfAxes[PJTI_R];
pjs->trigger[PJTI_L] = inputState.halfAxes[PJTI_L];
pjs->trigger[PJTI_L2] = inputState.halfAxes[PJTI_L2];
pjs->trigger[PJTI_R2] = inputState.halfAxes[PJTI_R2];
}
else if (settings.platform.isAtomiswave())
{
@ -290,27 +296,20 @@ static void createDreamcastDevices()
break;
case MDT_Keyboard:
mcfg_Create(MDT_Keyboard, bus, 5);
break;
case MDT_Mouse:
mcfg_Create(MDT_Mouse, bus, 5);
case MDT_MaracasController:
case MDT_FishingController:
case MDT_PopnMusicController:
case MDT_RacingController:
case MDT_DenshaDeGoController:
case MDT_Dreameye:
mcfg_Create(config::MapleMainDevices[bus], bus, 5);
break;
case MDT_LightGun:
mcfg_Create(MDT_LightGun, bus, 5);
if (config::MapleExpansionDevices[bus][0] != MDT_None)
mcfg_Create(config::MapleExpansionDevices[bus][0], bus, 0);
break;
case MDT_TwinStick:
mcfg_Create(MDT_TwinStick, bus, 5);
if (config::MapleExpansionDevices[bus][0] != MDT_None)
mcfg_Create(config::MapleExpansionDevices[bus][0], bus, 0);
break;
case MDT_AsciiStick:
mcfg_Create(MDT_AsciiStick, bus, 5);
mcfg_Create(config::MapleMainDevices[bus], bus, 5);
if (config::MapleExpansionDevices[bus][0] != MDT_None)
mcfg_Create(config::MapleExpansionDevices[bus][0], bus, 0);
break;

View File

@ -3,21 +3,25 @@
enum MapleDeviceType
{
MDT_SegaController,
MDT_SegaVMU,
MDT_Microphone,
MDT_PurupuruPack,
MDT_AsciiStick,
MDT_Keyboard,
MDT_Mouse,
MDT_LightGun,
MDT_TwinStick,
MDT_NaomiJamma,
MDT_None,
MDT_RFIDReaderWriter,
MDT_SegaController = 0,
MDT_SegaVMU = 1,
MDT_Microphone = 2,
MDT_PurupuruPack = 3,
MDT_AsciiStick = 4,
MDT_Keyboard = 5,
MDT_Mouse = 6,
MDT_LightGun = 7,
MDT_TwinStick = 8,
MDT_NaomiJamma = 9,
MDT_None = 10,
MDT_RFIDReaderWriter = 11,
MDT_MaracasController = 12,
MDT_FishingController = 13,
MDT_PopnMusicController = 14,
MDT_RacingController = 15,
MDT_DenshaDeGoController = 16,
MDT_Dreameye = 17,
MDT_Count
};
enum PlainJoystickAxisId
@ -26,24 +30,29 @@ enum PlainJoystickAxisId
PJAI_Y1 = 1,
PJAI_X2 = 2,
PJAI_Y2 = 3,
PJAI_Count = 4
PJAI_X3 = 4,
PJAI_Y3 = 5,
PJAI_Count = 6
};
enum PlainJoystickTriggerId
{
PJTI_L = 0,
PJTI_R = 1,
PJTI_Count = 2
PJTI_L2 = 2,
PJTI_R2 = 3,
PJTI_Count = 4
};
struct PlainJoystickState
{
PlainJoystickState()
{
joy[0]=joy[1]=joy[2]=joy[3]=0x80;
trigger[0]=trigger[1]=0;
u32 i;
for (i=0; i < PJAI_Count; i++)
joy[i] = 0x80;
for (i=0; i < PJTI_Count; i++)
trigger[i] = 0;
}
u32 kcode = ~0;
@ -81,8 +90,8 @@ struct MapleInputState
}
u32 kcode = ~0;
u8 halfAxes[PJTI_Count]; // LT, RT
int8_t fullAxes[PJAI_Count]; // Left X, Y, Right X, Y
u8 halfAxes[PJTI_Count]; // LT, RT, 2, 3
int8_t fullAxes[PJAI_Count]; // Left X, Y, Right X, Y, Other X, Other Y
u8 mouseButtons = ~0;
struct {
int x = -1;

View File

@ -11,16 +11,21 @@
#include <time.h>
const char* maple_sega_controller_name = "Dreamcast Controller";
const char* maple_sega_vmu_name = "Visual Memory";
const char* maple_sega_kbd_name = "Emulated Dreamcast Keyboard";
const char* maple_sega_mouse_name = "Emulated Dreamcast Mouse";
const char* maple_sega_dreameye_name_1 = "Dreamcast Camera Flash Devic";
const char* maple_sega_dreameye_name_2 = "Dreamcast Camera Flash LDevic";
const char* maple_sega_mic_name = "MicDevice for Dreameye";
const char* maple_sega_purupuru_name = "Puru Puru Pack";
const char* maple_sega_lightgun_name = "Dreamcast Gun";
const char* maple_sega_twinstick_name = "Twin Stick";
const char* maple_ascii_stick_name = "ASCII STICK";
const char* maple_sega_vmu_name = "Visual Memory";
const char* maple_sega_kbd_name = "Emulated Dreamcast Keyboard";
const char* maple_sega_mouse_name = "Emulated Dreamcast Mouse";
const char* maple_sega_dreameye_name_1 = "Dreamcast Camera Flash Device";
const char* maple_sega_dreameye_name_2 = "Dreamcast Camera Flash LDevice";
const char* maple_sega_mic_name = "MicDevice for Dreameye";
const char* maple_sega_purupuru_name = "Puru Puru Pack";
const char* maple_sega_lightgun_name = "Dreamcast Gun";
const char* maple_sega_twinstick_name = "Twin Stick";
const char* maple_ascii_stick_name = "ASCII STICK";
const char* maple_maracas_controller_name = "Maracas Controller";
const char* maple_fishing_controller_name = "Dreamcast Fishing Controller";
const char* maple_popnmusic_controller_name = "pop'n music controller";
const char* maple_racing_controller_name = "Racing Controller";
const char* maple_densha_controller_name = "TAITO 001 Controller";
const char* maple_sega_brand = "Produced By or Under License From SEGA ENTERPRISES,LTD.";
@ -104,6 +109,11 @@ struct maple_sega_controller: maple_base
return maple_sega_brand;
}
virtual u32 get_device_current(int get_max_current)
{
return get_max_current ? 0x01F4 : 0x01AE; // Max. 50 mA, standby: 43 mA
}
u32 dma(u32 cmd) override
{
//printf("maple_sega_controller::dma Called 0x%X;Command %d\n", bus_id, cmd);
@ -111,6 +121,8 @@ struct maple_sega_controller: maple_base
{
case MDC_DeviceRequest:
case MDC_AllStatusReq:
// Fixed Device Status
// (Device ID)
//caps
//4
w32(MFID_0_Input);
@ -121,23 +133,23 @@ struct maple_sega_controller: maple_base
w32(0);
w32(0);
//1 area code
//1 area code (Country specification)
w8(0xFF);
//1 direction
//1 direction (Connection method)
w8(0);
//30
//30 (Model name)
wstr(get_device_name(), 30);
//60
//60 (License)
wstr(get_device_brand(), 60);
//2
w16(0x01AE); // 43 mA
//2 (Standby current consumption)
w16(get_device_current(0));
//2
w16(0x01F4); // 50 mA
//2 (Maximum current consumption)
w16(get_device_current(1));
return cmd == MDC_DeviceRequest ? MDRS_DeviceStatus : MDRS_DeviceStatusAll;
@ -249,6 +261,10 @@ struct maple_sega_twinstick: maple_sega_controller
const char *get_device_name() override {
return maple_sega_twinstick_name;
}
u32 get_device_current(int get_max_current) override {
return get_max_current ? 0x012C : 0x00DC; // Max. 30 mA, standby: 22 mA
}
};
@ -284,14 +300,16 @@ struct maple_ascii_stick: maple_sega_controller
const char *get_device_name() override {
return maple_ascii_stick_name;
}
u32 get_device_current(int get_max_current) override {
return get_max_current ? 0x0172 : 0x010E; // Max. 37 mA, standby: 27 mA
}
};
/*
Sega Dreamcast Visual Memory Unit
This is pretty much done (?)
*/
u8 vmu_default[] = {
0x78,0x9c,0xed,0xd2,0x31,0x4e,0x02,0x61,0x10,0x06,0xd0,0x8f,0x04,0x28,0x4c,0x2c,
0x28,0x2d,0x0c,0xa5,0x57,0xe0,0x16,0x56,0x16,0x76,0x14,0x1e,0xc4,0x03,0x50,0x98,
@ -718,7 +736,6 @@ struct maple_sega_vmu: maple_base
}
};
struct maple_microphone: maple_base
{
u32 gain;
@ -896,7 +913,6 @@ struct maple_microphone: maple_base
}
};
struct maple_sega_purupuru : maple_base
{
u16 AST = 19, AST_ms = 5000;
@ -1327,6 +1343,391 @@ struct atomiswave_lightgun : maple_lightgun
}
};
struct maple_maracas_controller: maple_sega_controller
{
u32 get_capabilities() override {
// byte 0: 0 0 0 0 0 0 0 0
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
// byte 2: R2 L2 D2 U2 D X Y Z
// byte 3: R L D U St A B C
return 0x0f093c00; // 4 analog axes (2-5) A B C D Z Start
}
u32 transform_kcode(u32 kcode) override {
return kcode | 0xf6f0; // mask off DPad2, X, Y, DPad;
}
MapleDeviceType get_device_type() override {
return MDT_MaracasController;
}
u32 get_analog_axis(int index, const PlainJoystickState &pjs) override {
if (index < 2 || index > 5)
return 0;
return pjs.joy[index -2];
/* // This should be tested with real maracas to see if it is worth implementing or not
u8 maracas_saturation_reduction = 2;
s32 axis_val = (pjs.joy[index -2] - 0x80) / maracas_saturation_reduction + 0x80;
if (axis_val < 0) axis_val = 0;
else if (axis_val > 0xff) axis_val = 0xFF;
return axis_val; */
}
const char *get_device_name() override {
return maple_maracas_controller_name;
}
u32 get_device_current(int get_max_current) override {
return get_max_current ? 0x0546 : 0x044C; // Max. 130 mA, standby: 100 mA
}
};
struct maple_fishing_controller: maple_sega_controller
{
u32 get_capabilities() override {
// byte 0: 0 0 0 0 0 0 0 0
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
// byte 2: R2 L2 D2 U2 D X Y Z
// byte 3: R L D U St A B C
return 0x0fe063f00; // Ra,La,Da,Ua,A,B,X,Y,Start,A1,A2,A3,A4,A5,A6
}
u32 transform_kcode(u32 kcode) override {
mutualExclusion(kcode, DC_DPAD_UP | DC_DPAD_DOWN);
mutualExclusion(kcode, DC_DPAD_LEFT | DC_DPAD_RIGHT);
return kcode | 0xf901; // mask off DPad2, D, Z, C;
}
MapleDeviceType get_device_type() override {
return MDT_FishingController;
}
u32 get_analog_axis(int index, const PlainJoystickState &pjs) override {
// In the XYZ axes, acceleration sensor outputs 80 ± 8H (home position)
// in the static state (± 0G), F0h or greater for maximum force (+10G)
// in the positive direction and 11h or less
// for the maximum force (-10G) applied in the negative direction
// From the perspective of the player operating the controller:
// X: Right is positive, left is negative
// Y: Down is positive, up is negative
// Z: Forward is positive, backward is negative
if (index == 0)
return pjs.trigger[PJTI_R]; // A1: Reel handle output
else if (index == 1)
return pjs.joy[4]; // A2: acceleration sensor Z
else if (index >= 2 || index <= 5) // A3, A4 are also output as Ra, La, Ua, Da
return pjs.joy[index -2]; // A5, A6: acceleration sensors X and Y
return 0x80;
}
const char *get_device_name() override {
return maple_fishing_controller_name;
}
u32 get_device_current(int get_max_current) override {
return get_max_current ? 0x0960 : 0x0258; // Max. 240 mA, standby: 60 mA
}
u32 dma(u32 cmd) override {
//printf("maple_fishing_controller::dma Called 0x%X;Command %d\n", bus_id, cmd);
switch (cmd)
{
case MDC_DeviceRequest:
case MDC_AllStatusReq:
// Fixed Device Status
// (Device ID)
//caps
//4
w32(MFID_0_Input);
//struct data
//3*4
w32(get_capabilities());
w32(0);
w32(0);
//1 area code (Country specification)
w8(0xFF);
//1 direction (Connection method)
w8(0);
//30 (Model name)
wstr(get_device_name(), 30);
//60 (License)
wstr(get_device_brand(), 60);
//2 (Standby current consumption)
w16(get_device_current(0));
//2 (Maximum current consumption)
w16(get_device_current(1));
return cmd == MDC_DeviceRequest ? MDRS_DeviceStatus : MDRS_DeviceStatusAll;
//controller condition
case MDCF_GetCondition:
{
PlainJoystickState pjs;
config->GetInput(&pjs);
//INFO_LOG(MAPLE, "maple_fishing_controller: MDCF_GetCondition: r32(): %d", r32());
//caps
//4
w32(MFID_0_Input);
//state data
//2 key code
w16(transform_kcode(pjs.kcode));
//triggers
//1 R
w8(get_analog_axis(0, pjs));
//1 L
w8(get_analog_axis(1, pjs));
//joyx
//1
w8(get_analog_axis(2, pjs));
//joyy
//1
w8(get_analog_axis(3, pjs));
//not used on dreamcast
//1
w8(get_analog_axis(4, pjs));
//1
w8(get_analog_axis(5, pjs));
}
return MDRS_DataTransfer;
case MDC_DeviceReset:
return MDRS_DeviceReply;
case MDC_DeviceKill:
return MDRS_DeviceReply;
default:
INFO_LOG(MAPLE, "maple_fishing_controller: Unknown maple command %d", cmd);
return MDRE_UnknownCmd;
}
}
};
struct maple_popnmusic_controller: maple_sega_controller
{
u32 get_capabilities() override {
// byte 0: 0 0 0 0 0 0 0 0
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
// byte 2: R2 L2 D2 U2 D X Y Z
// byte 3: R L D U St A B C
return 0xff060000; // no analog axes, X Y A B C Start U/D/L/R
}
u32 transform_kcode(u32 kcode) override
{
return kcode | 0xf100; // mask off DPad2 and Z
}
MapleDeviceType get_device_type() override {
return MDT_PopnMusicController;
}
u32 get_analog_axis(int index, const PlainJoystickState &pjs) override {
if (index == 0 || index == 1)
return 0; // Right and left triggers
return 0x80;
}
const char *get_device_name() override {
return maple_popnmusic_controller_name;
}
u32 get_device_current(int get_max_current) override {
return get_max_current ? 0x012C : 0x00AA; // Max. 30 mA, standby: 17 mA
}
};
struct maple_racing_controller: maple_sega_controller
{
u32 get_capabilities() override {
// byte 0: 0 0 0 0 0 0 0 0
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
// byte 2: R2 L2 D2 U2 D X Y Z
// byte 3: R L D U St A B C
return 0xfe003700; // Steering + accelerator/brake unit: Ra,La,Da,Ua,A,B,Start,A1,A2,A3,A5,A6
// (A5 & A6 only valid when the accelerator/brake unit is connected.)
//return 0xfe000700; // Steering only
}
u32 transform_kcode_racing(const PlainJoystickState &pjs) {
// Ra, La are ON when A3 threshold values (La: 40h, Ra: BEh) are exceeded
u32 kcode = pjs.kcode;
if (pjs.joy[PJAI_X1] < 0x40)
kcode &= 0xffff -DC_DPAD_LEFT;
else if (pjs.joy[PJAI_X1] > 0xBE)
kcode &= 0xffff -DC_DPAD_RIGHT;
mutualExclusion(kcode, DC_DPAD_UP | DC_DPAD_DOWN);
mutualExclusion(kcode, DC_DPAD_LEFT | DC_DPAD_RIGHT);
return kcode | 0xff01; // mask off DPad2, D, X, Y, Z, C
}
MapleDeviceType get_device_type() override {
return MDT_RacingController;
}
u32 get_analog_axis(int index, const PlainJoystickState &pjs) override {
if (index == 0)
return pjs.trigger[PJTI_R]; // A1: lever, 0 at rest
else if (index == 1)
return pjs.trigger[PJTI_L]; // A2: lever, 0 at rest
else if (index == 2)
return pjs.joy[PJAI_X1]; // A3: 0-0xff, 0x80 at rest
else if (index == 4) // (A5 and A6 are only valid when the accelerator/brake unit is connected)
return pjs.trigger[PJTI_R2];// A5: lever, 0 at rest
else if (index == 5)
return pjs.trigger[PJTI_L2];// A6: lever, 0 at rest
return 0x80; // unused
}
const char *get_device_name() override {
return maple_racing_controller_name;
}
u32 get_device_current(int get_max_current) override {
return get_max_current ? 0x0226 : 0x01B8; // Max. 55 mA, standby: 44 mA
}
u32 dma(u32 cmd) override
{
//printf("maple_sega_controller::dma Called 0x%X;Command %d\n", bus_id, cmd);
switch (cmd)
{
case MDC_DeviceRequest:
case MDC_AllStatusReq:
// Fixed Device Status
// (Device ID)
//caps
//4
w32(MFID_0_Input);
//struct data
//3*4
w32(get_capabilities());
w32(0);
w32(0);
//1 area code (Country specification)
w8(0xFF);
//1 direction (Connection method)
w8(0);
//30 (Model name)
wstr(get_device_name(), 30);
//60 (License)
wstr(get_device_brand(), 60);
//2 (Standby current consumption)
w16(get_device_current(0));
//2 (Maximum current consumption)
w16(get_device_current(1));
return cmd == MDC_DeviceRequest ? MDRS_DeviceStatus : MDRS_DeviceStatusAll;
//controller condition
case MDCF_GetCondition:
{
PlainJoystickState pjs;
config->GetInput(&pjs);
//caps
//4
w32(MFID_0_Input);
//state data
//2 key code
w16(transform_kcode_racing(pjs));
//triggers
//1 R
w8(get_analog_axis(0, pjs));
//1 L
w8(get_analog_axis(1, pjs));
//joyx
//1
w8(get_analog_axis(2, pjs));
//joyy
//1
w8(get_analog_axis(3, pjs));
//not used on dreamcast
//1
w8(get_analog_axis(4, pjs));
//1
w8(get_analog_axis(5, pjs));
}
return MDRS_DataTransfer;
case MDC_DeviceReset:
return MDRS_DeviceReply;
case MDC_DeviceKill:
return MDRS_DeviceReply;
default:
INFO_LOG(MAPLE, "maple_racing_controller: Unknown maple command %d", cmd);
return MDRE_UnknownCmd;
}
}
};
struct maple_densha_controller: maple_sega_controller
{
u32 get_capabilities() override {
// byte 0: 0 0 0 0 0 0 0 0
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
// byte 2: R2 L2 D2 U2 D X Y Z
// byte 3: R L D U St A B C
return 0xff0f3f00; // Ra,La,Da,Ua A,B,C,D,X,Y,Z,Start Xa,Ya,Xb,Yb Analog levers R,L
}
u32 transform_kcode(u32 kcode) override {
// Ra,La,Da,Ua are used together, corresponding to the brake lever.
return kcode | 0xF000; // mask off DPad2
}
MapleDeviceType get_device_type() override {
return MDT_DenshaDeGoController;
}
u32 get_analog_axis(int index, const PlainJoystickState &pjs) override {
if (index == 2 || index == 3)
return 0;
if (index == 0 || index == 1 || index == 4 || index == 5)
return 0xff;
return 0xff;
}
const char *get_device_name() override {
return maple_densha_controller_name;
}
u32 get_device_current(int get_max_current) override {
return get_max_current ? 0x01F4 : 0x00DC; // Max. 50 mA, standby: 22 mA
}
};
// Emulates a 838-14245-92 maple to RS232 converter
// wired to a 838-14243 RFID reader/writer (apparently Saxa HW210)
struct RFIDReaderWriter : maple_base
@ -1689,6 +2090,26 @@ maple_device* maple_Create(MapleDeviceType type)
rv = new maple_ascii_stick();
break;
case MDT_MaracasController:
rv = new maple_maracas_controller();
break;
case MDT_FishingController:
rv = new maple_fishing_controller();
break;
case MDT_PopnMusicController:
rv = new maple_popnmusic_controller();
break;
case MDT_RacingController:
rv = new maple_racing_controller();
break;
case MDT_DenshaDeGoController:
rv = new maple_densha_controller();
break;
case MDT_RFIDReaderWriter:
rv = new RFIDReaderWriter();
break;

View File

@ -55,6 +55,8 @@ enum DreamcastKey
DC_AXIS_TRIGGERS = 0x1000000,
DC_AXIS_LT,
DC_AXIS_RT,
DC_AXIS_LT2,
DC_AXIS_RT2,
DC_AXIS_STICKS = 0x2000000,
DC_AXIS_LEFT,
DC_AXIS_RIGHT,
@ -64,6 +66,10 @@ enum DreamcastKey
DC_AXIS2_RIGHT,
DC_AXIS2_UP,
DC_AXIS2_DOWN,
DC_AXIS3_LEFT,
DC_AXIS3_RIGHT,
DC_AXIS3_UP,
DC_AXIS3_DOWN,
// System axes
EMU_AXIS_NONE = 0,

View File

@ -39,7 +39,11 @@ s8 joyrx[4];
s8 joyry[4];
u8 rt[4];
u8 lt[4];
s8 joy3x[4];
s8 joy3y[4];
// Keyboards
u8 lt2[4];
u8 rt2[4];
u8 kb_shift[MAPLE_PORTS]; // shift keys pressed (bitmask)
u8 kb_key[MAPLE_PORTS][6]; // normal keys pressed
@ -103,7 +107,14 @@ bool GamepadDevice::handleButtonInput(int port, DreamcastKey key, bool pressed)
if (port >= 0)
rt[port] = pressed ? 255 : 0;
break;
case DC_AXIS_LT2:
if (port >= 0)
lt2[port] = pressed ? 255 : 0;
break;
case DC_AXIS_RT2:
if (port >= 0)
rt2[port] = pressed ? 255 : 0;
break;
case DC_AXIS_UP:
case DC_AXIS_DOWN:
buttonToAnalogInput<DC_AXIS_UP, DIGANA_UP, DIGANA_DOWN>(port, key, pressed, joyy[port]);
@ -120,6 +131,14 @@ bool GamepadDevice::handleButtonInput(int port, DreamcastKey key, bool pressed)
case DC_AXIS2_RIGHT:
buttonToAnalogInput<DC_AXIS2_LEFT, DIGANA2_LEFT, DIGANA2_RIGHT>(port, key, pressed, joyrx[port]);
break;
case DC_AXIS3_UP:
case DC_AXIS3_DOWN:
buttonToAnalogInput<DC_AXIS3_UP, DIGANA3_UP, DIGANA3_DOWN>(port, key, pressed, joy3y[port]);
break;
case DC_AXIS3_LEFT:
case DC_AXIS3_RIGHT:
buttonToAnalogInput<DC_AXIS3_LEFT, DIGANA3_LEFT, DIGANA3_RIGHT>(port, key, pressed, joy3x[port]);
break;
default:
return false;
@ -186,6 +205,10 @@ bool GamepadDevice::gamepad_axis_input(u32 code, int value)
lt[port] = std::min(std::abs(v) >> 7, 255);
else if (key == DC_AXIS_RT)
rt[port] = std::min(std::abs(v) >> 7, 255);
else if (key == DC_AXIS_LT2)
lt2[port] = std::min(std::abs(v) >> 7, 255);
else if (key == DC_AXIS_RT2)
rt2[port] = std::min(std::abs(v) >> 7, 255);
else
return false;
}
@ -229,6 +252,22 @@ bool GamepadDevice::gamepad_axis_input(u32 code, int value)
other_axis = &joyrx[port];
break;
case DC_AXIS3_RIGHT:
axisDirection = 1;
//no break
case DC_AXIS3_LEFT:
this_axis = &joy3x[port];
other_axis = &joy3y[port];
break;
case DC_AXIS3_DOWN:
axisDirection = 1;
//no break
case DC_AXIS3_UP:
this_axis = &joy3y[port];
other_axis = &joy3x[port];
break;
default:
return false;
}

View File

@ -124,6 +124,10 @@ private:
DIGANA2_RIGHT = 1 << 5,
DIGANA2_UP = 1 << 6,
DIGANA2_DOWN = 1 << 7,
DIGANA3_LEFT = 1 << 8,
DIGANA3_RIGHT = 1 << 9,
DIGANA3_UP = 1 << 10,
DIGANA3_DOWN = 1 << 11,
};
template<DreamcastKey DcNegDir, DigAnalog NegDir, DigAnalog PosDir>
@ -167,6 +171,7 @@ void replay_input();
#endif
extern u32 kcode[4];
extern u8 rt[4], lt[4];
extern u8 rt[4], lt[4], rt2[4], lt2[4];
extern s8 joyx[4], joyy[4];
extern s8 joyrx[4], joyry[4];
extern s8 joy3x[4], joy3y[4];

View File

@ -50,6 +50,8 @@ button_list[] =
{ EMU_BTN_FFORWARD, "emulator", "btn_fforward" },
{ DC_AXIS_LT, "compat", "btn_trigger_left" },
{ DC_AXIS_RT, "compat", "btn_trigger_right" },
{ DC_AXIS_LT2, "compat", "btn_trigger_left2" },
{ DC_AXIS_RT2, "compat", "btn_trigger_right2" },
{ DC_AXIS_UP, "compat", "btn_analog_up" },
{ DC_AXIS_DOWN, "compat", "btn_analog_down" },
{ DC_AXIS_LEFT, "compat", "btn_analog_left" },
@ -79,8 +81,14 @@ axis_list[] =
{ DC_AXIS2_RIGHT, "", "axis2_right", "", "" },
{ DC_AXIS2_UP, "", "axis2_up", "", "" },
{ DC_AXIS2_DOWN, "", "axis2_down", "", "" },
{ DC_AXIS3_LEFT, "", "axis3_left", "", "" },
{ DC_AXIS3_RIGHT, "", "axis3_right", "", "" },
{ DC_AXIS3_UP, "", "axis3_up", "", "" },
{ DC_AXIS3_DOWN, "", "axis3_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_LT2, "dreamcast", "axis_trigger_left2", "compat", "axis_trigger_left2_inverted" },
{ DC_AXIS_RT2, "dreamcast", "axis_trigger_right2", "compat", "axis_trigger_right2_inverted" },
// legacy (v2)
{ DC_AXIS_RIGHT, "dreamcast", "axis_x", "compat", "axis_x_inverted" },
@ -306,6 +314,10 @@ void InputMapping::loadv1(ConfigFile& mf)
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);
else if (axis_list[i].id == DC_AXIS3_RIGHT)
this->set_axis(port, DC_AXIS3_LEFT, axis_code, inverted);
else if (axis_list[i].id == DC_AXIS3_DOWN)
this->set_axis(port, DC_AXIS3_UP, axis_code, inverted);
}
}
}

View File

@ -116,9 +116,15 @@ public:
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_AXIS_LT2, DC_AXIS_LT2, true);
set_axis(0, DC_AXIS_RT2, DC_AXIS_RT2, 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);
set_axis(0, DC_AXIS3_LEFT, DC_AXIS3_LEFT, true);
set_axis(0, DC_AXIS3_RIGHT, DC_AXIS3_RIGHT, true);
set_axis(0, DC_AXIS3_UP, DC_AXIS3_UP, true);
set_axis(0, DC_AXIS3_DOWN, DC_AXIS3_DOWN, true);
}
};

View File

@ -43,10 +43,14 @@ static void getLocalInput(MapleInputState inputState[4])
state.kcode = kcode[player];
state.halfAxes[PJTI_L] = lt[player];
state.halfAxes[PJTI_R] = rt[player];
state.halfAxes[PJTI_L2] = lt2[player];
state.halfAxes[PJTI_R2] = rt2[player];
state.fullAxes[PJAI_X1] = joyx[player];
state.fullAxes[PJAI_Y1] = joyy[player];
state.fullAxes[PJAI_X2] = joyrx[player];
state.fullAxes[PJAI_Y2] = joyry[player];
state.fullAxes[PJAI_X3] = joy3x[player];
state.fullAxes[PJAI_Y3] = joy3y[player];
state.mouseButtons = mo_buttons[player];
state.absPos.x = mo_x_abs[player];
state.absPos.y = mo_y_abs[player];

View File

@ -656,8 +656,30 @@ inline static void header(const char *title)
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" };
const char *maple_device_types[] =
{
"None",
"Sega Controller",
"Light Gun",
"Keyboard",
"Mouse",
"Twin Stick",
"Ascii Stick",
"Maracas Controller",
"Fishing Controller",
"Pop'n Music controller",
"Racing Controller",
"Densha de Go! Controller",
"Dreameye",
};
const char *maple_expansion_device_types[] =
{
"None",
"Sega VMU",
"Purupuru",
"Microphone"
};
static const char *maple_device_name(MapleDeviceType type)
{
@ -675,6 +697,18 @@ static const char *maple_device_name(MapleDeviceType type)
return maple_device_types[5];
case MDT_AsciiStick:
return maple_device_types[6];
case MDT_MaracasController:
return maple_device_types[7];
case MDT_FishingController:
return maple_device_types[8];
case MDT_PopnMusicController:
return maple_device_types[9];
case MDT_RacingController:
return maple_device_types[10];
case MDT_DenshaDeGoController:
return maple_device_types[11];
case MDT_Dreameye:
return maple_device_types[12];
case MDT_None:
default:
return maple_device_types[0];
@ -697,6 +731,18 @@ static MapleDeviceType maple_device_type_from_index(int idx)
return MDT_TwinStick;
case 6:
return MDT_AsciiStick;
case 7:
return MDT_MaracasController;
case 8:
return MDT_FishingController;
case 9:
return MDT_PopnMusicController;
case 10:
return MDT_RacingController;
case 11:
return MDT_DenshaDeGoController;
case 12:
return MDT_Dreameye;
case 0:
default:
return MDT_None;
@ -738,9 +784,19 @@ const Mapping dcButtons[] = {
{ 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_AXIS2_UP, "R.Thumbstick Up" },
{ DC_AXIS2_DOWN, "R.Thumbstick Down" },
{ DC_AXIS2_LEFT, "R.Thumbstick Left" },
{ DC_AXIS2_RIGHT, "R.Thumbstick Right" },
{ DC_AXIS3_UP, "Axis 3 Up" },
{ DC_AXIS3_DOWN, "Axis 3 Down" },
{ DC_AXIS3_LEFT, "Axis 3 Left" },
{ DC_AXIS3_RIGHT, "Axis 3 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" },
@ -752,9 +808,11 @@ const Mapping dcButtons[] = {
{ 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, "Triggers" },
{ DC_AXIS_LT, "Left Trigger" },
{ DC_AXIS_RT, "Right Trigger" },
{ DC_AXIS_LT2, "Left Trigger 2" },
{ DC_AXIS_RT2, "Right Trigger 2" },
{ EMU_BTN_NONE, "System Buttons" },
{ DC_BTN_START, "Start" },
@ -886,6 +944,14 @@ static DreamcastKey getOppositeDirectionKey(DreamcastKey key)
return DC_AXIS2_RIGHT;
case DC_AXIS2_RIGHT:
return DC_AXIS2_LEFT;
case DC_AXIS3_UP:
return DC_AXIS3_DOWN;
case DC_AXIS3_DOWN:
return DC_AXIS3_UP;
case DC_AXIS3_LEFT:
return DC_AXIS3_RIGHT;
case DC_AXIS3_RIGHT:
return DC_AXIS3_LEFT;
default:
return EMU_BTN_NONE;
}
@ -1646,9 +1712,19 @@ static void gui_display_settings()
}
ImGui::EndCombo();
}
int port_count = config::MapleMainDevices[bus] == MDT_SegaController ? 2
: config::MapleMainDevices[bus] == MDT_LightGun || config::MapleMainDevices[bus] == MDT_TwinStick || config::MapleMainDevices[bus] == MDT_AsciiStick ? 1
: 0;
int port_count = 0;
switch (config::MapleMainDevices[bus]) {
case MDT_SegaController:
port_count = 2;
break;
case MDT_LightGun:
case MDT_TwinStick:
case MDT_AsciiStick:
case MDT_RacingController:
port_count = 1;
break;
default: break;
}
for (int port = 0; port < port_count; port++)
{
ImGui::SameLine();

View File

@ -61,7 +61,8 @@ public:
V34,
V35,
V36,
Current = V36,
V37,
Current = V37,
Next = Current + 1,
};

View File

@ -130,9 +130,12 @@ static bool lightgunSettingsShown = true;
u32 kcode[4] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
u8 rt[4];
u8 lt[4];
u8 lt2[4];
u8 rt2[4];
u32 vks[4];
s8 joyx[4], joyy[4];
s8 joyrx[4], joyry[4];
s8 joy3x[4], joy3y[4];
// Mouse buttons
// bit 0: Button C
// bit 1: Right button (B)