我想要一个 Bool 属性,代表按下了选项键
@Publised var isOptionPressed = false
。 我会用它来更改 SwiftUI 视图。
为此,我认为我应该使用Combine 来观察按键压力。
我试图找到该事件的 NSNotification,但在我看来,没有任何 NSNotification,这可能对我有用。
好的,我找到了解决问题的简单方法:
class KeyPressedController: ObservableObject {
@Published var isOptionPressed = false
init() {
NSEvent.addLocalMonitorForEvents(matching: .flagsChanged) { [weak self] event -> NSEvent? in
if event.modifierFlags.contains(.option) {
self?.isOptionPressed = true
} else {
self?.isOptionPressed = false
}
return event
}
}
}
由于您正在使用 SwiftUI 进行工作,因此我建议您除了观察发布者之外,还可以将修改器标志的状态放入 SwiftUI 中
Environment
。我认为它非常适合 SwiftUI 的声明性语法。
我有另一个实现,但采用了您找到的解决方案并进行了调整。
import Cocoa
import SwiftUI
import Combine
struct KeyModifierFlags: EnvironmentKey {
static let defaultValue = NSEvent.ModifierFlags([])
}
extension EnvironmentValues {
var keyModifierFlags: NSEvent.ModifierFlags {
get { self[KeyModifierFlags.self] }
set { self[KeyModifierFlags.self] = newValue }
}
}
struct ModifierFlagEnvironment<Content>: View where Content:View {
@StateObject var flagState = ModifierFlags()
let content: Content;
init(@ViewBuilder content: () -> Content) {
self.content = content();
}
var body: some View {
content
.environment(\.keyModifierFlags, flagState.modifierFlags)
}
}
final class ModifierFlags: ObservableObject {
@Published var modifierFlags = NSEvent.ModifierFlags([])
init() {
NSEvent.addLocalMonitorForEvents(matching: .flagsChanged) { [weak self] event in
self?.modifierFlags = event.modifierFlags
return event;
}
}
}
请注意,我的事件闭包正在返回传入的事件。如果您返回
nil
,您将阻止事件进一步发展,并且系统中的其他人可能想看到它。
结构体
KeyModifierFlags
设置要添加到视图Environment
的新项目。 EnvironmentValues
的扩展让我们可以存储和
从环境中检索当前标志。
最后是
ModifierFlagEnvironment
视图。它没有自己的内容 - 在 @ViewBuilder
函数中传递给初始化器。它所做的就是提供包含状态监视器的 StateObject
,并将修改器标志的当前值传递到内容的 Environment
。
要使用
ModifierFlagEnvironment
,您可以用它在层次结构中包装一个顶级视图。在从默认 Xcode 模板构建的简单 Cocoa 应用程序中,我将应用程序 SwiftUI 内容更改为:
struct KeyWatcherApp: App {
var body: some Scene {
WindowGroup {
ModifierFlagEnvironment {
ContentView()
}
}
}
}
因此应用程序中的所有视图都可以观看这些标志。
然后要使用它,你可以这样做:
struct ContentView: View {
@Environment(\.keyModifierFlags) var modifierFlags: NSEvent.ModifierFlags
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
if(modifierFlags.contains(.option)) {
Text("Option is pressed")
} else {
Text("Option is up")
}
}
.padding()
}
}
这里内容视图监视环境中的标志,并且视图使用当前修饰符决定显示什么。