Skip to content

Instantly share code, notes, and snippets.

@lucasteles
Last active October 2, 2025 17:13
Show Gist options
  • Save lucasteles/ce2bff2ceebae2f96247fd9bd6ad0ba2 to your computer and use it in GitHub Desktop.
Save lucasteles/ce2bff2ceebae2f96247fd9bd6ad0ba2 to your computer and use it in GitHub Desktop.
C# Enum player input viewer
[Flags]
public enum PlayerInput : ushort
{
None = 0,
Up = 1 << 0,
Down = 1 << 1,
Left = 1 << 2,
Right = 1 << 3,
UpLeft = Up | Left,
UpRight = Up | Right,
DownLeft = Down | Left,
DownRight = Down | Right,
P1 = 1 << 4,
P2 = 1 << 5,
P3 = 1 << 6,
K1 = 1 << 7,
K2 = 1 << 8,
K3 = 1 << 9,
Macro1 = 1 << 10,
Macro2 = 1 << 11,
Select = 1 << 13,
Start = 1 << 14,
}
public static class PlayerInputExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PlayerInput Set(this PlayerInput flags, in PlayerInput flag, bool value) =>
value ? flags | flag : flags & ~flag;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PlayerInput Unflag(this PlayerInput flags, in PlayerInput flag) =>
flags.Set(in flag, false);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PlayerInput Flag(this PlayerInput flags, in PlayerInput flag) =>
flags.Set(in flag, true);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool HasAll(this PlayerInput pressed, in PlayerInput input) => (pressed & input) == input;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool HasAny(this PlayerInput pressed, in PlayerInput input) => (pressed & input) is not PlayerInput.None;
}
using System.Text;
public class PlayerInputView(PlayerInput input = PlayerInput.None)
{
public PlayerInput Input = input;
public void Reset() => Input = PlayerInput.None;
public bool IsEmpty => Input is PlayerInput.None;
public static implicit operator PlayerInput(PlayerInputView @this) => @this.Input;
public static implicit operator PlayerInputView(PlayerInput padButtons) => new(padButtons);
public bool Up
{
get => Input.HasAll(PlayerInput.Up);
set => Input = Input.Set(PlayerInput.Up, value);
}
public bool Down
{
get => Input.HasAll(PlayerInput.Down);
set => Input = Input.Set(PlayerInput.Down, value);
}
public bool Left
{
get => Input.HasAll(PlayerInput.Left);
set => Input = Input.Set(PlayerInput.Left, value);
}
public bool Right
{
get => Input.HasAll(PlayerInput.Right);
set => Input = Input.Set(PlayerInput.Right, value);
}
public bool LP
{
get => Input.HasAll(PlayerInput.P1);
set => Input = Input.Set(PlayerInput.P1, value);
}
public bool MP
{
get => Input.HasAll(PlayerInput.P2);
set => Input = Input.Set(PlayerInput.P2, value);
}
public bool HP
{
get => Input.HasAll(PlayerInput.P3);
set => Input = Input.Set(PlayerInput.P3, value);
}
public bool LK
{
get => Input.HasAll(PlayerInput.K1);
set => Input = Input.Set(PlayerInput.K1, value);
}
public bool MK
{
get => Input.HasAll(PlayerInput.K2);
set => Input = Input.Set(PlayerInput.K2, value);
}
public bool HK
{
get => Input.HasAll(PlayerInput.K3);
set => Input = Input.Set(PlayerInput.K3, value);
}
public bool Macro1
{
get => Input.HasAll(PlayerInput.Macro1);
set => Input = Input.Set(PlayerInput.Macro1, value);
}
public bool Macro2
{
get => Input.HasAll(PlayerInput.Macro2);
set => Input = Input.Set(PlayerInput.Macro2, value);
}
public bool Select
{
get => Input.HasAll(PlayerInput.Select);
set => Input = Input.Set(PlayerInput.Select, value);
}
public bool Start
{
get => Input.HasAll(PlayerInput.Start);
set => Input = Input.Set(PlayerInput.Start, value);
}
public bool UpLeft
{
get => Input.HasAll(PlayerInput.UpLeft);
set => Input = Input.Set(PlayerInput.UpLeft, value);
}
public bool UpRight
{
get => Input.HasAll(PlayerInput.UpRight);
set => Input = Input.Set(PlayerInput.UpRight, value);
}
public bool DownLeft
{
get => Input.HasAll(PlayerInput.DownLeft);
set => Input = Input.Set(PlayerInput.DownLeft, value);
}
public bool DownRight
{
get => Input.HasAll(PlayerInput.DownRight);
set => Input = Input.Set(PlayerInput.DownRight, value);
}
const char Sep = ' ';
public void Append(StringBuilder builder)
{
AppendDir(builder);
builder.Append(Sep);
AppendButton(builder);
}
public void AppendInverted(StringBuilder builder)
{
AppendButton(builder);
builder.Append(Sep);
AppendDir(builder);
}
void AppendButton(StringBuilder builder)
{
if (LP)
{
builder.Append(nameof(LP));
builder.Append(Sep);
}
if (MP)
{
builder.Append(nameof(MP));
builder.Append(Sep);
}
if (HP)
{
builder.Append(nameof(HP));
builder.Append(Sep);
}
if (LK)
{
builder.Append(nameof(LK));
builder.Append(Sep);
}
if (MK)
{
builder.Append(nameof(MK));
builder.Append(Sep);
}
if (HK)
{
builder.Append(nameof(HK));
builder.Append(Sep);
}
if (Macro1)
{
builder.Append(PlayerInput.Macro1);
builder.Append(Sep);
}
if (Macro1)
{
builder.Append(PlayerInput.Macro2);
builder.Append(Sep);
}
if (Start)
{
builder.Append(nameof(Start));
builder.Append(Sep);
}
if (Select)
{
builder.Append(nameof(Select));
builder.Append(Sep);
}
}
void AppendDir(StringBuilder builder)
{
Span<char> dpad = stackalloc char[4];
if (Left) dpad[0] = '←';
if (Up) dpad[1] = '↑';
if (Down) dpad[2] = '↓';
if (Right) dpad[3] = '→';
var dir = dpad switch
{
['\0', '↑', '\0', '→'] => '↗',
['←', '↑', '\0', '\0'] => '↖',
['←', '\0', '↓', '\0'] => '↙',
['\0', '\0', '↓', '→'] => '↘',
['\0', '\0', '\0', '\0'] => 'N',
_ => '\0',
};
if (dir != '\0')
builder.Append(dir);
else
for (var i = 0; i < dpad.Length; i++)
{
dir = dpad[i];
if (dir != '\0')
builder.Append(dir);
}
}
public string ToString(bool inverted)
{
StringBuilder builder = new();
if (inverted)
AppendInverted(builder);
else
Append(builder);
return builder.ToString();
}
public override string ToString() => ToString(false);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment