DiamondGamepad.cs
using System;
using Sandbox;

namespace Diamonds;

/// <summary>
/// Reads both controller sticks as four digital directions. D-pad and face buttons are bound in Input.config;
/// s&amp;box has no gamepad codes for stick directions, so they are thresholded here.
/// </summary>
public static class DiamondGamepad
{
	// Hysteresis stops a stick resting near the threshold from chattering between held and released.
	const float PressThreshold = 0.5f;
	const float ReleaseThreshold = 0.35f;

	static bool leftHeld, rightHeld, upHeld, downHeld;
	static bool upPressed, downPressed;

	public static bool Left => leftHeld;
	public static bool Right => rightHeld;
	public static bool Up => upHeld;
	public static bool Down => downHeld;
	/// <summary>A stick was pushed up/down this frame, for stepping menu selections.</summary>
	public static bool UpPressed => upPressed;
	public static bool DownPressed => downPressed;

	/// <summary>Sample the first controller's sticks once per frame.</summary>
	public static void Update()
	{
		float x, y;
		// Outside a controller scope, GetAnalog reads zero until a controller button or positive axis marks the controller active.
		using ( Input.PlayerScope( Input.PlayerIndex.Controller1 ) )
		{
			float leftX = Input.GetAnalog( InputAnalog.LeftStickX ), leftY = Input.GetAnalog( InputAnalog.LeftStickY );
			float rightX = Input.GetAnalog( InputAnalog.RightStickX ), rightY = Input.GetAnalog( InputAnalog.RightStickY );
			// Either stick can drive each direction; take whichever is pushed farther.
			x = MathF.Abs( leftX ) >= MathF.Abs( rightX ) ? leftX : rightX;
			y = MathF.Abs( leftY ) >= MathF.Abs( rightY ) ? leftY : rightY;
		}
		leftHeld = Latch( leftHeld, -x );
		rightHeld = Latch( rightHeld, x );
		// SDL stick Y is positive downward.
		bool wasUp = upHeld, wasDown = downHeld;
		upHeld = Latch( upHeld, -y );
		downHeld = Latch( downHeld, y );
		upPressed = upHeld && !wasUp;
		downPressed = downHeld && !wasDown;
	}

	public static void Clear() => leftHeld = rightHeld = upHeld = downHeld = upPressed = downPressed = false;

	static bool Latch( bool held, float amount ) => amount >= (held ? ReleaseThreshold : PressThreshold);
}