Skip to content

Commit

Permalink
Add option to disable DirectInput
Browse files Browse the repository at this point in the history
DirectInput might end up causing random freezes for a few seconds due to faulty drivers, even with no controllers attached. This seems to be rare, but annoying enough where a keyboard user probably would want to disable DirectInput to avoid this issue.
  • Loading branch information
CasualPokePlayer committed Apr 16, 2024
1 parent f003a4e commit f7e6f1c
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 7 deletions.
15 changes: 12 additions & 3 deletions GSR.Input/InputManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public sealed class InputManager : IDisposable
private volatile Exception _inputThreadException;

private readonly SDL_SysWMinfo _mainWindowWmInfo;
private volatile bool _enableDirectInput;

// These must be created/destroyed on the input thread!
private IKeyInput _keyInput;
Expand All @@ -47,7 +48,7 @@ private void InputThreadProc()
try
{
_keyInput = KeyInputFactory.CreateKeyInput(in _mainWindowWmInfo);
_sdlJoysticks = new();
_sdlJoysticks = new(_enableDirectInput);

_inputThreadInitFinished.Set();

Expand All @@ -62,7 +63,7 @@ private void InputThreadProc()
}
#endif
var keyEvents = _keyInput.GetEvents();
var joystickInputs = _sdlJoysticks.GetInputs();
var joystickInputs = _sdlJoysticks.GetInputs(_enableDirectInput);

foreach (var keyEvent in keyEvents)
{
Expand Down Expand Up @@ -120,9 +121,10 @@ private void CheckInputThreadException()
}
}

public InputManager(in SDL_SysWMinfo mainWindowWmInfo)
public InputManager(in SDL_SysWMinfo mainWindowWmInfo, bool enableDirectInput)
{
_mainWindowWmInfo = mainWindowWmInfo;
_enableDirectInput = enableDirectInput;
_inputThread = new(InputThreadProc) { IsBackground = true, Name = "Input Thread" };
_inputThread.Start();
_inputThreadInitFinished.Wait();
Expand All @@ -143,6 +145,13 @@ public void Dispose()
_inputThreadLoopThrottle.Dispose();
}

#if GSR_WINDOWS
public void SetDirectInputEnable(bool enableDirectInput)
{
_enableDirectInput = enableDirectInput;
}
#endif

/// <summary>
/// NOTE: CALLED ON GUI THREAD
/// </summary>
Expand Down
24 changes: 21 additions & 3 deletions GSR.Input/Joysticks/SDLJoysticks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,25 @@ namespace GSR.Input.Joysticks;

internal class SDLJoysticks : IDisposable
{
private readonly Dictionary<int, SDL2Joystick> Joysticks = new();
private readonly Dictionary<int, SDL2Joystick> Joysticks = [];
private readonly SDL_Event[] _sdlEvents = new SDL_Event[10];
private bool _enableDirectInput;

static SDLJoysticks()
{
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI, "1");
}

public SDLJoysticks()
public SDLJoysticks(bool enableDirectInput)
{
Initialize(enableDirectInput);
}

private void Initialize(bool enableDirectInput)
{
_enableDirectInput = enableDirectInput;
SDL_SetHint("SDL_DIRECTINPUT_ENABLED", _enableDirectInput ? "1" : "0");
if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) != 0)
{
throw new($"SDL failed to init, SDL error: {SDL_GetError()}");
Expand All @@ -35,6 +43,7 @@ public void Dispose()
}

SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
SDL_FlushEvents(SDL_EventType.SDL_JOYDEVICEADDED, SDL_EventType.SDL_JOYDEVICEREMOVED);
}

private void RefreshJoyIndexes()
Expand Down Expand Up @@ -85,8 +94,17 @@ public void RemoveJoyDevice(int deviceInstanceId)
RefreshJoyIndexes();
}

public IEnumerable<JoystickInput> GetInputs()
public IEnumerable<JoystickInput> GetInputs(bool enableDirectInput)
{
// to change direct input being enabled, we have to deinit and init again
// this can only be done on the input thread, hence the deferring
if (_enableDirectInput != enableDirectInput)
{
Dispose();
Joysticks.Clear();
Initialize(enableDirectInput);
}

// This is needed to add joy add/remove events
SDL_JoystickUpdate();

Expand Down
1 change: 1 addition & 0 deletions GSR/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ internal sealed class Config
public HotkeyBindings HotkeyBindings { get; set; } = new();
public bool AllowBackgroundInput { get; set; }
public bool BackgroundInputForJoysticksOnly { get; set; }
public bool EnableDirectInput { get; set; } = true;

public bool KeepAspectRatio { get; set; } = true;
public ScalingFilter OutputFilter { get; set; } = ScalingFilter.SharpBilinear;
Expand Down
2 changes: 1 addition & 1 deletion GSR/GSR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ public GSR()
{
_config = Config.LoadConfig(PathResolver.GetConfigPath());
_mainWindow = new("GSR", _config, true);
_inputManager = new(in _mainWindow.SdlSysWMInfo);
_inputManager = new(in _mainWindow.SdlSysWMInfo, _config.EnableDirectInput);
// input manager is needed to fully load the config, as input bindings depend on user's keyboard layout
// default bindings will be set if this fails for some reason
_config.DeserializeInputBindings(_inputManager, _mainWindow);
Expand Down
11 changes: 11 additions & 0 deletions GSR/Gui/ImGuiModals.cs
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,17 @@ static string AddBiosPathButton(string system, string biosPathConfig, ImGuiWindo
ImGui.EndDisabled();
}

#if GSR_WINDOWS
ImGui.Separator();

var enableDirectInput = _config.EnableDirectInput;
if (ImGui.Checkbox("Enable DirectInput", ref enableDirectInput))
{
_config.EnableDirectInput = enableDirectInput;
_inputManager.SetDirectInputEnable(enableDirectInput);
}
#endif

ImGui.EndTabItem();
}
#endif
Expand Down

0 comments on commit f7e6f1c

Please sign in to comment.