【问题标题】:Connecting Keyboard actions to UIButton Actions in Mac Catalyst App在 Mac Catalyst App 中将键盘操作连接到 UIButton 操作
【发布时间】:2020-08-15 05:24:46
【问题描述】:

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

【问题讨论】:

  • 我不认为 Catalyst 支持这样的键盘输入,但我相信这是他们计划添加的一项功能
  • 我不知道您是如何获得内幕信息的,但您对此是正确的,Apple 确实按照公认答案的建议添加了支持并指明了方向。

标签: ios swift macos ipad mac-catalyst


【解决方案1】:

如果满足以下条件,我发现它可以工作:

0) 为 UIKeyCommands 的简单构建创建一个结构

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

` 1) 子类 UIWINdow 2)您覆盖“场景窗口”中的 keyCommands 变量,并为您希望窗口捕获的每个键创建键命令。我的应用程序有多个场景,所以我保存的场景 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。 (模型是这个应用程序的单例类)。

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

        }

    }

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 2014-05-04
      • 1970-01-01
      • 1970-01-01
      • 2014-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-28
      相关资源
      最近更新 更多