在 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
我有一个 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