diff --git a/core/sdl/sdl.cpp b/core/sdl/sdl.cpp index e185a0332..2ad0d30f7 100644 --- a/core/sdl/sdl.cpp +++ b/core/sdl/sdl.cpp @@ -41,7 +41,7 @@ static void sdl_open_joystick(int index) INFO_LOG(INPUT, "SDL: Cannot open joystick %d", index + 1); return; } - std::shared_ptr gamepad = std::make_shared(index < MAPLE_PORTS ? index : -1, pJoystick); + std::shared_ptr gamepad = std::make_shared(index < MAPLE_PORTS ? index : -1, index, pJoystick); SDLGamepadDevice::AddSDLGamepad(gamepad); } @@ -59,9 +59,17 @@ void input_sdl_init() // We want joystick events even if we loose focus SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) - { die("SDL: error initializing Joystick subsystem"); + + std::string db = get_readonly_data_path("gamecontrollerdb.txt"); + int rv = SDL_GameControllerAddMappingsFromFile(db.c_str()); + if (rv < 0) + { + db = get_readonly_config_path("gamecontrollerdb.txt"); + rv = SDL_GameControllerAddMappingsFromFile(db.c_str()); } + if (rv > 0) + DEBUG_LOG(INPUT ,"%d mappings loaded from %s", rv, db.c_str()); } if (SDL_WasInit(SDL_INIT_HAPTIC) == 0) SDL_InitSubSystem(SDL_INIT_HAPTIC); diff --git a/core/sdl/sdl_gamepad.h b/core/sdl/sdl_gamepad.h index ecf40f677..00685170d 100644 --- a/core/sdl/sdl_gamepad.h +++ b/core/sdl/sdl_gamepad.h @@ -21,34 +21,88 @@ public: set_axis(DC_AXIS_Y2, 3, false); dirty = false; } -}; -class Xbox360InputMapping : public InputMapping -{ -public: - Xbox360InputMapping() + DefaultInputMapping(int joystick_idx) : DefaultInputMapping() { - name = "Xbox 360"; - set_button(DC_BTN_A, 0); - set_button(DC_BTN_B, 1); - set_button(DC_BTN_X, 2); - set_button(DC_BTN_Y, 3); - set_button(DC_BTN_START, 7); + if (SDL_IsGameController(joystick_idx)) + { + SDL_GameController *sdl_controller = SDL_GameControllerOpen(joystick_idx); + name = SDL_GameControllerName(sdl_controller); + INFO_LOG(INPUT, "SDL: using SDL game controller mappings for '%s'", name.c_str()); - set_axis(DC_AXIS_X, 0, false); - set_axis(DC_AXIS_Y, 1, false); - set_axis(DC_AXIS_LT, 2, false); - set_axis(DC_AXIS_RT, 5, false); - set_axis(DC_DPAD_LEFT, 6, false); - set_axis(DC_DPAD_UP, 7, false); - dirty = false; + auto map_button = [&](SDL_GameControllerButton sdl_btn, DreamcastKey dc_btn) { + SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton(sdl_controller, sdl_btn); + if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) + set_button(dc_btn, bind.value.button); + else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT) + { + int dir; + switch (bind.value.hat.hat_mask) + { + case SDL_HAT_UP: + dir = 0; + break; + case SDL_HAT_DOWN: + dir = 1; + break; + case SDL_HAT_LEFT: + dir = 2; + break; + case SDL_HAT_RIGHT: + dir = 3; + break; + default: + return; + } + 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); + if (bind.bindType != SDL_CONTROLLER_BINDTYPE_AXIS) + return false; + + bool invert_axis = false; + 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); + 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); + dirty = false; + } + else + INFO_LOG(INPUT, "using default mapping"); } }; class SDLGamepadDevice : public GamepadDevice { public: - SDLGamepadDevice(int maple_port, SDL_Joystick* sdl_joystick) : GamepadDevice(maple_port, "SDL"), sdl_joystick(sdl_joystick) + SDLGamepadDevice(int maple_port, int joystick_idx, SDL_Joystick* sdl_joystick) : GamepadDevice(maple_port, "SDL"), sdl_joystick(sdl_joystick) { _name = SDL_JoystickName(sdl_joystick); sdl_joystick_instance = SDL_JoystickInstanceID(sdl_joystick); @@ -56,19 +110,7 @@ public: 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 (!find_mapping()) - { - if (_name == "Microsoft X-Box 360 pad") - { - input_mapper = std::make_shared(); - INFO_LOG(INPUT, "using Xbox 360 mapping"); - } - else - { - input_mapper = std::make_shared(); - INFO_LOG(INPUT, "using default mapping"); - } - save_mapping(); - } + input_mapper = std::make_shared(joystick_idx); else INFO_LOG(INPUT, "using custom mapping '%s'", input_mapper->name.c_str()); sdl_haptic = SDL_HapticOpenFromJoystick(sdl_joystick); @@ -77,7 +119,6 @@ public: SDL_HapticClose(sdl_haptic); sdl_haptic = NULL; } - } virtual void rumble(float power, float inclination, u32 duration_ms) override