Yun*_*urk 1 sdl joystick gamecontroller gamepad sdl-2
我正在尝试在物理游戏控制器设备和虚拟设备 (vJoy) 之间建立 1 对 1 的映射。我想要实现的是,当在物理设备上按下没有 X 的按钮时,使在虚拟设备上按下没有 X 的按钮。
由于我正在尝试在物理和虚拟控制器按钮和轴之间进行 1-1 映射,因此我不应该与映射有任何关系。所以我决定使用 SDL2 库的“Joystick”相关函数而不是“GameController”相关函数。
输入(物理)=> MyApp => 输出(vJoy)
我可以与几乎所有控制器实现一一对应,除了一个 PS4 控制器。
通过 SDL 输入读取函数(下面的代码),我得到这些:
当我按下左肩按钮时,event.jbutton.button 显示 9
当我按下右肩按钮时,event.jbutton.button显示10
(它还在游戏控制器模式下显示 9 和 10,而不是操纵杆模式,相同。我确认我没有错误地使用控制器模式,通过在其他控制器上尝试相同的方法而不进行任何更改)
SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_EVENTS);
SDL_JoystickEventState(SDL_ENABLE);
SDL_Event event;
while(SDL_WaitEventTimeout(&event, 50))
{
switch(event.type){
case SDL_JOYDEVICEADDED:
m_Joystick = SDL_JoystickOpen(device);
break;
//
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
qDebug() << "JoystickButton(" << QString(SDL_GameControllerGetStringForButton((SDL_GameControllerButton)event.jbutton.button)) << ")" << event.jbutton.button<< " -> " << event.jbutton.state;
break;
}
}
Run Code Online (Sandbox Code Playgroud)
但是当我用其他工具测试它时,他们给出了左肩 4 和右肩 5 作为按钮编号。
0-) 我的应用案例
左肩按钮 => 9
右肩按钮 => 10
1-) Windows 的内部游戏控制器实用程序(索引从 1 开始,组成 4-5)
2-) 结果来自https://gamepad-tester.com/
3-) 来自https://greggman.github.io/html5-gamepad-test/的结果
由于我使用的是操纵杆相关的功能,因此我希望按原样读取输入,而不进行映射。但SDL2的结果似乎与其他的不同。自从
1 - 我应该如何读取操纵杆输入,以便与其他工具给出相同的结果
2 - SDL2 和我的代码有什么问题?
小智 6
SDL2 试图保护您免受游戏手柄输入标准化不良的影响。它根据游戏手柄上每个按钮的物理位置对按钮重新排序,以匹配其自己的标准按钮顺序。顺序由SDL_GamepadButton 枚举定义。这就是“9”的来源,SDL_GAMEPAD_BUTTON_LEFT_SHOUDLER值为 9。在 SDL2 中,任何正确映射的游戏手柄都会在索引 9 处具有 L1 按钮。
Gamepad API(由在线工具使用)正在做同样的事情。游戏手柄 API 定义了一个标准游戏手柄,其“左上前按钮”为buttons[4]。在游戏手柄 API 中,任何正确映射的游戏手柄都会在索引 4 处具有 L1 按钮。
您可以相当轻松地在 SDL2 和 Gamepad API 按钮之间进行转换,因为它们本质上都定义了同一组标准按钮。
Windows 游戏控制器实用程序 (joy.cpl) 不会尝试重新映射游戏手柄按钮。它使用 DirectInput API,根据分配给每个按钮输入的 HID 使用标识符来选择按钮索引。
把它们放在一起:
| DS4 | HID 使用 ID | SDL2 | 游戏手柄API |
|---|---|---|---|
| 叉 | 按钮2 | SDL_GAMEPAD_BUTTON_A(0) |
buttons[0] |
| 圆圈 | 按钮3 | SDL_GAMEPAD_BUTTON_B(1) |
buttons[1] |
| 正方形 | 按钮1 | SDL_GAMEPAD_BUTTON_X(2) |
buttons[2] |
| 三角形 | 按钮4 | SDL_GAMEPAD_BUTTON_Y(3) |
buttons[3] |
| 分享 | 按钮9 | SDL_GAMEPAD_BUTTON_BACK(4) |
buttons[8] |
| 聚苯乙烯 | 按钮13 | SDL_GAMEPAD_BUTTON_GUIDE(5) |
buttons[16] |
| 选项 | 按钮10 | SDL_GAMEPAD_BUTTON_START(6) |
buttons[9] |
| L3 | 按钮11 | SDL_GAMEPAD_BUTTON_LEFT_STICK(7) |
buttons[10] |
| R3 | 按钮12 | SDL_GAMEPAD_BUTTON_RIGHT_STICK(8) |
buttons[11] |
| L1 | 按钮5 | SDL_GAMEPAD_BUTTON_LEFT_SHOULDER(9) |
buttons[4] |
| R1 | 按钮6 | SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER(10) |
buttons[5] |
| 方向键向上 | 通用桌面帽子开关 | SDL_GAMEPAD_BUTTON_DPAD_UP(11) |
buttons[12] |
| 方向键向下 | 通用桌面帽子开关 | SDL_GAMEPAD_BUTTON_DPAD_DOWN(12) |
buttons[13] |
| 方向键左 | 通用桌面帽子开关 | SDL_GAMEPAD_BUTTON_DPAD_LEFT(13) |
buttons[14] |
| 方向键右 | 通用桌面帽子开关 | SDL_GAMEPAD_BUTTON_DPAD_RIGHT(14) |
buttons[15] |
| 触摸板按钮 | 按钮14 | SDL_GAMEPAD_BUTTON_TOUCHPAD(20) |
buttons[16](非标) |
| 左摇杆X | 通用桌面 X | SDL_GAMEPAD_AXIS_LEFTX(0) |
axes[0] |
| 左摇杆Y | 通用桌面Y | SDL_GAMEPAD_AXIS_LEFTY(1) |
axes[1] |
| 右摇杆X | 通用桌面Z | SDL_GAMEPAD_AXIS_RIGHTX(2) |
axes[2] |
| 右摇杆Y | 通用桌面 Rz | SDL_GAMEPAD_AXIS_RIGHTY(3) |
axes[3] |
| L2触发器 | 按钮 7(数字),通用桌面 Rx(模拟) | SDL_GAMEPAD_AXIS_LEFT_TRIGGER(4) |
buttons[6] |
| R2触发器 | 按钮 8(数字),通用桌面 Ry(模拟) | SDL_GAMEPAD_AXIS_RIGHT_TRIGGER(5) |
buttons[7] |
由于我使用的是操纵杆相关的功能,因此我希望按原样读取输入,而不进行映射。
这是“原样”。SDL2 了解 DS4 输入报告的确切布局,并从报告缓冲区中读取按钮和轴值。不会发生重新映射,输入始终正确映射。
但SDL2的结果似乎与其他的不同。
是的,它使用特定于 SDL2 的标准按钮顺序。
1 - 我应该如何读取操纵杆输入,以便与其他工具给出相同的结果
还有哪些其他工具?它们都略有不同。如果您想在 SDL2 和 Gamepad API 之间进行转换,您可以使用上表。
2 - SDL2 和我的代码有什么问题?
没什么,游戏手柄很复杂而且标准化很差。