У меня возникают некоторые проблемы при попытке использовать SDL (версия 2.0.3) для обработки нескольких игровых контроллеров в программе SDL / OpenGL / C ++.
Я обновляю события, используя SDL_PollEvent (&m_events) цикл и поиск SDL_JOYBUTTONDOWN (или SDL_JOYBUTTONUP / SDL_JOYAXISMOTION / SDL_HATMOTION) событий с переключателем (m_events.type).
Я хочу использовать значения m_events.jbutton.which и m_events.jbutton.button (или эквиваленты для осей и шляп), чтобы обновить массивы, содержащие состояние моих контроллеров.
Я использую Windows 7 Pro 64bit и Code :: Blocks 13.12, хотя это не должно ничего менять.
Вот мой (отладочный) код, я попытался сохранить только соответствующие части:
main.cpp
#include "SceneOpenGL.h"int main(int argc, char *argv[])
{
SceneOpenGL scene(/* some args for window size */);
if(!scene.initWindow())
return -1;
scene.mainLoop();
return 0;
}
SceneOpenGL.h
#ifndef SCENEOPENGL_H_INCLUDED
#define SCENEOPENGL_H_INCLUDED
#include <iostream>
#include "Input.h"#include <SDL2/SDL.h>
class SceneOpenGL
{
public:
SceneOpenGL(/* some args for window size */);
~SceneOpenGL();
bool initWindow();
void mainLoop();
private:
SDL_Window* m_window;
SDL_Event m_event;
Input m_input;
bool m_useJoysticks;
};
#endif
SceneOpenGL.cpp
SceneOpenGL::SceneOpenGL(/* some args for window size */) :
m_window(0), m_input()
{
if(SDL_NumJoysticks())
m_useJoysticks = true;
}
bool SceneOpenGL::initWindow()
{
if(SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK ) == -1)
{
std::cout << "Error while initializing SDL : " << SDL_GetError() << std::endl;
SDL_Quit();
return false;
}
/*
**** Creation of SDL Window and GLContext ****
*/
return true;
}
void SceneOpenGL::mainLoop()
{
if(m_useJoysticks)
{
m_input.openJoysticks();
SDL_JoystickEventState(SDL_ENABLE);
}
while(!m_input.terminate()) // m_input.terminate() sends true when SDL receives SDL_WINDOWEVENT_CLOSE event
{
m_input.updateEvents(); // this is the other loop where I update the joystick, keyboard & mouse state
/* ...
**** moving opengl objects & render ****
*/
}
}
Input.h
#ifndef INPUT_H_INCLUDED
#define INPUT_H_INCLUDED
#include <SDL2/SDL.h>
#include <iostream>
class Input
{
public:
Input();
~Input();
void updateEvents();
bool terminate() const;
void openJoysticks();
private:
SDL_Event m_events;
int m_numJoysticks;
SDL_Joysticks* m_joysticks[4]; // Array containing the first 4 joysicks
bool m_terminate; // used for ending program
};
Input.cpp
#include "Input.h"
Input::Input() :
m_numJoysticks(0), m_terminate(false)
{}
Input::~Input()
{
for(int i(0); i < SDL_NumJoysticks(); i++)
SDL_JoystickClose(m_joysticks[i]); // Closes joysticks before exiting
}
void Input::openJoysticks()
{
m_numJoysticks = SDL_NumJoysticks; // Counts the connected joysticks
if(m_numJoysticks > 4)
m_numJoysticks = 4; // Sets maximum joysticks to 4
for(int i(0); i < m_numJoysticks; i++)
{
m_joysticks[i] = SDL_JoystickOpen(0) // Open existing joysticks
std::cout << "Joystick #" << i << " OK" << std::endl;
}
}
void Input::updateEvents()
{
while(SDL_PollEvent(&m_events))
{
switch(m_events.type)
{
/* ... Keyboard and mouse events, no problem there */
case SDL_JOYBUTTONDOWN:
std::cout << "JOYBUTTONDOWN" << std::endl;
std::cout << "type : " << m_events.jbutton.type << std::endl;
std::cout << "which : " << m_events.jbutton.which << std::endl;
std::cout << "button : " << m_events.jbutton.button << std::endl;
std::cout << "state : " << m_events.jbutton.state << std:: endl << std::endl;
break;
/* ... Same thing for SDL_JOYBUTTONUP, SDL_JOYAXISMOTION, SDL_JOYHATMOTION */
case SDL_WINDOWEVENT:
if(m_events.window.event == SDL_WINDOWEVENT_CLOSE)
m_terminate = true; // end program
break;
default:
break;
}
}
}
bool Input::terminate() const
{
return m_terminate;
}
Итак, вот вывод консоли, когда я нажимаю A, B, X, Y на моем контроллере x360 (= кнопки 0, 1, 2 & 3):
Joystick #0 OK
JOYBUTTONDOWN
type : 1539
which : 65536
button : §
state : Ý
JOYBUTTONDOWN
type : 1539
which : 1996554496
button :
state :
JOYBUTTONDOWN
type : 1539
which : 1996554752
button :
state :
JOYBUTTONDOWN
type : 1539
which : 1996555008
button :
state :
Process returned 0 (0x0) execution time : 7.437 s
Press any key to continue.
Как видите, это не совсем нормально. Я даже иногда получаю разные значения для одного и того же входа (например, здесь, когда нажата первая кнопка), но я заметил, что разница между значениями «which» равна 256, поэтому она не является полностью случайной. И значения в основном одинаковы, если я перезапущу программу или дважды нажму одну и ту же кнопку.
Ну, похоже, что «event.jbutton.which» содержит информацию об индексе кнопки (который должен быть Uint8)
Я не знаю, делаю ли я это неправильно или это ошибка в SDL2.
Ваши числа кажутся побитовым ИЛИ множества полей флага, возможно, с полем значения.
Изучение их в гексе сделает это очевидным:
1996554752 = 0x77010200
1996554496 = 0x77010100
1996555008 = 0x77010300
Похоже, ваш «номер кнопки» может быть в битах 15-8, т. Е. Значения 2, 1, 3
Это почти наверняка отражено в соответствующей документации