4

While working with XNA today, I noticed that one of the enum types that uses [Flags] did not have a None = 0 value:

[Flags]
public enum Buttons
{
    DPadUp = 1,
    DPadDown = 2,
    DPadLeft = 4,
    DPadRight = 8,
    Start = 16,
    Back = 32,
    LeftStick = 64,
    RightStick = 128,
    LeftShoulder = 256,
    RightShoulder = 512,
    BigButton = 2048,
    A = 4096,
    B = 8192,
    X = 16384,
    Y = 32768,
    LeftThumbstickLeft = 2097152,
    RightTrigger = 4194304,
    LeftTrigger = 8388608,
    RightThumbstickUp = 16777216,
    RightThumbstickDown = 33554432,
    RightThumbstickRight = 67108864,
    RightThumbstickLeft = 134217728,
    LeftThumbstickUp = 268435456,
    LeftThumbstickDown = 536870912,
    LeftThumbstickRight = 1073741824,
}

According to MSDN regarding the proper use of the [Flags] attribute:

Do name the zero value of flags enumerations None. For a flags enumeration, the value must always mean all flags are cleared.

If I wanted to indicate a value where no buttons are pressed, would it go against the intent of the enum type to use a value of 0 and cast it to Buttons? According to the design guidelines, it should have this value, but it doesn't.

Kyle Baran
  • 1,793
  • 2
  • 15
  • 30
  • 1
    The enum is used in the GamePadState.IsButtonUp/Down() methods. It makes no sense to ask if no button is down with those methods. So it didn't make sense to include None. You can't change the type, it is baked into XNA, but since 0 is always a valid value for an enum you can always use default(Buttons). – Hans Passant May 18 '15 at 09:31
  • I figured it was something like that. I'm not fond of how button polling is handled differently for each input type (mouse buttons don't even have their own enum type, unlike the keyboard and gamepad). My current project is making a common wrapper class around the different types of input that eg holds a current and previous `KeyboardState`, so that I can easily poll whether a key or button was just pressed or released. As a result, I can either have clients poll the IsPressed() methods I make or subscribe to events, so this was a consequence of making GamePadEventArgs contain a Buttons value. – Kyle Baran May 18 '15 at 09:46

2 Answers2

3

Yes. Since it is a Flags enum, the state of none of the possible values being set is going to be (Buttons)0 (or default(Buttons) if you'd prefer to indicate it in some way that reflects the type directly in your code), whether the designer of the type assigned a name to it or not.

Consider that if we can express "no button that isn't the A button is pressed and also the A button isn't pressed" through Buttons.A & ~Buttons.A and the result will be (Buttons)0. The "no button pressed" state is already 0.

(The one justification I can think of for leaving out None is that you were intending that a type is never used in a case where None is the value pressed. E.g., you are only using this for code that reacts to a button being pressed, and hence None never comes up. Even then one can find using the None/0 value useful in code, but it can mean that leaving it unnamed is more reasonable).

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
1

It's hard to say without the context. If you would like to represent a state where either something was pressed or not I would go for Nullable<Buttons> in this case:

class Input
{
    ...
    private Buttons? _buttons;
    ...
}

It also shields you from future versions of Buttons where 0might be added to mean something other than "None". Yes, unlikely, but not entirely impossible.

rjnilsson
  • 2,343
  • 15
  • 20