Encapsulate input method, revive DirectInput, cleanup Input.Instance

This commit is contained in:
YoshiRulz 2020-04-17 00:46:51 +10:00
parent 0aa8d71a3f
commit fa1c494ad8
No known key found for this signature in database
GPG Key ID: C4DE31C245353FB7
11 changed files with 194 additions and 123 deletions

View File

@ -326,5 +326,7 @@ namespace BizHawk.Client.Common
// ReSharper disable once UnusedMember.Global
public string LastWrittenFromDetailed { get; set; } = VersionInfo.GetEmuVersion();
public EHostInputMethod HostInputMethod { get; set; } = EHostInputMethod.OpenTK;
}
}

View File

@ -40,4 +40,10 @@
Tas = 3,
N64Tas = 4
}
public enum EHostInputMethod
{
OpenTK = 0,
DirectInput = 1
}
}

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using BizHawk.Common;
@ -15,7 +14,7 @@ namespace BizHawk.Client.EmuHawk
private static readonly List<GamePad> Devices = new List<GamePad>();
private static DirectInput _directInput;
public static void Initialize(Control parent)
public static void Initialize(IntPtr mainFormHandle)
{
lock (SyncObj)
{
@ -31,7 +30,7 @@ namespace BizHawk.Client.EmuHawk
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(_directInput, device.InstanceGuid);
joystick.SetCooperativeLevel(parent.Handle, CooperativeLevel.Background | CooperativeLevel.Nonexclusive);
joystick.SetCooperativeLevel(mainFormHandle, CooperativeLevel.Background | CooperativeLevel.Nonexclusive);
foreach (DeviceObjectInstance deviceObject in joystick.GetObjects())
{
if ((deviceObject.ObjectType & ObjectDeviceType.Axis) != 0)
@ -125,7 +124,7 @@ namespace BizHawk.Client.EmuHawk
return;
}
public IEnumerable<(string AxisID, float Value)> GetFloats()
public IEnumerable<(string AxisID, float Value)> GetAxes()
{
var pis = typeof(JoystickState).GetProperties();
foreach (var pi in pis)

View File

@ -154,7 +154,7 @@ namespace BizHawk.Client.EmuHawk
}
}
public IEnumerable<(string AxisID, float Value)> GetFloats()
public IEnumerable<(string AxisID, float Value)> GetAxes()
{
var g = _state.Gamepad;

View File

@ -0,0 +1,98 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using static BizHawk.Client.EmuHawk.Input;
namespace BizHawk.Client.EmuHawk
{
/// <remarks>this was easier than trying to make static classes instantiable...</remarks>
public interface HostInputAdapter
{
void DeInitAll();
void FirstInitAll(IntPtr mainFormHandle);
void ReInitGamepads(IntPtr mainFormHandle);
void PreprocessHostGamepads();
void ProcessHostGamepads(Action<string?, bool, InputFocus> handleButton, Action<string?, float> handleAxis);
IEnumerable<KeyEvent> ProcessHostKeyboards();
}
internal sealed class DirectInputAdapter : HostInputAdapter
{
public void DeInitAll()
{
KeyInput.Cleanup();
GamePad.Cleanup();
}
public void FirstInitAll(IntPtr mainFormHandle)
{
KeyInput.Initialize(mainFormHandle);
IPCKeyInput.Initialize();
ReInitGamepads(mainFormHandle);
}
public void ReInitGamepads(IntPtr mainFormHandle)
{
GamePad.Initialize(mainFormHandle);
GamePad360.Initialize();
}
public void PreprocessHostGamepads()
{
GamePad.UpdateAll();
GamePad360.UpdateAll();
}
public void ProcessHostGamepads(Action<string?, bool, InputFocus> handleButton, Action<string?, float> handleAxis)
{
foreach (var pad in GamePad360.EnumerateDevices())
{
var inputNamePrefix = $"X{pad.PlayerNumber} ";
for (int b = 0, n = pad.NumButtons; b < n; b++) handleButton(inputNamePrefix + pad.ButtonName(b), pad.Pressed(b), InputFocus.Pad);
foreach (var (axisName, f) in pad.GetAxes()) handleAxis(inputNamePrefix + axisName, f);
}
foreach (var pad in GamePad.EnumerateDevices())
{
var inputNamePrefix = $"J{pad.PlayerNumber} ";
for (int b = 0, n = pad.NumButtons; b < n; b++) handleButton(inputNamePrefix + pad.ButtonName(b), pad.Pressed(b), InputFocus.Pad);
foreach (var (axisName, f) in pad.GetAxes()) handleAxis(inputNamePrefix + axisName, f);
}
}
public IEnumerable<KeyEvent> ProcessHostKeyboards() => KeyInput.Update().Concat(IPCKeyInput.Update());
}
internal sealed class OpenTKInputAdapter : HostInputAdapter
{
public void DeInitAll() {}
public void FirstInitAll(IntPtr mainFormHandle)
{
OTK_Keyboard.Initialize();
OTK_GamePad.Initialize();
}
public void ReInitGamepads(IntPtr mainFormHandle) {}
public void PreprocessHostGamepads() => OTK_GamePad.UpdateAll();
public void ProcessHostGamepads(Action<string?, bool, InputFocus> handleButton, Action<string?, float> handleAxis)
{
foreach (var pad in OTK_GamePad.EnumerateDevices())
{
foreach (var but in pad.buttonObjects) handleButton(pad.InputNamePrefix + but.ButtonName, but.ButtonAction(), InputFocus.Pad);
foreach (var (axisID, f) in pad.GetAxes()) handleAxis($"{pad.InputNamePrefix}{axisID} Axis", f);
}
}
public IEnumerable<KeyEvent> ProcessHostKeyboards() => OTK_Keyboard.Update();
}
}

View File

@ -114,9 +114,19 @@ namespace BizHawk.Client.EmuHawk
Alt = 262144
}
public static Input Instance { get; private set; }
private static readonly Lazy<Input> _instance = new Lazy<Input>(() => new Input());
public static Input Instance => _instance.Value;
private readonly Thread UpdateThread;
public readonly HostInputAdapter Adapter = Global.Config.HostInputMethod switch
{
EHostInputMethod.OpenTK => new OpenTKInputAdapter(),
EHostInputMethod.DirectInput => new DirectInputAdapter(),
_ => throw new Exception()
};
private Input()
{
UpdateThread = new Thread(UpdateThreadProc)
@ -127,39 +137,6 @@ namespace BizHawk.Client.EmuHawk
UpdateThread.Start();
}
public static void Initialize(Control parent)
{
#if true
OTK_Keyboard.Initialize();
OTK_GamePad.Initialize();
#else
if (OSTailoredCode.IsUnixHost)
{
OTK_Keyboard.Initialize();
OTK_GamePad.Initialize();
}
else
{
KeyInput.Initialize(parent);
IPCKeyInput.Initialize();
GamePad.Initialize(parent);
GamePad360.Initialize();
}
#endif
Instance = new Input();
}
public static void Cleanup()
{
#if false
if (!OSTailoredCode.IsUnixHost)
{
KeyInput.Cleanup();
GamePad.Cleanup();
}
#endif
}
public enum InputEventType
{
Press, Release
@ -292,6 +269,12 @@ namespace BizHawk.Client.EmuHawk
}
}
private void HandleAxis(string axis, float newValue)
{
if (_trackDeltas) _axisDeltas[axis] += Math.Abs(newValue - _axisValues[axis]);
_axisValues[axis] = newValue;
}
private static ModifierKey ButtonToModifierKey(string button) => button switch
{
"LeftShift" => ModifierKey.Shift,
@ -356,23 +339,8 @@ namespace BizHawk.Client.EmuHawk
{
while (true)
{
#if true
var keyEvents = OTK_Keyboard.Update();
OTK_GamePad.UpdateAll();
#else
var keyEvents = OSTailoredCode.IsUnixHost
? OTK_Keyboard.Update()
: KeyInput.Update().Concat(IPCKeyInput.Update());
if (OSTailoredCode.IsUnixHost)
{
OTK_GamePad.UpdateAll();
}
else
{
GamePad.UpdateAll();
GamePad360.UpdateAll();
}
#endif
var keyEvents = Adapter.ProcessHostKeyboards();
Adapter.PreprocessHostGamepads();
//this block is going to massively modify data structures that the binding method uses, so we have to lock it all
lock (this)
@ -386,57 +354,7 @@ namespace BizHawk.Client.EmuHawk
lock (_axisValues)
{
//_axisValues.Clear();
// analyze OpenTK xinput (or is it libinput?)
foreach (var pad in OTK_GamePad.EnumerateDevices())
{
foreach (var but in pad.buttonObjects)
{
HandleButton(pad.InputNamePrefix + but.ButtonName, but.ButtonAction(), InputFocus.Pad);
}
foreach (var (axisID, f) in pad.GetAxes())
{
var n = $"{pad.InputNamePrefix}{axisID} Axis";
if (_trackDeltas) _axisDeltas[n] += Math.Abs(f - _axisValues[n]);
_axisValues[n] = f;
}
}
#if false
// analyze xinput
foreach (var pad in GamePad360.EnumerateDevices())
{
string xName = $"X{pad.PlayerNumber} ";
for (int b = 0; b < pad.NumButtons; b++)
HandleButton(xName + pad.ButtonName(b), pad.Pressed(b), InputFocus.Pad);
foreach (var sv in pad.GetAxes())
{
string n = xName + sv.Item1;
float f = sv.Item2;
if (_trackDeltas)
_axisDeltas[n] += Math.Abs(f - _axisValues[n]);
_axisValues[n] = f;
}
}
// analyze joysticks
foreach (var pad in GamePad.EnumerateDevices())
{
string jName = $"J{pad.PlayerNumber} ";
for (int b = 0; b < pad.NumButtons; b++)
HandleButton(jName + pad.ButtonName(b), pad.Pressed(b), InputFocus.Pad);
foreach (var sv in pad.GetAxes())
{
string n = jName + sv.Item1;
float f = sv.Item2;
//if (n == "J5 RotationZ")
// System.Diagnostics.Debugger.Break();
if (_trackDeltas)
_axisDeltas[n] += Math.Abs(f - _axisValues[n]);
_axisValues[n] = f;
}
}
#endif
Adapter.ProcessHostGamepads(HandleButton, HandleAxis);
// analyze moose
// other sorts of mouse api (raw input) could easily be added as a separate listing under a different class

View File

@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Windows.Forms;
using System;
using System.Collections.Generic;
using SlimDX;
using SlimDX.DirectInput;
@ -12,7 +13,7 @@ namespace BizHawk.Client.EmuHawk
private static DirectInput _directInput;
private static Keyboard _keyboard;
public static void Initialize(Control parent)
public static void Initialize(IntPtr mainFormHandle)
{
lock (SyncObj)
{
@ -21,7 +22,7 @@ namespace BizHawk.Client.EmuHawk
_directInput = new DirectInput();
_keyboard = new Keyboard(_directInput);
_keyboard.SetCooperativeLevel(parent.Handle, CooperativeLevel.Background | CooperativeLevel.Nonexclusive);
_keyboard.SetCooperativeLevel(mainFormHandle, CooperativeLevel.Background | CooperativeLevel.Nonexclusive);
_keyboard.Properties.BufferSize = 8;
}
}

View File

@ -316,7 +316,7 @@ namespace BizHawk.Client.EmuHawk
Sound?.StartSound();
};
Input.Initialize(this);
Input.Instance.Adapter.FirstInitAll(Handle);
InitControls();
Global.InputManager.ActiveController = new Controller(NullController.Instance.Definition);
@ -2721,13 +2721,7 @@ namespace BizHawk.Client.EmuHawk
// Alt key hacks
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WmDeviceChange:
GamePad.Initialize(this);
GamePad360.Initialize();
break;
}
if (m.Msg == WmDeviceChange) Input.Instance.Adapter.ReInitGamepads(Handle);
// this is necessary to trap plain alt keypresses so that only our hotkey system gets them
if (m.Msg == 0x0112) // WM_SYSCOMMAND

View File

@ -242,7 +242,7 @@ namespace BizHawk.Client.EmuHawk
GlobalWin.Sound?.Dispose();
GlobalWin.Sound = null;
GlobalWin.GL.Dispose();
Input.Cleanup();
Input.Instance.Adapter.DeInitAll();
}
//cleanup:

View File

@ -88,6 +88,10 @@
this.rbLuaInterface = new BizHawk.WinForms.Controls.RadioButtonEx(grpLuaEngine.Tracker);
this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
this.flpDialogButtons = new BizHawk.WinForms.Controls.LocSzSingleRowFLP();
this.grpInputMethod = new BizHawk.WinForms.Controls.SzGroupBoxEx();
this.flpGrpInputMethod = new BizHawk.WinForms.Controls.LocSingleRowFLP();
this.rbInputMethodOpenTK = new BizHawk.WinForms.Controls.RadioButtonEx(grpInputMethod.Tracker);
this.rbInputMethodDirectInput = new BizHawk.WinForms.Controls.RadioButtonEx(grpInputMethod.Tracker);
this.tcDialog.SuspendLayout();
this.tpGeneral.SuspendLayout();
this.flpTpGeneral.SuspendLayout();
@ -111,6 +115,8 @@
this.grpLuaEngine.SuspendLayout();
this.flpGrpLuaEngine.SuspendLayout();
this.flpDialogButtons.SuspendLayout();
this.grpInputMethod.SuspendLayout();
this.flpGrpInputMethod.SuspendLayout();
this.SuspendLayout();
//
// btnDialogOK
@ -142,7 +148,7 @@
this.tcDialog.Location = new System.Drawing.Point(4, 4);
this.tcDialog.Name = "tcDialog";
this.tcDialog.SelectedIndex = 0;
this.tcDialog.Size = new System.Drawing.Size(379, 363);
this.tcDialog.Size = new System.Drawing.Size(379, 389);
this.tcDialog.TabIndex = 0;
//
// tpGeneral
@ -160,6 +166,7 @@
this.flpTpGeneral.Controls.Add(this.cbNeverAskForSave);
this.flpTpGeneral.Controls.Add(this.flpNoFocusEmulate);
this.flpTpGeneral.Controls.Add(this.flpNoFocusInput);
this.flpTpGeneral.Controls.Add(this.grpInputMethod);
this.flpTpGeneral.Controls.Add(this.cbNonQWERTY);
this.flpTpGeneral.Controls.Add(this.grpStartup);
this.flpTpGeneral.Name = "flpTpGeneral";
@ -492,18 +499,44 @@
this.flpDialogButtons.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.flpDialogButtons.Controls.Add(this.btnDialogOK);
this.flpDialogButtons.Controls.Add(this.btnDialogCancel);
this.flpDialogButtons.Location = new System.Drawing.Point(247, 370);
this.flpDialogButtons.Location = new System.Drawing.Point(247, 396);
this.flpDialogButtons.MinimumSize = new System.Drawing.Size(24, 24);
this.flpDialogButtons.Name = "flpDialogButtons";
this.flpDialogButtons.Size = new System.Drawing.Size(132, 29);
//
// grpInputMethod
//
this.grpInputMethod.Controls.Add(this.flpGrpInputMethod);
this.grpInputMethod.Name = "grpInputMethod";
this.grpInputMethod.Size = new System.Drawing.Size(334, 45);
this.grpInputMethod.Text = "Input Method (requires restart)";
//
// flpGrpInputMethod
//
this.flpGrpInputMethod.Controls.Add(this.rbInputMethodDirectInput);
this.flpGrpInputMethod.Controls.Add(this.rbInputMethodOpenTK);
this.flpGrpInputMethod.Location = new System.Drawing.Point(4, 12);
this.flpGrpInputMethod.Name = "flpGrpInputMethod";
//
// rbInputMethodOpenTK
//
this.rbInputMethodOpenTK.Name = "rbInputMethodOpenTK";
this.rbInputMethodOpenTK.Tag = BizHawk.Client.Common.EHostInputMethod.OpenTK;
this.rbInputMethodOpenTK.Text = "OpenTK";
//
// rbInputMethodDirectInput
//
this.rbInputMethodDirectInput.Name = "rbInputMethodDirectInput";
this.rbInputMethodDirectInput.Tag = BizHawk.Client.Common.EHostInputMethod.DirectInput;
this.rbInputMethodDirectInput.Text = "DirectInput";
//
// EmuHawkOptions
//
this.AcceptButton = this.btnDialogOK;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnDialogCancel;
this.ClientSize = new System.Drawing.Size(385, 405);
this.ClientSize = new System.Drawing.Size(385, 431);
this.Controls.Add(this.flpDialogButtons);
this.Controls.Add(this.tcDialog);
this.MinimumSize = new System.Drawing.Size(401, 444);
@ -555,6 +588,10 @@
this.flpGrpLuaEngine.ResumeLayout(false);
this.flpGrpLuaEngine.PerformLayout();
this.flpDialogButtons.ResumeLayout(false);
this.grpInputMethod.ResumeLayout(false);
this.grpInputMethod.PerformLayout();
this.flpGrpInputMethod.ResumeLayout(false);
this.flpGrpInputMethod.PerformLayout();
this.ResumeLayout(false);
}
@ -620,5 +657,9 @@
private BizHawk.WinForms.Controls.SzGroupBoxEx grpLuaEngine;
private BizHawk.WinForms.Controls.LocSingleColumnFLP flpGrpLuaEngine;
private BizHawk.WinForms.Controls.LocSzSingleRowFLP flpDialogButtons;
private BizHawk.WinForms.Controls.SzGroupBoxEx grpInputMethod;
private BizHawk.WinForms.Controls.LocSingleRowFLP flpGrpInputMethod;
private BizHawk.WinForms.Controls.RadioButtonEx rbInputMethodDirectInput;
private BizHawk.WinForms.Controls.RadioButtonEx rbInputMethodOpenTK;
}
}

View File

@ -64,6 +64,17 @@ namespace BizHawk.Client.EmuHawk
cbNoFocusEmulate.Checked = _config.RunInBackground;
cbNoFocusInput.Checked = _config.AcceptBackgroundInput;
cbNoFocusInputGamepadOnly.Checked = _config.AcceptBackgroundInputControllerOnly;
switch (_config.HostInputMethod)
{
case EHostInputMethod.OpenTK:
rbInputMethodOpenTK.Checked = true;
break;
case EHostInputMethod.DirectInput:
rbInputMethodDirectInput.Checked = true;
break;
default:
throw new InvalidOperationException();
}
cbNonQWERTY.Checked = _config.HandleAlternateKeyboardLayouts;
cbNeverAskForSave.Checked = _config.SuppressAskSave;
cbSingleInstance.Checked = _config.SingleInstanceMode;
@ -100,6 +111,7 @@ namespace BizHawk.Client.EmuHawk
_config.RunInBackground = cbNoFocusEmulate.Checked;
_config.AcceptBackgroundInput = cbNoFocusInput.Checked;
_config.AcceptBackgroundInputControllerOnly = cbNoFocusInputGamepadOnly.Checked;
_config.HostInputMethod = grpInputMethod.Tracker.GetSelectionTagAs<EHostInputMethod>() ?? throw new InvalidOperationException();
_config.HandleAlternateKeyboardLayouts = cbNonQWERTY.Checked;
_config.SuppressAskSave = cbNeverAskForSave.Checked;
_config.SingleInstanceMode = cbSingleInstance.Checked;