Skip to content

Commit

Permalink
0.6.0.32 - Input Device QoL (#775)
Browse files Browse the repository at this point in the history
- Allow input devices to be recognized after plugging in past startup
- Fix joystick devices failing to send inputs (Fixes tatacons)
- Unsupported keyboard key inputs no longer crash the game
- Devices being plugged/unplugged are now logged
DragonRatTiger authored Jan 2, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent b449079 commit 3e16bbc
Showing 10 changed files with 114 additions and 41 deletions.
1 change: 1 addition & 0 deletions FDK/src/02.Input/CInputButtonsBase.cs
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@ public CInputButtonsBase(int nButtonStates) {

#region [ IInputDevice 実装 ]
//-----------------
public Silk.NET.Input.IInputDevice Device { get; protected set; }
public InputDeviceType CurrentType { get; protected set; }
public string GUID { get; protected set; }
public int ID { get; protected set; }
42 changes: 36 additions & 6 deletions FDK/src/02.Input/CInputGamepad.cs
Original file line number Diff line number Diff line change
@@ -3,28 +3,58 @@
namespace FDK;

public class CInputGamepad : CInputButtonsBase, IInputDevice, IDisposable {
private IGamepad Gamepad { get; set; }

public CInputGamepad(IGamepad gamepad) : base(15) {
this.Gamepad = gamepad;
this.Device = gamepad;
this.CurrentType = InputDeviceType.Gamepad;
this.GUID = gamepad.Index.ToString();
this.ID = gamepad.Index;
this.Name = gamepad.Name;

gamepad.ButtonDown += Joystick_ButtonDown;
gamepad.ButtonUp += Joystick_ButtonUp;
gamepad.Deadzone = new Deadzone(0.5f, DeadzoneMethod.Traditional);
gamepad.ButtonDown += Gamepad_ButtonDown;
gamepad.ButtonUp += Gamepad_ButtonUp;
gamepad.ThumbstickMoved += Gamepad_ThumbstickMoved;
gamepad.TriggerMoved += Gamepad_TriggerMoved;
}

private void Joystick_ButtonDown(IGamepad joystick, Button button) {
private void Gamepad_TriggerMoved(IGamepad gamepad, Trigger trigger) {
if (trigger.Position == 1) {

}
}
private void Gamepad_ThumbstickMoved(IGamepad gamepad, Thumbstick thumbstick) {
if (gamepad.Deadzone.Apply(thumbstick.Position) > 0) {
ThumbstickDirection direction = GetDirectionFromThumbstick(thumbstick.Direction);
}
}

private void Gamepad_ButtonDown(IGamepad gamepad, Button button) {
if (button.Name != ButtonName.Unknown) {
base.ButtonDown((int)button.Name);
}
}

private void Joystick_ButtonUp(IGamepad joystick, Button button) {
private void Gamepad_ButtonUp(IGamepad gamepad, Button button) {
if (button.Name != ButtonName.Unknown) {
base.ButtonUp((int)button.Name);
}
}

private ThumbstickDirection GetDirectionFromThumbstick(float raw) {
float value = raw * (180 / MathF.PI);
if (value >= -90 - 45 / 2f && value <= -90 + 45 / 2f) return ThumbstickDirection.Up;
if (value >= 0 - 45 / 2f && value <= 0 + 45 / 2f) return ThumbstickDirection.Right;
if (value >= 90 - 45 / 2f && value <= 90 + 45 / 2f) return ThumbstickDirection.Down;
if (value >= 180 - 45 / 2f || value <= -180 + 45 / 2f) return ThumbstickDirection.Left;
return ThumbstickDirection.Unknown;
}

private enum ThumbstickDirection {
Right,
Down,
Left,
Up,
Unknown,
}
}
11 changes: 5 additions & 6 deletions FDK/src/02.Input/CInputJoystick.cs
Original file line number Diff line number Diff line change
@@ -3,10 +3,9 @@
namespace FDK;

public class CInputJoystick : CInputButtonsBase, IInputDevice, IDisposable {
public IJoystick Joystick { get; private set; }

public CInputJoystick(IJoystick joystick) : base(18) {
this.Joystick = joystick;
this.Device = joystick;
this.CurrentType = InputDeviceType.Joystick;
this.GUID = joystick.Index.ToString();
this.ID = joystick.Index;
@@ -17,14 +16,14 @@ public CInputJoystick(IJoystick joystick) : base(18) {
}

private void Joystick_ButtonDown(IJoystick joystick, Button button) {
if (button.Name != ButtonName.Unknown) {
base.ButtonDown((int)button.Name);
if (button.Index >= 0 && button.Index < ButtonStates.Length) {
base.ButtonDown(button.Index);
}
}

private void Joystick_ButtonUp(IJoystick joystick, Button button) {
if (button.Name != ButtonName.Unknown) {
base.ButtonUp((int)button.Name);
if (button.Index >= 0 && button.Index < ButtonStates.Length) {
base.ButtonUp(button.Index);
}
}
}
33 changes: 15 additions & 18 deletions FDK/src/02.Input/CInputKeyboard.cs
Original file line number Diff line number Diff line change
@@ -3,33 +3,30 @@
namespace FDK;

public class CInputKeyboard : CInputButtonsBase, IInputDevice, IDisposable {
public CInputKeyboard(IReadOnlyList<IKeyboard> keyboards) : base(144) {
public CInputKeyboard(IKeyboard keyboard) : base(144) {
this.Device = keyboard;
this.CurrentType = InputDeviceType.Keyboard;
this.GUID = "";
this.GUID = keyboard.Name;
this.ID = 0;
this.Name = keyboards.Count > 0 ? keyboards[0].Name : "";
this.Name = keyboard.Name;

foreach (var keyboard in keyboards) {
keyboard.KeyDown += KeyDown;
keyboard.KeyUp += KeyUp;
keyboard.KeyChar += KeyChar;
}
keyboard.KeyDown += KeyDown;
keyboard.KeyUp += KeyUp;
keyboard.KeyChar += KeyChar;
}

public (bool isPressed, int state)[] KeyStates => this.ButtonStates;

private void KeyDown(IKeyboard keyboard, Key key, int keyCode) {
if (key != Key.Unknown) {
var keyNum = DeviceConstantConverter.DIKtoKey(key);
base.ButtonDown((int)keyNum);
}
var keyNum = DeviceConstantConverter.DIKtoKey(key);
if ((int)keyNum >= this.ButtonStates.Length || keyNum == SlimDXKeys.Key.Unknown) return;

base.ButtonDown((int)keyNum);
}

private void KeyUp(IKeyboard keyboard, Key key, int keyCode) {
if (key != Key.Unknown) {
var keyNum = DeviceConstantConverter.DIKtoKey(key);
base.ButtonUp((int)keyNum);
}
var keyNum = DeviceConstantConverter.DIKtoKey(key);
if ((int)keyNum >= this.ButtonStates.Length || keyNum == SlimDXKeys.Key.Unknown) return;

base.ButtonUp((int)keyNum);
}

private void KeyChar(IKeyboard keyboard, char ch) {
2 changes: 2 additions & 0 deletions FDK/src/02.Input/CInputMIDI.cs
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ public class CInputMIDI : IInputDevice, IDisposable {
// Constructor

public CInputMIDI(uint nID) {
this.Device = null;
this.MidiInPtr = IntPtr.Zero;
this.EventBuffers = new List<STInputEvent>(32);
this.InputEvents = [];
@@ -58,6 +59,7 @@ public void tメッセージからMIDI信号のみ受信(uint wMsg, IntPtr dwIns

#region [ IInputDevice 実装 ]
//-----------------
public Silk.NET.Input.IInputDevice Device { get; private set; }
public InputDeviceType CurrentType { get; private set; }
public string GUID { get; private set; }
public int ID { get; private set; }
54 changes: 49 additions & 5 deletions FDK/src/02.Input/CInputManager.cs
Original file line number Diff line number Diff line change
@@ -53,13 +53,14 @@ public CInputManager(IWindow window, bool useBufferedInput, bool bUseMidiIn = tr

public void Initialize(IWindow window, bool useBufferedInput, bool bUseMidiIn) {
Context = window.CreateInput();
Context.ConnectionChanged += this.ConnectionChanged;

this.InputDevices = new List<IInputDevice>(10);
#region [ Enumerate keyboard/mouse: exception is masked if keyboard/mouse is not connected ]
CInputKeyboard cinputkeyboard = null;
CInputMouse cinputmouse = null;
try {
cinputkeyboard = new CInputKeyboard(Context.Keyboards);
cinputkeyboard = new CInputKeyboard(Context.Keyboards[0]);
cinputmouse = new CInputMouse(Context.Mice[0]);
} catch {
}
@@ -88,6 +89,49 @@ public void Initialize(IWindow window, bool useBufferedInput, bool bUseMidiIn) {
SampleFramework.Game.InitImGuiController(window, Context);
}

private void ConnectionChanged(Silk.NET.Input.IInputDevice device, bool connected) {
if (connected) {
if (device is IKeyboard) {
if (Keyboard == null) {
this.InputDevices.Add(new CInputKeyboard((IKeyboard)device));
Trace.TraceInformation($"A keyboard was connected. Device name: {device.Name}");
}
else {
Trace.TraceWarning($"A keyboard was connected, but there is another keyboard already loaded. This keyboard will not be used. Device name: {device.Name}");
}
}
else if (device is IMouse) {
if (Mouse == null) {
this.InputDevices.Add(new CInputMouse((IMouse)device));
Trace.TraceInformation($"A mouse was connected. Device name: {device.Name}");
} else {
Trace.TraceWarning($"A mouse was connected, but there is another mouse already loaded. This mouse will not be used. Device name: {device.Name}");
}
}
else if (device is IGamepad) {
this.InputDevices.Add(new CInputGamepad((IGamepad)device));
Trace.TraceInformation($"A gamepad was connected. Device name: {device.Name} / Index: {device.Index}");
}
else if (device is IJoystick) {
this.InputDevices.Add(new CInputJoystick((IJoystick)device));
Trace.TraceInformation($"A joystick was connected. Device name: {device.Name} / Index: {device.Index}");
}
else {
Trace.TraceWarning($"An input device was connected, but Silk.NET could not recognize what type of device this is. It will not be used. Device name: {device.Name}");
}
}
else {
for (int i = InputDevices.Count; i-- > 0;) {
var inputdevice = InputDevices[i];
if (!inputdevice.Device.IsConnected) {
Trace.TraceInformation($"An input device was disconnected. Device name: {inputdevice.Name} / Index: {inputdevice.ID} / Device Type: {inputdevice.CurrentType}");
inputdevice.Dispose();
this.InputDevices.Remove(inputdevice);
}
}
}
}


// メソッド

@@ -145,14 +189,14 @@ public void Polling() {
// foreach( IInputDevice device in this.list入力デバイス )
for (int i = this.InputDevices.Count - 1; i >= 0; i--) // #24016 2011.1.6 yyagi: change not to use "foreach" to avoid InvalidOperation exception by Remove().
{
IInputDevice device = this.InputDevices[i];
try {
IInputDevice device = this.InputDevices[i];
device.Polling();
} catch (Exception e) // #24016 2011.1.6 yyagi: catch exception for unplugging USB joystick, and remove the device object from the polling items.
{
this.InputDevices.Remove(device);
device.Dispose();
Trace.TraceError("tポーリング時に対象deviceが抜かれており例外発生。同deviceをポーリング対象からRemoveしました。");
//this.InputDevices.Remove(device);
//device.Dispose();
//Trace.TraceError("tポーリング時に対象deviceが抜かれており例外発生。同deviceをポーリング対象からRemoveしました。");
}
}
}
1 change: 1 addition & 0 deletions FDK/src/02.Input/CInputMouse.cs
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ public class CInputMouse : CInputButtonsBase, IInputDevice, IDisposable {
public const int MouseButtonCount = 8;

public CInputMouse(IMouse mouse) : base(12) {
this.Device = mouse;
this.CurrentType = InputDeviceType.Mouse;
this.GUID = "";
this.ID = 0;
2 changes: 1 addition & 1 deletion FDK/src/02.Input/DeviceConstantConverter.cs
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ public static class DeviceConstantConverter {
// メソッド

public static Key DIKtoKey(Silk.NET.Input.Key key) {
return _DIKtoKey[key];
return _DIKtoKey.TryGetValue(key, out Key value) ? value : Key.Unknown;
}


3 changes: 3 additions & 0 deletions FDK/src/02.Input/IInputDevice.cs
Original file line number Diff line number Diff line change
@@ -3,6 +3,9 @@
public interface IInputDevice : IDisposable {
// Properties

Silk.NET.Input.IInputDevice Device {
get;
}
InputDeviceType CurrentType {
get;
}
6 changes: 1 addition & 5 deletions OpenTaiko/src/Common/ImGuiDebugWindow.cs
Original file line number Diff line number Diff line change
@@ -104,7 +104,7 @@ private static void Inputs() {
switch (device.CurrentType) {
case InputDeviceType.Keyboard:
var keyboard = (CInputKeyboard)device;
for (int i = 0; i < keyboard.KeyStates.Length; i++) {
for (int i = 0; i < keyboard.ButtonStates.Length; i++) {
if (keyboard.KeyPressed(i)) { ImGui.Text((SlimDXKeys.Key)i + " Pressed!"); }
if (keyboard.KeyPressing(i)) { ImGui.Text((SlimDXKeys.Key)i + " Pressing!"); }
if (keyboard.KeyReleased(i)) { ImGui.Text((SlimDXKeys.Key)i + " Released!"); }
@@ -143,10 +143,6 @@ private static void Inputs() {
//}
ImGui.TextColored(new Vector4(1, 0, 0, 1), "MIDI input polling is currently disabled.");
break;
case InputDeviceType.Unknown:
ImGui.TextDisabled("Unknown input device type.");
ImGui.TextDisabled("GUID: " + device.GUID);
break;
}
ImGui.TreePop();
}

0 comments on commit 3e16bbc

Please sign in to comment.