[SDL2] Fixed mapping of instance ids to device ids

This commit is contained in:
thefiddler 2013-12-30 14:57:28 +01:00
parent a4366e52f5
commit 52b8762593

View file

@ -56,9 +56,12 @@ namespace OpenTK.Platform.SDL2
} }
} }
int last_controllers_instance = 0;
readonly List<JoystickDevice> joysticks = new List<JoystickDevice>(4); 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_joyid_to_joysticks = new Dictionary<int, int>();
readonly Dictionary<int, Sdl2GamePad> controllers = new Dictionary<int, Sdl2GamePad>(); readonly List<Sdl2GamePad> controllers = new List<Sdl2GamePad>(4);
readonly Dictionary<int, int> sdl_instanceid_to_controllers = new Dictionary<int, int>();
IList<JoystickDevice> joysticks_readonly; IList<JoystickDevice> joysticks_readonly;
bool disposed; bool disposed;
@ -112,7 +115,12 @@ namespace OpenTK.Platform.SDL2
bool IsControllerValid(int id) bool IsControllerValid(int id)
{ {
return controllers.ContainsKey(id); return id >= 0 && id < controllers.Count;
}
bool IsControllerInstanceValid(int instance_id)
{
return sdl_instanceid_to_controllers.ContainsKey(instance_id);
} }
GamePadAxes GetBoundAxes(IntPtr gamecontroller) GamePadAxes GetBoundAxes(IntPtr gamecontroller)
@ -306,12 +314,20 @@ namespace OpenTK.Platform.SDL2
IntPtr handle = SDL.GameControllerOpen(id); IntPtr handle = SDL.GameControllerOpen(id);
if (handle != IntPtr.Zero) if (handle != IntPtr.Zero)
{ {
// The id variable here corresponds to a device_id between 0 and Sdl.NumJoysticks().
// It is only used in the ADDED event. All other events use an instance_id which increases
// monotonically in each ADDED event.
// The idea is that device_id refers to the n-th connected joystick, whereas instance_id
// refers to the actual hardware device behind the n-th joystick.
// Yes, it's confusing.
int device_id = id;
int instance_id = last_controllers_instance++;
Sdl2GamePad pad = new Sdl2GamePad(handle); Sdl2GamePad pad = new Sdl2GamePad(handle);
IntPtr joystick = SDL.GameControllerGetJoystick(handle); IntPtr joystick = SDL.GameControllerGetJoystick(handle);
if (joystick != IntPtr.Zero) if (joystick != IntPtr.Zero)
{ {
SDL.JoystickNumAxes(joystick);
pad.Capabilities = new GamePadCapabilities( pad.Capabilities = new GamePadCapabilities(
GamePadType.GamePad, GamePadType.GamePad,
GetBoundAxes(joystick), GetBoundAxes(joystick),
@ -319,10 +335,17 @@ namespace OpenTK.Platform.SDL2
true); true);
pad.State.SetConnected(true); pad.State.SetConnected(true);
// Check whether the device has ever been connected before // Connect this device and add the relevant device index
if (!controllers.ContainsKey(id)) if (controllers.Count <= id)
controllers.Add(id, null); {
controllers[id] = pad; controllers.Add(pad);
}
else
{
controllers[device_id] = pad;
}
sdl_instanceid_to_controllers.Add(instance_id, device_id);
} }
else else
{ {
@ -332,11 +355,15 @@ namespace OpenTK.Platform.SDL2
break; break;
case EventType.CONTROLLERDEVICEREMOVED: case EventType.CONTROLLERDEVICEREMOVED:
if (IsControllerValid(id))
{ {
controllers[id].State.SetConnected(false); int instance_id = id;
if (IsControllerInstanceValid(id))
{
controllers[id].State.SetConnected(false);
sdl_instanceid_to_controllers.Remove(instance_id);
}
break;
} }
break;
case EventType.CONTROLLERDEVICEREMAPPED: case EventType.CONTROLLERDEVICEREMAPPED:
// Todo: what should we do in this case? // Todo: what should we do in this case?
@ -346,27 +373,29 @@ namespace OpenTK.Platform.SDL2
public void ProcessControllerEvent(ControllerAxisEvent ev) public void ProcessControllerEvent(ControllerAxisEvent ev)
{ {
int id = ev.Which; int instance_id = ev.Which;
if (IsControllerValid(id)) if (IsControllerInstanceValid(instance_id))
{ {
controllers[id].State.SetAxis(TranslateAxis(ev.Axis), ev.Value); int id = sdl_instanceid_to_controllers[instance_id];
controllers[id].State.SetAxis(TranslateAxis(ev.Axis), ev.Value);
} }
else else
{ {
Debug.Print("[SDL2] Invalid game controller handle {0} in {1}", id, ev.Type); Debug.Print("[SDL2] Invalid game controller instance {0} in {1}", instance_id, ev.Type);
} }
} }
public void ProcessControllerEvent(ControllerButtonEvent ev) public void ProcessControllerEvent(ControllerButtonEvent ev)
{ {
int id = ev.Which; int instance_id = ev.Which;
if (IsControllerValid(id)) if (IsControllerInstanceValid(instance_id))
{ {
int id = sdl_instanceid_to_controllers[instance_id];
controllers[id].State.SetButton((Buttons)ev.Button, ev.State == State.Pressed); controllers[id].State.SetButton((Buttons)ev.Button, ev.State == State.Pressed);
} }
else else
{ {
Debug.Print("[SDL2] Invalid game controller handle {0} in {1}", id, ev.Type); Debug.Print("[SDL2] Invalid game controller instance {0} in {1}", instance_id, ev.Type);
} }
} }