Use SDL2 for better gamepad support and hotplug
This commit is contained in:
parent
cd7aa2c90c
commit
00cb6c2d48
@ -7,11 +7,14 @@ sudo: false
|
||||
language: cpp
|
||||
os:
|
||||
- linux
|
||||
# - osx
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
|
||||
matrix:
|
||||
# include:
|
||||
# - osx_image: xcode11.3
|
||||
fast_finish: true
|
||||
|
||||
env:
|
||||
@ -36,6 +39,7 @@ addons:
|
||||
- libogg-dev
|
||||
- libopenal-dev
|
||||
- libpng-dev
|
||||
- libsdl2-dev
|
||||
- libvorbis-dev
|
||||
- libxrandr-dev
|
||||
- mesa-common-dev
|
||||
|
2
Brewfile
2
Brewfile
@ -4,8 +4,8 @@ brew "libvorbis"
|
||||
brew "openal-soft"
|
||||
brew "freetype"
|
||||
brew "curl"
|
||||
brew "nettle"
|
||||
brew "fribidi"
|
||||
brew "glew"
|
||||
brew "harfbuzz"
|
||||
brew "libjpeg"
|
||||
brew "sdl2"
|
||||
|
@ -296,6 +296,19 @@ if(NOT SERVER_ONLY)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT SERVER_ONLY)
|
||||
# SDL2
|
||||
find_library(SDL2_LIBRARY NAMES SDL2 libSDL2)
|
||||
find_path(SDL2_INCLUDEDIR NAMES SDL.h PATH_SUFFIXES SDL2 include/SDL2 include PATHS)
|
||||
if (NOT SDL2_LIBRARY OR NOT SDL2_INCLUDEDIR)
|
||||
message(FATAL_ERROR "SDL2 not found. "
|
||||
"SDL2 is required to handle gamepad in SuperTuxKart.")
|
||||
else()
|
||||
include_directories("${SDL2_INCLUDEDIR}")
|
||||
MESSAGE(STATUS "Use system SDL2: ${SDL2_LIBRARY}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Build the irrlicht library
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/lib/irrlicht")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/lib/irrlicht/include")
|
||||
@ -404,7 +417,6 @@ if (NOT SERVER_ONLY)
|
||||
include_directories("${RAQM_INCLUDEDIR}")
|
||||
MESSAGE(STATUS "Use system libraqm: ${RAQM_LIBRARY}")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
# OpenGL
|
||||
@ -656,6 +668,7 @@ if(NOT SERVER_ONLY)
|
||||
${FRIBIDI_LIBRARIES}
|
||||
${FREETYPE_LIBRARIES}
|
||||
${HARFBUZZ_LIBRARY}
|
||||
${SDL2_LIBRARY}
|
||||
graphics_utils)
|
||||
endif()
|
||||
|
||||
@ -713,7 +726,7 @@ if(MSVC OR MINGW)
|
||||
endif()
|
||||
|
||||
if(MINGW)
|
||||
target_link_libraries(supertuxkart -ldxguid -ldinput8 -ldnsapi)
|
||||
target_link_libraries(supertuxkart -ldxguid -ldnsapi)
|
||||
if (NOT CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
target_link_libraries(supertuxkart -mwindows)
|
||||
endif()
|
||||
|
@ -26,12 +26,13 @@ To build SuperTuxKart from source, you'll need to install the following packages
|
||||
* libpng (libpng-devel)
|
||||
* zlib (zlib-devel)
|
||||
* jpeg (libjpeg-turbo-devel)
|
||||
* SDL2 (libsdl2-devel)
|
||||
|
||||
Fedora command:
|
||||
|
||||
```bash
|
||||
sudo dnf install @development-tools angelscript-devel \
|
||||
bluez-libs-devel cmake desktop-file-utils \
|
||||
bluez-libs-devel cmake desktop-file-utils SDL2-devel \
|
||||
freealut-devel freeglut-devel freetype-devel fribidi-devel \
|
||||
gcc-c++ git-core libXrandr-devel libcurl-devel libjpeg-turbo-devel \
|
||||
libpng-devel libsquish-devel libtool libvorbis-devel mesa-libEGL-devel \
|
||||
@ -44,7 +45,7 @@ Mageia 6 command:
|
||||
|
||||
```bash
|
||||
su -c 'urpmi gcc-c++ cmake openssl-devel libcurl-devel freetype-devel harfbuzz-devel \
|
||||
fribidi-devel libjpeg-turbo-devel libogg-devel openal-soft-devel \
|
||||
fribidi-devel libjpeg-turbo-devel libogg-devel openal-soft-devel SDL2-devel \
|
||||
libpng-devel libvorbis-devel nettle-devel zlib-devel git subversion \
|
||||
mesa-comon-devel libxrandr-devel libbluez-devel libfreetype6-devel'
|
||||
```
|
||||
@ -52,7 +53,7 @@ mesa-comon-devel libxrandr-devel libbluez-devel libfreetype6-devel'
|
||||
openSUSE command:
|
||||
|
||||
```bash
|
||||
sudo zypper install gcc-c++ cmake openssl-devel libcurl-devel \
|
||||
sudo zypper install gcc-c++ cmake openssl-devel libcurl-devel libSDL2-devel \
|
||||
freetype-devel harfbuzz-devel fribidi-devel libogg-devel openal-soft-devel libpng-devel \
|
||||
libvorbis-devel libXrandr-devel pkgconf zlib-devel enet-devel glew-devel \
|
||||
libjpeg-devel bluez-devel freetype2-devel glu-devel
|
||||
@ -61,7 +62,7 @@ libjpeg-devel bluez-devel freetype2-devel glu-devel
|
||||
Ubuntu command:
|
||||
|
||||
```bash
|
||||
sudo apt-get install build-essential cmake libbluetooth-dev \
|
||||
sudo apt-get install build-essential cmake libbluetooth-dev libsdl2-devel \
|
||||
libcurl4-openssl-dev libenet-dev libfreetype6-dev libharfbuzz-dev libfribidi-dev \
|
||||
libgl1-mesa-dev libglew-dev libjpeg-dev libogg-dev libopenal-dev libpng-dev \
|
||||
libssl-dev libvorbis-dev libxrandr-dev libx11-dev nettle-dev pkg-config zlib1g-dev
|
||||
|
@ -487,10 +487,6 @@ struct SEvent
|
||||
NUMBER_OF_AXES = 32
|
||||
};
|
||||
|
||||
/** A bitmap of button states. You can use IsButtonPressed() to
|
||||
( check the state of each button from 0 to (NUMBER_OF_BUTTONS - 1) */
|
||||
u32 ButtonStates;
|
||||
|
||||
/** For AXIS_X, AXIS_Y, AXIS_Z, AXIS_R, AXIS_U and AXIS_V
|
||||
* Values are in the range -32768 to 32767, with 0 representing
|
||||
* the center position. You will receive the raw value from the
|
||||
@ -501,17 +497,28 @@ struct SEvent
|
||||
*/
|
||||
s16 Axis[NUMBER_OF_AXES];
|
||||
|
||||
/** The POV represents the angle of the POV hat in degrees * 100,
|
||||
* from 0 to 35,900. A value of 65535 indicates that the POV hat
|
||||
* is centered (or not present).
|
||||
* This value is only supported on Windows. On Linux, the POV hat
|
||||
* will be sent as 2 axes instead. */
|
||||
u16 POV;
|
||||
//! The ID of the joystick which generated this event.
|
||||
/** This is an internal Irrlicht index; it does not map directly
|
||||
* to any particular hardware joystick. */
|
||||
u32 AxisChanged;
|
||||
|
||||
/** A bitmap of button states. You can use IsButtonPressed() to
|
||||
( check the state of each button from 0 to (NUMBER_OF_BUTTONS - 1) */
|
||||
u32 ButtonStates;
|
||||
|
||||
//! The ID of the joystick which generated this event.
|
||||
/** This is an internal Irrlicht index; it does not map directly
|
||||
* to any particular hardware joystick. */
|
||||
u8 Joystick;
|
||||
u32 Joystick;
|
||||
|
||||
//! A helper function to check if a button is pressed.
|
||||
bool IsAxisChanged(u32 axis) const
|
||||
{
|
||||
if(axis >= (u32)NUMBER_OF_AXES)
|
||||
return false;
|
||||
|
||||
return (AxisChanged & (1 << axis)) ? true : false;
|
||||
}
|
||||
|
||||
//! A helper function to check if a button is pressed.
|
||||
bool IsButtonPressed(u32 button) const
|
||||
|
@ -129,11 +129,7 @@
|
||||
#endif
|
||||
|
||||
//! Define _IRR_COMPILE_WITH_JOYSTICK_SUPPORT_ if you want joystick events.
|
||||
#define _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
|
||||
#ifdef NO_IRR_COMPILE_WITH_JOYSTICK_EVENTS_
|
||||
#undef _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
|
||||
#endif
|
||||
|
||||
|
||||
//! Maximum number of texture an SMaterial can have, up to 8 are supported by Irrlicht.
|
||||
#define _IRR_MATERIAL_MAX_TEXTURES_ 8
|
||||
|
@ -66,6 +66,8 @@ extern bool GLContextDebugBit;
|
||||
#define XRANDR_ROTATION_LEFT (1 << 1)
|
||||
#define XRANDR_ROTATION_RIGHT (1 << 3)
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
|
@ -352,11 +352,10 @@ struct SJoystickWin32Control
|
||||
|
||||
void pollJoysticks()
|
||||
{
|
||||
if (0 == ActiveJoysticks.size())
|
||||
return;
|
||||
|
||||
#if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
|
||||
#ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
|
||||
if (0 == ActiveJoysticks.size())
|
||||
return;
|
||||
|
||||
u32 joystick;
|
||||
DIJOYSTATE2 info;
|
||||
|
@ -31,19 +31,6 @@
|
||||
#import <time.h>
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
|
||||
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/IOCFPlugIn.h>
|
||||
#ifdef MACOS_10_0_4
|
||||
#include <IOKit/hidsystem/IOHIDUsageTables.h>
|
||||
#else
|
||||
/* The header was moved here in Mac OS X 10.1 */
|
||||
#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
|
||||
#endif
|
||||
#include <IOKit/hid/IOHIDLib.h>
|
||||
#include <IOKit/hid/IOHIDKeys.h>
|
||||
|
||||
// only OSX 10.5 seems to not need these defines...
|
||||
#if !defined(__MAC_10_5) || defined(__MAC_10_6)
|
||||
// Contents from Events.h from Carbon/HIToolbox but we need it with Cocoa too
|
||||
@ -185,6 +172,19 @@ enum {
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
|
||||
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/IOCFPlugIn.h>
|
||||
#ifdef MACOS_10_0_4
|
||||
#include <IOKit/hidsystem/IOHIDUsageTables.h>
|
||||
#else
|
||||
/* The header was moved here in Mac OS X 10.1 */
|
||||
#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
|
||||
#endif
|
||||
#include <IOKit/hid/IOHIDLib.h>
|
||||
#include <IOKit/hid/IOHIDKeys.h>
|
||||
|
||||
struct JoystickComponent
|
||||
{
|
||||
IOHIDElementCookie cookie; // unique value which identifies element, will NOT change
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Modify this file to change the last-modified date when you add/remove a file.
|
||||
# This will then trigger a new cmake run automatically.
|
||||
# This will then trigger a new cmake run automatically.
|
||||
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
|
||||
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
|
||||
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")
|
||||
|
@ -144,6 +144,14 @@ public:
|
||||
/** Returns if this config is sed by any devices. */
|
||||
bool isPlugged() const { return m_plugged > 0; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Decrease ref counter. */
|
||||
void unPlugged()
|
||||
{
|
||||
m_plugged--;
|
||||
assert(m_plugged >= 0);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the number of devices using this configuration. */
|
||||
int getNumberOfDevices() const { return m_plugged; }
|
||||
|
@ -58,8 +58,6 @@ DeviceManager::~DeviceManager()
|
||||
// -----------------------------------------------------------------------------
|
||||
bool DeviceManager::initialize()
|
||||
{
|
||||
GamepadConfig *gamepadConfig = NULL;
|
||||
GamePadDevice *gamepadDevice = NULL;
|
||||
m_map_fire_to_select = false;
|
||||
bool created = false;
|
||||
|
||||
@ -110,65 +108,6 @@ bool DeviceManager::initialize()
|
||||
m_keyboards.push_back(new KeyboardDevice(m_keyboard_configs.get(n)));
|
||||
}
|
||||
|
||||
if(UserConfigParams::logMisc())
|
||||
Log::info("Device manager","Initializing gamepad support.");
|
||||
|
||||
irr_driver->getDevice()->activateJoysticks(m_irrlicht_gamepads);
|
||||
|
||||
int num_gamepads = m_irrlicht_gamepads.size();
|
||||
if(UserConfigParams::logMisc())
|
||||
{
|
||||
Log::info("Device manager","Irrlicht reports %d gamepads are attached to the system.",
|
||||
num_gamepads);
|
||||
}
|
||||
|
||||
// Create GamePadDevice for each physical gamepad and find a GamepadConfig to match
|
||||
for (int id = 0; id < num_gamepads; id++)
|
||||
{
|
||||
core::stringc name = m_irrlicht_gamepads[id].Name;
|
||||
|
||||
// Some systems report a disk accelerometer as a gamepad, skip that
|
||||
if (name.find("LIS3LV02DL") != -1) continue;
|
||||
if (name == "applesmc") continue;
|
||||
if (name.find("VirtualBox") == 0) continue;
|
||||
|
||||
if(m_irrlicht_gamepads[id].HasGenericName)
|
||||
{
|
||||
// On Windows all gamepads are given the same name ('microsoft
|
||||
// pc-joystick driver'). Irrlicht now tries to get a better name
|
||||
// from the registry, but in case this should fail we still have
|
||||
// all gamepads with the same name shown in the GUI. This makes
|
||||
// configuration totally useless, so append an ID to the name.
|
||||
name = name + " " + StringUtils::toString(id).c_str();
|
||||
}
|
||||
|
||||
if (UserConfigParams::logMisc())
|
||||
{
|
||||
Log::info("Device manager","#%d: %s detected...", id, name.c_str());
|
||||
}
|
||||
|
||||
// Returns true if new configuration was created
|
||||
if (getConfigForGamepad(id, name.c_str(), &gamepadConfig) == true)
|
||||
{
|
||||
if(UserConfigParams::logMisc())
|
||||
Log::info("Device manager","creating new configuration.");
|
||||
created = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(UserConfigParams::logMisc())
|
||||
Log::info("Device manager","using existing configuration.");
|
||||
}
|
||||
|
||||
gamepadConfig->setPlugged();
|
||||
gamepadDevice = new GamePadDevice(id,
|
||||
name.c_str(),
|
||||
m_irrlicht_gamepads[id].Axes,
|
||||
m_irrlicht_gamepads[id].Buttons,
|
||||
gamepadConfig );
|
||||
addGamepad(gamepadDevice);
|
||||
} // end for
|
||||
|
||||
if ((UserConfigParams::m_multitouch_active == 1 &&
|
||||
irr_driver->getDevice()->supportsTouchDevice()) ||
|
||||
UserConfigParams::m_multitouch_active > 1)
|
||||
@ -268,20 +207,9 @@ bool DeviceManager::getConfigForGamepad(const int irr_id,
|
||||
// If we can't find an appropriate configuration then create one.
|
||||
if (!found)
|
||||
{
|
||||
if(irr_id < (int)(m_irrlicht_gamepads.size()))
|
||||
{
|
||||
*config = new GamepadConfig( name,
|
||||
m_irrlicht_gamepads[irr_id].Axes,
|
||||
m_irrlicht_gamepads[irr_id].Buttons );
|
||||
}
|
||||
#ifdef ENABLE_WIIUSE
|
||||
else // Wiimotes have a higher ID and do not refer to m_irrlicht_gamepads
|
||||
{
|
||||
// The Wiimote manager will set number of buttons and axis
|
||||
*config = new GamepadConfig(name.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
// The Wiimote manager and SDL controller will set number of buttons and
|
||||
// axes
|
||||
*config = new GamepadConfig(name.c_str());
|
||||
// Add new config to list
|
||||
m_gamepad_configs.push_back(*config);
|
||||
configCreated = true;
|
||||
|
@ -69,8 +69,6 @@ private:
|
||||
PtrVector<GamepadConfig, HOLD> m_gamepad_configs;
|
||||
MultitouchDevice* m_multitouch_device;
|
||||
|
||||
/** The list of all joysticks that were found and activated. */
|
||||
core::array<SJoystickInfo> m_irrlicht_gamepads;
|
||||
InputDevice* m_latest_used_device;
|
||||
PlayerAssignMode m_assign_mode;
|
||||
|
||||
|
@ -40,20 +40,9 @@ GamePadDevice::GamePadDevice(const int irr_index, const std::string &name,
|
||||
config->setNumberOfButtons(button_count);
|
||||
}
|
||||
|
||||
// HAT/POV buttons will be reported as additional axis with the values
|
||||
// HAT_V_ID > HAT_H_ID. So increase the number of axis to be large
|
||||
// enough to handle HAT_V/H_ID as axis number.
|
||||
assert(Input::HAT_V_ID > Input::HAT_H_ID);
|
||||
int adj_axis_count = axis_count > Input::HAT_V_ID ? axis_count
|
||||
: Input::HAT_V_ID+1;
|
||||
|
||||
if(m_configuration->getNumberOfAxes()<adj_axis_count)
|
||||
{
|
||||
config->setNumberOfAxis(adj_axis_count);
|
||||
}
|
||||
m_prev_axis_directions.resize(adj_axis_count);
|
||||
m_prev_axis_value.resize(adj_axis_count);
|
||||
m_axis_ok.resize(adj_axis_count);
|
||||
m_prev_axis_directions.resize(axis_count);
|
||||
m_prev_axis_value.resize(axis_count);
|
||||
m_axis_ok.resize(axis_count);
|
||||
m_irr_index = irr_index;
|
||||
m_name = name;
|
||||
|
||||
|
@ -73,6 +73,7 @@ public:
|
||||
int getIrrIndex() const { return m_irr_index; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
void setIrrIndex(int i ) { m_irr_index = i; }
|
||||
|
||||
}; // class GamepadDevice
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
InputDevice::InputDevice()
|
||||
{
|
||||
m_connected = true;
|
||||
m_player = NULL;
|
||||
m_configuration = NULL;
|
||||
} // InputDevice
|
||||
|
@ -47,6 +47,9 @@ enum DeviceType
|
||||
class InputDevice: public NoCopy
|
||||
{
|
||||
protected:
|
||||
/** For SDL controller it's set false when it's unplugged. */
|
||||
bool m_connected;
|
||||
|
||||
/** Device type (keyboard, gamepad). */
|
||||
DeviceType m_type;
|
||||
|
||||
@ -107,6 +110,10 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the name of this device. */
|
||||
const std::string& getName() const { return m_name; }
|
||||
// ------------------------------------------------------------------------
|
||||
void setConnected(bool val) { m_connected = val; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool isConnected() const { return m_connected; }
|
||||
}; // class InputDevice
|
||||
|
||||
#endif
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "input/input.hpp"
|
||||
#include "input/keyboard_device.hpp"
|
||||
#include "input/multitouch_device.hpp"
|
||||
#include "input/sdl_controller.hpp"
|
||||
#include "input/wiimote_manager.hpp"
|
||||
#include "karts/controller/controller.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
@ -62,6 +63,9 @@
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#ifndef SERVER_ONLY
|
||||
#include <SDL.h>
|
||||
#endif
|
||||
|
||||
InputManager *input_manager;
|
||||
|
||||
@ -83,7 +87,14 @@ InputManager::InputManager() : m_mode(BOOTSTRAP),
|
||||
m_timer_in_use = false;
|
||||
m_master_player_only = false;
|
||||
m_timer = 0;
|
||||
|
||||
#ifndef SERVER_ONLY
|
||||
SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1");
|
||||
if (SDL_Init(SDL_INIT_GAMECONTROLLER) != 0)
|
||||
{
|
||||
Log::error("InputManager", "Unable to initialize SDL: %s",
|
||||
SDL_GetError());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
void InputManager::update(float dt)
|
||||
@ -93,6 +104,65 @@ void InputManager::update(float dt)
|
||||
wiimote_manager->update();
|
||||
#endif
|
||||
|
||||
#ifndef SERVER_ONLY
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
case SDL_QUIT:
|
||||
{
|
||||
exit(-1);
|
||||
break;
|
||||
}
|
||||
case SDL_JOYDEVICEADDED:
|
||||
{
|
||||
std::unique_ptr<SDLController> c(
|
||||
new SDLController(event.jdevice.which));
|
||||
SDL_JoystickID id = c->getInstanceID();
|
||||
m_sdl_controller[id] = std::move(c);
|
||||
break;
|
||||
}
|
||||
case SDL_JOYDEVICEREMOVED:
|
||||
{
|
||||
m_sdl_controller.erase(event.jdevice.which);
|
||||
break;
|
||||
}
|
||||
case SDL_JOYAXISMOTION:
|
||||
{
|
||||
auto& controller = m_sdl_controller.at(event.jaxis.which);
|
||||
if (controller->handleAxis(event))
|
||||
input(controller->getEvent());
|
||||
break;
|
||||
}
|
||||
case SDL_JOYHATMOTION:
|
||||
{
|
||||
auto& controller = m_sdl_controller.at(event.jhat.which);
|
||||
if (controller->handleHat(event))
|
||||
input(controller->getEvent());
|
||||
break;
|
||||
}
|
||||
case SDL_JOYBUTTONUP:
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
{
|
||||
auto& controller = m_sdl_controller.at(event.jbutton.which);
|
||||
if (controller->handleButton(event))
|
||||
input(controller->getEvent());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
Log::error("SDLController", "%s", e.what());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if(m_timer_in_use)
|
||||
{
|
||||
m_timer -= dt;
|
||||
@ -105,6 +175,11 @@ void InputManager::update(float dt)
|
||||
*/
|
||||
InputManager::~InputManager()
|
||||
{
|
||||
#ifndef SERVER_ONLY
|
||||
m_sdl_controller.clear();
|
||||
SDL_Quit();
|
||||
#endif
|
||||
|
||||
delete m_device_manager;
|
||||
} // ~InputManager
|
||||
|
||||
@ -952,11 +1027,11 @@ EventPropagation InputManager::input(const SEvent& event)
|
||||
const float ORIENTATION_MULTIPLIER = 10.0f;
|
||||
if (event.EventType == EET_JOYSTICK_INPUT_EVENT)
|
||||
{
|
||||
// Axes - FIXME, instead of checking all of them, ask the bindings
|
||||
// which ones to poll
|
||||
for (int axis_id=0; axis_id<SEvent::SJoystickEvent::NUMBER_OF_AXES ;
|
||||
axis_id++)
|
||||
{
|
||||
if (!event.JoystickEvent.IsAxisChanged(axis_id))
|
||||
continue;
|
||||
int value = event.JoystickEvent.Axis[axis_id];
|
||||
|
||||
if (UserConfigParams::m_gamepad_debug)
|
||||
@ -970,26 +1045,6 @@ EventPropagation InputManager::input(const SEvent& event)
|
||||
axis_id, Input::AD_NEUTRAL, value);
|
||||
}
|
||||
|
||||
if (event.JoystickEvent.POV == 65535)
|
||||
{
|
||||
dispatchInput(Input::IT_STICKMOTION, event.JoystickEvent.Joystick,
|
||||
Input::HAT_H_ID, Input::AD_NEUTRAL, 0);
|
||||
dispatchInput(Input::IT_STICKMOTION, event.JoystickEvent.Joystick,
|
||||
Input::HAT_V_ID, Input::AD_NEUTRAL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// *0.017453925f is to convert degrees to radians
|
||||
dispatchInput(Input::IT_STICKMOTION, event.JoystickEvent.Joystick,
|
||||
Input::HAT_H_ID, Input::AD_NEUTRAL,
|
||||
(int)(cosf(event.JoystickEvent.POV*0.017453925f/100.0f)
|
||||
*Input::MAX_VALUE));
|
||||
dispatchInput(Input::IT_STICKMOTION, event.JoystickEvent.Joystick,
|
||||
Input::HAT_V_ID, Input::AD_NEUTRAL,
|
||||
(int)(sinf(event.JoystickEvent.POV*0.017453925f/100.0f)
|
||||
*Input::MAX_VALUE));
|
||||
}
|
||||
|
||||
GamePadDevice* gp =
|
||||
getDeviceManager()->getGamePadFromIrrID(event.JoystickEvent.Joystick);
|
||||
|
||||
|
@ -20,6 +20,8 @@
|
||||
#ifndef HEADER_INPUT_MANAGER_HPP
|
||||
#define HEADER_INPUT_MANAGER_HPP
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
@ -29,6 +31,7 @@
|
||||
#include "utils/no_copy.hpp"
|
||||
|
||||
class DeviceManager;
|
||||
class SDLController;
|
||||
|
||||
/**
|
||||
* \brief Class to handle input.
|
||||
@ -74,6 +77,11 @@ private:
|
||||
void handleStaticAction(int id0, int value);
|
||||
void inputSensing(Input::InputType type, int deviceID, int btnID,
|
||||
Input::AxisDirection axisDirection, int value);
|
||||
|
||||
#ifndef SERVER_ONLY
|
||||
std::map<int, std::unique_ptr<SDLController> > m_sdl_controller;
|
||||
#endif
|
||||
|
||||
public:
|
||||
InputManager();
|
||||
~InputManager();
|
||||
@ -101,6 +109,14 @@ public:
|
||||
/** Returns the ID of the player that plays with the keyboard,
|
||||
* or -1 if none. */
|
||||
int getPlayerKeyboardID() const;
|
||||
#ifdef SERVER_ONLY
|
||||
size_t getGamepadCount() const { return 0; }
|
||||
#else
|
||||
/** Returns number of active connected gamepad (with SDL), notice the
|
||||
* disconnected gamepad will not be removed from device manager to allow
|
||||
* re-plugging later with the same ID. */
|
||||
size_t getGamepadCount() const { return m_sdl_controller.size(); }
|
||||
#endif
|
||||
};
|
||||
|
||||
extern InputManager *input_manager;
|
||||
|
180
src/input/sdl_controller.cpp
Normal file
180
src/input/sdl_controller.cpp
Normal file
@ -0,0 +1,180 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2020 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef SERVER_ONLY
|
||||
|
||||
#include "input/sdl_controller.hpp"
|
||||
#include "input/device_config.hpp"
|
||||
#include "input/device_manager.hpp"
|
||||
#include "input/gamepad_device.hpp"
|
||||
#include "input/input_manager.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
SDLController::SDLController(int device_id)
|
||||
: m_gamepad(NULL)
|
||||
{
|
||||
m_irr_event = {};
|
||||
m_irr_event.EventType = irr::EET_JOYSTICK_INPUT_EVENT;
|
||||
m_game_controller = NULL;
|
||||
m_joystick = NULL;
|
||||
m_id = -1;
|
||||
|
||||
if (SDL_IsGameController(device_id))
|
||||
{
|
||||
m_game_controller = SDL_GameControllerOpen(device_id);
|
||||
if (!m_game_controller)
|
||||
throw std::runtime_error(SDL_GetError());
|
||||
m_joystick = SDL_GameControllerGetJoystick(m_game_controller);
|
||||
if (!m_joystick)
|
||||
{
|
||||
SDL_GameControllerClose(m_game_controller);
|
||||
throw std::runtime_error(SDL_GetError());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_joystick = SDL_JoystickOpen(device_id);
|
||||
if (!m_joystick)
|
||||
throw std::runtime_error(SDL_GetError());
|
||||
}
|
||||
|
||||
m_id = SDL_JoystickInstanceID(m_joystick);
|
||||
if (m_id < 0)
|
||||
{
|
||||
if (m_game_controller)
|
||||
SDL_GameControllerClose(m_game_controller);
|
||||
else
|
||||
SDL_JoystickClose(m_joystick);
|
||||
throw std::runtime_error(SDL_GetError());
|
||||
}
|
||||
|
||||
m_irr_event.JoystickEvent.Joystick = m_id;
|
||||
const char* name_cstr = SDL_JoystickName(m_joystick);
|
||||
if (name_cstr == NULL)
|
||||
{
|
||||
if (m_game_controller)
|
||||
SDL_GameControllerClose(m_game_controller);
|
||||
else
|
||||
SDL_JoystickClose(m_joystick);
|
||||
throw std::runtime_error("missing name for joystick");
|
||||
}
|
||||
std::string name = name_cstr;
|
||||
|
||||
m_buttons = SDL_JoystickNumButtons(m_joystick);
|
||||
if (m_buttons < 0)
|
||||
{
|
||||
if (m_game_controller)
|
||||
SDL_GameControllerClose(m_game_controller);
|
||||
else
|
||||
SDL_JoystickClose(m_joystick);
|
||||
throw std::runtime_error(SDL_GetError());
|
||||
}
|
||||
|
||||
m_axes = SDL_JoystickNumAxes(m_joystick);
|
||||
if (m_axes < 0)
|
||||
{
|
||||
if (m_game_controller)
|
||||
SDL_GameControllerClose(m_game_controller);
|
||||
else
|
||||
SDL_JoystickClose(m_joystick);
|
||||
throw std::runtime_error(SDL_GetError());
|
||||
}
|
||||
|
||||
m_hats = SDL_JoystickNumHats(m_joystick);
|
||||
if (m_hats < 0)
|
||||
{
|
||||
if (m_game_controller)
|
||||
SDL_GameControllerClose(m_game_controller);
|
||||
else
|
||||
SDL_JoystickClose(m_joystick);
|
||||
throw std::runtime_error(SDL_GetError());
|
||||
}
|
||||
|
||||
Log::info("SDLController",
|
||||
"%s plugged in: buttons: %d, axes: %d, hats: %d.", name.c_str(),
|
||||
m_buttons, m_axes, m_hats);
|
||||
if (m_game_controller && SDL_GameControllerName(m_game_controller))
|
||||
{
|
||||
Log::info("SDLController", "%s uses game controller mapping %s.",
|
||||
name.c_str(), SDL_GameControllerName(m_game_controller));
|
||||
}
|
||||
|
||||
if (m_buttons > irr::SEvent::SJoystickEvent::NUMBER_OF_BUTTONS)
|
||||
m_buttons = irr::SEvent::SJoystickEvent::NUMBER_OF_BUTTONS;
|
||||
if (m_axes > irr::SEvent::SJoystickEvent::NUMBER_OF_AXES)
|
||||
m_axes = irr::SEvent::SJoystickEvent::NUMBER_OF_AXES;
|
||||
// We store hats event with 4 buttons
|
||||
int max_buttons_with_hats =
|
||||
irr::SEvent::SJoystickEvent::NUMBER_OF_BUTTONS - (m_hats * 4);
|
||||
if (m_buttons > max_buttons_with_hats)
|
||||
m_hats = 0;
|
||||
else
|
||||
m_buttons += m_hats * 4;
|
||||
|
||||
DeviceManager* dm = input_manager->getDeviceManager();
|
||||
GamepadConfig* cfg = NULL;
|
||||
bool created = false;
|
||||
|
||||
if (dm->getConfigForGamepad(m_id, name, &cfg) == true)
|
||||
{
|
||||
Log::info("SDLController", "creating new configuration for %s.",
|
||||
name.c_str());
|
||||
created = true;
|
||||
}
|
||||
|
||||
cfg->setNumberOfButtons(m_buttons);
|
||||
cfg->setNumberOfAxis(m_axes);
|
||||
cfg->setPlugged();
|
||||
for (int i = 0; i < dm->getGamePadAmount(); i++)
|
||||
{
|
||||
GamePadDevice* d = dm->getGamePad(i);
|
||||
if (d->getName() == name && !d->isConnected())
|
||||
{
|
||||
m_gamepad = d;
|
||||
d->setConnected(true);
|
||||
d->setIrrIndex(m_id);
|
||||
d->setConfiguration(cfg);
|
||||
if (created)
|
||||
dm->save();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_gamepad = new GamePadDevice(m_id, name, m_axes, m_buttons, cfg);
|
||||
dm->addGamepad(m_gamepad);
|
||||
if (created)
|
||||
dm->save();
|
||||
} // SDLController
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
SDLController::~SDLController()
|
||||
{
|
||||
Log::info("SDLController", "%s unplugged.", SDL_JoystickName(m_joystick));
|
||||
if (m_game_controller)
|
||||
SDL_GameControllerClose(m_game_controller);
|
||||
else
|
||||
SDL_JoystickClose(m_joystick);
|
||||
m_gamepad->getConfiguration()->unPlugged();
|
||||
m_gamepad->setIrrIndex(-1);
|
||||
m_gamepad->setConnected(false);
|
||||
} // ~SDLController
|
||||
|
||||
#endif
|
131
src/input/sdl_controller.hpp
Normal file
131
src/input/sdl_controller.hpp
Normal file
@ -0,0 +1,131 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2020 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_SDL_CONTROLLER_HPP
|
||||
#define HEADER_SDL_CONTROLLER_HPP
|
||||
|
||||
#ifndef SERVER_ONLY
|
||||
|
||||
#include <SDL.h>
|
||||
#include <IEventReceiver.h>
|
||||
#include "utils/types.hpp"
|
||||
|
||||
class GamePadDevice;
|
||||
|
||||
class SDLController
|
||||
{
|
||||
private:
|
||||
SDL_GameController* m_game_controller;
|
||||
|
||||
SDL_Joystick* m_joystick;
|
||||
|
||||
GamePadDevice* m_gamepad;
|
||||
|
||||
int m_buttons;
|
||||
|
||||
int m_axes;
|
||||
|
||||
int m_hats;
|
||||
|
||||
SDL_JoystickID m_id;
|
||||
|
||||
irr::SEvent m_irr_event;
|
||||
public:
|
||||
// ------------------------------------------------------------------------
|
||||
SDLController(int device_id);
|
||||
// ------------------------------------------------------------------------
|
||||
~SDLController();
|
||||
// ------------------------------------------------------------------------
|
||||
const irr::SEvent& getEvent() const { return m_irr_event; }
|
||||
// ------------------------------------------------------------------------
|
||||
SDL_JoystickID getInstanceID() const { return m_id; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool handleAxis(const SDL_Event& event)
|
||||
{
|
||||
if (event.jaxis.axis > m_axes)
|
||||
return false;
|
||||
m_irr_event.JoystickEvent.Axis[event.jaxis.axis] = event.jaxis.value;
|
||||
uint32_t value = 1 << event.jaxis.axis;
|
||||
m_irr_event.JoystickEvent.AxisChanged = value;
|
||||
return true;
|
||||
} // handleAxis
|
||||
// ------------------------------------------------------------------------
|
||||
bool handleHat(const SDL_Event& event)
|
||||
{
|
||||
if (event.jhat.hat > m_hats)
|
||||
return false;
|
||||
uint32_t value = 0;
|
||||
// Up, right, down and left (4 buttons)
|
||||
switch (event.jhat.value)
|
||||
{
|
||||
case SDL_HAT_UP:
|
||||
value = 1;
|
||||
break;
|
||||
case SDL_HAT_RIGHTUP:
|
||||
value = 1 | (1 << 1);
|
||||
break;
|
||||
case SDL_HAT_RIGHT:
|
||||
value = 1 << 1;
|
||||
break;
|
||||
case SDL_HAT_RIGHTDOWN:
|
||||
value = (1 << 1) | (1 << 2);
|
||||
break;
|
||||
case SDL_HAT_DOWN:
|
||||
value = 1 << 2;
|
||||
break;
|
||||
case SDL_HAT_LEFTDOWN:
|
||||
value = (1 << 2) | (1 << 3);
|
||||
break;
|
||||
case SDL_HAT_LEFT:
|
||||
value = 1 << 3;
|
||||
break;
|
||||
case SDL_HAT_LEFTUP:
|
||||
value = (1 << 3) | 1;
|
||||
break;
|
||||
case SDL_HAT_CENTERED:
|
||||
default:
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
int hat_start = m_buttons - (m_hats * 4);
|
||||
unsigned hat_mask = (unsigned)((1 << hat_start) - 1);
|
||||
m_irr_event.JoystickEvent.ButtonStates &= hat_mask;
|
||||
value <<= hat_start;
|
||||
value <<= (m_hats - 1) * 4;
|
||||
m_irr_event.JoystickEvent.ButtonStates |= value;
|
||||
m_irr_event.JoystickEvent.AxisChanged = 0;
|
||||
return true;
|
||||
} // handleHat
|
||||
// ------------------------------------------------------------------------
|
||||
bool handleButton(const SDL_Event& event)
|
||||
{
|
||||
if (event.jbutton.button > m_buttons)
|
||||
return false;
|
||||
bool pressed = event.jbutton.state == SDL_PRESSED;
|
||||
uint32_t value = 1 << event.jbutton.button;
|
||||
if (pressed)
|
||||
m_irr_event.JoystickEvent.ButtonStates |= value;
|
||||
else
|
||||
m_irr_event.JoystickEvent.ButtonStates &= (uint32_t)~value;
|
||||
m_irr_event.JoystickEvent.AxisChanged = 0;
|
||||
return true;
|
||||
} // handleButton
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -68,8 +68,8 @@ void Wiimote::resetIrrEvent()
|
||||
event.EventType = irr::EET_JOYSTICK_INPUT_EVENT;
|
||||
for(int i=0 ; i < irr::SEvent::SJoystickEvent::NUMBER_OF_AXES ; i++)
|
||||
event.JoystickEvent.Axis[i] = 0;
|
||||
event.JoystickEvent.AxisChanged = 1;
|
||||
event.JoystickEvent.Joystick = getIrrId();
|
||||
event.JoystickEvent.POV = 65535;
|
||||
event.JoystickEvent.ButtonStates = 0;
|
||||
} // resetIrrEvent
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user