Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VMUs and Rumble Packs with Original Dreamcast Controllers #1810

Merged
merged 10 commits into from
Jan 25, 2025
21 changes: 17 additions & 4 deletions core/sdl/dreamconn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ void DreamConn::connect()
case TYPE_DREAMCONN:
{
#if !defined(_WIN32)
WARN_LOG(INPUT, "DreamcastController[%d] connection failed: DreamConn+ Controller supported on Windows only", bus);
WARN_LOG(INPUT, "DreamcastController[%d] connection failed: DreamConn+ / DreamConn S Controller supported on Windows only", bus);
return;
#endif
iostream = asio::ip::tcp::iostream("localhost", std::to_string(BASE_PORT + bus));
Expand Down Expand Up @@ -240,7 +240,7 @@ void DreamConn::connect()

if (hasVmu() || hasRumble())
{
NOTICE_LOG(INPUT, "Connected to DreamcastController[%d]: Type:%s, VMU:%d, Rumble Pack:%d", bus, dreamcastControllerType == 1 ? "DreamConn+ Controller" : "Dreamcast Controller USB", hasVmu(), hasRumble());
NOTICE_LOG(INPUT, "Connected to DreamcastController[%d]: Type:%s, VMU:%d, Rumble Pack:%d", bus, dreamcastControllerType == 1 ? "DreamConn+ / DreamcConn S Controller" : "Dreamcast Controller USB", hasVmu(), hasRumble());
maple_io_connected = true;
}
else
Expand Down Expand Up @@ -316,7 +316,7 @@ DreamConnGamepad::DreamConnGamepad(int maple_port, int joystick_idx, SDL_Joystic
if (memcmp("5744000043440000", guid_str + 8, 16) == 0)
{
dreamcastControllerType = TYPE_DREAMCONN;
_name = "DreamConn+ Controller";
_name = "DreamConn+ / DreamConn S Controller";
}
else if (memcmp("09120000072f0000", guid_str + 8, 16) == 0)
{
Expand Down Expand Up @@ -372,14 +372,27 @@ bool DreamConnGamepad::gamepad_axis_input(u32 code, int value)
{
if (!is_detecting_input())
{
// For DreamcastControllerUsb, we need to diff between Linux which exposes the UDB HID event codes as expected, and MacOS/Windows which require a dedicated mapping
// Change is temporary for testing - will be superseded by an extension of SDL providing default mappings for DreamcastControllerUsb
kosekmi marked this conversation as resolved.
Show resolved Hide resolved
#if defined(_WIN32) || (defined(__APPLE__) && defined(TARGET_OS_MAC))
if ((code == leftTrigger && dreamcastControllerType == TYPE_DREAMCONN) || (code == 2 && dreamcastControllerType == TYPE_DREAMCASTCONTROLLERUSB)) {
ltrigPressed = value > 0;
checkKeyCombo();
}
if ((code == rightTrigger && dreamcastControllerType == TYPE_DREAMCONN) || (code == 5 && dreamcastControllerType == TYPE_DREAMCASTCONTROLLERUSB)) {
rtrigPressed = value > 0;
checkKeyCombo();
}
#elif defined(__linux__)
if (code == leftTrigger) {
ltrigPressed = value > 0;
checkKeyCombo();
}
else if (code == rightTrigger) {
if (code == rightTrigger) {
rtrigPressed = value > 0;
checkKeyCombo();
}
#endif
}
else {
ltrigPressed = false;
Expand Down
123 changes: 97 additions & 26 deletions core/sdl/sdl_gamepad.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,73 @@
#include "stdclass.h"
#include "sdl.h"

template<bool Arcade = false, bool Gamepad = false>
template<bool Arcade = false, bool Gamepad = false, bool DreamcastControllerUsb = false>
class DefaultInputMapping : public InputMapping
{
public:
DefaultInputMapping()
{
name = "Default";
set_button(DC_BTN_Y, 0);
set_button(DC_BTN_B, 1);
set_button(DC_BTN_A, 2);
set_button(DC_BTN_X, 3);
set_button(DC_BTN_START, 9);

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;
if (!DreamcastControllerUsb)
{
kosekmi marked this conversation as resolved.
Show resolved Hide resolved
name = "Default";
set_button(DC_BTN_Y, 0);
set_button(DC_BTN_B, 1);
set_button(DC_BTN_A, 2);
set_button(DC_BTN_X, 3);
set_button(DC_BTN_START, 9);

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;
}
else
{
// For DreamcastControllerUsb, we need to diff between Linux which exposes the UDB HID event codes as expected, and MacOS/Windows which require a dedicated mapping
// Change is temporary for testing - will be superseded by an extension of SDL providing default mappings for DreamcastControllerUsb
name = "Dreamcast Controller USB";
#if defined(__linux__)
set_button(DC_BTN_Y, 0);
set_button(DC_BTN_B, 1);
set_button(DC_BTN_A, 2);
set_button(DC_BTN_X, 3);
set_button(DC_BTN_START, 9);

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;
#elif defined(_WIN32) || (defined(__APPLE__) && defined(TARGET_OS_MAC))
set_button(DC_DPAD_UP, 256);
set_button(DC_DPAD_DOWN, 257);
set_button(DC_DPAD_LEFT, 258);
set_button(DC_DPAD_RIGHT, 259);

set_button(DC_BTN_Y, 4);
set_button(DC_BTN_B, 1);
set_button(DC_BTN_A, 0);
set_button(DC_BTN_X, 3);
set_button(DC_BTN_START, 11);

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_AXIS_LT, 2, true);
set_axis(0, DC_AXIS_RT, 5, true);
dirty = false;
#endif
}
}

DefaultInputMapping(SDL_GameController *sdlController) : DefaultInputMapping()
Expand Down Expand Up @@ -157,7 +202,10 @@ class DefaultInputMapping : public InputMapping
dirty = false;
}
else
INFO_LOG(INPUT, "using default mapping");
if (DreamcastControllerUsb)
INFO_LOG(INPUT, "using default mapping for Dreamcast Controller USB");
else
INFO_LOG(INPUT, "using default mapping");
}
};

Expand Down Expand Up @@ -197,7 +245,18 @@ class SDLGamepad : public GamepadDevice
}

if (!find_mapping())
input_mapper = std::make_shared<DefaultInputMapping<>>(sdl_controller);
{
// We explicitely check for Dreamcast Controller USB with VID:1209 PID:2f07 to override the default button mapping
// Change is temporary for testing - will be superseded by an extension of SDL providing default mappings for DreamcastControllerUsb
char guid_str[33] {};
SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(joystick_idx), guid_str, sizeof(guid_str));
if (memcmp("09120000072f0000", guid_str + 8, 16) == 0)
{
input_mapper = std::make_shared<DefaultInputMapping<false, true, true>>(sdl_controller);
}
else
input_mapper = std::make_shared<DefaultInputMapping<>>(sdl_controller);
}
else
INFO_LOG(INPUT, "using custom mapping '%s'", input_mapper->name.c_str());

Expand Down Expand Up @@ -607,16 +666,28 @@ class SDLGamepad : public GamepadDevice

void resetMappingToDefault(bool arcade, bool gamepad) override
{
NOTICE_LOG(INPUT, "Resetting SDL gamepad to default: %d %d", arcade, gamepad);
if (arcade)
// We explicitely check for Dreamcast Controller USB with VID:1209 PID:2f07 to override the default button mapping
// Change is temporary for testing - will be superseded by an extension of SDL providing default mappings for DreamcastControllerUsb
char guid_str[33] {};
SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(this->sdl_joystick), guid_str, sizeof(guid_str));
if (memcmp("09120000072f0000", guid_str + 8, 16) == 0)
{
if (gamepad)
input_mapper = std::make_shared<DefaultInputMapping<true, true>>(sdl_controller);
else
input_mapper = std::make_shared<DefaultInputMapping<true, false>>(sdl_controller);
NOTICE_LOG(INPUT, "Resetting SDL gamepad to default for Dreamcast Controller USB");
input_mapper = std::make_shared<DefaultInputMapping<false, true, true>>(sdl_controller);
}
else
input_mapper = std::make_shared<DefaultInputMapping<false, false>>(sdl_controller);
{
NOTICE_LOG(INPUT, "Resetting SDL gamepad to default: %d %d", arcade, gamepad);
if (arcade)
{
if (gamepad)
input_mapper = std::make_shared<DefaultInputMapping<true, true, false>>(sdl_controller);
else
input_mapper = std::make_shared<DefaultInputMapping<true, false, false>>(sdl_controller);
}
else
input_mapper = std::make_shared<DefaultInputMapping<false, false, false>>(sdl_controller);
}
}


Expand Down
Loading