Skip to content

Commit

Permalink
0.6.0.35 - Add Trigger & Thumbstick support for Gamepads (#776)
Browse files Browse the repository at this point in the history
- Add Trigger & Thumbstick support for Gamepads
  • Loading branch information
DragonRatTiger authored Jan 5, 2025
1 parent 3d65858 commit a865b47
Show file tree
Hide file tree
Showing 19 changed files with 124 additions and 86 deletions.
59 changes: 50 additions & 9 deletions FDK/src/02.Input/CInputGamepad.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,52 @@ namespace FDK;

public class CInputGamepad : CInputButtonsBase, IInputDevice, IDisposable {

public CInputGamepad(IGamepad gamepad) : base(15) {
public CInputGamepad(IGamepad gamepad, float deadzone = 0.5f) : base(gamepad.Buttons.Count + gamepad.Triggers.Count + (gamepad.Thumbsticks.Count * 4)) {
this.Device = gamepad;
this.CurrentType = InputDeviceType.Gamepad;
this.GUID = gamepad.Index.ToString();
this.ID = gamepad.Index;
this.Name = gamepad.Name;

gamepad.Deadzone = new Deadzone(0.5f, DeadzoneMethod.Traditional);
ButtonCount = gamepad.Buttons.Count;
TriggerCount = gamepad.Triggers.Count;
ThumbstickCount = gamepad.Thumbsticks.Count;

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

private void Gamepad_TriggerMoved(IGamepad gamepad, Trigger trigger) {
if (trigger.Position == 1) {
int trigger_index = ButtonCount + trigger.Index;

if (trigger.Position == 1) {
if (!KeyPressing(trigger_index)) { base.ButtonDown(trigger_index); }
} else {
if (!KeyReleased(trigger_index)) { base.ButtonUp(trigger_index); }
}
}
private void Gamepad_ThumbstickMoved(IGamepad gamepad, Thumbstick thumbstick) {
ThumbstickDirection direction = GetDirectionFromThumbstick(thumbstick.Direction);
if (direction == ThumbstickDirection.Unknown) return;

int thumbstick_index = ButtonCount + TriggerCount +
(thumbstick.Index * 4);

if (gamepad.Deadzone.Apply(thumbstick.Position) > 0) {
ThumbstickDirection direction = GetDirectionFromThumbstick(thumbstick.Direction);
if (!KeyPressing(thumbstick_index)) {
for (int i = 0; i < 4; i++) {
if (i != (int)direction)
base.ButtonUp(thumbstick_index + i);
}
base.ButtonDown(thumbstick_index + (int)direction);
}
} else {
for (int i = 0; i < 4; i++) {
base.ButtonUp(thumbstick_index + i);
}
}
}

Expand All @@ -51,10 +75,27 @@ private ThumbstickDirection GetDirectionFromThumbstick(float raw) {
}

private enum ThumbstickDirection {
Right,
Down,
Left,
Up,
Unknown,
Up = 0,
Right = 1,
Down = 2,
Left = 3,
Unknown = -1,
}

private int ButtonCount;
private int TriggerCount;
private int ThumbstickCount;

public string GetButtonName(int index) {
var gamepad = (IGamepad)Device;
if (index >= ButtonCount + TriggerCount) {
int thumbstick_index = index - (ButtonCount + TriggerCount);
return $"Thumbstick{thumbstick_index / 4} - {(ThumbstickDirection)(thumbstick_index % 4)}";
}
if (index >= ButtonCount) {
int trigger_index = index - ButtonCount;
return $"Trigger{trigger_index}";
}
return gamepad.Buttons[index].Name.ToString();
}
}
11 changes: 10 additions & 1 deletion FDK/src/02.Input/CInputJoystick.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ namespace FDK;

public class CInputJoystick : CInputButtonsBase, IInputDevice, IDisposable {

public CInputJoystick(IJoystick joystick) : base(18) {
public CInputJoystick(IJoystick joystick) : base(32) {
// While the Gamepad's button count can be read from the start,
// the Joystick's button count can only be read after pressing
// any button. To be safe, we'll just leave some room for a lot
// of buttons.

this.Device = joystick;
this.CurrentType = InputDeviceType.Joystick;
this.GUID = joystick.Index.ToString();
Expand All @@ -26,4 +31,8 @@ private void Joystick_ButtonUp(IJoystick joystick, Button button) {
base.ButtonUp(button.Index);
}
}

public string GetButtonName(int index) {
return $"Button{index}";
}
}
12 changes: 7 additions & 5 deletions FDK/src/02.Input/CInputManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,18 @@ public IInputDevice Mouse {
return null;
}
}
public float Deadzone = 0.5f;


// Constructor
public CInputManager(IWindow window, bool useBufferedInput, bool bUseMidiIn = true) {
Initialize(window, useBufferedInput, bUseMidiIn);
public CInputManager(IWindow window, bool useBufferedInput, bool bUseMidiIn = true, float gamepad_deadzone = 0.5f) {
Initialize(window, useBufferedInput, bUseMidiIn, gamepad_deadzone);
}

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

this.InputDevices = new List<IInputDevice>(10);
#region [ Enumerate keyboard/mouse: exception is masked if keyboard/mouse is not connected ]
Expand All @@ -76,7 +78,7 @@ public void Initialize(IWindow window, bool useBufferedInput, bool bUseMidiIn) {
this.InputDevices.Add(new CInputJoystick(joysticks));
}
foreach (var gamepad in Context.Gamepads) {
this.InputDevices.Add(new CInputGamepad(gamepad));
this.InputDevices.Add(new CInputGamepad(gamepad, Deadzone));
}
#endregion
Trace.TraceInformation("Found {0} Input Device{1}", InputDevices.Count, InputDevices.Count != 1 ? "s:" : ":");
Expand Down Expand Up @@ -109,7 +111,7 @@ private void ConnectionChanged(Silk.NET.Input.IInputDevice device, bool connecte
}
}
else if (device is IGamepad) {
this.InputDevices.Add(new CInputGamepad((IGamepad)device));
this.InputDevices.Add(new CInputGamepad((IGamepad)device, Deadzone));
Trace.TraceInformation($"A gamepad was connected. Device name: {device.Name} / Index: {device.Index}");
}
else if (device is IJoystick) {
Expand Down
1 change: 1 addition & 0 deletions FDK/src/02.Input/IInputDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ List<STInputEvent> InputEvents {
bool KeyReleased(List<int> nKey) { return nKey.Any(key => KeyReleased(key)); }
bool KeyReleasing(int nKey);
bool KeyReleasing(List<int> nKey) { return nKey.Any(key => KeyReleasing(key)); }
string GetButtonName(int nKey) { return $"Button{nKey}"; }
}
3 changes: 3 additions & 0 deletions OpenTaiko/Lang/de/lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@
"SETTINGS_GAME_CALIBRATION_DESC": "Kalibriert deinen Offset.\nDer globale Offset wird überschrieben, wenn gespeichert.",
"SETTINGS_GAME_CALIBRATION_OFFSET": "OFFSET: {0}",

"SETTINGS_GAME_CONTROLLERDEADZONE": "Controller Deadzone",
"SETTINGS_GAME_CONTROLLERDEADZONE_DESC": "Adjust the thumbstick deadzone for all connected\ncontrollers. Can be between 10% to 90%.\n\nAfter saving, reconnect the controller or\nrestart the game to apply changes.",

"SETTINGS_GAME_BADCOUNT": "Kanpeki-Modus",
"SETTINGS_GAME_BADCOUNT_DESC": "Bestimmt, wie viele ÜBEL erlaubt sind,\nbevor ein Lied automatisch scheitert.\nSetze dies auf 0, um den Modus zu deaktivieren.",
"SETTINGS_GAME_NOTELOCK": "Notelock-Modus",
Expand Down
3 changes: 3 additions & 0 deletions OpenTaiko/Lang/en/lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@
"SETTINGS_GAME_CALIBRATION_DESC": "Calibrate your offset.\nGlobal Offset will be overwritten if saved.",
"SETTINGS_GAME_CALIBRATION_OFFSET": "OFFSET: {0}",

"SETTINGS_GAME_CONTROLLERDEADZONE": "Controller Deadzone",
"SETTINGS_GAME_CONTROLLERDEADZONE_DESC": "Adjust the thumbstick deadzone for all connected\ncontrollers. Can be between 10% to 90%.\n\nAfter saving, reconnect the controller or\nrestart the game to apply changes.",

"SETTINGS_GAME_BADCOUNT": "Kanpeki Mode",
"SETTINGS_GAME_BADCOUNT_DESC": "Choose how many BADs are allowed\nbefore a song is automatically failed.\nSet this to 0 to disable the mode.",
"SETTINGS_GAME_NOTELOCK": "Notelock Mode",
Expand Down
3 changes: 3 additions & 0 deletions OpenTaiko/Lang/es/lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@
"SETTINGS_GAME_CALIBRATION_DESC": "Calibrate your offset.\nGlobal Offset will be overwritten if saved.",
"SETTINGS_GAME_CALIBRATION_OFFSET": "OFFSET: {0}",

"SETTINGS_GAME_CONTROLLERDEADZONE": "Controller Deadzone",
"SETTINGS_GAME_CONTROLLERDEADZONE_DESC": "Adjust the thumbstick deadzone for all connected\ncontrollers. Can be between 10% to 90%.\n\nAfter saving, reconnect the controller or\nrestart the game to apply changes.",

"SETTINGS_GAME_BADCOUNT": "Modo Kanpeki",
"SETTINGS_GAME_BADCOUNT_DESC": "Modo Kanpeki:\nElige el número de fallos antes de\n que se considere un intento fallido.\nDejar en 0 para deshabilitar el modo Kanpeki.",
"SETTINGS_GAME_NOTELOCK": "Bloqueo de notas",
Expand Down
3 changes: 3 additions & 0 deletions OpenTaiko/Lang/fr/lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@
"SETTINGS_GAME_CALIBRATION_DESC": "Calibrate your offset.\nGlobal Offset will be overwritten if saved.",
"SETTINGS_GAME_CALIBRATION_OFFSET": "OFFSET: {0}",

"SETTINGS_GAME_CONTROLLERDEADZONE": "Controller Deadzone",
"SETTINGS_GAME_CONTROLLERDEADZONE_DESC": "Adjust the thumbstick deadzone for all connected\ncontrollers. Can be between 10% to 90%.\n\nAfter saving, reconnect the controller or\nrestart the game to apply changes.",

"SETTINGS_GAME_BADCOUNT": "Mort subite",
"SETTINGS_GAME_BADCOUNT_DESC": "Mode mort subite :\nSi 1 ou plus, spécifiez le nombre de \nnotes ratées maximales autorisées avant \nde perdre la partie.\nSi 0 le mode mort subite est désactivé.",
"SETTINGS_GAME_NOTELOCK": "Notes vérouillées",
Expand Down
3 changes: 3 additions & 0 deletions OpenTaiko/Lang/ja/lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@
"SETTINGS_GAME_CALIBRATION_DESC": "Calibrate your offset.\nGlobal Offset will be overwritten if saved.",
"SETTINGS_GAME_CALIBRATION_OFFSET": "OFFSET: {0}",

"SETTINGS_GAME_CONTROLLERDEADZONE": "Controller Deadzone",
"SETTINGS_GAME_CONTROLLERDEADZONE_DESC": "Adjust the thumbstick deadzone for all connected\ncontrollers. Can be between 10% to 90%.\n\nAfter saving, reconnect the controller or\nrestart the game to apply changes.",

"SETTINGS_GAME_BADCOUNT": "完璧モード",
"SETTINGS_GAME_BADCOUNT_DESC": "Riskyモードの設定:\n1以上の値にすると、その回数分の\n不可で演奏が強制終了します。\n0にすると無効になり、\nノルマゲージのみになります。\n",
"SETTINGS_GAME_NOTELOCK": "タイト",
Expand Down
3 changes: 3 additions & 0 deletions OpenTaiko/Lang/ko/lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@
"SETTINGS_GAME_CALIBRATION_DESC": "오프셋을 보정합니다.\n저장하면 글로벌 오프셋을 덮어씁니다.",
"SETTINGS_GAME_CALIBRATION_OFFSET": "OFFSET: {0}",

"SETTINGS_GAME_CONTROLLERDEADZONE": "Controller Deadzone",
"SETTINGS_GAME_CONTROLLERDEADZONE_DESC": "Adjust the thumbstick deadzone for all connected\ncontrollers. Can be between 10% to 90%.\n\nAfter saving, reconnect the controller or\nrestart the game to apply changes.",

"SETTINGS_GAME_BADCOUNT": "완벽하게 모드",
"SETTINGS_GAME_BADCOUNT_DESC": "노래가 자동으로 실패하기 전에 허용되는 BAD 수를 선택합니다.\n모드를 비활성화하려면 이 값을 0으로 설정하세요.",
"SETTINGS_GAME_NOTELOCK": "노트잠금 모드",
Expand Down
3 changes: 3 additions & 0 deletions OpenTaiko/Lang/nl/lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@
"SETTINGS_GAME_CALIBRATION_DESC": "Kalibreert de offset.\nGlobale Offset wordt overschreven waneer dit opslaat.",
"SETTINGS_GAME_CALIBRATION_OFFSET": "OFFSET: {0}",

"SETTINGS_GAME_CONTROLLERDEADZONE": "Controller Deadzone",
"SETTINGS_GAME_CONTROLLERDEADZONE_DESC": "Adjust the thumbstick deadzone for all connected\ncontrollers. Can be between 10% to 90%.\n\nAfter saving, reconnect the controller or\nrestart the game to apply changes.",

"SETTINGS_GAME_BADCOUNT": "Kanpeki Modus",
"SETTINGS_GAME_BADCOUNT_DESC": "Kies hoeveel 'BAD's zijn toegestaan\nvoordat een lied automatisch mislukt.\nZet de waarde op 0 om het uit te schakelen.",
"SETTINGS_GAME_NOTELOCK": "Notelock Modus",
Expand Down
3 changes: 3 additions & 0 deletions OpenTaiko/Lang/ru/lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@
"SETTINGS_GAME_CALIBRATION_DESC": "Откалибровает ваш офсет.\nГлобальный офсет будет перезаписан, если он\nбудет сохранен.",
"SETTINGS_GAME_CALIBRATION_OFFSET": "ОФСЕТ: {0}",

"SETTINGS_GAME_CONTROLLERDEADZONE": "Controller Deadzone",
"SETTINGS_GAME_CONTROLLERDEADZONE_DESC": "Adjust the thumbstick deadzone for all connected\ncontrollers. Can be between 10% to 90%.\n\nAfter saving, reconnect the controller or\nrestart the game to apply changes.",

"SETTINGS_GAME_BADCOUNT": "Режим Канпэки",
"SETTINGS_GAME_BADCOUNT_DESC": "Выбрает сколько «Плохо» позволяют раньше\nпесни автоматически проиграно.\nУстановите значение 0, чтобы выключить этот\nрежим.",
"SETTINGS_GAME_NOTELOCK": "Режим замока ноты",
Expand Down
3 changes: 3 additions & 0 deletions OpenTaiko/Lang/zh/lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@
"SETTINGS_GAME_CALIBRATION_DESC": "校准您的偏移量。\n如果保存,将覆盖全局偏移量。",
"SETTINGS_GAME_CALIBRATION_OFFSET": "偏移量:{0}",

"SETTINGS_GAME_CONTROLLERDEADZONE": "Controller Deadzone",
"SETTINGS_GAME_CONTROLLERDEADZONE_DESC": "Adjust the thumbstick deadzone for all connected\ncontrollers. Can be between 10% to 90%.\n\nAfter saving, reconnect the controller or\nrestart the game to apply changes.",

"SETTINGS_GAME_BADCOUNT": "完美模式",
"SETTINGS_GAME_BADCOUNT_DESC": "选择打出多少个“不可”时会导致演奏失败。\n— 0:禁用此选项",
"SETTINGS_GAME_NOTELOCK": "锁定音符模式",
Expand Down
8 changes: 8 additions & 0 deletions OpenTaiko/src/Common/CConfigIni.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1117,6 +1117,7 @@ public int nPlayerCount {
public int nDefaultAILevel = 4;
public int nAILevel = 4;
public bool bAIBattleMode = false;
public int nControllerDeadzone = 50;

public CAIPerformances[] apAIPerformances = {
new CAIPerformances(500, 400, 100, 7, 200),
Expand Down Expand Up @@ -2124,6 +2125,10 @@ public void t書き出し(string iniファイル名) {
sw.WriteLine("; Using Buffered input (0:OFF, 1:ON)");
sw.WriteLine("BufferedInput={0}", this.bBufferedInputs ? 1 : 0);
sw.WriteLine();
sw.WriteLine("; Set the deadzone for all connected controllers' thumbsticks.");
sw.WriteLine("; Can be between 10% and 90%.");
sw.WriteLine("ControllerDeadzone={0}", this.nControllerDeadzone);
sw.WriteLine();
sw.WriteLine("; リザルト画像自動保存機能(0:OFF, 1:ON)"); // #25399 2011.6.9 yyagi
sw.WriteLine("; Set \"1\" if you'd like to save result screen image automatically"); //
sw.WriteLine("; when you get hiscore/hiskill."); //
Expand Down Expand Up @@ -2898,6 +2903,9 @@ private void ProcessSystemSection(string key, string value) {
case "BufferedInput":
this.bBufferedInputs = CConversion.bONorOFF(value[0]);
break;
case "ControllerDeadzone":
this.nControllerDeadzone = CConversion.ParseIntInRange(value, 10, 90, this.nControllerDeadzone);
break;
case "PolyphonicSounds":
this.nPoliphonicSounds = CConversion.ParseIntInRange(value, 1, 8, this.nPoliphonicSounds);
break;
Expand Down
12 changes: 6 additions & 6 deletions OpenTaiko/src/Common/ImGuiDebugWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,17 +121,17 @@ private static void Inputs() {
case InputDeviceType.Gamepad:
var gamepad = (CInputGamepad)device;
for (int i = 0; i < gamepad.ButtonStates.Length; i++) {
if (gamepad.KeyPressed(i)) { ImGui.Text((Silk.NET.Input.ButtonName)i + " Pressed!"); }
if (gamepad.KeyPressing(i)) { ImGui.Text((Silk.NET.Input.ButtonName)i + " Pressing!"); }
if (gamepad.KeyReleased(i)) { ImGui.Text((Silk.NET.Input.ButtonName)i + " Released!"); }
if (gamepad.KeyPressed(i)) { ImGui.Text(gamepad.GetButtonName(i) + " Pressed!"); }
if (gamepad.KeyPressing(i)) { ImGui.Text(gamepad.GetButtonName(i) + " Pressing!"); }
if (gamepad.KeyReleased(i)) { ImGui.Text(gamepad.GetButtonName(i) + " Released!"); }
}
break;
case InputDeviceType.Joystick:
var joystick = (CInputJoystick)device;
for (int i = 0; i < joystick.ButtonStates.Length; i++) {
if (joystick.KeyPressed(i)) { ImGui.Text((Silk.NET.Input.ButtonName)i + " Pressed!"); }
if (joystick.KeyPressing(i)) { ImGui.Text((Silk.NET.Input.ButtonName)i + " Pressing!"); }
if (joystick.KeyReleased(i)) { ImGui.Text((Silk.NET.Input.ButtonName)i + " Released!"); }
if (joystick.KeyPressed(i)) { ImGui.Text(joystick.GetButtonName(i) + " Pressed!"); }
if (joystick.KeyPressing(i)) { ImGui.Text(joystick.GetButtonName(i) + " Pressing!"); }
if (joystick.KeyReleased(i)) { ImGui.Text(joystick.GetButtonName(i) + " Released!"); }
}
break;
case InputDeviceType.MidiIn:
Expand Down
3 changes: 1 addition & 2 deletions OpenTaiko/src/Common/OpenTaiko.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1677,8 +1677,7 @@ private void tStartupProcess() {
Trace.TraceInformation("Initializing DirectInput and MIDI input...");
Trace.Indent();
try {
bool bUseMIDIIn = true;
InputManager = new CInputManager(Window_, OpenTaiko.ConfigIni.bBufferedInputs);
InputManager = new CInputManager(Window_, OpenTaiko.ConfigIni.bBufferedInputs, true, OpenTaiko.ConfigIni.nControllerDeadzone / 100.0f);
foreach (IInputDevice device in InputManager.InputDevices) {
if ((device.CurrentType == InputDeviceType.Joystick) && !ConfigIni.dicJoystick.ContainsValue(device.GUID)) {
int key = 0;
Expand Down
Loading

0 comments on commit a865b47

Please sign in to comment.