Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm working on picking up XNA and this was a confusing point for me.

KeyboardState keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.Left) || keyState.IsKeyDown(Keys.A))
{
    //Do stuff...
}

The book I'm using (Learning XNA 4.0, O'Rielly) says that this method accepts a bitwise OR series of keys, which I think should look like this...

KeyboardState keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.Left | Keys.A))
{
    //Do stuff...
}

But I can't get it work. I also tried using !IsKeyUp(... | ...) as it said that all keys had to be down for it to be true, but had no luck with that either. Ideas? Thanks.

share|improve this question
1  
Is it really worth it? Just use an extra keyState.IsKeyDown() with || –  indeed005 Sep 24 '12 at 22:14
1  
First of all your two blocks are not equivalent. "keyState.IsKeyDown(Keys.Left) && keyState.IsKeyDown(Keys.A)" for the top would make the blocks logically equivalent. Also could you describe what "But I can't get it work" means? Where is this code. Are threads involved? The second block it should be true iff A and Left are both pressed. Are you not experiencing this behavior? –  ClassicThunder Sep 24 '12 at 22:15
    
I'm only trying to avoid extra code and method calls if I can - this seems like something that should be common with alternate keys in games? I know they're not equivalent, that is why I mentioned the IsKeyUp alternative. By "it doesn't work" I meant that I can't ever get it to be true - it doesn't matter if both keys are up, one key is down, or both keys is down. In one of those cases it should be true, but none of them were. –  jocull Sep 24 '12 at 22:49
2  
a better thing to avoid than extra code is confusing code. The second block has confused you and has a higher probability of confusing others so in this case it should be avoided... Even if you get it to work as expected. –  Steve H Sep 25 '12 at 1:46
2  
I have this book and just checked the section on Keyboard input. I saw absolutely nothing mentioning bitwise operators. However, there is a section about Gamepad input that claims you can use bitwise to pass multiple Buttons to the IsButtonDown method. –  Justin Skiles Sep 25 '12 at 2:43
show 1 more comment

2 Answers 2

up vote 10 down vote accepted

The XNA Keys struct is not marked with the Flags Attribute which means that it's not legal to | a load of keys together like that.

Keys keyCombo = Keys.Left | Keys.A;
Console.WriteLine(keyCombo);

Will print NumPad5, which is clearly not what you want here! You've never been able to do this in any version of XNA, I think the book is just wrong here :O

Copying from one of my own games, this is how I solved it:

#if WINDOWS
public static bool Any(this KeyboardState state, params Keys[] keys)
{
    return keys.Any(state.IsKeyDown);
}
#endif

And then you can just do:

KeyboardState k = Keyboard.GetState();

if (k.Any(Keys.Left, Keys.A))
    DoStuff();

However, as someone in the comments pointed out this method is bad practice on the xbox due to it allocating (params array allocation, and LINQ allocating an Enumerator). An alternative system for xbox is this:

Keys[] doStuffKeys; //Allocate an array of keys for this particular action

Initialize()
{
    doStuffKeyBinding = new[] { Keys.Left, Keys.A };
}

Update()
{
    KeyboardState k = Keyboard.GetState();

    if (k.Any(doStuffKeys)) //No allocations here!
        DoStuff();
}

The Any method needs modifying too:

#if XBOX
public static bool Any(this KeyboardState state, Keys[] keys)
{
    for (int i = 0; i < keys.Length; i++)
        if (state.IsKeyDown(keys[i]))
            return true;
    return false;
}
#endif

It's a while since I've done any work for the xbox, but this now shouldn't allocate.

share|improve this answer
    
Really like the use the extension method here. Thanks! I think that should be return keys.Any(x => state.IsKeyDown(x)); –  jocull Sep 25 '12 at 1:58
1  
@jocull, I don't need x => state.IsKeyDown(x), the above compiles just fine :) –  Martin Sep 25 '12 at 4:40
2  
+1 For extension methods and LINQ. And @jocull, That's right. It's like how events/delegates can be associated with a lambda expression, anonymous method, or a named method. –  michael.bartnett Sep 25 '12 at 7:02
2  
@Jocull, absolutely right. Any takes a Func<Keys, bool> and IsKeyDown is a Func<Keys, bool> so all is fine :D –  Martin Sep 25 '12 at 7:34
3  
One minor note, if you are using XNA to develop on the xbox using params and linq will typically generate garbage, which is best avoided. It's not pretty but overloading the method with 1, 2, 3... parameters would get around this. –  George Duckett Sep 25 '12 at 15:03
show 4 more comments

IsKeyDown takes an enum Key for its type. I don't see from the documentation that it can take multiple emums ORed together. Perhaps your book is wrong?

You could create your own method if you wanted the shortcut:

boolean anyOfTheseDown(KeyboardState keyState, params Keys[] keys) {
   boolean result = false;
   for (int i = 0; i < keys.Length; i++)
   {
       result |= keyState.IsKeyDown(keys[i]);
   }    
   return result;
}

Then use it like:

KeyboardState keyState = Keyboard.GetState();
if (anyOfTheseDown(keyState, Keys.Left, Keys.A))
{
    //Do stuff...
}

Code is untested.

share|improve this answer
    
I like this solution if bitwise is out of the question. Is the for loop considered unnecessary overhead? Would it be better to just write it twice with a traditional ||? Not trying to micro-optimize and scrutinize this too much, but genuinely curious about writing the best code I can. –  jocull Sep 24 '12 at 22:52
2  
It depends, the method above will allow 1 or more keys to be checked. The for loop will not add any (noticeable) additional overhead for checking multiple key states. But you do appear to be pre-micro-optimizing :) If you worry this much about this level of detail, you'll never finish. –  Byte56 Sep 24 '12 at 22:58
    
@joculi For your case this seems the most convenient, doesn't it? Using enum flags would be more useful in checking for a group of keys being pressed exclusively, but making sure that each frame you build an "isDown" enum value of the keys that are down this frame to bitwise-compare to the requested key combination. But even that's still prematurely optimizing. –  michael.bartnett Sep 25 '12 at 0:55
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.