interface IAxisInput
{
    // returns values in range -infinity, +infinity

    float GetValue();
    
    ChannelReader<float> GetReader();
}

interface ITriggerInput
{
    // returns values in range 0, +infinity

    float GetValue();
    
    ChannelReader<float> GetReader();
}

struct ButtonKind
{
    // pressure-sensitive button
    Analogue,
    // on-off button
    Digital
}

interface IButtonInput
{
    ButtonKind Kind { get; }
    
    // returns pressure level of pressure-sensitive buttons
    float GetAnalogueValue();
    
    // returns on-off state of digital buttons
    bool GetDigitalValue();
    
    ChannelReader<float> GetAnalogueReader();
    
    ChannelReader<bool> GetDigitalReader();
}

interface IPointerInput
{
    // pointer input, e.g. mouse or touch screen
    
    Vector2 GetValue();
    
    ChannelReader<Vector2> GetReader();
}

interface IPressureSensitivePointerInput : IPointerInput
{
    // pointer input with pressure sensitivity, e.g. graphics tablet
    
    // these are implemented as DIMs, since it's unlikely an implementor will need to override these.
    Vector2 IPointerInput.GetValue()
    {
        var value = GetValue();
        return new Vector2(value.X, value.Y);
    }

    ChannelReader<Vector2> IPointerInput.GetReader()
    {
        return new InternalImplementationDetail(GetReader());
    }
    
    Vector3 GetValue();
    ChannelReader<Vector3> GetReader();
}