Configurable Gamepad Inputs for Mini Menu (#1320)

* Updating for main menu ( mini menu ) gamepad button masks

* Added Mini Menu gamepad input as a web configurable option.

This means we can use a toggle on the gamepad settings page / in the board config for allowing the mini menu to be controlled by the gamepad (directional, B1/B2).

A user will still have to set Menu Toggle using the pins in web config, but this gets us much closer.

Also cleaned a little bit of code.

* Duelpad Zen does not need gamepad mini menu input as we have dedicated pins!

* Removed comment

* Missed adding the mini menu option to the webconfig

* Disable mini menu gamepad input by default

* Removed some leftover code
This commit is contained in:
Luke A
2025-03-24 19:16:40 -04:00
committed by GitHub
parent 1ed4f638b9
commit 84cc1c131b
11 changed files with 61 additions and 19 deletions

View File

@@ -40,6 +40,7 @@
#define GPIO_PIN_03 GpioAction::BUTTON_PRESS_MACRO_2
#define MINI_MENU_GAMEPAD_INPUT 0 // Disable Gamepad Input for Mini Menu
// Keyboard Mapping Configuration
// // GP2040 | Xinput | Switch | PS3/4/5 | Dinput | Arcade |

View File

@@ -81,6 +81,7 @@ class MainMenuScreen : public GPScreen {
std::vector<MenuEntry>* currentMenu;
std::vector<MenuEntry>* previousMenu;
uint16_t prevButtonState = 0;
uint8_t prevDpadState = 0;
Mask_t prevValues;
GPMenu* gpMenu;
const uint8_t menuLineSize = 4;

View File

@@ -136,7 +136,6 @@ public:
void setSOCDMode(SOCDMode socdMode) { options.socdMode = socdMode; }
void setDpadMode(DpadMode dpadMode) { options.dpadMode = dpadMode; }
GamepadState rawState;
GamepadState state;
GamepadState turboState;
GamepadAuxState auxState;

View File

@@ -36,6 +36,7 @@ message GamepadOptions
optional bool usbOverrideID = 29;
optional uint32 usbProductID = 30;
optional uint32 usbVendorID = 31;
optional uint32 miniMenuGamepadInput = 32;
}
message KeyboardMapping

View File

@@ -172,6 +172,10 @@
#define DEFAULT_USB_PRODUCT_ID 0x82C0
#endif
#ifndef MINI_MENU_GAMEPAD_INPUT
#define MINI_MENU_GAMEPAD_INPUT 0
#endif
#ifndef GPIO_PIN_00
#define GPIO_PIN_00 GpioAction::NONE
#endif
@@ -311,6 +315,7 @@ void ConfigUtils::initUnsetPropertiesWithDefaults(Config& config)
INIT_UNSET_PROPERTY(config.gamepadOptions, usbOverrideID, DEFAULT_USB_ID_OVERRIDE);
INIT_UNSET_PROPERTY(config.gamepadOptions, usbVendorID, DEFAULT_USB_VENDOR_ID);
INIT_UNSET_PROPERTY(config.gamepadOptions, usbProductID, DEFAULT_USB_PRODUCT_ID);
INIT_UNSET_PROPERTY(config.gamepadOptions, miniMenuGamepadInput, MINI_MENU_GAMEPAD_INPUT);
// hotkeyOptions
HotkeyOptions& hotkeyOptions = config.hotkeyOptions;

View File

@@ -691,6 +691,7 @@ std::string setGamepadOptions()
readDoc(gamepadOptions.xinputAuthType, doc, "xinputAuthType");
readDoc(gamepadOptions.ps4ControllerIDMode, doc, "ps4ControllerIDMode");
readDoc(gamepadOptions.usbDescOverride, doc, "usbDescOverride");
readDoc(gamepadOptions.miniMenuGamepadInput, doc, "miniMenuGamepadInput");
// Copy USB descriptor strings
size_t strSize = sizeof(gamepadOptions.usbDescManufacturer);
strncpy(gamepadOptions.usbDescManufacturer, doc["usbDescManufacturer"], strSize - 1);
@@ -762,6 +763,7 @@ std::string getGamepadOptions()
writeDoc(doc, "usbDescProduct", gamepadOptions.usbDescProduct);
writeDoc(doc, "usbDescVersion", gamepadOptions.usbDescVersion);
writeDoc(doc, "usbOverrideID", gamepadOptions.usbOverrideID);
writeDoc(doc, "miniMenuGamepadInput", gamepadOptions.miniMenuGamepadInput);
// Write USB Vendor ID and Product ID as 4 character hex strings with 0 padding
char usbVendorStr[5];
snprintf(usbVendorStr, 5, "%04X", gamepadOptions.usbVendorID);

View File

@@ -23,12 +23,12 @@ void MainMenuScreen::init() {
gpMenu->setMenuTitle(MAIN_MENU_NAME);
addElement(gpMenu);
mapMenuUp = new GamepadButtonMapping(0);
mapMenuDown = new GamepadButtonMapping(0);
mapMenuLeft = new GamepadButtonMapping(0);
mapMenuRight = new GamepadButtonMapping(0);
mapMenuSelect = new GamepadButtonMapping(0);
mapMenuBack = new GamepadButtonMapping(0);
mapMenuUp = new GamepadButtonMapping(GAMEPAD_MASK_UP);
mapMenuDown = new GamepadButtonMapping(GAMEPAD_MASK_DOWN);
mapMenuLeft = new GamepadButtonMapping(GAMEPAD_MASK_LEFT);
mapMenuRight = new GamepadButtonMapping(GAMEPAD_MASK_RIGHT);
mapMenuSelect = new GamepadButtonMapping(GAMEPAD_MASK_B1);
mapMenuBack = new GamepadButtonMapping(GAMEPAD_MASK_B2);
mapMenuToggle = new GamepadButtonMapping(0);
// populate the profiles menu
@@ -126,23 +126,38 @@ void MainMenuScreen::setMenuHome() {
int8_t MainMenuScreen::update() {
if (isMenuReady) {
Gamepad * gamepad = Storage::getInstance().GetGamepad();
GamepadOptions & gamepadOptions = Storage::getInstance().getGamepadOptions();
Mask_t values = Storage::getInstance().GetGamepad()->debouncedGpio;
uint16_t buttonState = getGamepad()->state.buttons;
uint8_t dpadState = getGamepad()->state.dpad;
if (!isPressed && prevValues != values) {
if (values & mapMenuUp->pinMask) updateMenuNavigation(GpioAction::MENU_NAVIGATION_UP);
if (values & mapMenuDown->pinMask) updateMenuNavigation(GpioAction::MENU_NAVIGATION_DOWN);
if (values & mapMenuLeft->pinMask) updateMenuNavigation(GpioAction::MENU_NAVIGATION_LEFT);
if (values & mapMenuRight->pinMask) updateMenuNavigation(GpioAction::MENU_NAVIGATION_RIGHT);
if (values & mapMenuSelect->pinMask) updateMenuNavigation(GpioAction::MENU_NAVIGATION_SELECT);
if (values & mapMenuBack->pinMask) updateMenuNavigation(GpioAction::MENU_NAVIGATION_BACK);
if (!isPressed) {
if (prevValues != values) {
if (values & mapMenuUp->pinMask) updateMenuNavigation(GpioAction::MENU_NAVIGATION_UP);
else if (values & mapMenuDown->pinMask) updateMenuNavigation(GpioAction::MENU_NAVIGATION_DOWN);
else if (values & mapMenuLeft->pinMask) updateMenuNavigation(GpioAction::MENU_NAVIGATION_LEFT);
else if (values & mapMenuRight->pinMask) updateMenuNavigation(GpioAction::MENU_NAVIGATION_RIGHT);
else if (values & mapMenuSelect->pinMask) updateMenuNavigation(GpioAction::MENU_NAVIGATION_SELECT);
else if (values & mapMenuBack->pinMask) updateMenuNavigation(GpioAction::MENU_NAVIGATION_BACK);
}
if (gamepadOptions.miniMenuGamepadInput == true ) {
if (prevDpadState != dpadState ) {
if (dpadState == mapMenuUp->buttonMask) updateMenuNavigation(GpioAction::MENU_NAVIGATION_UP);
else if (dpadState == mapMenuDown->buttonMask) updateMenuNavigation(GpioAction::MENU_NAVIGATION_DOWN);
else if (dpadState == mapMenuLeft->buttonMask) updateMenuNavigation(GpioAction::MENU_NAVIGATION_LEFT);
else if (dpadState == mapMenuRight->buttonMask) updateMenuNavigation(GpioAction::MENU_NAVIGATION_RIGHT);
}
if ( prevButtonState != buttonState ) {
if (buttonState == mapMenuSelect->buttonMask) updateMenuNavigation(GpioAction::MENU_NAVIGATION_SELECT);
else if (buttonState == mapMenuBack->buttonMask) updateMenuNavigation(GpioAction::MENU_NAVIGATION_BACK);
}
}
} else {
isPressed = false;
isPressed = false; // Flip isPressed to false
}
prevButtonState = buttonState;
prevDpadState = dpadState;
prevValues = values;
if ((exitToScreen != -1) && ((changeRequiresSave) || (changeRequiresReboot))) {

View File

@@ -248,8 +248,6 @@ void Gamepad::reinit()
void Gamepad::process()
{
memcpy(&rawState, &state, sizeof(GamepadState));
// Get the midpoint value for the current mode
uint16_t joystickMid = GAMEPAD_JOYSTICK_MID;
if ( DriverManager::getInstance().getDriver() != nullptr ) {

View File

@@ -134,6 +134,7 @@ app.get('/api/getGamepadOptions', (req, res) => {
usbOverrideID: 0,
usbVendorID: '10C4',
usbProductID: '82C0',
miniMenuGamepadInput: 1,
hotkey01: {
auxMask: 32768,
buttonsMask: 66304,

View File

@@ -57,6 +57,7 @@ export default {
},
'profile-label': 'Profile',
'debounce-delay-label': 'Debounce Delay in milliseconds',
'mini-menu-gamepad-input': 'Use Gamepad Input for Display Mini Menu',
'ps4-mode-explanation-text':
'PS4 mode allows GP2040-CE to run as an authenticated PS4 controller.',
'ps4-mode-warning-text':

View File

@@ -407,6 +407,7 @@ const schema = yup.object().shape({
.oneOf(AUTHENTICATION_TYPES.map((o) => o.value))
.label('X-Input Authentication Type'),
debounceDelay: yup.number().required().label('Debounce Delay'),
miniMenuGamepadInput: yup.number().required().label('Mini Menu'),
inputModeB1: yup
.number()
.required()
@@ -1603,6 +1604,23 @@ export default function SettingsPage() {
/>
</Col>
</Form.Group>
<Form.Group className="row mb-5">
<Col sm={5}>
<Form.Check
label={t('SettingsPage:mini-menu-gamepad-input')}
type="switch"
id="miniMenuGamepadInput"
isInvalid={false}
checked={Boolean(values.miniMenuGamepadInput)}
onChange={(e) => {
setFieldValue(
'miniMenuGamepadInput',
e.target.checked ? 1 : 0,
);
}}
/>
</Col>
</Form.Group>
<Button type="submit">
{t('Common:button-save-label')}
</Button>