0

My son noted that he could not use the cursor keys to move in a simple game I wrote. I followed the guide found here on SO, and now you can move the four cardinal directions. But the game allows eight directions...

keyDown captures whichever was hit first and only returns a single keycode at a time. Now I keep capturing keyDowns and set local ivars and then trigger on keyUp.

It works, but am I missing a canonical method for this? This is my first time on the macOS side, I've always worked on iOS before, so key handling is new and I want to be sure I'm not missing some simpler solution.

Maury Markowitz
  • 9,082
  • 11
  • 46
  • 98
  • pls clarify the question. are you essentially asking how to use four keys (arrow keys) to capture eight inputs? why not just use QWE/ASD/ZXC instead of the arrow keys? – Fault Nov 06 '22 at 18:39
  • @Fault - simply because the cursor keys make more sense in this context, and more generally, I just want to know if there is a general solution. – Maury Markowitz Nov 07 '22 at 12:41

1 Answers1

0

Here's how I solved this. Basically, you keep capturing keydown codes until you get a keyup. In the keyup you reset the keydown codes and then decode the results. Works like a champ. Game.Move is an enum I had created previously, but for macOS-only code it could be replaced with the keycode int instead.

var keys: Set<Int> = []
override func keyDown(with event: NSEvent) {
    keys.insert(Int(event.keyCode))
}
override func keyUp(with event: NSEvent) {
    // add the codes to make one of eight cases
    var keycode: Int = 0
    for key in keys {
        keycode += key
    }
    
    // now figure out the result, and default to none
    var move: Game.Move
    switch keycode {
    case kVK_LeftArrow: move = Game.Move.left
    case kVK_RightArrow: move = Game.Move.right
    case kVK_UpArrow: move = Game.Move.up
    case kVK_DownArrow: move = Game.Move.down
        
    case kVK_LeftArrow + kVK_UpArrow: move = Game.Move.upleft
    case kVK_LeftArrow + kVK_DownArrow: move = Game.Move.downleft
    case kVK_RightArrow + kVK_UpArrow: move = Game.Move.upright
    case kVK_RightArrow + kVK_DownArrow: move = Game.Move.downright
        
    default: move = Game.Move.dontmove
    }
    
    // reset the keyset
    keys = []
    
    // and do the move
    doMove(move)
}
Maury Markowitz
  • 9,082
  • 11
  • 46
  • 98
  • there's a bug here. since you're summing the integer keyCodes, you have a conflict in two case: the upleft (126 + 123 = 249) and the downright (124 + 125 = 249). which ever comes first in the switch will override the other. you'll have to make your logic slightly more complex. ex: don't sum the set, but rather test against discrete elements in the set. and test for the exotic (diagonal) cases first, then the orthogonal cases. – Fault Nov 07 '22 at 17:49
  • Yeah, changed after the post. I thought they were orthogonal cases until a robot caught me... – Maury Markowitz Nov 07 '22 at 18:36