在下面的代码中,A
键被重新Map到B
键,反之亦然。重新Map是通过SwiftUI
切换开关激活的。
在这里给出的示例中,同一代码块用于三个不同的功能。
此外,在所有这三个函数中还使用了迭代函数调用的循环。
一天多以来,我一直在努力简化这段代码,减少冗余。如有任何帮助,我将不胜感激。
let aKey: UInt64 = 0x700000004
let bKey: UInt64 = 0x700000005
func isKeyboardServiceClientForUsagePage(_ serviceClient: IOHIDServiceClient, _ usagePage: UInt32, _ usage: UInt32) -> Bool {
return IOHIDServiceClientConformsTo(serviceClient, usagePage, usage) == 1
}
func updateKeyboardKeyMapping(_ keyMap: [[String: UInt64]]) {
let eventSystemClient = IOHIDEventSystemClientCreateSimpleClient(kCFAllocatorDefault)
guard let serviceClients = IOHIDEventSystemClientCopyServices(eventSystemClient) as? [IOHIDServiceClient] else {
return
}
for serviceClient in serviceClients {
let usagePage = UInt32(kHIDPage_GenericDesktop)
let usage = UInt32(kHIDUsage_GD_Keyboard)
if isKeyboardServiceClientForUsagePage(serviceClient, usagePage, usage) {
IOHIDServiceClientSetProperty(serviceClient, kIOHIDUserKeyUsageMapKey as CFString, keyMap as CFArray)
}
}
}
func areKeysMappedOnAnyServiceClient() -> Bool {
let eventSystemClient = IOHIDEventSystemClientCreateSimpleClient(kCFAllocatorDefault)
guard let serviceClients = IOHIDEventSystemClientCopyServices(eventSystemClient) as? [IOHIDServiceClient] else {
return false
}
for serviceClient in serviceClients {
let usagePage = UInt32(kHIDPage_GenericDesktop)
let usage = UInt32(kHIDUsage_GD_Keyboard)
if isKeyboardServiceClientForUsagePage(serviceClient, usagePage, usage) {
guard let keyMapping = IOHIDServiceClientCopyProperty(serviceClient, kIOHIDUserKeyUsageMapKey as CFString) as? [[String: UInt64]] else {
return false
}
if keyMapping.contains(where: { $0[kIOHIDKeyboardModifierMappingSrcKey] == aKey && $0[kIOHIDKeyboardModifierMappingDstKey] == bKey }) &&
keyMapping.contains(where: { $0[kIOHIDKeyboardModifierMappingSrcKey] == bKey && $0[kIOHIDKeyboardModifierMappingDstKey] == aKey })
{
return true
}
}
}
return false
}
func remapABBA() {
let keyMap: [[String: UInt64]] = [
[
kIOHIDKeyboardModifierMappingSrcKey: aKey,
kIOHIDKeyboardModifierMappingDstKey: bKey,
],
[
kIOHIDKeyboardModifierMappingSrcKey: bKey,
kIOHIDKeyboardModifierMappingDstKey: aKey,
],
]
updateKeyboardKeyMapping(keyMap)
}
func resetKeyMapping() {
updateKeyboardKeyMapping([])
}
如果你想试试这个应用程序,这里是SwiftUI
部分:
import SwiftUI
struct ContentView: View {
@State private var remapKeys = areKeysMappedOnAnyServiceClient()
var body: some View {
HStack {
Spacer()
Toggle(isOn: $remapKeys, label: { Text("Remap A → B and B → A.") })
.toggleStyle(SwitchToggleStyle())
.onChange(of: remapKeys, perform: toggleKeyboardRemapping)
Spacer()
}
}
}
private func toggleKeyboardRemapping(_ remapKeys: Bool) {
if remapKeys {
remapABBA()
} else {
resetKeyMapping()
}
}
1条答案
按热度按时间tzdcorbm1#
好吧......这需要一些时间来回答。
看起来你缺少一个地方来存储东西。这就是为什么你必须一遍又一遍地使用相同的代码块。我们可以用视图模型来解决这个问题...
在这里,我将隐藏视图中正在发生的逻辑,只暴露视图需要访问的内容,以便显示自己。
我将扩展
IOHIDServiceClient
和IOHIDEventSystemClientRef
来封装您的逻辑...执行所有这些操作意味着您的视图可能类似于以下内容...
这包含了你所有相同的逻辑和TBH已经不是太坏了。
我的主要修改是将自由函数和变量添加到各自的类型中。
因此,
update
和areKeysMapped...
函数现在属于IOHIDEventSystemClientRef
类型。isForGDKeyboard
和keyMapping
变量现在属于IOHIDServiceClient
类型。这样做删除了很多重复的代码,因为你不再需要不断地调用免费函数。这也意味着我们解锁了一些非常快速的
keyPath
用法,这有助于使一些逻辑更加简洁。然后我们做了一个视图模型,这样我们就可以把视图的所有移动部分都放在一个地方,这样就有了一个地方来方便客户端,也意味着我们可以通过私有化来隐藏视图模型中的很多东西。
这意味着视图只能做一件事,那就是使用绑定到
toggleState
,其他的一切都是关起门来的。