SDL2 和其他工具(Windows 和在线工具)之间的游戏控制器按钮数量不兼容

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)

Windows - 游戏控制器按钮结果

2-) 结果来自https://gamepad-tester.com/

gamepad-tester.com 结果

3-) 来自https://greggman.github.io/html5-gamepad-test/的结果

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 和我的代码有什么问题?

没什么,游戏手柄很复杂而且标准化很差。