cpp - 使用Windows时SDL_JOYHATMOTION不同?

cpp - SDL_JOYHATMOTION different when using Windows?

本文关键字:JOYHATMOTION 不同 SDL 使用 Windows cpp      更新时间:2023-10-16

我在程序中使用 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中,这很好。只要我在任何游戏手柄上使用帽子,它就会触发事件。但是,它不适用于窗口。代码的其余部分按预期运行(包括指定的轴、按钮等事件(,但使用 Hat 不会引起任何反应。这是什么原因呢?在 Windows 下使用 SDL2 时,是否需要指定游戏手柄?

谢谢和问候,喃喃自语

编辑1: 冲浪,我可能确实找到了我的问题的解释: https://forums.libsdl.org/viewtopic.php?p=39991 我想在使用操纵杆 API 时,DPAD 不会被检测为 HAT,而是被检测为 Windows 下的模拟摇杆?

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

我确实在目标窗口机器上更新了SDL2 - 整个事情都按预期工作。代码很好。

感谢任何人的帮助,很高兴了解游戏控制器-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 级别稍低,处理实际操纵杆、方向盘和(在您的用例中(与设备无法区分的游戏手柄等内容。这意味着 API 在设备之间可能不一致,例如,两个不同的游戏手柄可能会将按钮映射到不同的索引。

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

在 SDL 的源代码树中,有一个可以加载的控制器数据库(或者默认情况下加载,我没有检查(,您还可以检查此链接,我认为还有另一个数据库,其中包含各种控制器的映射,您可以手动加载到程序中。

此示例使用游戏控制器 API 而不是操纵杆 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_UPn");
if (ev.button == SDL_CONTROLLER_BUTTON_DPAD_UP)
printf("SDL_DPAD_HAT_UP_UPn");
if (ev.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT)
printf("SDL_DPAD_HAT_RIGHT_UPn");
if (ev.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT)
printf("SDL_DPAD_HAT_LEFT_UPn");
}
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;
}

另一方面,您可能会遇到驱动程序问题(在带有 rando 控制器的窗口中并不少见(或针对尚未映射的游戏手柄。(我用 PS4 控制器在 Linux 上尝试过,它工作正常,但 PS2 控制器的廉价仿冒品却没有(。