2010-10-13 16:30:31 +00:00
|
|
|
#include <SDL_joystick.h>
|
|
|
|
|
2012-04-29 00:53:27 +00:00
|
|
|
#include "doomdef.h"
|
2010-10-13 16:30:31 +00:00
|
|
|
#include "m_joy.h"
|
|
|
|
|
|
|
|
class SDLInputJoystick: public IJoystickConfig
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
SDLInputJoystick(int DeviceIndex) : DeviceIndex(DeviceIndex), Multiplier(1.0f)
|
|
|
|
{
|
|
|
|
Device = SDL_JoystickOpen(DeviceIndex);
|
|
|
|
if(Device != NULL)
|
2012-04-29 00:53:27 +00:00
|
|
|
{
|
|
|
|
NumAxes = SDL_JoystickNumAxes(Device);
|
|
|
|
NumHats = SDL_JoystickNumHats(Device);
|
|
|
|
|
2010-10-13 16:30:31 +00:00
|
|
|
SetDefaultConfig();
|
2012-04-29 00:53:27 +00:00
|
|
|
}
|
2010-10-13 16:30:31 +00:00
|
|
|
}
|
|
|
|
~SDLInputJoystick()
|
|
|
|
{
|
|
|
|
if(Device != NULL)
|
|
|
|
M_SaveJoystickConfig(this);
|
|
|
|
SDL_JoystickClose(Device);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsValid() const
|
|
|
|
{
|
|
|
|
return Device != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
FString GetName()
|
|
|
|
{
|
|
|
|
return SDL_JoystickName(DeviceIndex);
|
|
|
|
}
|
|
|
|
float GetSensitivity()
|
|
|
|
{
|
|
|
|
return Multiplier;
|
|
|
|
}
|
|
|
|
void SetSensitivity(float scale)
|
|
|
|
{
|
|
|
|
Multiplier = scale;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetNumAxes()
|
|
|
|
{
|
2012-04-29 00:53:27 +00:00
|
|
|
return NumAxes + NumHats*2;
|
2010-10-13 16:30:31 +00:00
|
|
|
}
|
|
|
|
float GetAxisDeadZone(int axis)
|
|
|
|
{
|
|
|
|
return Axes[axis].DeadZone;
|
|
|
|
}
|
|
|
|
EJoyAxis GetAxisMap(int axis)
|
|
|
|
{
|
|
|
|
return Axes[axis].GameAxis;
|
|
|
|
}
|
|
|
|
const char *GetAxisName(int axis)
|
|
|
|
{
|
|
|
|
return Axes[axis].Name.GetChars();
|
|
|
|
}
|
|
|
|
float GetAxisScale(int axis)
|
|
|
|
{
|
|
|
|
return Axes[axis].Multiplier;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetAxisDeadZone(int axis, float zone)
|
|
|
|
{
|
|
|
|
Axes[axis].DeadZone = zone;
|
|
|
|
}
|
|
|
|
void SetAxisMap(int axis, EJoyAxis gameaxis)
|
|
|
|
{
|
|
|
|
Axes[axis].GameAxis = gameaxis;
|
|
|
|
}
|
|
|
|
void SetAxisScale(int axis, float scale)
|
|
|
|
{
|
|
|
|
Axes[axis].Multiplier = scale;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Used by the saver to not save properties that are at their defaults.
|
|
|
|
bool IsSensitivityDefault()
|
|
|
|
{
|
|
|
|
return Multiplier == 1.0f;
|
|
|
|
}
|
|
|
|
bool IsAxisDeadZoneDefault(int axis)
|
|
|
|
{
|
|
|
|
return Axes[axis].DeadZone == 0.0f;
|
|
|
|
}
|
|
|
|
bool IsAxisMapDefault(int axis)
|
|
|
|
{
|
|
|
|
if(axis >= 5)
|
|
|
|
return Axes[axis].GameAxis == JOYAXIS_None;
|
|
|
|
return Axes[axis].GameAxis == DefaultAxes[axis];
|
|
|
|
}
|
|
|
|
bool IsAxisScaleDefault(int axis)
|
|
|
|
{
|
|
|
|
return Axes[axis].Multiplier == 1.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetDefaultConfig()
|
|
|
|
{
|
|
|
|
for(int i = 0;i < GetNumAxes();i++)
|
|
|
|
{
|
|
|
|
AxisInfo info;
|
2012-04-29 00:53:27 +00:00
|
|
|
if(i < NumAxes)
|
|
|
|
info.Name.Format("Axis %d", i+1);
|
|
|
|
else
|
|
|
|
info.Name.Format("Hat %d (%c)", (i-NumAxes)/2 + 1, (i-NumAxes)%2 == 0 ? 'x' : 'y');
|
2010-10-13 16:30:31 +00:00
|
|
|
info.DeadZone = 0.0f;
|
|
|
|
info.Multiplier = 1.0f;
|
2012-04-28 03:44:10 +00:00
|
|
|
info.Value = 0.0;
|
2012-04-29 00:53:27 +00:00
|
|
|
info.ButtonValue = 0;
|
2010-10-13 16:30:31 +00:00
|
|
|
if(i >= 5)
|
|
|
|
info.GameAxis = JOYAXIS_None;
|
|
|
|
else
|
|
|
|
info.GameAxis = DefaultAxes[i];
|
|
|
|
Axes.Push(info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FString GetIdentifier()
|
|
|
|
{
|
|
|
|
char id[16];
|
|
|
|
mysnprintf(id, countof(id), "JS:%d", DeviceIndex);
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddAxes(float axes[NUM_JOYAXIS])
|
|
|
|
{
|
|
|
|
// Add to game axes.
|
|
|
|
for (int i = 0; i < GetNumAxes(); ++i)
|
|
|
|
{
|
2010-10-13 20:07:16 +00:00
|
|
|
if(Axes[i].GameAxis != JOYAXIS_None)
|
2012-04-28 03:44:10 +00:00
|
|
|
axes[Axes[i].GameAxis] -= float(Axes[i].Value * Multiplier * Axes[i].Multiplier);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ProcessInput()
|
|
|
|
{
|
2012-04-29 00:53:27 +00:00
|
|
|
BYTE buttonstate;
|
|
|
|
|
|
|
|
for (int i = 0; i < NumAxes; ++i)
|
2012-04-28 03:44:10 +00:00
|
|
|
{
|
2012-04-29 00:53:27 +00:00
|
|
|
buttonstate = 0;
|
|
|
|
|
2012-04-28 03:44:10 +00:00
|
|
|
Axes[i].Value = SDL_JoystickGetAxis(Device, i)/32768.0;
|
2012-04-29 00:53:27 +00:00
|
|
|
Axes[i].Value = Joy_RemoveDeadZone(Axes[i].Value, Axes[i].DeadZone, &buttonstate);
|
|
|
|
|
|
|
|
// Map button to axis
|
|
|
|
// X and Y are handled differently so if we have 2 or more axes then we'll use that code instead.
|
|
|
|
if (NumAxes == 1 || (i >= 2 && i < NUM_JOYAXISBUTTONS))
|
|
|
|
{
|
|
|
|
Joy_GenerateButtonEvents(Axes[i].ButtonValue, buttonstate, 2, KEY_JOYAXIS1PLUS + i*2);
|
|
|
|
Axes[i].ButtonValue = buttonstate;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(NumAxes > 1)
|
|
|
|
{
|
|
|
|
buttonstate = Joy_XYAxesToButtons(Axes[0].Value, Axes[1].Value);
|
|
|
|
Joy_GenerateButtonEvents(Axes[0].ButtonValue, buttonstate, 4, KEY_JOYAXIS1PLUS);
|
|
|
|
Axes[0].ButtonValue = buttonstate;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Map POV hats to buttons and axes. Why axes? Well apparently I have
|
|
|
|
// a gamepad where the left control stick is a POV hat (instead of the
|
|
|
|
// d-pad like you would expect, no that's pressure sensitive). Also
|
|
|
|
// KDE's joystick dialog maps them to axes as well.
|
|
|
|
for (int i = 0; i < NumHats; ++i)
|
|
|
|
{
|
|
|
|
AxisInfo &x = Axes[NumAxes + i*2];
|
|
|
|
AxisInfo &y = Axes[NumAxes + i*2 + 1];
|
|
|
|
|
|
|
|
buttonstate = SDL_JoystickGetHat(Device, i);
|
|
|
|
switch(buttonstate)
|
|
|
|
{
|
|
|
|
case SDL_HAT_LEFTUP:
|
|
|
|
x.Value = -1.0;
|
|
|
|
y.Value = -1.0;
|
|
|
|
break;
|
|
|
|
case SDL_HAT_LEFT:
|
|
|
|
x.Value = -1.0;
|
|
|
|
y.Value = 0.0;
|
|
|
|
break;
|
|
|
|
case SDL_HAT_LEFTDOWN:
|
|
|
|
x.Value = -1.0;
|
|
|
|
y.Value = 1.0;
|
|
|
|
break;
|
|
|
|
case SDL_HAT_RIGHTUP:
|
|
|
|
x.Value = 1.0;
|
|
|
|
y.Value = -1.0;
|
|
|
|
break;
|
|
|
|
case SDL_HAT_RIGHT:
|
|
|
|
x.Value = 1.0;
|
|
|
|
y.Value = 0.0;
|
|
|
|
break;
|
|
|
|
case SDL_HAT_RIGHTDOWN:
|
|
|
|
x.Value = 1.0;
|
|
|
|
y.Value = 1.0;
|
|
|
|
break;
|
|
|
|
case SDL_HAT_UP:
|
|
|
|
x.Value = 0.0;
|
|
|
|
y.Value = -1.0;
|
|
|
|
break;
|
|
|
|
case SDL_HAT_DOWN:
|
|
|
|
x.Value = 0.0;
|
|
|
|
y.Value = 1.0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
x.Value = 0.0;
|
|
|
|
y.Value = 0.0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(i < 4)
|
|
|
|
{
|
|
|
|
Joy_GenerateButtonEvents(x.ButtonValue, buttonstate, 4, KEY_JOYPOV1_UP + i*4);
|
|
|
|
x.ButtonValue = buttonstate;
|
|
|
|
}
|
2010-10-13 16:30:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
struct AxisInfo
|
|
|
|
{
|
|
|
|
FString Name;
|
|
|
|
float DeadZone;
|
|
|
|
float Multiplier;
|
|
|
|
EJoyAxis GameAxis;
|
2012-04-28 03:44:10 +00:00
|
|
|
double Value;
|
2012-04-29 00:53:27 +00:00
|
|
|
BYTE ButtonValue;
|
2010-10-13 16:30:31 +00:00
|
|
|
};
|
|
|
|
static const EJoyAxis DefaultAxes[5];
|
|
|
|
|
|
|
|
int DeviceIndex;
|
|
|
|
SDL_Joystick *Device;
|
|
|
|
|
|
|
|
float Multiplier;
|
|
|
|
TArray<AxisInfo> Axes;
|
2012-04-29 00:53:27 +00:00
|
|
|
int NumAxes;
|
|
|
|
int NumHats;
|
2010-10-13 16:30:31 +00:00
|
|
|
};
|
|
|
|
const EJoyAxis SDLInputJoystick::DefaultAxes[5] = {JOYAXIS_Side, JOYAXIS_Forward, JOYAXIS_Pitch, JOYAXIS_Yaw, JOYAXIS_Up};
|
|
|
|
|
|
|
|
class SDLInputJoystickManager
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
SDLInputJoystickManager()
|
|
|
|
{
|
|
|
|
for(int i = 0;i < SDL_NumJoysticks();i++)
|
|
|
|
{
|
|
|
|
SDLInputJoystick *device = new SDLInputJoystick(i);
|
|
|
|
if(device->IsValid())
|
|
|
|
Joysticks.Push(device);
|
|
|
|
else
|
|
|
|
delete device;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
~SDLInputJoystickManager()
|
|
|
|
{
|
|
|
|
for(unsigned int i = 0;i < Joysticks.Size();i++)
|
|
|
|
delete Joysticks[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddAxes(float axes[NUM_JOYAXIS])
|
|
|
|
{
|
|
|
|
for(unsigned int i = 0;i < Joysticks.Size();i++)
|
|
|
|
Joysticks[i]->AddAxes(axes);
|
|
|
|
}
|
|
|
|
void GetDevices(TArray<IJoystickConfig *> &sticks)
|
|
|
|
{
|
|
|
|
for(unsigned int i = 0;i < Joysticks.Size();i++)
|
|
|
|
{
|
|
|
|
M_LoadJoystickConfig(Joysticks[i]);
|
|
|
|
sticks.Push(Joysticks[i]);
|
|
|
|
}
|
|
|
|
}
|
2012-04-28 03:44:10 +00:00
|
|
|
|
|
|
|
void ProcessInput() const
|
|
|
|
{
|
|
|
|
for(unsigned int i = 0;i < Joysticks.Size();++i)
|
|
|
|
Joysticks[i]->ProcessInput();
|
|
|
|
}
|
2010-10-13 16:30:31 +00:00
|
|
|
protected:
|
|
|
|
TArray<SDLInputJoystick *> Joysticks;
|
|
|
|
};
|
|
|
|
static SDLInputJoystickManager *JoystickManager;
|
|
|
|
|
|
|
|
void I_StartupJoysticks()
|
|
|
|
{
|
|
|
|
JoystickManager = new SDLInputJoystickManager();
|
|
|
|
}
|
|
|
|
void I_ShutdownJoysticks()
|
|
|
|
{
|
|
|
|
delete JoystickManager;
|
|
|
|
}
|
|
|
|
|
|
|
|
void I_GetJoysticks(TArray<IJoystickConfig *> &sticks)
|
|
|
|
{
|
|
|
|
sticks.Clear();
|
|
|
|
|
|
|
|
JoystickManager->GetDevices(sticks);
|
|
|
|
}
|
|
|
|
|
|
|
|
void I_GetAxes(float axes[NUM_JOYAXIS])
|
|
|
|
{
|
|
|
|
for (int i = 0; i < NUM_JOYAXIS; ++i)
|
|
|
|
{
|
|
|
|
axes[i] = 0;
|
|
|
|
}
|
|
|
|
if (use_joystick)
|
|
|
|
{
|
|
|
|
JoystickManager->AddAxes(axes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-28 03:44:10 +00:00
|
|
|
void I_ProcessJoysticks()
|
|
|
|
{
|
|
|
|
if (use_joystick)
|
|
|
|
JoystickManager->ProcessInput();
|
|
|
|
}
|
|
|
|
|
2010-10-13 16:30:31 +00:00
|
|
|
IJoystickConfig *I_UpdateDeviceList()
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|