[SDL2] Fixed joystick hotplugging

SDL2 uses a weird system of device ids and instance ids to report
joystick events, where the ADDED event uses a device id and the rest use
instance ids.

The SDL2 joystick driver is now fixed to correctly distinguish between
the two, which fixes hotplugging support for joystick devices.
This commit is contained in:
Stefanos A. 2013-12-30 15:24:48 +01:00
parent 52b8762593
commit 6faa58aac3

View file

@ -56,10 +56,11 @@ namespace OpenTK.Platform.SDL2
}
}
int last_joystick_instance = 0;
int last_controllers_instance = 0;
readonly List<JoystickDevice> joysticks = new List<JoystickDevice>(4);
readonly Dictionary<int, int> sdl_joyid_to_joysticks = new Dictionary<int, int>();
readonly Dictionary<int, int> sdl_instanceid_to_joysticks = new Dictionary<int, int>();
readonly List<Sdl2GamePad> controllers = new List<Sdl2GamePad>(4);
readonly Dictionary<int, int> sdl_instanceid_to_controllers = new Dictionary<int, int>();
@ -113,6 +114,11 @@ namespace OpenTK.Platform.SDL2
return id >= 0 && id < joysticks.Count;
}
bool IsJoystickInstanceValid(int instance_id)
{
return sdl_instanceid_to_joysticks.ContainsKey(instance_id);
}
bool IsControllerValid(int id)
{
return id >= 0 && id < controllers.Count;
@ -217,28 +223,41 @@ namespace OpenTK.Platform.SDL2
IntPtr handle = SDL.JoystickOpen(id);
if (handle != IntPtr.Zero)
{
int device_id = id;
int instance_id = last_joystick_instance++;
JoystickDevice<Sdl2JoystickDetails> joystick = OpenJoystick(id);
if (joystick != null)
{
joystick.Details.IsConnected = true;
if (!sdl_joyid_to_joysticks.ContainsKey(id))
if (device_id < joysticks.Count)
{
sdl_joyid_to_joysticks.Add(id, joysticks.Count);
joysticks.Add(null);
joysticks[device_id] = joystick;
}
int index = sdl_joyid_to_joysticks[id];
joysticks[index] = joystick;
else
{
joysticks.Add(joystick);
}
sdl_instanceid_to_joysticks.Add(instance_id, device_id);
}
}
}
break;
case EventType.JOYDEVICEREMOVED:
if (IsJoystickInstanceValid(id))
{
int index = sdl_joyid_to_joysticks[id];
JoystickDevice<Sdl2JoystickDetails> joystick = (JoystickDevice<Sdl2JoystickDetails>)joysticks[index];
int instance_id = sdl_instanceid_to_joysticks[id];
sdl_instanceid_to_joysticks.Remove(id);
JoystickDevice<Sdl2JoystickDetails> joystick = (JoystickDevice<Sdl2JoystickDetails>)joysticks[instance_id];
joystick.Details.IsConnected = false;
}
else
{
Debug.Print("[SDL2] Invalid joystick id {0} in {1}", id, ev.Type);
}
break;
}
}
@ -246,9 +265,9 @@ namespace OpenTK.Platform.SDL2
public void ProcessJoystickEvent(JoyAxisEvent ev)
{
int id = ev.Which;
if (IsJoystickValid(id))
if (IsJoystickInstanceValid(id))
{
int index = sdl_joyid_to_joysticks[id];
int index = sdl_instanceid_to_joysticks[id];
JoystickDevice<Sdl2JoystickDetails> joystick = (JoystickDevice<Sdl2JoystickDetails>)joysticks[index];
float value = ev.Value * RangeMultiplier;
joystick.SetAxis((JoystickAxis)ev.Axis, value);
@ -262,9 +281,9 @@ namespace OpenTK.Platform.SDL2
public void ProcessJoystickEvent(JoyBallEvent ev)
{
int id = ev.Which;
if (IsJoystickValid(id))
if (IsJoystickInstanceValid(id))
{
int index = sdl_joyid_to_joysticks[id];
int index = sdl_instanceid_to_joysticks[id];
JoystickDevice<Sdl2JoystickDetails> joystick = (JoystickDevice<Sdl2JoystickDetails>)joysticks[index];
// Todo: does it make sense to support balls?
}
@ -277,9 +296,9 @@ namespace OpenTK.Platform.SDL2
public void ProcessJoystickEvent(JoyButtonEvent ev)
{
int id = ev.Which;
if (IsJoystickValid(id))
if (IsJoystickInstanceValid(id))
{
int index = sdl_joyid_to_joysticks[id];
int index = sdl_instanceid_to_joysticks[id];
JoystickDevice<Sdl2JoystickDetails> joystick = (JoystickDevice<Sdl2JoystickDetails>)joysticks[index];
joystick.SetButton((JoystickButton)ev.Button, ev.State == State.Pressed);
}
@ -292,9 +311,9 @@ namespace OpenTK.Platform.SDL2
public void ProcessJoystickEvent(JoyHatEvent ev)
{
int id = ev.Which;
if (IsJoystickValid(id))
if (IsJoystickInstanceValid(id))
{
int index = sdl_joyid_to_joysticks[id];
int index = sdl_instanceid_to_joysticks[id];
JoystickDevice<Sdl2JoystickDetails> joystick = (JoystickDevice<Sdl2JoystickDetails>)joysticks[index];
// Todo: map hat to an extra axis
}
@ -307,6 +326,11 @@ namespace OpenTK.Platform.SDL2
public void ProcessControllerEvent(ControllerDeviceEvent ev)
{
int id = ev.Which;
if (id < 0)
{
Debug.Print("[SDL2] Invalid controller id {0} in {1}", id, ev.Type);
return;
}
switch (ev.Type)
{
@ -355,18 +379,26 @@ namespace OpenTK.Platform.SDL2
break;
case EventType.CONTROLLERDEVICEREMOVED:
if (IsControllerInstanceValid(id))
{
int instance_id = id;
if (IsControllerInstanceValid(id))
{
controllers[id].State.SetConnected(false);
sdl_instanceid_to_controllers.Remove(instance_id);
}
break;
controllers[id].State.SetConnected(false);
sdl_instanceid_to_controllers.Remove(id);
}
else
{
Debug.Print("[SDL2] Invalid game controller instance {0} in {1}", id, ev.Type);
}
break;
case EventType.CONTROLLERDEVICEREMAPPED:
// Todo: what should we do in this case?
if (IsControllerInstanceValid(id))
{
// Todo: what should we do in this case?
}
else
{
Debug.Print("[SDL2] Invalid game controller instance {0} in {1}", id, ev.Type);
}
break;
}
}
@ -453,7 +485,7 @@ namespace OpenTK.Platform.SDL2
if (IsJoystickValid(index))
{
JoystickDevice<Sdl2JoystickDetails> joystick =
(JoystickDevice<Sdl2JoystickDetails>)joysticks[sdl_joyid_to_joysticks[index]];
(JoystickDevice<Sdl2JoystickDetails>)joysticks[index];
for (int i = 0; i < joystick.Axis.Count; i++)
{
@ -465,7 +497,7 @@ namespace OpenTK.Platform.SDL2
state.SetButton(JoystickButton.Button0 + i, joystick.Button[i]);
}
state.SetIsConnected(true);
state.SetIsConnected(joystick.Details.IsConnected);
}
return state;
@ -476,12 +508,12 @@ namespace OpenTK.Platform.SDL2
if (IsJoystickValid(index))
{
JoystickDevice<Sdl2JoystickDetails> joystick =
(JoystickDevice<Sdl2JoystickDetails>)joysticks[sdl_joyid_to_joysticks[index]];
(JoystickDevice<Sdl2JoystickDetails>)joysticks[index];
return new JoystickCapabilities(
joystick.Axis.Count,
joystick.Button.Count,
true);
joystick.Details.IsConnected);
}
return new JoystickCapabilities();
}