SDL2与其他工具间PS4手柄按键编号不兼容问题求助
问题分析与解决方案
一、SDL2及代码存在的问题
- Joystick模式的本质:SDL的
JoystickAPI读取的是手柄硬件的原始输入编号,不同厂商的手柄原始按键布局差异很大——PS4手柄的L1/R1原始编号就是9/10,这是硬件本身的输入定义,而非SDL的问题。 - 代码逻辑错误:你在
Joystick模式下调用了SDL_GameControllerGetStringForButton,这个函数是为GameControllerAPI设计的,它会把SDL_GameControllerButton枚举值转换成字符串,而非将原始Joystick按键ID映射到标准按键。强行转换会导致逻辑混乱,因为两者的编号体系完全无关。
二、获取与其他工具一致的按键编号的方法
其他工具(Windows内置控制器工具、网页测试工具)采用的是XInput标准按键布局(Windows平台通用的游戏手柄输入标准),要拿到一致的编号,有两种可行方案:
方案1:改用SDL GameController模式(推荐)
SDL的GameController API会自动将不同厂商的手柄输入映射到统一的XInput标准布局,L1/R1会对应标准编号4/5,和其他工具完全一致。修改代码如下:
SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS); SDL_GameControllerEventState(SDL_ENABLE); SDL_Event event; while(SDL_WaitEventTimeout(&event, 50)) { switch(event.type){ case SDL_CONTROLLERDEVICEADDED: m_GameController = SDL_GameControllerOpen(event.cdevice.which); break; case SDL_CONTROLLERBUTTONDOWN: case SDL_CONTROLLERBUTTONUP: qDebug() << "ControllerButton(" << QString(SDL_GameControllerGetStringForButton(event.cbutton.button)) << ")" << event.cbutton.button << " -> " << event.cbutton.state; break; } }
该方案无需手动适配不同手柄,SDL会自动处理映射,通用性更强。
方案2:手动建立原始按键到XInput的映射表(仅适用于固定手柄型号)
若必须坚持使用Joystick模式,需针对PS4手柄的原始按键ID,手动映射到XInput标准编号。示例代码如下:
// PS4手柄原始按键ID -> XInput标准编号(与其他工具一致) std::unordered_map<int, int> ps4ToXInputBtnMap = { {0, 0}, // 交叉键X -> A {1, 1}, // 圆圈O -> B {2, 2}, // 方块□ -> X {3, 3}, // 三角△ -> Y {9, 4}, // L1 -> Left Shoulder {10, 5}, // R1 -> Right Shoulder // 补充其他按键的映射,比如L2/R2、摇杆按键等 }; // 在处理Joystick按键事件时转换编号 case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: auto it = ps4ToXInputBtnMap.find(event.jbutton.button); int standardBtnId = (it != ps4ToXInputBtnMap.end()) ? it->second : -1; qDebug() << "原始按键ID:" << event.jbutton.button << "标准按键ID:" << standardBtnId << "状态:" << event.jbutton.state; break;
注意:该方案仅适用于固定型号的手柄,更换其他手柄需重新调整映射表,维护成本较高。
内容的提问来源于stack exchange,提问作者Yunus Yurtturk
相关产品推荐
相关产品推荐

