From e297c8cc64bbb4b2b2c74208a2e12ae7ac6d0837 Mon Sep 17 00:00:00 2001 From: Ani Date: Sat, 27 Jun 2026 21:47:33 +0200 Subject: [PATCH 1/6] settings: Default "Show shader compilation hint" to disabled --- rpcs3/Emu/system_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index ea7de326f8..83fc51f0af 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -366,7 +366,7 @@ struct cfg_root : cfg::node cfg::_bool prevent_display_sleep{ this, "Prevent display sleep while running games", true, true }; cfg::_bool show_trophy_popups{ this, "Show trophy popups", true, true }; cfg::_bool show_rpcn_popups{ this, "Show RPCN popups", true, true }; - cfg::_bool show_shader_compilation_hint{ this, "Show shader compilation hint", true, true }; + cfg::_bool show_shader_compilation_hint{ this, "Show shader compilation hint", false, true }; cfg::_bool show_ppu_compilation_hint{ this, "Show PPU compilation hint", true, true }; cfg::_bool show_autosave_autoload_hint{ this, "Show autosave/autoload hint", false, true }; cfg::_bool show_pressure_intensity_toggle_hint{ this, "Show pressure intensity toggle hint", true, true }; From 2f0daa62fc87004685e55ae728122f8cc2b75cf6 Mon Sep 17 00:00:00 2001 From: Ani Date: Sat, 27 Jun 2026 21:45:47 +0200 Subject: [PATCH 2/6] settings: Default Shader Mode to "Async with Shader Interpreter" --- rpcs3/Emu/system_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index 83fc51f0af..c431ee2f5a 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -126,7 +126,7 @@ struct cfg_root : cfg::node cfg::_enum frame_limit{ this, "Frame limit", frame_limit_type::_auto, true }; cfg::_float<0, 1000> second_frame_limit{ this, "Second Frame Limit", 0, true }; // 0 disables its effect cfg::_enum antialiasing_level{ this, "MSAA", msaa_level::_auto }; - cfg::_enum shadermode{ this, "Shader Mode", shader_mode::async_recompiler }; + cfg::_enum shadermode{ this, "Shader Mode", shader_mode::async_with_interpreter }; cfg::_enum shader_precision{ this, "Shader Precision", gpu_preset_level::high }; cfg::_enum vsync{ this, "VSync Mode", vsync_mode::off, true }; From f5e8a2bfa987f4cb7a2a8a58c2abc0ee788aed82 Mon Sep 17 00:00:00 2001 From: Ani Date: Mon, 29 Jun 2026 18:31:48 +0200 Subject: [PATCH 3/6] misc: Update README and metainfo --- README.md | 2 +- rpcs3/rpcs3.metainfo.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8ccf4f12ce..351688be64 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ The world's first free and open-source PlayStation 3 emulator/debugger, written You can find some basic information on our [**website**](https://rpcs3.net/). Game info is being populated on the [**Wiki**](https://wiki.rpcs3.net/). For discussion about this emulator, PS3 emulation, and game compatibility reports, please visit our [**forums**](https://forums.rpcs3.net) and our [**Discord server**](https://discord.gg/RPCS3). -[**Support Lead Developers Nekotekina and kd-11 on Patreon**](https://www.patreon.com/Nekotekina) +[**Support the Lead Developers on Patreon**](https://rpcs3.net/patreon) ## Contributing diff --git a/rpcs3/rpcs3.metainfo.xml b/rpcs3/rpcs3.metainfo.xml index 327c90c0f2..3449f39c7f 100644 --- a/rpcs3/rpcs3.metainfo.xml +++ b/rpcs3/rpcs3.metainfo.xml @@ -29,7 +29,7 @@ Most of this information can be found on the PlayStation 3 Developer Wiki.

https://github.com/RPCS3/rpcs3/issues https://rpcs3.net/faq https://rpcs3.net/quickstart - https://www.patreon.com/Nekotekina + https://rpcs3.net/patreon https://github.com/RPCS3/rpcs3 https://github.com/RPCS3/rpcs3#contributing From bec42ea93e2e7c8af82f82fb173843ecf3f83674 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Tue, 23 Jun 2026 08:04:31 +0200 Subject: [PATCH 4/6] Linux: get unshifted Qt keys --- rpcs3/CMakeLists.txt | 2 +- rpcs3/Emu/Cell/Modules/cellKb.cpp | 2 +- rpcs3/Emu/Io/KeyboardHandler.h | 6 +- rpcs3/Input/basic_keyboard_handler.cpp | 85 +++++++++++++++++++++++--- rpcs3/Input/basic_keyboard_handler.h | 2 +- 5 files changed, 84 insertions(+), 13 deletions(-) diff --git a/rpcs3/CMakeLists.txt b/rpcs3/CMakeLists.txt index fee8fa4327..373017197a 100644 --- a/rpcs3/CMakeLists.txt +++ b/rpcs3/CMakeLists.txt @@ -81,7 +81,7 @@ if (NOT ANDROID) # Unix display manager if(X11_FOUND) - target_link_libraries(rpcs3_lib PRIVATE X11::X11) + target_link_libraries(rpcs3_lib PRIVATE X11::X11 xkbcommon-x11) elseif(USE_VULKAN AND UNIX AND NOT WAYLAND_FOUND AND NOT APPLE AND NOT ANDROID) # Wayland has been checked in 3rdparty/CMakeLists.txt already. message(FATAL_ERROR "RPCS3 requires either X11 or Wayland (or both) for Vulkan.") diff --git a/rpcs3/Emu/Cell/Modules/cellKb.cpp b/rpcs3/Emu/Cell/Modules/cellKb.cpp index 0682d32fc8..adfa849bfb 100644 --- a/rpcs3/Emu/Cell/Modules/cellKb.cpp +++ b/rpcs3/Emu/Cell/Modules/cellKb.cpp @@ -381,7 +381,7 @@ error_code cellKbRead(u32 port_no, vm::ptr data) data->keycode[i] = current_data.buttons[i].m_keyCode; } - KbConfig& current_config = consumer.GetConfig(port_no); + const KbConfig& current_config = consumer.GetConfig(port_no); // For single character mode to work properly we need to "flush" the buffer after reading or else we'll constantly get the same key presses with each call. // Actual key repeats are handled by adding a new key code to the buffer periodically. Key releases are handled in a similar fashion. diff --git a/rpcs3/Emu/Io/KeyboardHandler.h b/rpcs3/Emu/Io/KeyboardHandler.h index 594f7be3f8..2a5261ff8b 100644 --- a/rpcs3/Emu/Io/KeyboardHandler.h +++ b/rpcs3/Emu/Io/KeyboardHandler.h @@ -128,9 +128,9 @@ public: KbInfo& GetInfo() { return m_info; } std::vector& GetKeyboards() { return m_keyboards; } - KbData& GetData(const u32 keyboard) { return m_keyboards[keyboard].m_data; } - KbExtraData& GetExtraData(const u32 keyboard) { return m_keyboards[keyboard].m_extra_data; } - KbConfig& GetConfig(const u32 keyboard) { return m_keyboards[keyboard].m_config; } + KbData& GetData(const u32 keyboard) { return ::at32(m_keyboards, keyboard).m_data; } + KbExtraData& GetExtraData(const u32 keyboard) { return ::at32(m_keyboards, keyboard).m_extra_data; } + KbConfig& GetConfig(const u32 keyboard) { return ::at32(m_keyboards, keyboard).m_config; } identifier id() const { return m_id; } void ReleaseAllKeys(); diff --git a/rpcs3/Input/basic_keyboard_handler.cpp b/rpcs3/Input/basic_keyboard_handler.cpp index 3fa7acf876..a40190f3e8 100644 --- a/rpcs3/Input/basic_keyboard_handler.cpp +++ b/rpcs3/Input/basic_keyboard_handler.cpp @@ -7,6 +7,11 @@ #ifdef _WIN32 #include "windows.h" +#elif __linux__ +#include +#include +#include +#include #endif LOG_CHANNEL(input_log, "Input"); @@ -44,7 +49,7 @@ void basic_keyboard_handler::Init(keyboard_consumer& consumer, const u32 max_con /* Sets the target window for the event handler, and also installs an event filter on the target. */ void basic_keyboard_handler::SetTargetWindow(QWindow* target) { - if (target != nullptr) + if (target) { m_target = target; target->installEventFilter(this); @@ -119,7 +124,7 @@ void basic_keyboard_handler::keyPressEvent(QKeyEvent* keyEvent) return; } - const int key = getUnmodifiedKey(keyEvent); + const int key = get_unmodified_key(keyEvent); if (key < 0 || !HandleKey(static_cast(key), keyEvent->nativeScanCode(), true, keyEvent->isAutoRepeat(), keyEvent->text().toStdU32String())) { @@ -140,7 +145,7 @@ void basic_keyboard_handler::keyReleaseEvent(QKeyEvent* keyEvent) return; } - const int key = getUnmodifiedKey(keyEvent); + const int key = get_unmodified_key(keyEvent); if (key < 0 || !HandleKey(static_cast(key), keyEvent->nativeScanCode(), false, keyEvent->isAutoRepeat(), keyEvent->text().toStdU32String())) { @@ -149,8 +154,10 @@ void basic_keyboard_handler::keyReleaseEvent(QKeyEvent* keyEvent) } // This should get the actual unmodified key without getting too crazy. -// key() only shows the modifiers and the modified key (e.g. no easy way of knowing that - was pressed in 'SHIFT+-' in order to get _) -s32 basic_keyboard_handler::getUnmodifiedKey(QKeyEvent* keyEvent) +// key() only shows the modifiers and the modified key. +// e.g. 'Shift+1' may result in Qt::Key_Exclam, so we lose the information that Qt::Key_1 was pressed. +// We want to find the actual physical key that was pressed (and return Qt::Key_1 in this example). +s32 basic_keyboard_handler::get_unmodified_key(QKeyEvent* keyEvent) { if (!keyEvent) [[unlikely]] { @@ -166,9 +173,9 @@ s32 basic_keyboard_handler::getUnmodifiedKey(QKeyEvent* keyEvent) u32 raw_key = static_cast(key); -#ifdef _WIN32 if (keyEvent->modifiers() != Qt::NoModifier && !keyEvent->text().isEmpty()) { +#ifdef _WIN32 u32 mapped_key = static_cast(MapVirtualKeyA(static_cast(keyEvent->nativeVirtualKey()), MAPVK_VK_TO_CHAR)); if (raw_key != mapped_key) @@ -179,8 +186,72 @@ s32 basic_keyboard_handler::getUnmodifiedKey(QKeyEvent* keyEvent) } raw_key = mapped_key; } - } +#elif __linux__ + class kb_mapper + { + public: + kb_mapper() + { + m_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + } + + ~kb_mapper() + { + if (m_ctx) xkb_context_unref(m_ctx); + } + + s32 get_unmodified_key(u32 qt_native_scan_code) + { + if (!m_ctx) return -1; + + auto* connection = get_connection(); + if (!connection) return -1; + + const int device_id = xkb_x11_get_core_keyboard_device_id(connection); + + xkb_keymap* keymap = xkb_x11_keymap_new_from_device(m_ctx, connection, device_id, XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) return -1; + + xkb_state* state = xkb_x11_state_new_from_device(keymap, connection, device_id); + if (!state) + { + xkb_keymap_unref(keymap); + return -1; + } + + const xkb_keycode_t code = static_cast(qt_native_scan_code); + const xkb_layout_index_t layout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_EFFECTIVE); + const xkb_keysym_t* syms = nullptr; + const int count = xkb_keymap_key_get_syms_by_level(keymap, code, layout, 0, &syms); + + const auto new_key = (syms && count > 0) ? QXkbCommon::keysymToQtKey(syms[0], Qt::NoModifier, nullptr, code) : -1; + + xkb_state_unref(state); + xkb_keymap_unref(keymap); + + return new_key; + } + + private: + xcb_connection_t* get_connection() + { + if (!qGuiApp) return nullptr; + auto* native_interface = qGuiApp->nativeInterface(); + return native_interface ? native_interface->connection() : nullptr; + } + + xkb_context* m_ctx = nullptr; + }; + + static kb_mapper mapper = kb_mapper(); + if (const int res = mapper.get_unmodified_key(keyEvent->nativeScanCode()); res > 0) + { + raw_key = res; + } +#elif __APPLE__ + // TODO #endif + } return static_cast(raw_key); } diff --git a/rpcs3/Input/basic_keyboard_handler.h b/rpcs3/Input/basic_keyboard_handler.h index 284890025f..353d054834 100644 --- a/rpcs3/Input/basic_keyboard_handler.h +++ b/rpcs3/Input/basic_keyboard_handler.h @@ -17,7 +17,7 @@ public: bool eventFilter(QObject* watched, QEvent* event) override; void keyPressEvent(QKeyEvent* event); void keyReleaseEvent(QKeyEvent* event); - static s32 getUnmodifiedKey(QKeyEvent* event); + static s32 get_unmodified_key(QKeyEvent* event); private: void LoadSettings(Keyboard& keyboard); From 8c89adf17704c0e12811531ee1aa38f29e3dbd3d Mon Sep 17 00:00:00 2001 From: silvatyrant Date: Tue, 30 Jun 2026 20:21:49 +0200 Subject: [PATCH 5/6] macOS: DJ Hero Turntable support (deck buttons, passthrough conflict) (#18957) --- rpcs3/Emu/Cell/lv2/sys_usbd.cpp | 11 +++++++++++ rpcs3/Input/sdl_pad_handler.cpp | 8 +++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/rpcs3/Emu/Cell/lv2/sys_usbd.cpp b/rpcs3/Emu/Cell/lv2/sys_usbd.cpp index b84e3457cf..1362d106b5 100644 --- a/rpcs3/Emu/Cell/lv2/sys_usbd.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_usbd.cpp @@ -391,6 +391,17 @@ void usb_handler_thread::perform_scan() && desc.idProduct >= entry.id_product_min && desc.idProduct <= entry.id_product_max) { +#ifdef __APPLE__ + // On macOS, libusb cannot claim HID interfaces, so passing through a real + // controller that also has an emulated implementation yields a non-functional + // device and silently overrides the user's emulated-device setting (the emulated + // setup below only fills slots not already passed through). Prefer the emulated + // implementation whenever the user has enabled it. (e.g. DJ Hero Turntable) + if (entry.make_instance && entry.max_device_count && entry.max_device_count() > 0) + { + continue; + } +#endif sys_usbd.success("Found device: %s", std::basic_string(entry.device_name)); libusb_ref_device(dev); std::shared_ptr usb_dev = std::make_shared(dev, desc, get_new_location()); diff --git a/rpcs3/Input/sdl_pad_handler.cpp b/rpcs3/Input/sdl_pad_handler.cpp index 099de9000e..76c1c3a9db 100644 --- a/rpcs3/Input/sdl_pad_handler.cpp +++ b/rpcs3/Input/sdl_pad_handler.cpp @@ -341,7 +341,13 @@ SDLDevice::sdl_info sdl_pad_handler::get_sdl_info(SDL_JoystickID id) 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; + // The DJ Hero Turntable (VID 0x12BA, PID 0x0140) coincidentally matches the + // DS3 axis/button counts (16 axes, 11 buttons) but is NOT a pressure-sensitive + // DS3. Routing its face buttons through the pressure axes drops the green (Cross) + // and blue (Square) deck buttons, so exclude it and read its buttons digitally. + const bool is_dj_hero_turntable = info.vid == 0x12BA && info.pid == 0x0140; + + info.is_ds3_with_pressure_buttons = num_axes == 16 && num_buttons == 11 && !is_dj_hero_turntable; 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); From 67ee6c1ab9482015907d1300468ec7d52cc1dc67 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Tue, 30 Jun 2026 19:53:22 +0200 Subject: [PATCH 6/6] Fix OOB in Dimensions --- rpcs3/Emu/Io/Dimensions.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/rpcs3/Emu/Io/Dimensions.cpp b/rpcs3/Emu/Io/Dimensions.cpp index fb3327779d..179be8ef3c 100644 --- a/rpcs3/Emu/Io/Dimensions.cpp +++ b/rpcs3/Emu/Io/Dimensions.cpp @@ -530,11 +530,10 @@ bool dimensions_toypad::create_blank_character(std::array& buf, std::array dimensions_toypad::pwd_generate(const std::array& uid) { - std::vector pwd_calc = {PWD_CONSTANT.begin(), PWD_CONSTANT.end() - 1}; - for (u8 i = 0; i < uid.size(); i++) - { - pwd_calc.insert(pwd_calc.begin() + i, uid[i]); - } + std::vector pwd_calc; + pwd_calc.reserve(uid.size() + PWD_CONSTANT.size()); + pwd_calc.insert(pwd_calc.end(), uid.begin(), uid.end()); + pwd_calc.insert(pwd_calc.end(), PWD_CONSTANT.begin(), PWD_CONSTANT.end()); return dimensions_randomize(pwd_calc, 8); }