15

I am porting an iOS app on MacOS using UIKit for Mac also known as iPad Apps for Mac or Project Catalyst.

The app uses keyCommands from UIKit to detect a single modifier key press:

UIKeyCommand(input: "", modifierFlags: .shift, action: #selector(singleShift))

This code works perfectly on iPad with an external keyboard, I am getting the event fired with every single ⇧ press. However, this does not work on MacOS, although single non-modifier events and modifier + non-modifier combinations work.

How do I achieve the desired behavior and get notified about single modifier key events?

Or maybe I should just give up on UIKeyCommand and try UIGestureRecognizer instead?

Paulo Mattos
  • 16,310
  • 10
  • 64
  • 73
Dmitriy
  • 1,738
  • 1
  • 12
  • 23

2 Answers2

1

This may not be your problem make sure you don't have any keyboard apps or apps that intercept keyboard input running. I had a problem like this when I had Karibeaner-elements installed.

Otherwise, if this is a limitation of catalyst consider wrapping a more stable API from app kit or use UIGestureRecognizer.

  • UIGestureRecognizer doesn't (as far as I know) provide a way to detect modifier keys. Am I missing something? My workaround now is as you suggest just to load an AppKit bundle. It would be nice to be able to do this in UIKit though. – Confused Vorlon Feb 19 '20 at 10:36
  • I think you're correct, My suggestion was based on the OP saying they could use UIGestureRecognizer as a workaround, I wasn't aware of it's capability of recognizing mod keys – Matthew Weldon Feb 19 '20 at 14:26
  • @ConfusedVorlon UIGestureRecognizer does provide a `.modifierFlags` property. – Minsheng Liu May 14 '20 at 02:38
  • @MinshengLiu - nice spot. Added in 13.4 - perhaps Apple do listen ;) – Confused Vorlon May 14 '20 at 08:10
  • @ConfusedVorlon Didn't realize that it was so new. I am really lucky then! – Minsheng Liu May 19 '20 at 05:43
0

I'd recommend getting familiar with pressesBegan and pressesEnded in UIResponder. There's a lot of shortcut power outside of UIKeyCommands (like length of press and such to trigger different actions).

Here's what should solve your question in this framework:

    override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
    guard let key = presses.first?.key else { return }

    switch key.keyCode {
    case .keyboardLeftShift, .keyboardRightShift:
        print("Shifted")
        // Call below if you want other views to catch the shift press:
        // I call this non-blocking, no idea what it's called:

        // super.pressesBegan(presses, with: event)
    
    default:
        // Pass through other presses to views in hierarchy
        super.pressesBegan(presses, with: event)
    }
}
CMill4
  • 86
  • 3