Keep the layout combination out of the title's hands

sco: the button that steps through screen layouts also reaches the game,
so switching layout fires whatever the title has bound to L3, R3, the
shoulders or Select at the same time.

The frame a combination fires in is now a frame the title sees no input at
all: the GamePad state is cleared after it is built, and the two accessors
the Wii Remotes read through answer empty for that frame as well. A flag
rather than per-button bookkeeping, which is what sco asked for and is
enough here - the combinations are deliberately unusual, so a pad holding
one meant the layout change and nothing else.
This commit is contained in:
WizzardSK committed 2026-09-20 16:00:32 +02:00
1 parent 01a804d02a
commit e7e33340d8
1 file changed
+32
+32
View File
@@ -635,6 +635,13 @@ enum class LibretroLayoutButton
};
static LibretroLayoutButton s_next_layout_button = LibretroLayoutButton::None;
static bool s_next_layout_button_held = false;
// Set for the one frame a layout combination fires in. Every button in those
// combinations means something to a title as well - L3, R3, the shoulders,
// Select - so without this a layout change also fires whatever the game has on
// them. The combinations are deliberately unusual, so anything holding them
// meant the layout change and nothing else; dropping the whole frame's input is
// enough and needs no per-button bookkeeping.
static bool s_layout_switched_this_frame = false;
static retro_hw_render_callback s_hw_render{};
@@ -4591,6 +4598,8 @@ static void libretro_poll_input()
input_poll_cb();
s_layout_switched_this_frame = false;
// Raw pad state for the ports that drive something, for the Wii Remotes
// behind InputManager - and for the GamePad below, which is built from
// port 0 rather than asking the frontend the same twenty questions a
@@ -4658,7 +4667,10 @@ static void libretro_poll_input()
{
const bool down = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_TAB) != 0;
if (down && !s_next_layout_button_held)
{
libretro_next_screen_layout();
s_layout_switched_this_frame = true;
}
s_next_layout_button_held = down;
}
else if (s_next_layout_button != LibretroLayoutButton::None)
@@ -4683,10 +4695,26 @@ static void libretro_poll_input()
break;
}
if (down && !s_next_layout_button_held)
{
libretro_next_screen_layout();
s_layout_switched_this_frame = true;
}
s_next_layout_button_held = down;
}
// The frame the layout changed in is the frame the title does not see. The
// pad state above is already built, so it is cleared here rather than
// guarded at every assignment, and the accessors the Wii Remotes read
// through answer the same way for this frame.
if (s_layout_switched_this_frame)
{
std::memset(state.buttons, 0, sizeof(state.buttons));
state.left_x = 0;
state.left_y = 0;
state.right_x = 0;
state.right_y = 0;
}
// Touchscreen (mouse/pointer mapped to GamePad touchscreen)
state.touch_pressed = input_state_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED) != 0;
if (state.touch_pressed)
@@ -4701,6 +4729,8 @@ static void libretro_poll_input()
bool libretro_get_button_state(uint32_t button_id)
{
if (s_layout_switched_this_frame)
return false;
if (button_id >= VPADController::kButtonId_Max)
return false;
return s_input_state.buttons[button_id] != 0;
@@ -4710,6 +4740,8 @@ bool libretro_get_button_state(uint32_t button_id)
bool libretro_get_joypad_button(uint32_t port, uint32_t retro_id)
{
if (s_layout_switched_this_frame)
return false;
if (port >= kLibretroMaxPorts || retro_id >= 16)
return false;
return s_port_state[port].buttons[retro_id] != 0;