diff --git a/rpcs3/Emu/Cell/Modules/cellPad.cpp b/rpcs3/Emu/Cell/Modules/cellPad.cpp index 663235c160..5182ed4869 100644 --- a/rpcs3/Emu/Cell/Modules/cellPad.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPad.cpp @@ -5,6 +5,7 @@ #include "Emu/Io/pad_types.h" #include "Input/pad_thread.h" +#include "Input/product_info.h" #include "cellPad.h" LOG_CHANNEL(sys_io); @@ -636,43 +637,40 @@ error_code cellPadGetInfo(vm::ptr info) pads[i]->m_port_status &= ~CELL_PAD_STATUS_ASSIGN_CHANGES; // TODO: should ASSIGN flags be cleared here? info->status[i] = pads[i]->m_port_status; - // TODO: Allow selecting different product IDs - switch (pads[i]->m_class_type) + if (pads[i]->m_vendor_id == 0 || pads[i]->m_product_id == 0) { - case CELL_PAD_PCLASS_TYPE_GUITAR: - // Sony Computer Entertainment America - info->vendor_id[i] = 0x12BA; - // RedOctane Guitar (Guitar Hero) - info->product_id[i] = 0x0100; - // Harmonix Guitar (Rock Band) - // info->product_id[i] = 0x0200; - break; - case CELL_PAD_PCLASS_TYPE_DRUM: - // Sony Computer Entertainment America - info->vendor_id[i] = 0x12BA; - // RedOctane Drum Kit (Guitar Hero) - info->product_id[i] = 0x0120; - // Harmonix Drum Kit (Rock Band) - // info->product_id[i] = 0x0210; - break; - case CELL_PAD_PCLASS_TYPE_DJ: - // Sony Computer Entertainment America - info->vendor_id[i] = 0x12BA; - // DJ Hero Turntable - info->product_id[i] = 0x0140; - break; - case CELL_PAD_PCLASS_TYPE_DANCEMAT: - // Konami Digital Entertainment - info->vendor_id[i] = 0x1CCF; - // Dance Dance Revolution Mat - info->product_id[i] = 0x0140; - break; - default: - // Sony Corp. - info->vendor_id[i] = 0x054C; - // PlayStation 3 Controller - info->product_id[i] = 0x0268; - break; + // Fallback to defaults + + input::product_info product; + + switch (pads[i]->m_class_type) + { + case CELL_PAD_PCLASS_TYPE_GUITAR: + product = input::get_product_info(input::product_type::red_octane_gh_guitar); + break; + case CELL_PAD_PCLASS_TYPE_DRUM: + product = input::get_product_info(input::product_type::red_octane_gh_drum_kit); + break; + case CELL_PAD_PCLASS_TYPE_DJ: + product = input::get_product_info(input::product_type::dj_hero_turntable); + break; + case CELL_PAD_PCLASS_TYPE_DANCEMAT: + product = input::get_product_info(input::product_type::dance_dance_revolution_mat); + break; + case CELL_PAD_PCLASS_TYPE_NAVIGATION: + case CELL_PAD_PCLASS_TYPE_STANDARD: + default: + product = input::get_product_info(input::product_type::playstation_3_controller); + break; + } + + info->vendor_id[i] = product.vendor_id; + info->product_id[i] = product.product_id; + } + else + { + info->vendor_id[i] = pads[i]->m_vendor_id; + info->product_id[i] = pads[i]->m_product_id; } } @@ -927,8 +925,18 @@ error_code cellPadLddRegisterController() if (handle < 0) return CELL_PAD_ERROR_TOO_MANY_DEVICES; + const auto product = input::get_product_info(input::product_type::playstation_3_controller); + auto& pads = handler->GetPads(); - pads[handle]->Init(CELL_PAD_STATUS_CONNECTED | CELL_PAD_STATUS_ASSIGN_CHANGES | CELL_PAD_STATUS_CUSTOM_CONTROLLER, CELL_PAD_CAPABILITY_PS3_CONFORMITY, CELL_PAD_DEV_TYPE_LDD, 0); + pads[handle]->Init + ( + CELL_PAD_STATUS_CONNECTED | CELL_PAD_STATUS_ASSIGN_CHANGES | CELL_PAD_STATUS_CUSTOM_CONTROLLER, + CELL_PAD_CAPABILITY_PS3_CONFORMITY, + CELL_PAD_DEV_TYPE_LDD, + CELL_PAD_PCLASS_TYPE_STANDARD, + product.vendor_id, + product.product_id + ); config->port_setting[handle] = 0; return not_an_error(handle); diff --git a/rpcs3/Emu/Io/PadHandler.cpp b/rpcs3/Emu/Io/PadHandler.cpp index 0d11bebca8..74fc7fa765 100644 --- a/rpcs3/Emu/Io/PadHandler.cpp +++ b/rpcs3/Emu/Io/PadHandler.cpp @@ -434,7 +434,9 @@ bool PadHandlerBase::bindPadToDevice(std::shared_ptr pad, const std::string CELL_PAD_STATUS_DISCONNECTED, CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_HP_ANALOG_STICK | CELL_PAD_CAPABILITY_ACTUATOR | CELL_PAD_CAPABILITY_SENSOR_MODE, CELL_PAD_DEV_TYPE_STANDARD, - profile->device_class_type + profile->device_class_type, + profile->vendor_id, + profile->product_id ); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, mapping[button::up], CELL_PAD_CTRL_UP); diff --git a/rpcs3/Emu/Io/pad_config.h b/rpcs3/Emu/Io/pad_config.h index c7abe7f602..eab99d5aaf 100644 --- a/rpcs3/Emu/Io/pad_config.h +++ b/rpcs3/Emu/Io/pad_config.h @@ -94,6 +94,8 @@ struct pad_config final : cfg::node cfg::_int<0, 100> trigger_lerp_factor{ this, "Trigger Lerp Factor", 100 }; cfg::_int<0, 5> device_class_type{ this, "Device Class Type", 0 }; + cfg::_int<0, 65535> vendor_id{ this, "Vendor ID", 0 }; + cfg::_int<0, 65535> product_id{ this, "Product ID", 0 }; bool exist(); bool load(); diff --git a/rpcs3/Emu/Io/pad_types.h b/rpcs3/Emu/Io/pad_types.h index 17c08b6c7c..eddb56a967 100644 --- a/rpcs3/Emu/Io/pad_types.h +++ b/rpcs3/Emu/Io/pad_types.h @@ -181,6 +181,9 @@ struct Pad u32 m_device_type; u32 m_class_type; + u16 m_vendor_id; + u16 m_product_id; + // Cable State: 0 - 1 plugged in ? u8 m_cable_state; @@ -226,12 +229,14 @@ struct Pad bool ldd = false; u8 ldd_data[132] = {}; - void Init(u32 port_status, u32 device_capability, u32 device_type, u32 class_type) + void Init(u32 port_status, u32 device_capability, u32 device_type, u32 class_type, u16 vendor_id, u16 product_id) { m_port_status = port_status; m_device_capability = device_capability; m_device_type = device_type; m_class_type = class_type; + m_vendor_id = vendor_id; + m_product_id = product_id; } Pad(u32 port_status, u32 device_capability, u32 device_type) @@ -240,6 +245,8 @@ struct Pad , m_device_capability(device_capability) , m_device_type(device_type) , m_class_type(0) + , m_vendor_id(0) + , m_product_id(0) , m_cable_state(0) , m_battery_level(0) diff --git a/rpcs3/Input/evdev_joystick_handler.cpp b/rpcs3/Input/evdev_joystick_handler.cpp index d5471a3e45..8a5516d0b2 100644 --- a/rpcs3/Input/evdev_joystick_handler.cpp +++ b/rpcs3/Input/evdev_joystick_handler.cpp @@ -927,7 +927,9 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, const std CELL_PAD_STATUS_DISCONNECTED, CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_HP_ANALOG_STICK | CELL_PAD_CAPABILITY_ACTUATOR | CELL_PAD_CAPABILITY_SENSOR_MODE, CELL_PAD_DEV_TYPE_STANDARD, - p_profile->device_class_type + p_profile->device_class_type, + p_profile->vendor_id, + p_profile->product_id ); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->triangle), CELL_PAD_CTRL_TRIANGLE); diff --git a/rpcs3/Input/keyboard_pad_handler.cpp b/rpcs3/Input/keyboard_pad_handler.cpp index 49490fd853..32ec899306 100644 --- a/rpcs3/Input/keyboard_pad_handler.cpp +++ b/rpcs3/Input/keyboard_pad_handler.cpp @@ -612,7 +612,9 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr pad, const std:: CELL_PAD_STATUS_DISCONNECTED, CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_HP_ANALOG_STICK | CELL_PAD_CAPABILITY_ACTUATOR | CELL_PAD_CAPABILITY_SENSOR_MODE, CELL_PAD_DEV_TYPE_STANDARD, - p_profile->device_class_type + p_profile->device_class_type, + p_profile->vendor_id, + p_profile->product_id ); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->left), CELL_PAD_CTRL_LEFT); diff --git a/rpcs3/Input/product_info.h b/rpcs3/Input/product_info.h new file mode 100644 index 0000000000..651d4484b5 --- /dev/null +++ b/rpcs3/Input/product_info.h @@ -0,0 +1,130 @@ +#pragma once + +#include + +namespace input +{ + enum class product_type + { + playstation_3_controller, + red_octane_gh_guitar, + red_octane_gh_drum_kit, + dance_dance_revolution_mat, + dj_hero_turntable, + harmonix_rockband_guitar, + harmonix_rockband_drum_kit, + }; + + enum vendor_id + { + sony_corp = 0x054C, // Sony Corp. + sony_cea = 0x12BA, // Sony Computer Entertainment America + konami_de = 0x1CCF, // Konami Digital Entertainment + }; + + enum product_id + { + red_octane_gh_guitar = 0x0100, // RedOctane Guitar (Guitar Hero) + red_octane_gh_drum_kit = 0x0120, // RedOctane Drum Kit (Guitar Hero) + dance_dance_revolution_mat = 0x0140, // Dance Dance Revolution Mat + dj_hero_turntable = 0x0140, // DJ Hero Turntable + harmonix_rockband_guitar = 0x0200, // Harmonix Guitar (Rock Band) + harmonix_rockband_drum_kit = 0x0210, // Harmonix Drum Kit (Rock Band) + playstation_3_controller = 0x0268, // PlayStation 3 Controller + }; + + struct product_info + { + product_type type; + uint16_t vendor_id; + uint16_t product_id; + }; + + static product_info get_product_info(product_type type) + { + switch (type) + { + default: + case product_type::playstation_3_controller: + { + return product_info{ type, vendor_id::sony_corp, product_id::playstation_3_controller }; + } + case product_type::dance_dance_revolution_mat: + { + return product_info{ type, vendor_id::konami_de, product_id::dance_dance_revolution_mat }; + } + case product_type::dj_hero_turntable: + { + return product_info{ type, vendor_id::sony_cea, product_id::dj_hero_turntable }; + } + case product_type::harmonix_rockband_drum_kit: + { + return product_info{ type, vendor_id::sony_cea, product_id::harmonix_rockband_drum_kit }; + } + case product_type::harmonix_rockband_guitar: + { + return product_info{ type, vendor_id::sony_cea, product_id::harmonix_rockband_guitar }; + } + case product_type::red_octane_gh_drum_kit: + { + return product_info{ type, vendor_id::sony_cea, product_id::red_octane_gh_drum_kit }; + } + case product_type::red_octane_gh_guitar: + { + return product_info{ type, vendor_id::sony_cea, product_id::red_octane_gh_guitar }; + } + } + } + + static std::vector get_products_by_class(int class_id) + { + switch (class_id) + { + default: + case 0: // CELL_PAD_PCLASS_TYPE_STANDARD + { + return + { + get_product_info(product_type::playstation_3_controller) + }; + } + case 1: // CELL_PAD_PCLASS_TYPE_GUITAR + { + return + { + get_product_info(product_type::red_octane_gh_guitar), + get_product_info(product_type::harmonix_rockband_guitar) + }; + } + case 2: // CELL_PAD_PCLASS_TYPE_DRUM + { + return + { + get_product_info(product_type::red_octane_gh_drum_kit), + get_product_info(product_type::harmonix_rockband_drum_kit) + }; + } + case 3: // CELL_PAD_PCLASS_TYPE_DJ + { + return + { + get_product_info(product_type::dj_hero_turntable) + }; + } + case 4: // CELL_PAD_PCLASS_TYPE_DANCEMAT + { + return + { + get_product_info(product_type::dance_dance_revolution_mat) + }; + } + case 5: // CELL_PAD_PCLASS_TYPE_NAVIGATION + { + return + { + get_product_info(product_type::playstation_3_controller) + }; + } + } + } +}; diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 01a2263abb..cfa5868caf 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -1904,6 +1904,7 @@ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent" + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 3631977385..1767dd75b2 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -1140,6 +1140,9 @@ Gui\settings + + Io + diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.cpp b/rpcs3/rpcs3qt/pad_settings_dialog.cpp index 9a069525ef..0204c6808d 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/pad_settings_dialog.cpp @@ -15,6 +15,7 @@ #include "Emu/Io/Null/NullPadHandler.h" +#include "Input/product_info.h" #include "Input/keyboard_pad_handler.h" #include "Input/ds3_pad_handler.h" #include "Input/ds4_pad_handler.h" @@ -187,6 +188,8 @@ pad_settings_dialog::pad_settings_dialog(QWidget *parent, const GameInfo *game) ui->chooseClass->addItem(tr("Dance Mat")); // CELL_PAD_PCLASS_TYPE_DANCEMAT = 0x04, ui->chooseClass->addItem(tr("Navigation")); // CELL_PAD_PCLASS_TYPE_NAVIGATION = 0x05, + connect(ui->chooseClass, QOverload::of(&QComboBox::currentIndexChanged), this, &pad_settings_dialog::HandleDeviceClassChange); + // Initialize configurable buttons InitButtons(); @@ -527,6 +530,20 @@ void pad_settings_dialog::ReloadButtons() ui->chooseClass->setCurrentIndex(m_handler_cfg.device_class_type); + // Trigger the change manually in case that the class dropdown didn't fire an event + HandleDeviceClassChange(ui->chooseClass->currentIndex()); + + const auto products = input::get_products_by_class(m_handler_cfg.device_class_type); + + for (size_t i = 0; i < products.size(); i++) + { + if (products[i].vendor_id == m_handler_cfg.vendor_id && products[i].product_id == m_handler_cfg.product_id) + { + ui->chooseProduct->setCurrentIndex(static_cast(i)); + break; + } + } + // Enable Mouse Deadzones std::vector mouse_dz_range_x = m_handler_cfg.mouse_deadzone_x.to_list(); ui->mouse_dz_x->setRange(std::stoi(mouse_dz_range_x.front()), std::stoi(mouse_dz_range_x.back())); @@ -620,6 +637,7 @@ void pad_settings_dialog::ReactivateButtons() ui->chooseHandler->setFocusPolicy(Qt::WheelFocus); ui->chooseDevice->setFocusPolicy(Qt::WheelFocus); ui->chooseClass->setFocusPolicy(Qt::WheelFocus); + ui->chooseProduct->setFocusPolicy(Qt::WheelFocus); } void pad_settings_dialog::RepaintPreviewLabel(QLabel* l, int deadzone, int desired_width, int x, int y) @@ -926,6 +944,7 @@ void pad_settings_dialog::OnPadButtonClicked(int id) ui->chooseHandler->setFocusPolicy(Qt::ClickFocus); ui->chooseDevice->setFocusPolicy(Qt::ClickFocus); ui->chooseClass->setFocusPolicy(Qt::ClickFocus); + ui->chooseProduct->setFocusPolicy(Qt::ClickFocus); m_last_pos = QCursor::pos(); @@ -1086,6 +1105,7 @@ void pad_settings_dialog::ChangeInputType() bool config_enabled = force_enable || (m_handler->m_type != pad_handler::null && ui->chooseDevice->count() > 0); ui->chooseDevice->setEnabled(config_enabled); ui->chooseClass->setEnabled(config_enabled); + ui->chooseProduct->setEnabled(config_enabled); if (config_enabled) { @@ -1212,6 +1232,59 @@ void pad_settings_dialog::ChangeProfile() } } +void pad_settings_dialog::HandleDeviceClassChange(int index) +{ + if (index < 0) + { + return; + } + + ui->chooseProduct->clear(); + + for (const auto& product : input::get_products_by_class(index)) + { + switch (product.type) + { + default: + case input::product_type::playstation_3_controller: + { + ui->chooseProduct->addItem(tr("PS3 Controller", "PlayStation 3 Controller"), static_cast(product.type)); + break; + } + case input::product_type::dance_dance_revolution_mat: + { + ui->chooseProduct->addItem(tr("Dance Dance Revolution", "Dance Dance Revolution Mat"), static_cast(product.type)); + break; + } + case input::product_type::dj_hero_turntable: + { + ui->chooseProduct->addItem(tr("DJ Hero Turntable", "DJ Hero Turntable"), static_cast(product.type)); + break; + } + case input::product_type::harmonix_rockband_drum_kit: + { + ui->chooseProduct->addItem(tr("Rockband", "Harmonix Rockband Drum Kit"), static_cast(product.type)); + break; + } + case input::product_type::harmonix_rockband_guitar: + { + ui->chooseProduct->addItem(tr("Rockband", "Harmonix Rockband Guitar"), static_cast(product.type)); + break; + } + case input::product_type::red_octane_gh_drum_kit: + { + ui->chooseProduct->addItem(tr("Guitar Hero", "RedOctane Guitar Hero Drum Kit"), static_cast(product.type)); + break; + } + case input::product_type::red_octane_gh_guitar: + { + ui->chooseProduct->addItem(tr("Guitar Hero", "RedOctane Guitar Hero Guitar"), static_cast(product.type)); + break; + } + } + } +} + void pad_settings_dialog::RefreshInputTypes() { const auto& handler = g_cfg_input.player[m_tabs->currentIndex()]->handler; @@ -1264,6 +1337,11 @@ void pad_settings_dialog::SaveProfile() m_handler_cfg.device_class_type.set(ui->chooseClass->currentIndex()); + const auto info = input::get_product_info(static_cast(ui->chooseProduct->currentData().toInt())); + + m_handler_cfg.vendor_id.set(info.vendor_id); + m_handler_cfg.product_id.set(info.product_id); + m_handler_cfg.save(); } diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.h b/rpcs3/rpcs3qt/pad_settings_dialog.h index 0372148b98..c159879da0 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.h +++ b/rpcs3/rpcs3qt/pad_settings_dialog.h @@ -98,6 +98,7 @@ private Q_SLOTS: void OnTabChanged(int index); void RefreshInputTypes(); void ChangeInputType(); + void HandleDeviceClassChange(int index); /** Save the Pad Configuration to the current Pad Handler Config File */ void SaveProfile(); void SaveExit(); diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.ui b/rpcs3/rpcs3qt/pad_settings_dialog.ui index a16a02db37..698a4892b2 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.ui +++ b/rpcs3/rpcs3qt/pad_settings_dialog.ui @@ -1471,10 +1471,25 @@ Device Class: - - + + + 5 + + + 5 + + + 5 + + + 5 + + + + + @@ -1490,6 +1505,18 @@ Battery status and LED + + 5 + + + 5 + + + 5 + + + 5 +