Make sure DirectInput objects are disposed properly. Also includes a better fix for thread safety issues (#722).
This commit is contained in:
parent
5446a636ba
commit
a2aba7e3c2
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using SlimDX;
|
||||
using SlimDX.DirectInput;
|
||||
|
@ -10,50 +9,77 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
// ********************************** Static interface **********************************
|
||||
|
||||
static DirectInput dinput;
|
||||
public static List<GamePad> Devices;
|
||||
private static readonly object _syncObj = new object();
|
||||
private static readonly List<GamePad> _devices = new List<GamePad>();
|
||||
private static DirectInput _dinput;
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
if (dinput == null)
|
||||
dinput = new DirectInput();
|
||||
|
||||
Devices = new List<GamePad>();
|
||||
|
||||
foreach (DeviceInstance device in dinput.GetDevices(DeviceClass.GameController, DeviceEnumerationFlags.AttachedOnly))
|
||||
lock (_syncObj)
|
||||
{
|
||||
Console.WriteLine("joydevice: {0} `{1}`", device.InstanceGuid, device.ProductName);
|
||||
Cleanup();
|
||||
|
||||
if (device.ProductName.Contains("XBOX 360"))
|
||||
continue; // Don't input XBOX 360 controllers into here; we'll process them via XInput (there are limitations in some trigger axes when xbox pads go over xinput)
|
||||
_dinput = new DirectInput();
|
||||
|
||||
var joystick = new Joystick(dinput, device.InstanceGuid);
|
||||
joystick.SetCooperativeLevel(GlobalWin.MainForm.Handle, CooperativeLevel.Background | CooperativeLevel.Nonexclusive);
|
||||
foreach (DeviceObjectInstance deviceObject in joystick.GetObjects())
|
||||
foreach (DeviceInstance device in _dinput.GetDevices(DeviceClass.GameController, DeviceEnumerationFlags.AttachedOnly))
|
||||
{
|
||||
if ((deviceObject.ObjectType & ObjectDeviceType.Axis) != 0)
|
||||
joystick.GetObjectPropertiesById((int)deviceObject.ObjectType).SetRange(-1000, 1000);
|
||||
}
|
||||
joystick.Acquire();
|
||||
Console.WriteLine("joydevice: {0} `{1}`", device.InstanceGuid, device.ProductName);
|
||||
|
||||
GamePad p = new GamePad(device.InstanceName, device.InstanceGuid, joystick);
|
||||
Devices.Add(p);
|
||||
if (device.ProductName.Contains("XBOX 360"))
|
||||
continue; // Don't input XBOX 360 controllers into here; we'll process them via XInput (there are limitations in some trigger axes when xbox pads go over xinput)
|
||||
|
||||
var joystick = new Joystick(_dinput, device.InstanceGuid);
|
||||
joystick.SetCooperativeLevel(GlobalWin.MainForm.Handle, CooperativeLevel.Background | CooperativeLevel.Nonexclusive);
|
||||
foreach (DeviceObjectInstance deviceObject in joystick.GetObjects())
|
||||
{
|
||||
if ((deviceObject.ObjectType & ObjectDeviceType.Axis) != 0)
|
||||
joystick.GetObjectPropertiesById((int)deviceObject.ObjectType).SetRange(-1000, 1000);
|
||||
}
|
||||
joystick.Acquire();
|
||||
|
||||
GamePad p = new GamePad(device.InstanceName, device.InstanceGuid, joystick);
|
||||
_devices.Add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<GamePad> EnumerateDevices()
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
foreach (var device in _devices)
|
||||
{
|
||||
yield return device;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateAll()
|
||||
{
|
||||
foreach (var device in Devices.ToList())
|
||||
device.Update();
|
||||
lock (_syncObj)
|
||||
{
|
||||
foreach (var device in _devices)
|
||||
{
|
||||
device.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void CloseAll()
|
||||
public static void Cleanup()
|
||||
{
|
||||
if (Devices != null)
|
||||
lock (_syncObj)
|
||||
{
|
||||
foreach (var device in Devices)
|
||||
foreach (var device in _devices)
|
||||
{
|
||||
device.joystick.Dispose();
|
||||
Devices.Clear();
|
||||
}
|
||||
_devices.Clear();
|
||||
|
||||
if (_dinput != null)
|
||||
{
|
||||
_dinput.Dispose();
|
||||
_dinput = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using SlimDX.XInput;
|
||||
|
||||
#pragma warning disable 169
|
||||
|
@ -13,9 +12,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
// ********************************** Static interface **********************************
|
||||
|
||||
public static List<GamePad360> Devices = new List<GamePad360>();
|
||||
|
||||
static bool IsAvailable;
|
||||
private static readonly object _syncObj = new object();
|
||||
private static readonly List<GamePad360> _devices = new List<GamePad360>();
|
||||
private static readonly bool _isAvailable = IsAvailable();
|
||||
|
||||
[DllImport("kernel32", SetLastError = true, EntryPoint = "GetProcAddress")]
|
||||
static extern IntPtr GetProcAddressOrdinal(IntPtr hModule, IntPtr procName);
|
||||
|
@ -43,9 +42,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
public XINPUT_GAMEPAD Gamepad;
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
private static bool IsAvailable()
|
||||
{
|
||||
IsAvailable = false;
|
||||
try
|
||||
{
|
||||
//some users wont even have xinput installed. in order to avoid spurious exceptions and possible instability, check for the library first
|
||||
|
@ -70,35 +68,60 @@ namespace BizHawk.Client.EmuHawk
|
|||
//don't remove this code. it's important to catch errors on systems with broken xinput installs.
|
||||
//(probably, checking for the library was adequate, but lets not get rid of this anyway)
|
||||
var test = new SlimDX.XInput.Controller(UserIndex.One).IsConnected;
|
||||
IsAvailable = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
catch { }
|
||||
|
||||
if (!IsAvailable) return;
|
||||
return false;
|
||||
}
|
||||
|
||||
//now, at this point, slimdx may be using one xinput, and we may be using another
|
||||
//i'm not sure how slimdx picks its dll to bind to.
|
||||
//i'm not sure how troublesome this will be
|
||||
//maybe we should get rid of slimdx for this altogether
|
||||
public static void Initialize()
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
_devices.Clear();
|
||||
|
||||
var c1 = new Controller(UserIndex.One);
|
||||
var c2 = new Controller(UserIndex.Two);
|
||||
var c3 = new Controller(UserIndex.Three);
|
||||
var c4 = new Controller(UserIndex.Four);
|
||||
if (!_isAvailable)
|
||||
return;
|
||||
|
||||
if (c1.IsConnected) Devices.Add(new GamePad360(0,c1));
|
||||
if (c2.IsConnected) Devices.Add(new GamePad360(1,c2));
|
||||
if (c3.IsConnected) Devices.Add(new GamePad360(2,c3));
|
||||
if (c4.IsConnected) Devices.Add(new GamePad360(3,c4));
|
||||
//now, at this point, slimdx may be using one xinput, and we may be using another
|
||||
//i'm not sure how slimdx picks its dll to bind to.
|
||||
//i'm not sure how troublesome this will be
|
||||
//maybe we should get rid of slimdx for this altogether
|
||||
|
||||
var c1 = new Controller(UserIndex.One);
|
||||
var c2 = new Controller(UserIndex.Two);
|
||||
var c3 = new Controller(UserIndex.Three);
|
||||
var c4 = new Controller(UserIndex.Four);
|
||||
|
||||
if (c1.IsConnected) _devices.Add(new GamePad360(0, c1));
|
||||
if (c2.IsConnected) _devices.Add(new GamePad360(1, c2));
|
||||
if (c3.IsConnected) _devices.Add(new GamePad360(2, c3));
|
||||
if (c4.IsConnected) _devices.Add(new GamePad360(3, c4));
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<GamePad360> EnumerateDevices()
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
foreach (var device in _devices)
|
||||
{
|
||||
yield return device;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateAll()
|
||||
{
|
||||
if(IsAvailable)
|
||||
foreach (var device in Devices.ToList())
|
||||
lock (_syncObj)
|
||||
{
|
||||
foreach (var device in _devices)
|
||||
{
|
||||
device.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ********************************** Instance Members **********************************
|
||||
|
|
|
@ -135,6 +135,14 @@ namespace BizHawk.Client.EmuHawk
|
|||
Instance = new Input();
|
||||
}
|
||||
|
||||
public static void Cleanup()
|
||||
{
|
||||
#if WINDOWS
|
||||
KeyInput.Cleanup();
|
||||
GamePad.Cleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
public enum InputEventType
|
||||
{
|
||||
Press, Release
|
||||
|
@ -338,9 +346,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
//FloatValues.Clear();
|
||||
|
||||
//analyze xinput
|
||||
for (int i = 0; i < GamePad360.Devices.Count; i++)
|
||||
foreach (var pad in GamePad360.EnumerateDevices())
|
||||
{
|
||||
var pad = GamePad360.Devices[i];
|
||||
string xname = "X" + (pad.PlayerNumber) + " ";
|
||||
for (int b = 0; b < pad.NumButtons; b++)
|
||||
HandleButton(xname + pad.ButtonName(b), pad.Pressed(b));
|
||||
|
@ -355,10 +362,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
|
||||
//analyze joysticks
|
||||
for (int i = 0; i < GamePad.Devices.Count; i++)
|
||||
foreach (var item in GamePad.EnumerateDevices().Select((n, i) => new { Device = n, Index = i }))
|
||||
{
|
||||
var pad = GamePad.Devices[i];
|
||||
string jname = "J" + (i + 1) + " ";
|
||||
var pad = item.Device;
|
||||
string jname = "J" + (item.Index + 1) + " ";
|
||||
|
||||
for (int b = 0; b < pad.NumButtons; b++)
|
||||
HandleButton(jname + pad.ButtonName(b), pad.Pressed(b));
|
||||
|
|
|
@ -6,50 +6,68 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
public static class KeyInput
|
||||
{
|
||||
private static DirectInput dinput;
|
||||
private static Keyboard keyboard;
|
||||
private static KeyboardState state = new KeyboardState();
|
||||
private static readonly object _syncObj = new object();
|
||||
private static readonly List<KeyEvent> _eventList = new List<KeyEvent>();
|
||||
private static DirectInput _dinput;
|
||||
private static Keyboard _keyboard;
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
if (dinput == null)
|
||||
dinput = new DirectInput();
|
||||
lock (_syncObj)
|
||||
{
|
||||
Cleanup();
|
||||
|
||||
if (keyboard == null || keyboard.Disposed)
|
||||
keyboard = new Keyboard(dinput);
|
||||
keyboard.SetCooperativeLevel(GlobalWin.MainForm.Handle, CooperativeLevel.Background | CooperativeLevel.Nonexclusive);
|
||||
keyboard.Properties.BufferSize = 8;
|
||||
_dinput = new DirectInput();
|
||||
|
||||
_keyboard = new Keyboard(_dinput);
|
||||
_keyboard.SetCooperativeLevel(GlobalWin.MainForm.Handle, CooperativeLevel.Background | CooperativeLevel.Nonexclusive);
|
||||
_keyboard.Properties.BufferSize = 8;
|
||||
}
|
||||
}
|
||||
|
||||
static List<KeyEvent> EmptyList = new List<KeyEvent>();
|
||||
static List<KeyEvent> EventList = new List<KeyEvent>();
|
||||
public static void Cleanup()
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (_keyboard != null)
|
||||
{
|
||||
_keyboard.Dispose();
|
||||
_keyboard = null;
|
||||
}
|
||||
|
||||
if (_dinput != null)
|
||||
{
|
||||
_dinput.Dispose();
|
||||
_dinput = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<KeyEvent> Update()
|
||||
{
|
||||
EventList.Clear();
|
||||
|
||||
if (keyboard.Acquire().IsFailure)
|
||||
return EmptyList;
|
||||
if (keyboard.Poll().IsFailure)
|
||||
return EmptyList;
|
||||
|
||||
for (; ; )
|
||||
lock (_syncObj)
|
||||
{
|
||||
var events = keyboard.GetBufferedData();
|
||||
if (Result.Last.IsFailure)
|
||||
return EventList;
|
||||
if (events.Count == 0)
|
||||
break;
|
||||
foreach (var e in events)
|
||||
{
|
||||
foreach (var k in e.PressedKeys)
|
||||
EventList.Add(new KeyEvent { Key = k, Pressed = true });
|
||||
foreach (var k in e.ReleasedKeys)
|
||||
EventList.Add(new KeyEvent { Key = k, Pressed = false });
|
||||
}
|
||||
}
|
||||
_eventList.Clear();
|
||||
|
||||
return EventList;
|
||||
if (_keyboard == null || _keyboard.Acquire().IsFailure || _keyboard.Poll().IsFailure)
|
||||
return _eventList;
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
var events = _keyboard.GetBufferedData();
|
||||
if (Result.Last.IsFailure || events.Count == 0)
|
||||
break;
|
||||
foreach (var e in events)
|
||||
{
|
||||
foreach (var k in e.PressedKeys)
|
||||
_eventList.Add(new KeyEvent { Key = k, Pressed = true });
|
||||
foreach (var k in e.ReleasedKeys)
|
||||
_eventList.Add(new KeyEvent { Key = k, Pressed = false });
|
||||
}
|
||||
}
|
||||
|
||||
return _eventList;
|
||||
}
|
||||
}
|
||||
|
||||
public struct KeyEvent
|
||||
|
@ -57,6 +75,5 @@ namespace BizHawk.Client.EmuHawk
|
|||
public Key Key;
|
||||
public bool Pressed;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -231,9 +231,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
GlobalWin.Sound = null;
|
||||
}
|
||||
GlobalWin.GL.Dispose();
|
||||
#if WINDOWS
|
||||
GamePad.CloseAll();
|
||||
#endif
|
||||
Input.Cleanup();
|
||||
}
|
||||
else
|
||||
{ // Display error message windows
|
||||
|
@ -305,9 +303,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
GlobalWin.Sound = null;
|
||||
}
|
||||
GlobalWin.GL.Dispose();
|
||||
#if WINDOWS
|
||||
GamePad.CloseAll();
|
||||
#endif
|
||||
Input.Cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue