diff --git a/rpcs3/Input/sdl_pad_handler.cpp b/rpcs3/Input/sdl_pad_handler.cpp index db1790757a..aa63143eb0 100644 --- a/rpcs3/Input/sdl_pad_handler.cpp +++ b/rpcs3/Input/sdl_pad_handler.cpp @@ -30,6 +30,14 @@ public: return instance; } + void set_hint(const char* name, const char* value) + { + if (!SDL_SetHint(name, value)) + { + sdl_log.error("Could not set hint '%s' to '%s': %s", name, value, SDL_GetError()); + } + } + bool initialize() { // Only init SDL once. SDL uses a global state internally... @@ -41,10 +49,14 @@ public: sdl_log.notice("Initializing SDL ..."); // Set non-dynamic hints before SDL_Init - if (!SDL_SetHint(SDL_HINT_JOYSTICK_THREAD, "1")) - { - sdl_log.error("Could not set SDL_HINT_JOYSTICK_THREAD: %s", SDL_GetError()); - } + set_hint(SDL_HINT_JOYSTICK_THREAD, "1"); + + // DS3 pressure sensitive buttons +#ifdef _WIN32 + set_hint(SDL_HINT_JOYSTICK_HIDAPI_PS3_SIXAXIS_DRIVER, "1"); +#else + set_hint(SDL_HINT_JOYSTICK_HIDAPI_PS3, "1"); +#endif if (!SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD)) { @@ -169,6 +181,16 @@ sdl_pad_handler::sdl_pad_handler() : PadHandlerBase(pad_handler::sdl) { SDLKeyCodes::RSXPos, "RS X+" }, { SDLKeyCodes::RSYPos, "RS Y+" }, { SDLKeyCodes::RSYNeg, "RS Y-" }, + { SDLKeyCodes::PressureCross, "South" }, // Same name as non-pressure button + { SDLKeyCodes::PressureCircle, "East" }, // Same name as non-pressure button + { SDLKeyCodes::PressureSquare, "West" }, // Same name as non-pressure button + { SDLKeyCodes::PressureTriangle, "North" }, // Same name as non-pressure button + { SDLKeyCodes::PressureL1, "LB" }, // Same name as non-pressure button + { SDLKeyCodes::PressureR1, "RB" }, // Same name as non-pressure button + { SDLKeyCodes::PressureUp, "Up" }, // Same name as non-pressure button + { SDLKeyCodes::PressureDown, "Down" }, // Same name as non-pressure button + { SDLKeyCodes::PressureLeft, "Left" }, // Same name as non-pressure button + { SDLKeyCodes::PressureRight, "Right" }, // Same name as non-pressure button }; init_configs(); @@ -360,6 +382,7 @@ SDLDevice::sdl_info sdl_pad_handler::get_sdl_info(SDL_JoystickID id) } info.type = SDL_GetGamepadType(info.gamepad); + info.real_type = SDL_GetRealGamepadType(info.gamepad); info.vid = SDL_GetGamepadVendor(info.gamepad); info.pid = SDL_GetGamepadProduct(info.gamepad); info.product_version = SDL_GetGamepadProductVersion(info.gamepad); @@ -393,8 +416,8 @@ SDLDevice::sdl_info sdl_pad_handler::get_sdl_info(SDL_JoystickID id) } } - sdl_log.notice("Found game pad %d: type=%d, name='%s', path='%s', serial='%s', vid=0x%x, pid=0x%x, product_version=0x%x, firmware_version=0x%x, has_led=%d, has_player_led=%d, has_mono_led=%d, has_rumble=%d, has_rumble_triggers=%d, has_accel=%d, has_gyro=%d", - id, static_cast(info.type), info.name, info.path, info.serial, info.vid, info.pid, info.product_version, info.firmware_version, info.has_led, info.has_player_led, info.has_mono_led, info.has_rumble, info.has_rumble_triggers, info.has_accel, info.has_gyro); + sdl_log.notice("Found game pad %d: type=%d, real_type=%d, name='%s', path='%s', serial='%s', vid=0x%x, pid=0x%x, product_version=0x%x, firmware_version=0x%x, has_led=%d, has_player_led=%d, has_mono_led=%d, has_rumble=%d, has_rumble_triggers=%d, has_accel=%d, has_gyro=%d", + id, static_cast(info.type), static_cast(info.real_type), info.name, info.path, info.serial, info.vid, info.pid, info.product_version, info.firmware_version, info.has_led, info.has_player_led, info.has_mono_led, info.has_rumble, info.has_rumble_triggers, info.has_accel, info.has_gyro); if (info.has_accel) { @@ -444,6 +467,33 @@ SDLDevice::sdl_info sdl_pad_handler::get_sdl_info(SDL_JoystickID id) } } + // The DS3 may have extra pressure sensitive buttons as axis + if (info.real_type == SDL_GamepadType::SDL_GAMEPAD_TYPE_PS3) + { + if (SDL_Joystick* joystick = SDL_GetGamepadJoystick(info.gamepad)) + { + const int num_axes = SDL_GetNumJoystickAxes(joystick); + const int num_buttons = SDL_GetNumJoystickButtons(joystick); + + info.is_ds3_with_pressure_buttons = num_axes == 16 && num_buttons == 11; + + sdl_log.notice("DS3 device %d has %d axis and %d buttons (has_pressure_buttons=%d)", id, num_axes, num_buttons, info.is_ds3_with_pressure_buttons); + + if (info.is_ds3_with_pressure_buttons) + { + // Add pressure buttons + for (int i = SDL_GAMEPAD_AXIS_COUNT; i < num_axes; i++) + { + const SDL_GamepadAxis axis_id = static_cast(i); + //if (SDL_GamepadHasAxis(info.gamepad, axis_id)) // Always returns false for axis >= SDL_GAMEPAD_AXIS_COUNT + { + info.axis_ids.insert(axis_id); + } + } + } + } + } + return info; } @@ -741,7 +791,7 @@ void sdl_pad_handler::get_extended_info(const pad_ensemble& binding) { const f32 accel_x = dev->values_accel[0]; // Angular speed around the x axis (pitch) const f32 accel_y = dev->values_accel[1]; // Angular speed around the y axis (yaw) - const f32 accel_z = dev->values_accel[2]; // Angular speed around the z axis (roll + const f32 accel_z = dev->values_accel[2]; // Angular speed around the z axis (roll) // Convert to ds3. The ds3 resolution is 113/G. pad->m_sensors[0].m_value = Clamp0To1023((accel_x / SDL_STANDARD_GRAVITY) * -1 * MOTION_ONE_G + 512); @@ -991,18 +1041,61 @@ std::unordered_map sdl_pad_handler::get_button_values(const std::share if (!dev || !dev->sdl.gamepad) return values; + std::set pressed_pressure_buttons; + for (SDL_GamepadButton button_id : dev->sdl.button_ids) { - const u8 value = SDL_GetGamepadButton(dev->sdl.gamepad, button_id); + const bool value = SDL_GetGamepadButton(dev->sdl.gamepad, button_id); const SDLKeyCodes key_code = get_button_code(button_id); - // TODO: SDL does not support DS3 button intensity in the current version + // NOTE: SDL does not simply support DS3 button intensity in the current version + // So we have to skip the normal buttons if a DS3 with pressure buttons was detected + if (dev->sdl.is_ds3_with_pressure_buttons) + { + switch (key_code) + { + case SDLKeyCodes::North: + case SDLKeyCodes::South: + case SDLKeyCodes::West: + case SDLKeyCodes::East: + case SDLKeyCodes::Left: + case SDLKeyCodes::Right: + case SDLKeyCodes::Up: + case SDLKeyCodes::Down: + case SDLKeyCodes::LB: + case SDLKeyCodes::RB: + { + static const std::map button_to_pressure = + { + { SDLKeyCodes::South, SDLKeyCodes::PressureCross }, + { SDLKeyCodes::East, SDLKeyCodes::PressureCircle }, + { SDLKeyCodes::West, SDLKeyCodes::PressureSquare }, + { SDLKeyCodes::North, SDLKeyCodes::PressureTriangle }, + { SDLKeyCodes::LB, SDLKeyCodes::PressureL1 }, + { SDLKeyCodes::RB, SDLKeyCodes::PressureR1 }, + { SDLKeyCodes::Up, SDLKeyCodes::PressureUp }, + { SDLKeyCodes::Down, SDLKeyCodes::PressureDown }, + { SDLKeyCodes::Left, SDLKeyCodes::PressureLeft }, + { SDLKeyCodes::Right, SDLKeyCodes::PressureRight } + }; + + if (value) + { + pressed_pressure_buttons.insert(::at32(button_to_pressure, key_code)); + } + continue; + } + default: + break; + } + } + values[key_code] = value ? 255 : 0; } for (SDL_GamepadAxis axis_id : dev->sdl.axis_ids) { - const s16 value = SDL_GetGamepadAxis(dev->sdl.gamepad, axis_id); + s16 value = SDL_GetGamepadAxis(dev->sdl.gamepad, axis_id); switch (axis_id) { @@ -1029,8 +1122,32 @@ std::unordered_map sdl_pad_handler::get_button_values(const std::share values[SDLKeyCodes::RSYPos] = value < 0 ? std::abs(value) - 1 : 0; break; default: + { + if (dev->sdl.is_ds3_with_pressure_buttons) + { + // Get pressure button value from axis + if (const int key_code = SDLKeyCodes::PressureBegin + 1 + axis_id - SDL_GAMEPAD_AXIS_COUNT; + key_code > SDLKeyCodes::PressureBegin && key_code < SDLKeyCodes::PressureEnd) + { + // We need to get the joystick value directly for axis >= SDL_GAMEPAD_AXIS_COUNT + if (SDL_Joystick* joystick = SDL_GetGamepadJoystick(dev->sdl.gamepad)) + { + value = SDL_GetJoystickAxis(joystick, axis_id); + } + + value = static_cast(ScaledInput(value, SDL_JOYSTICK_AXIS_MIN, SDL_JOYSTICK_AXIS_MAX, 0.0f, 255.0f)); + + if (value <= 0 && pressed_pressure_buttons.contains(static_cast(key_code))) + { + value = 1; + } + + values[key_code] = Clamp0To255(value); + } + } break; } + } } for (const SDLDevice::touchpad& touchpad : dev->sdl.touchpads) diff --git a/rpcs3/Input/sdl_pad_handler.h b/rpcs3/Input/sdl_pad_handler.h index 408c4a2fae..58ddcfda63 100644 --- a/rpcs3/Input/sdl_pad_handler.h +++ b/rpcs3/Input/sdl_pad_handler.h @@ -35,6 +35,7 @@ public: { SDL_Gamepad* gamepad = nullptr; SDL_GamepadType type = SDL_GamepadType::SDL_GAMEPAD_TYPE_UNKNOWN; + SDL_GamepadType real_type = SDL_GamepadType::SDL_GAMEPAD_TYPE_UNKNOWN; int power_level = 0; int last_power_level = 0; @@ -47,6 +48,7 @@ public: u16 firmware_version = 0; bool is_virtual_device = false; + bool is_ds3_with_pressure_buttons = false; bool has_led = false; bool has_mono_led = false; @@ -124,7 +126,21 @@ class sdl_pad_handler : public PadHandlerBase RSXNeg, RSXPos, RSYNeg, - RSYPos + RSYPos, + + // DS3 Pressure sensitive buttons (reported as axis) + PressureBegin, + PressureCross, // Cross axis 6 + PressureCircle, // Circle axis 7 + PressureSquare, // Square axis 8 + PressureTriangle, // Triangle axis 9 + PressureL1, // L1 axis 10 + PressureR1, // R1 axis 11 + PressureUp, // D-Pad Up axis 12 + PressureDown, // D-Pad Down axis 13 + PressureLeft, // D-Pad Left axis 14 + PressureRight, // D-Pad Right axis 15 + PressureEnd, }; public: