diff --git a/rpcs3/Emu/Io/Turntable.cpp b/rpcs3/Emu/Io/Turntable.cpp index 6068393da7..14c663ec60 100644 --- a/rpcs3/Emu/Io/Turntable.cpp +++ b/rpcs3/Emu/Io/Turntable.cpp @@ -5,9 +5,9 @@ #include "Emu/Cell/lv2/sys_usbd.h" #include "Input/pad_thread.h" -LOG_CHANNEL(turntable_log); +LOG_CHANNEL(turntable_log, "TURN"); -usb_device_turntable::usb_device_turntable(int controller_index, const std::array& location) +usb_device_turntable::usb_device_turntable(u32 controller_index, const std::array& location) : usb_device_emulated(location), m_controller_index(controller_index) { device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, UsbDeviceDescriptor{0x0100, 0x00, 0x00, 0x00, 0x40, 0x12BA, 0x0140, 0x0005, 0x01, 0x02, 0x00, 0x01}); @@ -16,6 +16,11 @@ usb_device_turntable::usb_device_turntable(int controller_index, const std::arra config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_HID, UsbDeviceHID{0x0110, 0x00, 0x01, 0x22, 0x0089})); config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x81, 0x03, 0x0040, 0x0a})); config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x02, 0x03, 0x0040, 0x0a})); + + if (!m_cfg.load()) + { + turntable_log.notice("Could not load turntable config. Using defaults."); + } } usb_device_turntable::~usb_device_turntable() @@ -121,130 +126,123 @@ void usb_device_turntable::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpo std::lock_guard lock(pad::g_pad_mutex); const auto handler = pad::get_current_handler(); - const auto& pad = handler->GetPads()[m_controller_index]; + const auto& pads = handler->GetPads(); + const auto& pad = ::at32(pads, m_controller_index); + const auto& cfg = ::at32(m_cfg.players, m_controller_index); if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) return; for (const Button& button : pad->m_buttons) { - if (button.m_pressed) + if (!button.m_pressed) + continue; + + if (const auto btn = cfg->find_button(button.m_offset, button.m_outKeyCode)) { - if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL2) + switch (btn.value()) { - switch (button.m_outKeyCode) + case turntable_btn::blue: + buf[0] |= 0x01; // Square Button + buf[7] = ~buf[7]; // Square Button + buf[23] |= 0x04; // Right Platter Blue + break; + case turntable_btn::green: + buf[0] |= 0x02; // Cross Button + buf[9] = ~buf[9]; // Cross Button + buf[23] |= 0x01; // Right Platter Green + break; + case turntable_btn::red: + buf[0] |= 0x04; // Circle Button + buf[12] = ~buf[12]; // Circle Button + buf[23] |= 0x02; // Right Platter Red + break; + case turntable_btn::triangle: + buf[0] |= 0x08; // Triangle Button / Euphoria + buf[11] = ~buf[11]; // Triangle Button / Euphoria + break; + case turntable_btn::cross: + buf[0] |= 0x02; // Cross Button Only + buf[9] = ~buf[9]; // Cross Button Only + break; + case turntable_btn::circle: + buf[0] |= 0x04; // Circle Button Only + buf[12] = ~buf[12]; // Circle Button Only + break; + case turntable_btn::square: + buf[0] |= 0x01; // Square Button Only + buf[7] = ~buf[7]; // Square Button Only + break; + case turntable_btn::dpad_down: + if (buf[2] == 0x02) // Right D-Pad { - case CELL_PAD_CTRL_SQUARE: - buf[0] |= 0x01; // Square Button - buf[7] = ~buf[7]; // Square Button - buf[23] |= 0x04; // Right Platter Blue - break; - case CELL_PAD_CTRL_CROSS: - buf[0] |= 0x02; // Cross Button - buf[9] = ~buf[9]; // Cross Button - buf[23] |= 0x01; // Right Platter Green - break; - case CELL_PAD_CTRL_CIRCLE: - buf[0] |= 0x04; // Circle Button - buf[12] = ~buf[12]; // Circle Button - buf[23] |= 0x02; // Right Platter Red - break; - case CELL_PAD_CTRL_TRIANGLE: - buf[0] |= 0x08; // Triangle Button / Euphoria - buf[11] = ~buf[11]; // Triangle Button / Euphoria - break; - case CELL_PAD_CTRL_R1: - buf[0] |= 0x02; // Cross Button Only - buf[9] = ~buf[9]; // Cross Button Only - break; - case CELL_PAD_CTRL_L1: - buf[0] |= 0x04; // Circle Button Only - buf[12] = ~buf[12]; // Circle Button Only - break; - case CELL_PAD_CTRL_R2: - buf[0] |= 0x01; // Square Button Only - buf[7] = ~buf[7]; // Square Button Only - break; - default: - break; + buf[2] = 0x03; // Right-Down D-Pad } - } - else if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL1) - { - switch (button.m_outKeyCode) + else if (buf[2] == 0x06) // Left D-Pad { - case CELL_PAD_CTRL_DOWN: - if (buf[2] == 0x02) // Right D-Pad - { - buf[2] = 0x03; // Right-Down D-Pad - } - else if (buf[2] == 0x06) // Left D-Pad - { - buf[2] = 0x05; // Left-Down D-Pad - } - else - { - buf[2] = 0x04; // Down D-Pad - } - buf[10] = ~buf[10]; // Down D-Pad; - break; - case CELL_PAD_CTRL_UP: - if (buf[2] == 0x02) // Right D-Pad - { - buf[2] = 0x01; // Right-Up D-Pad - } - else if (buf[2] == 0x06) // Left D-Pad - { - buf[2] = 0x07; // Left-Up D-Pad - } - else - { - buf[2] = 0x00; // Up D-Pad - } - buf[9] = ~buf[9]; // Up D-Pad; - break; - case CELL_PAD_CTRL_LEFT: - if (buf[2] == 0x00) // Up D-Pad - { - buf[2] = 0x07; // Left-Up D-Pad - } - else if (buf[2] == 0x04) // Down D-Pad - { - buf[2] = 0x05; // Left-Down D-Pad - } - else - { - buf[2] = 0x06; // Left D-Pad - } - buf[8] = ~buf[8]; // Left D-Pad; - break; - case CELL_PAD_CTRL_RIGHT: - if (buf[2] == 0x00) // Up D-Pad - { - buf[2] = 0x01; // Right-Up D-Pad - } - else if (buf[2] == 0x04) // Down D-Pad - { - buf[2] = 0x03; // Right-Down D-Pad - } - else - { - buf[2] = 0x02; // Right D-Pad - } - buf[7] = ~buf[7]; // Right D-Pad - break; - case CELL_PAD_CTRL_START: - buf[1] |= 0x02; // Start - break; - case CELL_PAD_CTRL_SELECT: - buf[1] |= 0x01; // Select - break; - default: - break; + buf[2] = 0x05; // Left-Down D-Pad } + else + { + buf[2] = 0x04; // Down D-Pad + } + buf[10] = ~buf[10]; // Down D-Pad; + break; + case turntable_btn::dpad_up: + if (buf[2] == 0x02) // Right D-Pad + { + buf[2] = 0x01; // Right-Up D-Pad + } + else if (buf[2] == 0x06) // Left D-Pad + { + buf[2] = 0x07; // Left-Up D-Pad + } + else + { + buf[2] = 0x00; // Up D-Pad + } + buf[9] = ~buf[9]; // Up D-Pad; + break; + case turntable_btn::dpad_left: + if (buf[2] == 0x00) // Up D-Pad + { + buf[2] = 0x07; // Left-Up D-Pad + } + else if (buf[2] == 0x04) // Down D-Pad + { + buf[2] = 0x05; // Left-Down D-Pad + } + else + { + buf[2] = 0x06; // Left D-Pad + } + buf[8] = ~buf[8]; // Left D-Pad; + break; + case turntable_btn::dpad_right: + if (buf[2] == 0x00) // Up D-Pad + { + buf[2] = 0x01; // Right-Up D-Pad + } + else if (buf[2] == 0x04) // Down D-Pad + { + buf[2] = 0x03; // Right-Down D-Pad + } + else + { + buf[2] = 0x02; // Right D-Pad + } + buf[7] = ~buf[7]; // Right D-Pad + break; + case turntable_btn::start: + buf[1] |= 0x02; // Start + break; + case turntable_btn::select: + buf[1] |= 0x01; // Select + break; } } } + for (const AnalogStick& stick : pad->m_sticks) { switch (stick.m_offset) diff --git a/rpcs3/Emu/Io/Turntable.h b/rpcs3/Emu/Io/Turntable.h index 1d43cc5875..49c8de4e1e 100644 --- a/rpcs3/Emu/Io/Turntable.h +++ b/rpcs3/Emu/Io/Turntable.h @@ -1,16 +1,18 @@ #pragma once #include "Emu/Io/usb_device.h" +#include "Emu/Io/turntable_config.h" class usb_device_turntable : public usb_device_emulated { -private: - int m_controller_index; - public: - usb_device_turntable(int controller_index, const std::array& location); + usb_device_turntable(u32 controller_index, const std::array& location); ~usb_device_turntable(); void control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) override; void interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) override; + +private: + u32 m_controller_index; + cfg_turntables m_cfg; }; diff --git a/rpcs3/Emu/Io/turntable_config.cpp b/rpcs3/Emu/Io/turntable_config.cpp new file mode 100644 index 0000000000..2e59b3c298 --- /dev/null +++ b/rpcs3/Emu/Io/turntable_config.cpp @@ -0,0 +1,86 @@ +#include "stdafx.h" +#include "turntable_config.h" + +LOG_CHANNEL(turntable_log, "TURN"); + +std::optional cfg_turntable::find_button(u32 offset, u32 keycode) const +{ + if (const auto it = buttons.find(offset); it != buttons.cend()) + { + if (const auto it2 = it->second.find(keycode); it2 != it->second.cend()) + { + return it2->second; + } + } + + return std::nullopt; +} + +bool cfg_turntables::load() +{ + bool result = false; + const std::string cfg_name = fs::get_config_dir() + "config/turntable.yml"; + turntable_log.notice("Loading turntable config: %s", cfg_name); + + from_default(); + + for (cfg_turntable* player : players) + { + player->buttons.clear(); + } + + if (fs::file cfg_file{ cfg_name, fs::read }) + { + if (std::string content = cfg_file.to_string(); !content.empty()) + { + result = from_string(content); + } + } + else + { + save(); + } + + for (cfg_turntable* player : players) + { + const auto set_button = [&player](pad_button pbtn, turntable_btn bbtn) + { + const u32 offset = pad_button_offset(pbtn); + const u32 keycode = pad_button_keycode(pbtn); + player->buttons[(offset >> 8) & 0xFF][keycode & 0xFF] = bbtn; + }; + set_button(player->red, turntable_btn::red); + set_button(player->green, turntable_btn::green); + set_button(player->blue, turntable_btn::blue); + set_button(player->dpad_up, turntable_btn::dpad_up); + set_button(player->dpad_down, turntable_btn::dpad_down); + set_button(player->dpad_left, turntable_btn::dpad_left); + set_button(player->dpad_right, turntable_btn::dpad_right); + set_button(player->start, turntable_btn::start); + set_button(player->select, turntable_btn::select); + set_button(player->square, turntable_btn::square); + set_button(player->circle, turntable_btn::circle); + set_button(player->cross, turntable_btn::cross); + set_button(player->triangle, turntable_btn::triangle); + } + + return result; +} + +void cfg_turntables::save() const +{ + const std::string cfg_name = fs::get_config_dir() + "config/turntable.yml"; + turntable_log.notice("Saving turntable config to '%s'", cfg_name); + + if (!fs::create_path(fs::get_parent_dir(cfg_name))) + { + turntable_log.fatal("Failed to create path: %s (%s)", cfg_name, fs::g_tls_error); + } + + fs::pending_file cfg_file(cfg_name); + + if (!cfg_file.file || (cfg_file.file.write(to_string()), !cfg_file.commit())) + { + turntable_log.error("Failed to save turntable config to '%s' (error=%s)", cfg_name, fs::g_tls_error); + } +} diff --git a/rpcs3/Emu/Io/turntable_config.h b/rpcs3/Emu/Io/turntable_config.h new file mode 100644 index 0000000000..d7859e084c --- /dev/null +++ b/rpcs3/Emu/Io/turntable_config.h @@ -0,0 +1,61 @@ +#pragma once + +#include "Utilities/Config.h" +#include "pad_types.h" + +#include + +enum class turntable_btn +{ + red, + green, + blue, + dpad_up, + dpad_down, + dpad_left, + dpad_right, + start, + select, + square, + circle, + cross, + triangle +}; + +struct cfg_turntable final : cfg::node +{ + cfg_turntable(node* owner, const std::string& name) : cfg::node(owner, name) {} + + cfg::_enum blue{ this, "Blue", pad_button::square }; + cfg::_enum green{ this, "Green", pad_button::cross }; + cfg::_enum red{ this, "Red", pad_button::circle }; + cfg::_enum dpad_up{ this, "D-Pad Up", pad_button::dpad_up }; + cfg::_enum dpad_down{ this, "D-Pad Down", pad_button::dpad_down }; + cfg::_enum dpad_left{ this, "D-Pad Left", pad_button::dpad_left }; + cfg::_enum dpad_right{ this, "D-Pad Right", pad_button::dpad_right }; + cfg::_enum start{ this, "Start", pad_button::start }; + cfg::_enum select{ this, "Select", pad_button::select }; + cfg::_enum square{ this, "Square", pad_button::R2 }; + cfg::_enum circle{ this, "Circle", pad_button::L1 }; + cfg::_enum cross{ this, "Cross", pad_button::R1 }; + cfg::_enum triangle{ this, "Triangle", pad_button::triangle }; + + std::map> buttons; + std::optional find_button(u32 offset, u32 keycode) const; +}; + +struct cfg_turntables final : cfg::node +{ + cfg_turntable player1{ this, "Player 1" }; + cfg_turntable player2{ this, "Player 2" }; + cfg_turntable player3{ this, "Player 3" }; + cfg_turntable player4{ this, "Player 4" }; + cfg_turntable player5{ this, "Player 5" }; + cfg_turntable player6{ this, "Player 6" }; + cfg_turntable player7{ this, "Player 7" }; + + std::array players{ &player1, &player2, &player3, &player4, &player5, &player6, &player7 }; // Thanks gcc! + + bool load(); + void save() const; +}; diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index b65ebaf189..6829db4764 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -78,6 +78,7 @@ + @@ -519,6 +520,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index b71c865c22..738a423942 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -1168,6 +1168,9 @@ Emu\Io + + Emu\Io + @@ -2353,6 +2356,9 @@ Emu\Io + + Emu\Io +