solve an apparent threading datastructure conflict bug in input binding vs input poll thread. print list of discovered gamepad devices while booting input system.

This commit is contained in:
zeromus 2013-08-25 17:11:19 +00:00
parent 3dc1e8dba2
commit 5ef675c116
2 changed files with 99 additions and 88 deletions

View File

@ -21,10 +21,12 @@ namespace BizHawk.MultiClient
foreach (DeviceInstance device in dinput.GetDevices(DeviceClass.GameController, DeviceEnumerationFlags.AttachedOnly))
{
if (device.ProductName.Contains("XBOX 360"))
continue; // Don't input XBOX 360 controllers into here; we'll process them via XInput.
var joystick = new Joystick(dinput, device.InstanceGuid);
Console.WriteLine("joydevice: {0} `{1}`", device.InstanceGuid, device.ProductName);
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(Global.MainForm.Handle, CooperativeLevel.Background | CooperativeLevel.Nonexclusive);
foreach (DeviceObjectInstance deviceObject in joystick.GetObjects())
{

View File

@ -278,71 +278,76 @@ namespace BizHawk.MultiClient
GamePad360.UpdateAll();
_Modifiers = KeyInput.GetModifierKeysAsKeys();
_NewEvents.Clear();
//analyze keys
var bleh = new HashSet<Key>();
foreach (var k in KeyInput.State.PressedKeys)
bleh.Add(k);
foreach (var k in KeyInput.State.AllKeys)
if (bleh.Contains(k))
HandleButton(k.ToString(), true);
else
HandleButton(k.ToString(), false);
lock (FloatValues)
//this block is going to massively modify data structures that the binding method uses, so we have to lock it all
lock (this)
{
//FloatValues.Clear();
_NewEvents.Clear();
//analyze xinput
for (int i = 0; i < GamePad360.Devices.Count; i++)
//analyze keys
var bleh = new HashSet<Key>();
foreach (var k in KeyInput.State.PressedKeys)
bleh.Add(k);
foreach (var k in KeyInput.State.AllKeys)
if (bleh.Contains(k))
HandleButton(k.ToString(), true);
else
HandleButton(k.ToString(), false);
lock (FloatValues)
{
var pad = GamePad360.Devices[i];
string xname = "X" + (i + 1) + " ";
for (int b = 0; b < pad.NumButtons; b++)
HandleButton(xname + pad.ButtonName(b), pad.Pressed(b));
foreach (var sv in pad.GetFloats())
//FloatValues.Clear();
//analyze xinput
for (int i = 0; i < GamePad360.Devices.Count; i++)
{
string n = xname = sv.Item1;
float f = sv.Item2;
if (trackdeltas)
FloatDeltas[n] += Math.Abs(f - FloatValues[n]);
FloatValues[n] = f;
var pad = GamePad360.Devices[i];
string xname = "X" + (i + 1) + " ";
for (int b = 0; b < pad.NumButtons; b++)
HandleButton(xname + pad.ButtonName(b), pad.Pressed(b));
foreach (var sv in pad.GetFloats())
{
string n = xname = sv.Item1;
float f = sv.Item2;
if (trackdeltas)
FloatDeltas[n] += Math.Abs(f - FloatValues[n]);
FloatValues[n] = f;
}
}
//analyze joysticks
for (int i = 0; i < GamePad.Devices.Count; i++)
{
var pad = GamePad.Devices[i];
string jname = "J" + (i + 1) + " ";
for (int b = 0; b < pad.NumButtons; b++)
HandleButton(jname + pad.ButtonName(b), pad.Pressed(b));
foreach (var sv in pad.GetFloats())
{
string n = jname + sv.Item1;
float f = sv.Item2;
//if (n == "J5 RotationZ")
// System.Diagnostics.Debugger.Break();
if (trackdeltas)
FloatDeltas[n] += Math.Abs(f - FloatValues[n]);
FloatValues[n] = f;
}
}
}
//analyze joysticks
for (int i = 0; i < GamePad.Devices.Count; i++)
bool swallow = !Global.MainForm.AllowInput;
foreach (var ie in _NewEvents)
{
var pad = GamePad.Devices[i];
string jname = "J" + (i + 1) + " ";
for (int b = 0; b < pad.NumButtons; b++)
HandleButton(jname + pad.ButtonName(b), pad.Pressed(b));
foreach (var sv in pad.GetFloats())
{
string n = jname + sv.Item1;
float f = sv.Item2;
//if (n == "J5 RotationZ")
// System.Diagnostics.Debugger.Break();
if (trackdeltas)
FloatDeltas[n] += Math.Abs(f - FloatValues[n]);
FloatValues[n] = f;
}
//events are swallowed in some cases:
if (ie.EventType == InputEventType.Press && swallow)
{ }
else
EnqueueEvent(ie);
}
}
bool swallow = !Global.MainForm.AllowInput;
foreach (var ie in _NewEvents)
{
//events are swallowed in some cases:
if (ie.EventType == InputEventType.Press && swallow)
{ }
else
EnqueueEvent(ie);
}
} //lock(this)
//arbitrary selection of polling frequency:
Thread.Sleep(10);
@ -390,40 +395,44 @@ namespace BizHawk.MultiClient
//returns the next Press event, if available. should be useful
public string GetNextBindEvent()
{
if (InputEvents.Count == 0) return null;
if (!Global.MainForm.AllowInput) return null;
//we only listen to releases for input binding, because we need to distinguish releases of pure modifierkeys from modified keys
//if you just pressed ctrl, wanting to bind ctrl, we'd see: pressed:ctrl, unpressed:ctrl
//if you just pressed ctrl+c, wanting to bind ctrl+c, we'd see: pressed:ctrl, pressed:ctrl+c, unpressed:ctrl+c, unpressed:ctrl
//so its the first unpress we need to listen for
while (InputEvents.Count != 0)
//this whole process is intimately involved with the data structures, which can conflict with the input thread.
lock (this)
{
var ie = DequeueEvent();
//as a special perk, we'll accept escape immediately
if (ie.EventType == InputEventType.Press && ie.LogicalButton.Button == "Escape")
goto ACCEPT;
if (ie.EventType == InputEventType.Press) continue;
if (InputEvents.Count == 0) return null;
if (!Global.MainForm.AllowInput) return null;
ACCEPT:
Console.WriteLine("Bind Event: {0} ", ie);
//we only listen to releases for input binding, because we need to distinguish releases of pure modifierkeys from modified keys
//if you just pressed ctrl, wanting to bind ctrl, we'd see: pressed:ctrl, unpressed:ctrl
//if you just pressed ctrl+c, wanting to bind ctrl+c, we'd see: pressed:ctrl, pressed:ctrl+c, unpressed:ctrl+c, unpressed:ctrl
//so its the first unpress we need to listen for
foreach (var kvp in LastState)
if (kvp.Value)
{
Console.WriteLine("Unpressing " + kvp.Key);
UnpressState[kvp.Key] = true;
}
InputEvents.Clear();
while (InputEvents.Count != 0)
{
var ie = DequeueEvent();
return ie.LogicalButton.ToString();
//as a special perk, we'll accept escape immediately
if (ie.EventType == InputEventType.Press && ie.LogicalButton.Button == "Escape")
goto ACCEPT;
if (ie.EventType == InputEventType.Press) continue;
ACCEPT:
Console.WriteLine("Bind Event: {0} ", ie);
foreach (var kvp in LastState)
if (kvp.Value)
{
Console.WriteLine("Unpressing " + kvp.Key);
UnpressState[kvp.Key] = true;
}
InputEvents.Clear();
return ie.LogicalButton.ToString();
}
return null;
}
return null;
}
//controls whether modifier keys will be ignored as key press events