mirror of
https://github.com/izzy2lost/xenia-edge.git
synced 2026-07-06 00:20:26 -07:00
[HID/UI] Ensure guide button closes dialogs / button presses consumed
Should prevent button close actions to carry into the game when dialogs are closed with controller inputs
This commit is contained in:
@@ -127,7 +127,20 @@ X_RESULT InputSystem::GetState(uint32_t user_index, uint32_t flags,
|
||||
return X_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
return GetStateForUI(user_index, flags, out_state);
|
||||
X_RESULT result = GetStateForUI(user_index, flags, out_state);
|
||||
|
||||
// Handle consumed buttons - these are buttons that were held when a UI dialog
|
||||
// closed. We mask them from the game until they are released.
|
||||
if (result == X_ERROR_SUCCESS && user_index < XUserMaxUserCount &&
|
||||
consumed_buttons_[user_index] != 0) {
|
||||
uint16_t buttons = out_state->gamepad.buttons;
|
||||
// Update consumed_buttons_ to only include buttons still being held
|
||||
consumed_buttons_[user_index] &= buttons;
|
||||
// Mask consumed buttons from the output
|
||||
out_state->gamepad.buttons = buttons & ~consumed_buttons_[user_index];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
X_RESULT InputSystem::GetStateForUI(uint32_t user_index, uint32_t flags,
|
||||
@@ -157,7 +170,19 @@ X_RESULT InputSystem::GetStateForUI(uint32_t user_index, uint32_t flags,
|
||||
|
||||
void InputSystem::AddUIInputBlocker() { ui_input_blockers_.fetch_add(1); }
|
||||
|
||||
void InputSystem::RemoveUIInputBlocker() { ui_input_blockers_.fetch_sub(1); }
|
||||
void InputSystem::RemoveUIInputBlocker() {
|
||||
// Before removing the blocker, capture any currently pressed buttons.
|
||||
// These will be masked from game input until they are released, preventing
|
||||
// the button press that closed the UI from carrying over into the game.
|
||||
X_INPUT_STATE state;
|
||||
for (uint32_t user_index = 0; user_index < XUserMaxUserCount; user_index++) {
|
||||
if (GetStateForUI(user_index, 1, &state) == X_ERROR_SUCCESS) {
|
||||
consumed_buttons_[user_index] |= state.gamepad.buttons;
|
||||
}
|
||||
}
|
||||
|
||||
ui_input_blockers_.fetch_sub(1);
|
||||
}
|
||||
|
||||
X_RESULT InputSystem::SetState(uint32_t user_index,
|
||||
X_INPUT_VIBRATION* vibration) {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#ifndef XENIA_HID_INPUT_SYSTEM_H_
|
||||
#define XENIA_HID_INPUT_SYSTEM_H_
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <bitset>
|
||||
#include <memory>
|
||||
@@ -96,6 +97,11 @@ class InputSystem {
|
||||
|
||||
// Reference count for UI elements blocking game input
|
||||
std::atomic<int> ui_input_blockers_{0};
|
||||
|
||||
// Buttons that should be masked from game input until released (per slot).
|
||||
// This prevents button presses used to close UI dialogs from being
|
||||
// seen by the game immediately after the dialog closes.
|
||||
std::array<uint16_t, XUserMaxUserCount> consumed_buttons_{};
|
||||
};
|
||||
|
||||
} // namespace hid
|
||||
|
||||
@@ -46,6 +46,16 @@ ContextMenuWidgetQt::ContextMenuWidgetQt(QWidget* parent,
|
||||
// Block input to the game while this menu is open
|
||||
input_system_->AddUIInputBlocker();
|
||||
|
||||
// Initialize prev_buttons_ to current state so held buttons aren't
|
||||
// detected as "just pressed" when the menu opens
|
||||
hid::X_INPUT_STATE state;
|
||||
for (uint32_t user_index = 0; user_index < 4; user_index++) {
|
||||
if (input_system_->GetStateForUI(user_index, 1, &state) == 0) {
|
||||
prev_buttons_ = state.gamepad.buttons;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
poll_timer_ = new QTimer(this);
|
||||
connect(poll_timer_, &QTimer::timeout, this,
|
||||
&ContextMenuWidgetQt::PollGamepad);
|
||||
@@ -257,8 +267,8 @@ void ContextMenuWidgetQt::PollGamepad() {
|
||||
ActivateFocusedItem();
|
||||
}
|
||||
|
||||
// B button to close
|
||||
if (pressed & 0x2000) {
|
||||
// B button, Back button, or Guide button to close
|
||||
if (pressed & (0x2000 | 0x0020 | 0x0400)) {
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
@@ -115,6 +115,9 @@ void GamepadDialog::PollGamepad() {
|
||||
if (pressed & 0x0020) { // Back button
|
||||
OnGamepadBack();
|
||||
}
|
||||
if (pressed & 0x0400) { // Guide button
|
||||
OnGamepadGuide();
|
||||
}
|
||||
|
||||
// D-pad navigation with repeat
|
||||
// First press (edge detection)
|
||||
|
||||
@@ -44,6 +44,7 @@ class GamepadDialog : public QDialog {
|
||||
virtual void OnGamepadButtonY() {}
|
||||
virtual void OnGamepadStart() { AcceptFocusedButton(); }
|
||||
virtual void OnGamepadBack() { reject(); }
|
||||
virtual void OnGamepadGuide() { reject(); }
|
||||
|
||||
// Override to customize which widgets are focusable
|
||||
virtual bool IsWidgetGamepadFocusable(QWidget* widget) const;
|
||||
|
||||
Reference in New Issue
Block a user