在 Mac Catalyst App 中将键盘操作连接到 UIButton 操作

Connecting Keyboard actions to UIButton Actions in Mac Catalyst App

我有一个 Mac Catalyst 应用程序,对于这个问题,您可以假设它是一个计算器。因此,它有很多 UIButton。一切正常。但我真正想要的是将物理键盘操作连接起来,例如按键盘上的 1、2、3 ... 按钮到这些键对应的 UIButtons。我怎样才能做到这一点?同样,它是 Mac Catalyst 应用程序,而不是 macOS 应用程序。

我发现这个在以下情况下有效:

0) 创建用于简单构建 UIKeyCommands 的结构

struct keyCommand {
    var input: String;
    var modifiers: UIKeyModifierFlags
}

` 1) 子class UIWIndow 2) 您覆盖 "scene window" 中的 keyCommands 变量,并为您希望 window 捕获的每个键创建键命令。我的应用程序有多个场景,所以我保存的场景 ID 字符串用于显示当前焦点(第一响应者)

class Window: UIWindow{
    var model: CCModel! // will load after the window established
    var app: AppDelegate!
    var scene: String!
    var keyCommandList: [keyCommand]
    var commands: [UIKeyCommand]?

    override init(frame: CGRect) {
        keyCommandList = [

            //arrow keys
            keyCommand(input: UIKeyCommand.inputUpArrow, modifiers:[]),
            keyCommand(input: UIKeyCommand.inputUpArrow, modifiers:.alternate),
            keyCommand(input: UIKeyCommand.inputUpArrow, modifiers:.command),
            keyCommand(input: UIKeyCommand.inputUpArrow, modifiers: .shift),
            keyCommand(input: UIKeyCommand.inputDownArrow, modifiers:[]),
            keyCommand(input: UIKeyCommand.inputDownArrow, modifiers:.alternate),
            keyCommand(input: UIKeyCommand.inputDownArrow, modifiers:.command),
            keyCommand(input: UIKeyCommand.inputDownArrow, modifiers: .shift),
            keyCommand(input: UIKeyCommand.inputLeftArrow, modifiers:[]),
            keyCommand(input: UIKeyCommand.inputLeftArrow, modifiers:.alternate),
            keyCommand(input: UIKeyCommand.inputLeftArrow, modifiers:.command),
            keyCommand(input: UIKeyCommand.inputLeftArrow, modifiers: .shift),
            keyCommand(input: UIKeyCommand.inputRightArrow, modifiers:[]),
            keyCommand(input: UIKeyCommand.inputRightArrow, modifiers:.alternate),
            keyCommand(input: UIKeyCommand.inputRightArrow, modifiers:.command),
            keyCommand(input: UIKeyCommand.inputRightArrow, modifiers: .shift),

            //escape
            keyCommand(input: UIKeyCommand.inputEscape, modifiers: []),

            // a (play arpegio), A - progression arpegio
            keyCommand(input: "a", modifiers: []),
            keyCommand(input: "a", modifiers: .shift),

            // c (play chord), S - progression chord
            keyCommand(input: "c", modifiers: []),
            keyCommand(input: "c", modifiers: .shift),

            // tab key,
            keyCommand(input: "\t", modifiers: []),
            keyCommand(input: "\t", modifiers: .shift),

            // return
            keyCommand(input: "\r", modifiers: []),
            keyCommand(input: "\r", modifiers: .shift),

            // +
            keyCommand(input: "+", modifiers: []),
            keyCommand(input: "=", modifiers: []),

            // -
            keyCommand(input: "-", modifiers: []),
            keyCommand(input: "_", modifiers: []),

            // space

            keyCommand(input: " ", modifiers: []),
            keyCommand(input: "0", modifiers: []), // toggle the accents

            keyCommand(input: "p", modifiers: []),
            keyCommand(input: "s", modifiers: []),
            keyCommand(input: "s", modifiers: .alternate),
            keyCommand(input: "s", modifiers: .command),


            keyCommand(input: "i", modifiers: []),
            keyCommand(input: "k", modifiers: []),
            keyCommand(input: "?", modifiers: []),
            keyCommand(input: "t", modifiers: []),
            keyCommand(input: "r", modifiers: []),
            keyCommand(input: "o", modifiers: []),
            keyCommand(input: "d", modifiers: []),
            keyCommand(input: "w", modifiers: []),
            keyCommand(input: "h", modifiers: []),
            keyCommand(input: "l", modifiers: []),



            keyCommand(input: "1", modifiers: []),
            keyCommand(input: "2", modifiers: []),
            keyCommand(input: "3", modifiers: []),
            keyCommand(input: "4", modifiers: []),
            keyCommand(input: "5", modifiers: []),

        ]
        self.commands = []
        for command in self.keyCommandList {
            let keycommand = UIKeyCommand(input: command.input, modifierFlags: command.modifiers, action: #selector(self.captureKey(sender:)))

            self.commands!.append(keycommand)
        }
        super.init(frame: frame)

   open override var keyCommands: [UIKeyCommand]? {
        return self.commands
    }

    @objc func captureKey(sender: UIKeyCommand) {
        self.model.onKeyCapture(sender, scene: self.scene)
    }
}

3) 将捕获的键和修饰符发送给委托来管理它。在我的例子中,这是方法 self.model.method。 (模型是此应用的单例 class)。

func onKeyCapture(_ sender: UIKeyCommand, scene: String) {
        let app = getApp()
        let input = sender.input
        let modifiers = sender.modifierFlags
        if scene == "main" {
            // handle main screen key commands
            // mode independent commands
            switch input {
            case "k","1":
                setMode(value: "C")
                selectSegment(0)
                return
            case "s","2":
                if modifiers == [] {  // allow modified "s" through
                    setMode(value: "S")
                    selectSegment(1)
                    return
                }
            case "i","?","3":
                setMode(value: "I")
                selectSegment(2)
                return
            case "p","4":
                setMode(value: "P")
                selectSegment(3)
                return
            default:
                break
            }
            switch input {
            case "t":
                switch modifiers {
                   case []:
                        playTuning()
                        return
                   default:
                       break
                   }
            default:
                break
            }
            switch mode {
            case "C": // chord mode
                switch input {
                case UIKeyCommand.inputUpArrow:
                    switch modifiers {
                    case []:
                        nextPrev(type: .prev)
                    default:
                        break
                    }
                case UIKeyCommand.inputDownArrow:
                    switch modifiers {
                    case []:
                        nextPrev(type: .next)
                    default:
                        break
                    }
                case UIKeyCommand.inputRightArrow:
                     switch modifiers {
                     case []:
                        app.chordTVC!.setbyKeyCommand(delta: +1)
                     default:
                         break
                     }
                 case UIKeyCommand.inputLeftArrow:
                     switch modifiers {
                     case []:
                         app.chordTVC!.setbyKeyCommand(delta: -1)
                     default:
                         break
                     }
                case " ":
                    toggleShowChordScale()
                case "0":
                    app.fretboardVC!.toggleAccents()
                case "c":
                    switch modifiers {
                    case []:
                        playChord()
                    default:
                        break
                    }
                case "a":
                    switch modifiers {
                    case []:
                        playArpeggio()
                    default:
                        break
                    }
                case "+","=":
                    if root == nil { // no root chosen, so set it to "C"
                        app.rootTVC!.setRootByValue(key: "C")
                    } else { // raise the key a semitone
                        incrementDecrementKey(direction: 1)
                    }
                case "-","_":
                    if root == nil { // no root chosen, so set it to "C"
                        app.rootTVC!.setRootByValue(key: "C")
                    } else { // lower the key a semitone
                        incrementDecrementKey(direction: -1)
                    }
                case "r":
                    app.filtersCVC!.toggleFilter("NOROOT_OK")
                case "5":
                    app.filtersCVC!.toggleFilter("NO5TH_OK")
                case "o":
                    app.filtersCVC!.toggleFilter("NO_OPEN")
                case "d":
                    app.filtersCVC!.toggleFilter("NO_DEAD")
                case "w":
                    app.filtersCVC!.toggleFilter("NO_WIDOW")
                case "h":
                    app.filtersCVC!.toggleHighLow("high")
                case "l":
                    app.filtersCVC!.toggleHighLow("low")
                default:
                    break
                }
            case "S": // Scale mode
                switch input {
                case UIKeyCommand.inputRightArrow:
                    switch modifiers {
                    case []:
                       app.scaleTVC!.setbyKeyCommand(delta: +1)
                    default:
                        break
                    }
                case UIKeyCommand.inputLeftArrow:
                    switch modifiers {
                    case []:
                        app.scaleTVC!.setbyKeyCommand(delta: -1)
                    default:
                        break
                    }
                case "+","=":
                    if root == nil { // no root chosen, so set it to "C"
                        app.rootTVC!.setRootByValue(key: "C")
                    } else { // raise the key a semitone
                        incrementDecrementKey(direction: 1)
                    }
                case "-","_":
                    if root == nil { // no root chosen, so set it to "C"
                        app.rootTVC!.setRootByValue(key: "C")
                    } else { // lower the key a semitone
                        incrementDecrementKey(direction: -1)
                    }
               case " ":
                   switch modifiers {
                   case []: // two finger tap equivalent
                        if scaleDisplayMode == "notes" {
                           scaleDisplayMode = "tones"
                       } else {
                           scaleDisplayMode = "notes"
                       }
                       FretboardNeedsDisplay()
                   default:
                       break
                   }
                case "a":
                    showAccents = !showAccents
                    FretboardNeedsDisplay()
                case "\r":
                    if modifiers == []{
                        playScale()
                    }
                default:
                    break
                }
            case "I": // Identify mode
                switch input {
                default:
                    break
                }
            case "P": // Progression mode
                switch input {
                case UIKeyCommand.inputUpArrow:
                    switch modifiers {
                    case []:
                        nextPrev(type: .prev)
                    default:
                        break
                    }
                case UIKeyCommand.inputDownArrow:
                    switch modifiers {
                    case []:
                        nextPrev(type: .next)
                    default:
                        break
                    }
                case UIKeyCommand.inputRightArrow:  // next previous progression
                     switch modifiers {
                     case []:
                        app.progDisplayTVC!.setbyKeyCommand(delta: +1)
                     default:
                         break
                     }
                 case UIKeyCommand.inputLeftArrow:
                     switch modifiers {
                     case []:
                         app.progDisplayTVC!.setbyKeyCommand(delta: -1)
                     default:
                         break
                     }
                case " ":
                    toggleShowChordScale()
                case "0":
                    app.fretboardVC!.toggleAccents()
                case "c":
                    switch modifiers {
                    case []:
                        playChord()
                    case .shift:
                        progPlayChord()
                    default:
                        break
                    }
                case "a":
                    switch modifiers {
                    case []:
                        playArpeggio()
                    case .shift:
                        progPlayArp()
                    default:
                        break
                    }
                case "+","=":
                    if root == nil { // no root chosen, so set it to "C"
                        app.rootTVC!.setRootByValue(key: "C")
                    } else { // raise the key a semitone
                        incrementDecrementKey(direction: 1)
                    }
                case "-","_":
                    if root == nil { // no root chosen, so set it to "C"
                        app.rootTVC!.setRootByValue(key: "C")
                    } else { // lower the key a semitone
                        incrementDecrementKey(direction: -1)
                    }
                case "r":
                    app.filtersCVC!.toggleFilter("NOROOT_OK")
                case "5":
                    app.filtersCVC!.toggleFilter("NO5TH_OK")
                case "o":
                    app.filtersCVC!.toggleFilter("NO_OPEN")
                case "d":
                    app.filtersCVC!.toggleFilter("NO_DEAD")
                case "w":
                    app.filtersCVC!.toggleFilter("NO_WIDOW")
                case "h":
                    app.filtersCVC!.toggleHighLow("high")
                case "l":
                    app.filtersCVC!.toggleHighLow("low")
                default:
                    break
                }
            default:
                break
            }
        }
        else if scene == "help" {
            // handle help screen key commands

        }

    }

使用 iOS 13.4,您可以使用 UIResponder 的 pressesBegan: 来捕获基于 UIKey 的 UIEvents

https://developer.apple.com/documentation/uikit/mac_catalyst/handling_key_presses_made_on_a_physical_keyboard