Diagonal moves with the keyboard in macOS

51 Views Asked by At

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.

1

There are 1 best solutions below

2
Maury Markowitz On

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)
}