cpp - SDL_JOYHATMOTION different when using Windows?

Multi tool use
cpp - SDL_JOYHATMOTION different when using Windows?
I'm using SDL2 in my programm.
The Gamepad is initialised using:
SDL_Joystick* Pad1 = NULL;
Pad1 = SDL_JoystickOpen( 0 );
In my Event-Handling function, i included this thing:
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;
Note that this code isn't targeting only the specified pad but should react to the input on any gamepad.
Within OpenSuse/Linux this is fine. As soon as I use the Hat on any Gamepad, it triggers the event. It however doesn't work for windows. The rest of the Code is running as intented (including the specified axis, button, etc. events) but using the Hat doesn't cause any reaction. What is the reason for this? Do i need to specifiy a gamepad when using SDL2 under Windows?
Thanks and greetings, mumbo
Edit1:
Surfing arround, I probably did find an explanation for my problem:
https://forums.libsdl.org/viewtopic.php?p=39991
I suppose that the DPAD isn't detected as an HAT but rather as an Analog-Stick under Windows when using the Joystick-API?
Edit2:
It was a bug in the SDL2.dll on the windows-machine i used for testing. Replacing the SDL2.dll with the fresh one solved the Problem, hats are responding as intended :)
Thanks for the help guys, good to know about the GameController-API.
Hi. 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.
– Mumbo
Jun 30 at 18:01
Crosspost @ discourse.libsdl.org/t/…
– Mumbo
Jun 30 at 23:24
2 Answers
2
tl;dr: On windows you might be having driver problems if your device is a weird one, and you might want to use the gamecontroller API if you're targeting gamepads as it gives you a more consistent interface to use.
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
So you mean the DPAD.
First, the joystick API from SDL is a bit lower level, handling stuff like actual joysticks, steering wheels and (in your use case) gamepads indistinguishable of the device. This means the API might not be consistent across devices, for example two different gamepads might map a button to different indexes.
Although I think the joyhat might be always mapped to the DPAD in the more common devices, the other buttons might not, (triggers, x, y, a, b star, circle, etc). Come GamePadController to save the day which gives you a more consistent way to handle the controller (by giving you an Xbox 360 like gamepad and a database of mappings for several devices).
In the source tree of SDL there is a databse of controllers you can load (or is loaded by default, I didn't check), you can also check this link where I think there is another database of mappings for all kinds of controllers that you can load into your program by hand.
This example uses the GameController API instead of the JoyStick API and prints values when the DPAD is pressed. I did a test on linux only, might hop on windows later to try it out.
#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;
}
On the other hand you might have DRIVER problems (not uncommon on windows with rando controllers) or be against a gamepad that isn't mapped yet. (I've tried on linux with a PS4 controller and it worked correctly but with a cheap knockoff of a PS2 controller it didn't).
Hej. Thanks to the effort. Think i'll try your idea with the GameController tomorrow (won't be able to do it tonight). However: It is a lot of effort. Any Idea why it isn't working under Windows? I'm using the same devices, so it is surely something within the OS. Also: I got a few Gamepads where the DPAD is actually realized with an AXIS-Component - so i supposed that the terminus "HAT" would be more precise.
– Mumbo
Jul 1 at 0:16
@Mumbo my example is complete, if you want to test it you can paste it instead of your current main and it should just work. As I said before, it depends on the device, which one is it? You might want to hunt the internet for drivers. Does it work with any other game? (For example does it work with Steam Big Picture mode?)
– Aram
Jul 1 at 0:25
Hej Aram. The gamepads - including the DPAD/HAT - are working with many other games. One of the gamepads is an original XBOX-PAD - I suppose it is supported. They do work under Steam Big Picture. Thanks for your code, but unfortunately I won't be able to test it until for the next 12 hours - I'm using a Linux machine (In which both codes run fine!) and won't be able to get access to a Windows computer before the night ends. - Again thanks for the help. Greetings - Mumbo
– Mumbo
Jul 1 at 0:37
@Mumbo DPAD represented as joystick axes is one of things SDL gamecontroller API attempts to handle. There are devices with analog DPAD, or even all buttons being analog (e.g. PS2 controller), but they are not widespread, and unless you explicitly want to support analog buttons for some tricky stuff like depending on pressure, - it's fine when SDL emulates digital buttons for you - and, most importantly, allows user to create their own mapping for their device. Of course it makes no sense for non-gamepad joysticks.
– keltar
Jul 1 at 5:41
Good Morning - Little Update: Made the Game running (more or less) using WIne, with the Hats reacting (Using the same Gamepad). I suppose that the Problem is caused by a Difference between the Way Windows and OpenSuse are parsing the Gamepads.
– Mumbo
Jul 1 at 6:36
I did update SDL2 on the target-windows-machine - and the whole thing is working as intented. Code is fine.
Thanks for the Help anyone, good to have learned about the GameController-API.
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
What is the Hat on a Gamepad?
– Aram
Jun 30 at 17:13