cpp - 使用 Windows 时 SDL_JOYHATMOTION 不同?

cpp - SDL_JOYHATMOTION different when using Windows?

我在我的程序中使用 SDL2。

手柄初始化使用:

SDL_Joystick* Pad1 = NULL;

Pad1 = SDL_JoystickOpen( 0 ); 

在我的事件处理函数中,我包含了这个东西:

 switch( event.type ){
 //Button-Event, as an example:
    case SDL_JOYBUTTONDOWN:
        //printf("Button: %d", event.jbutton.button, " ");
        if(event.jbutton.button==ControllP1.MoveLeftButton)
            MoveLeft=true;
 //lot of other cases

        case SDL_JOYHATMOTION:
            if(event.jhat.value==SDL_HAT_UP){MoveUp=true;MoveLeft=false; MoveRight=false; MoveDown=false;}
            if(event.jhat.value==SDL_HAT_DOWN){MoveDown=true;MoveUp=false; MoveLeft=false; MoveRight=false;}
            if(event.jhat.value==SDL_HAT_LEFT){MoveLeft=true; MoveDown=false; MoveUp=false; MoveRight=false;}
            if(event.jhat.value==SDL_HAT_RIGHT){MoveRight=true;MoveDown=false; MoveUp=false; MoveLeft=false; }
            if(event.jhat.value==SDL_HAT_CENTERED){MoveDown=false; MoveUp=false; MoveLeft=false; MoveRight=false;}
            if(event.jhat.value==SDL_HAT_LEFTUP){MoveDown=false; MoveUp=true; MoveLeft=true; MoveRight=false;}
            if(event.jhat.value==SDL_HAT_RIGHTUP){MoveDown=false; MoveUp=true; MoveLeft=false; MoveRight=true;}
            if(event.jhat.value==SDL_HAT_RIGHTDOWN){MoveDown=true; MoveUp=false; MoveLeft=false; MoveRight=true;}
            if(event.jhat.value==SDL_HAT_LEFTDOWN){MoveDown=true; MoveUp=false; MoveLeft=true; MoveRight=false;}
            break;

请注意,此代码不仅针对指定的手柄,而且应该对任何游戏手柄上的输入做出反应。

在 OpenSuse/Linux 内,这很好。只要我在任何游戏手柄上使用帽子,它就会触发事件。然而,它不适用于 windows。代码的其余部分按预期 运行(包括指定的轴、按钮等事件)但使用帽子不会引起任何反应。这是什么原因?在 Windows 下使用 SDL2 时是否需要指定游戏手柄?

谢谢和问候,mumbo

编辑1: 到处冲浪,我可能确实找到了我的问题的解释: https://forums.libsdl.org/viewtopic.php?p=39991 我想当使用 Joystick-API?

时,DPAD 未被检测为 HAT,而是被检测为 Windows 下的 Analog-Stick

编辑2: 这是我用于测试的 windows-机器上 SDL2.dll 中的一个错误。用新的替换 SDL2.dll 解决了问题,帽子按预期响应:) 感谢大家的帮助,很高兴知道 GameController-API.

tl;dr:在 windows 上,如果你的设备很奇怪,你可能会遇到驱动程序问题,如果你的目标是游戏手柄,你可能想使用游戏控制器 API为您提供更一致的使用界面。

Mumbo: The hat got usually the form of a cross (or a circle with a cross-form ontop). You can usually find it on the left side of your gamepad

所以你的意思是DPAD

首先,SDL 的操纵杆 API 级别较低,处理诸如实际 joysticks、方向盘和(在您的用例中)与设备无法区分的游戏手柄之类的东西。这意味着 API 可能在不同设备上不一致,例如,两个不同的游戏手柄可能将一个按钮映射到不同的索引。

虽然我认为在更常见的设备中,joyhat 可能总是映射到 DPAD,但其他按钮可能不会(触发器、x、y、a、b 星、圆圈等)。 GamePadController 来拯救这一天,它为您提供了一种更一致的方式来处理控制器(通过为您提供类似 Xbox 360 的游戏手柄和多个设备的映射数据库)。

在 SDL 的源代码树中有一个控制器的数据库,你可以加载(或者默认加载,我没有检查),你也可以检查这个 link 我认为还有另一个各种控制器的映射数据库,您可以手动将其加载到程序中。

此示例使用 GameController API 而不是 JoyStick API 并在按下 DPAD 时打印值。我只在 linux 上进行了测试,稍后可能会在 windows 上进行测试。

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <thread>

#define HEIGHT 600
#define WIDTH  800

using namespace std;

int main() {
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER);
    SDL_Window *window = SDL_CreateWindow("Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN);
    SDL_Event event;

    SDL_GameController *controller = SDL_GameControllerOpen(0);
    bool quit = false;
    //SDL_Joystick *joy = SDL_GameControllerGetJoystick(controller); 
    while (!quit) {
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_QUIT) {
                quit = true;
            }

            if (event.type == SDL_CONTROLLERBUTTONDOWN || event.type == SDL_CONTROLLERBUTTONUP) { 
                SDL_ControllerButtonEvent ev = event.cbutton;
                if (ev.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN)
                    printf("SDL_DPAD_HAT_DOWN_UP\n");
                if (ev.button == SDL_CONTROLLER_BUTTON_DPAD_UP)
                    printf("SDL_DPAD_HAT_UP_UP\n");
                if (ev.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT)
                    printf("SDL_DPAD_HAT_RIGHT_UP\n");
                if (ev.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT)
                    printf("SDL_DPAD_HAT_LEFT_UP\n");
            }

            if (event.type == SDL_CONTROLLERBUTTONDOWN) { puts ("DPAD DOWN STATE"); }

        }

        std::this_thread::sleep_for(std::chrono::milliseconds{33});
    }

    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}

另一方面,您可能遇到驱动程序问题(在 windows 随机控制器上并不少见)或者与尚未映射的游戏手柄对抗。 (我试过 linux 和 PS4 控制器,它工作正常,但用便宜的仿冒 PS2 控制器它没有)。

我确实在目标-windows-机器上更新了 SDL2 - 整个事情都按预期进行。代码没问题。

感谢任何人的帮助,很高兴了解了 GameController-API。