From 7b9a36be7d827a44491bbd025c8dbc16c6e81707 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Sat, 20 May 2023 12:31:33 +0200 Subject: [PATCH] input: add buzz config file Adds a buzz.yml and implements a generic way to save actual DS3 mapping independent of pad handlers --- rpcs3/Emu/Cell/Modules/cellOskDialog.cpp | 2 +- rpcs3/Emu/Cell/lv2/sys_hid.cpp | 2 +- rpcs3/Emu/Io/Buzz.cpp | 35 ++++---- rpcs3/Emu/Io/Buzz.h | 2 + rpcs3/Emu/Io/buzz_config.cpp | 78 ++++++++++++++++ rpcs3/Emu/Io/buzz_config.h | 45 ++++++++++ rpcs3/Emu/Io/pad_types.cpp | 109 +++++++++++++++++++++++ rpcs3/Emu/Io/pad_types.h | 35 ++++++++ rpcs3/Emu/RSX/Overlays/overlays.cpp | 20 +++-- rpcs3/Emu/RSX/Overlays/overlays.h | 35 +------- rpcs3/emucore.vcxproj | 3 + rpcs3/emucore.vcxproj.filters | 9 ++ 12 files changed, 316 insertions(+), 59 deletions(-) create mode 100644 rpcs3/Emu/Io/buzz_config.cpp create mode 100644 rpcs3/Emu/Io/buzz_config.h create mode 100644 rpcs3/Emu/Io/pad_types.cpp diff --git a/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp b/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp index dec13d926e..5884bf4713 100644 --- a/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp +++ b/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp @@ -506,7 +506,7 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr dia // Prepare callback variables vm::var keyMessage(key_message); vm::var action(CELL_OSKDIALOG_CHANGE_NO_EVENT); - vm::var> pActionInfo(string_to_send.size(), string_to_send.data()); + vm::var> pActionInfo(::narrow(string_to_send.size()), string_to_send.data()); // Create helpers for logging std::u16string utf16_string(reinterpret_cast(string_to_send.data()), string_to_send.size()); diff --git a/rpcs3/Emu/Cell/lv2/sys_hid.cpp b/rpcs3/Emu/Cell/lv2/sys_hid.cpp index 6746c0dc0c..0f297eaafb 100644 --- a/rpcs3/Emu/Cell/lv2/sys_hid.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_hid.cpp @@ -35,7 +35,7 @@ error_code sys_hid_manager_open(u64 device_type, u64 port_no, vm::ptr handl if (device_type == 1) { cellPadInit(7); - cellPadSetPortSetting(port_no /* 0 */, CELL_PAD_SETTING_LDD | CELL_PAD_SETTING_PRESS_ON | CELL_PAD_SETTING_SENSOR_ON); + cellPadSetPortSetting(::narrow(port_no) /* 0 */, CELL_PAD_SETTING_LDD | CELL_PAD_SETTING_PRESS_ON | CELL_PAD_SETTING_SENSOR_ON); } return CELL_OK; diff --git a/rpcs3/Emu/Io/Buzz.cpp b/rpcs3/Emu/Io/Buzz.cpp index 2300363f8f..a8e4363e63 100644 --- a/rpcs3/Emu/Io/Buzz.cpp +++ b/rpcs3/Emu/Io/Buzz.cpp @@ -5,7 +5,7 @@ #include "Emu/Cell/lv2/sys_usbd.h" #include "Input/pad_thread.h" -LOG_CHANNEL(buzz_log); +LOG_CHANNEL(buzz_log, "BUZZ"); usb_device_buzz::usb_device_buzz(u32 first_controller, u32 last_controller, const std::array& location) : usb_device_emulated(location) @@ -17,6 +17,11 @@ usb_device_buzz::usb_device_buzz(u32 first_controller, u32 last_controller, cons config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, UsbDeviceInterface{0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00})); config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_HID, UsbDeviceHID{0x0111, 0x33, 0x01, 0x22, 0x004e})); config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x81, 0x03, 0x0008, 0x0A})); + + if (!m_cfg.load()) + { + buzz_log.notice("Could not load buzz config. Using defaults."); + } } usb_device_buzz::~usb_device_buzz() @@ -72,10 +77,12 @@ void usb_device_buzz::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpoint*/ const auto handler = pad::get_current_handler(); const auto& pads = handler->GetPads(); ensure(pads.size() > m_last_controller); + ensure(m_cfg.players.size() > m_last_controller); for (u32 i = m_first_controller, index = 0; i <= m_last_controller; i++, index++) { const auto& pad = pads[i]; + const cfg_buzzer* cfg = m_cfg.players[i]; if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) { @@ -89,26 +96,24 @@ void usb_device_buzz::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpoint*/ continue; } - if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL2) + if (const auto btn = cfg->find_button(button.m_offset, button.m_outKeyCode)) { - switch (button.m_outKeyCode) + switch (btn.value()) { - case CELL_PAD_CTRL_R1: + case buzz_btn::red: buf[2 + (0 + 5 * index) / 8] |= 1 << ((0 + 5 * index) % 8); // Red break; - case CELL_PAD_CTRL_TRIANGLE: - buf[2 + (4 + 5 * index) / 8] |= 1 << ((4 + 5 * index) % 8); // Blue - break; - case CELL_PAD_CTRL_SQUARE: - buf[2 + (3 + 5 * index) / 8] |= 1 << ((3 + 5 * index) % 8); // Orange - break; - case CELL_PAD_CTRL_CIRCLE: - buf[2 + (2 + 5 * index) / 8] |= 1 << ((2 + 5 * index) % 8); // Green - break; - case CELL_PAD_CTRL_CROSS: + case buzz_btn::yellow: buf[2 + (1 + 5 * index) / 8] |= 1 << ((1 + 5 * index) % 8); // Yellow break; - default: + case buzz_btn::green: + buf[2 + (2 + 5 * index) / 8] |= 1 << ((2 + 5 * index) % 8); // Green + break; + case buzz_btn::orange: + buf[2 + (3 + 5 * index) / 8] |= 1 << ((3 + 5 * index) % 8); // Orange + break; + case buzz_btn::blue: + buf[2 + (4 + 5 * index) / 8] |= 1 << ((4 + 5 * index) % 8); // Blue break; } } diff --git a/rpcs3/Emu/Io/Buzz.h b/rpcs3/Emu/Io/Buzz.h index 0515dbac71..42c1b9588c 100644 --- a/rpcs3/Emu/Io/Buzz.h +++ b/rpcs3/Emu/Io/Buzz.h @@ -1,6 +1,7 @@ #pragma once #include "Emu/Io/usb_device.h" +#include "Emu/Io/buzz_config.h" class usb_device_buzz : public usb_device_emulated { @@ -14,4 +15,5 @@ public: private: u32 m_first_controller; u32 m_last_controller; + cfg_buzz m_cfg; }; diff --git a/rpcs3/Emu/Io/buzz_config.cpp b/rpcs3/Emu/Io/buzz_config.cpp new file mode 100644 index 0000000000..9d2cdc1542 --- /dev/null +++ b/rpcs3/Emu/Io/buzz_config.cpp @@ -0,0 +1,78 @@ +#include "stdafx.h" +#include "buzz_config.h" + +LOG_CHANNEL(buzz_log, "BUZZ"); + +std::optional cfg_buzzer::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_buzz::load() +{ + bool result = false; + const std::string cfg_name = fs::get_config_dir() + "config/buzz.yml"; + buzz_log.notice("Loading buzz config: %s", cfg_name); + + from_default(); + + for (cfg_buzzer* 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_buzzer* player : players) + { + const auto set_button = [&player](pad_button pbtn, buzz_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, buzz_btn::red); + set_button(player->yellow, buzz_btn::yellow); + set_button(player->green, buzz_btn::green); + set_button(player->orange, buzz_btn::orange); + set_button(player->blue, buzz_btn::blue); + } + + return result; +} + +void cfg_buzz::save() const +{ + const std::string cfg_name = fs::get_config_dir() + "config/buzz.yml"; + buzz_log.notice("Saving buzz config to '%s'", cfg_name); + + if (!fs::create_path(fs::get_parent_dir(cfg_name))) + { + buzz_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())) + { + buzz_log.error("Failed to save buzz config to '%s' (error=%s)", cfg_name, fs::g_tls_error); + } +} diff --git a/rpcs3/Emu/Io/buzz_config.h b/rpcs3/Emu/Io/buzz_config.h new file mode 100644 index 0000000000..c350880a13 --- /dev/null +++ b/rpcs3/Emu/Io/buzz_config.h @@ -0,0 +1,45 @@ +#pragma once + +#include "Utilities/Config.h" +#include "pad_types.h" + +#include + +enum class buzz_btn +{ + red, + yellow, + green, + orange, + blue +}; + +struct cfg_buzzer final : cfg::node +{ + cfg_buzzer(node* owner, const std::string& name) : cfg::node(owner, name) {} + + cfg::_enum red{ this, "Red", pad_button::R1 }; + cfg::_enum yellow{ this, "Yellow", pad_button::cross }; + cfg::_enum green{ this, "Green", pad_button::circle }; + cfg::_enum orange{ this, "Orange", pad_button::square }; + cfg::_enum blue{ this, "Blue", pad_button::triangle }; + + std::map> buttons; + std::optional find_button(u32 offset, u32 keycode) const; +}; + +struct cfg_buzz final : cfg::node +{ + cfg_buzzer player1{ this, "Player 1" }; + cfg_buzzer player2{ this, "Player 2" }; + cfg_buzzer player3{ this, "Player 3" }; + cfg_buzzer player4{ this, "Player 4" }; + cfg_buzzer player5{ this, "Player 5" }; + cfg_buzzer player6{ this, "Player 6" }; + cfg_buzzer 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/Emu/Io/pad_types.cpp b/rpcs3/Emu/Io/pad_types.cpp new file mode 100644 index 0000000000..777aca182e --- /dev/null +++ b/rpcs3/Emu/Io/pad_types.cpp @@ -0,0 +1,109 @@ +#include "stdafx.h" +#include "pad_types.h" + +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](pad_button value) + { + switch (value) + { + case pad_button::dpad_up: return "D-Pad Up"; + case pad_button::dpad_down: return "D-Pad Down"; + case pad_button::dpad_left: return "D-Pad Left"; + case pad_button::dpad_right: return "D-Pad Right"; + case pad_button::select: return "Select"; + case pad_button::start: return "Start"; + case pad_button::ps: return "PS"; + case pad_button::triangle: return "Triangle"; + case pad_button::circle: return "Circle"; + case pad_button::square: return "Square"; + case pad_button::cross: return "Cross"; + case pad_button::L1: return "L1"; + case pad_button::R1: return "R1"; + case pad_button::L2: return "L2"; + case pad_button::R2: return "R2"; + case pad_button::L3: return "L3"; + case pad_button::R3: return "R3"; + case pad_button::ls_up: return "Left Stick Up"; + case pad_button::ls_down: return "Left Stick Down"; + case pad_button::ls_left: return "Left Stick Left"; + case pad_button::ls_right: return "Left Stick Right"; + case pad_button::rs_up: return "Right Stick Up"; + case pad_button::rs_down: return "Right Stick Down"; + case pad_button::rs_left: return "Right Stick Left"; + case pad_button::rs_right: return "Right Stick Right"; + case pad_button::pad_button_max_enum: return unknown; + } + + return unknown; + }); +} + +u32 pad_button_offset(pad_button button) +{ + switch (button) + { + case pad_button::dpad_up: return CELL_PAD_BTN_OFFSET_DIGITAL1; + case pad_button::dpad_down: return CELL_PAD_BTN_OFFSET_DIGITAL1; + case pad_button::dpad_left: return CELL_PAD_BTN_OFFSET_DIGITAL1; + case pad_button::dpad_right: return CELL_PAD_BTN_OFFSET_DIGITAL1; + case pad_button::select: return CELL_PAD_BTN_OFFSET_DIGITAL1; + case pad_button::start: return CELL_PAD_BTN_OFFSET_DIGITAL1; + case pad_button::ps: return CELL_PAD_BTN_OFFSET_DIGITAL1; + case pad_button::triangle: return CELL_PAD_BTN_OFFSET_DIGITAL2; + case pad_button::circle: return CELL_PAD_BTN_OFFSET_DIGITAL2; + case pad_button::square: return CELL_PAD_BTN_OFFSET_DIGITAL2; + case pad_button::cross: return CELL_PAD_BTN_OFFSET_DIGITAL2; + case pad_button::L1: return CELL_PAD_BTN_OFFSET_DIGITAL2; + case pad_button::R1: return CELL_PAD_BTN_OFFSET_DIGITAL2; + case pad_button::L2: return CELL_PAD_BTN_OFFSET_DIGITAL2; + case pad_button::R2: return CELL_PAD_BTN_OFFSET_DIGITAL2; + case pad_button::L3: return CELL_PAD_BTN_OFFSET_DIGITAL1; + case pad_button::R3: return CELL_PAD_BTN_OFFSET_DIGITAL1; + case pad_button::ls_up: return CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y; + case pad_button::ls_down: return CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y; + case pad_button::ls_left: return CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X; + case pad_button::ls_right: return CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X; + case pad_button::rs_up: return CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y; + case pad_button::rs_down: return CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y; + case pad_button::rs_left: return CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X; + case pad_button::rs_right: return CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X; + case pad_button::pad_button_max_enum: return 0; + } + return 0; +} + +u32 pad_button_keycode(pad_button button) +{ + switch (button) + { + case pad_button::dpad_up: return CELL_PAD_CTRL_UP; + case pad_button::dpad_down: return CELL_PAD_CTRL_DOWN; + case pad_button::dpad_left: return CELL_PAD_CTRL_LEFT; + case pad_button::dpad_right: return CELL_PAD_CTRL_RIGHT; + case pad_button::select: return CELL_PAD_CTRL_SELECT; + case pad_button::start: return CELL_PAD_CTRL_START; + case pad_button::ps: return CELL_PAD_CTRL_PS; + case pad_button::triangle: return CELL_PAD_CTRL_TRIANGLE; + case pad_button::circle: return CELL_PAD_CTRL_CIRCLE; + case pad_button::square: return CELL_PAD_CTRL_SQUARE; + case pad_button::cross: return CELL_PAD_CTRL_CROSS; + case pad_button::L1: return CELL_PAD_CTRL_L1; + case pad_button::R1: return CELL_PAD_CTRL_R1; + case pad_button::L2: return CELL_PAD_CTRL_L2; + case pad_button::R2: return CELL_PAD_CTRL_R2; + case pad_button::L3: return CELL_PAD_CTRL_L3; + case pad_button::R3: return CELL_PAD_CTRL_R3; + case pad_button::ls_up: return 0; + case pad_button::ls_down: return 0; + case pad_button::ls_left: return 0; + case pad_button::ls_right: return 0; + case pad_button::rs_up: return 0; + case pad_button::rs_down: return 0; + case pad_button::rs_left: return 0; + case pad_button::rs_right: return 0; + case pad_button::pad_button_max_enum: return 0; + } + return 0; +} diff --git a/rpcs3/Emu/Io/pad_types.h b/rpcs3/Emu/Io/pad_types.h index cef93797e6..ef15276040 100644 --- a/rpcs3/Emu/Io/pad_types.h +++ b/rpcs3/Emu/Io/pad_types.h @@ -6,6 +6,41 @@ #include +enum class pad_button : u8 +{ + dpad_up = 0, + dpad_down, + dpad_left, + dpad_right, + select, + start, + ps, + triangle, + circle, + square, + cross, + L1, + R1, + L2, + R2, + L3, + R3, + + ls_up, + ls_down, + ls_left, + ls_right, + rs_up, + rs_down, + rs_left, + rs_right, + + pad_button_max_enum +}; + +u32 pad_button_offset(pad_button button); +u32 pad_button_keycode(pad_button button); + enum SystemInfo { CELL_PAD_INFO_INTERCEPTED = 0x00000001 diff --git a/rpcs3/Emu/RSX/Overlays/overlays.cpp b/rpcs3/Emu/RSX/Overlays/overlays.cpp index 9b3a58b552..f9230b6b39 100644 --- a/rpcs3/Emu/RSX/Overlays/overlays.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlays.cpp @@ -59,10 +59,10 @@ namespace rsx std::array initial_timestamp; initial_timestamp.fill(steady_clock::now()); - std::array last_auto_repeat_button; + std::array last_auto_repeat_button; last_auto_repeat_button.fill(pad_button::pad_button_max_enum); - std::array, CELL_PAD_MAX_PORT_NUM> last_button_state; + std::array(pad_button::pad_button_max_enum)>, CELL_PAD_MAX_PORT_NUM> last_button_state; for (auto& state : last_button_state) { // Initialize last button states as pressed to avoid unwanted button presses when entering the dialog. @@ -77,18 +77,20 @@ namespace rsx input::SetIntercepted(true); } - const auto handle_button_press = [&](u8 button_id, bool pressed, int pad_index) + const auto handle_button_press = [&](pad_button button_id, bool pressed, int pad_index) { if (button_id >= pad_button::pad_button_max_enum) { return; } + bool& last_state = last_button_state[pad_index][static_cast(button_id)]; + if (pressed) { const bool is_auto_repeat_button = m_auto_repeat_buttons.contains(button_id); - if (!last_button_state[pad_index][button_id]) + if (!last_state) { // The button was not pressed before, so this is a new button press. Reset auto-repeat. timestamp[pad_index] = steady_clock::now(); @@ -113,13 +115,13 @@ namespace rsx } } } - else if (last_button_state[pad_index][button_id] && last_auto_repeat_button[pad_index] == button_id) + else if (last_state && last_auto_repeat_button[pad_index] == button_id) { // We stopped pressing an auto-repeat button, so re-enable auto-repeat for other buttons. last_auto_repeat_button[pad_index] = pad_button::pad_button_max_enum; } - last_button_state[pad_index][button_id] = pressed; + last_state = pressed; }; while (!m_stop_input_loop) @@ -239,7 +241,7 @@ namespace rsx for (const Button& button : pad->m_buttons) { - u8 button_id = pad_button::pad_button_max_enum; + pad_button button_id = pad_button::pad_button_max_enum; if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL1) { switch (button.m_outKeyCode) @@ -316,8 +318,8 @@ namespace rsx for (const AnalogStick& stick : pad->m_sticks) { - u8 button_id = pad_button::pad_button_max_enum; - u8 release_id = pad_button::pad_button_max_enum; + pad_button button_id = pad_button::pad_button_max_enum; + pad_button release_id = pad_button::pad_button_max_enum; // Let's say sticks are only pressed if they are almost completely tilted. Otherwise navigation feels really wacky. const bool pressed = stick.m_value < 30 || stick.m_value > 225; diff --git a/rpcs3/Emu/RSX/Overlays/overlays.h b/rpcs3/Emu/RSX/Overlays/overlays.h index 1814d2fac4..05a2074e8d 100644 --- a/rpcs3/Emu/RSX/Overlays/overlays.h +++ b/rpcs3/Emu/RSX/Overlays/overlays.h @@ -3,6 +3,7 @@ #include "overlay_controls.h" #include "Emu/IdManager.h" +#include "Emu/Io/pad_types.h" #include "Utilities/mutex.h" #include "Utilities/Timer.h" @@ -18,38 +19,6 @@ namespace rsx { namespace overlays { - enum pad_button : u8 - { - dpad_up = 0, - dpad_down, - dpad_left, - dpad_right, - select, - start, - ps, - triangle, - circle, - square, - cross, - L1, - R1, - L2, - R2, - L3, - R3, - - ls_up, - ls_down, - ls_left, - ls_right, - rs_up, - rs_down, - rs_left, - rs_right, - - pad_button_max_enum - }; - // Bitfield of UI signals to overlay manager enum status_bits : u32 { @@ -96,7 +65,7 @@ namespace rsx protected: Timer m_input_timer; u64 m_auto_repeat_ms_interval = m_auto_repeat_ms_interval_default; - std::set m_auto_repeat_buttons = { + std::set m_auto_repeat_buttons = { pad_button::dpad_up, pad_button::dpad_down, pad_button::dpad_left, diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 9bea91eca1..b65ebaf189 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -68,8 +68,10 @@ + + @@ -504,6 +506,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 250a857259..b71c865c22 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -1162,6 +1162,12 @@ Emu\Io + + Emu\Io + + + Emu\Io + @@ -2344,6 +2350,9 @@ Emu\Io + + Emu\Io +