我有一个NSView
子类,希望当用户按下⇧ Shift键时它能够作出反应。然而,当前我重写的-[NSView keyDown:]
方法在仅按下修饰键时不会被调用。
如何在Shift键被按下时得到通知?
来自Cocoa事件处理指南:
flagsChanged: 方法可以用于检测在没有同时按下其他键的情况下按下修改键的按键操作。例如,如果用户单独按下 Option 键,则您的响应对象可以在其 flagsChanged: 实现中检测到此操作。
更多详细信息可以在这里找到。
NSResponder 的文档还说明了以下内容:
flagsChanged:
通知接收者用户已按下或释放修改键(Shift、Control 等)。
-- (void)flagsChanged:(NSEvent *)theEvent
这是一个示例,稍作修改自 Matt Gemmell 的 ModKeyTest 示例应用程序。 创建一个基本的 Cocoa 应用程序,并将一个按钮与 IBAction 钩连起来,如下所示。 然后尝试使用您想要的键组合。 文档有点模糊,但 Matt 的示例非常清晰,呈现了您需要从文档中进一步利用的所有内容。
- (IBAction)myAction:(id)sender {
NSUInteger flags = [[NSApp currentEvent] modifierFlags];
if ((flags & NSCommandKeyMask) && (flags & NSAlternateKeyMask) && (flags & NSControlKeyMask)) {
NSBeginInformationalAlertSheet(@"Modifier keys Command Option Control detected", nil, nil, nil, [NSApp mainWindow], self, nil, nil, nil,
@"You sneaky thing!");
}
if ((flags & NSCommandKeyMask) && (flags & NSShiftKeyMask)) {
NSBeginInformationalAlertSheet(@"Modifier keys Command Shift detected", nil, nil, nil, [NSApp mainWindow], self, nil, nil, nil,
@"You sneaky thing!");
}
if ((flags & NSAlphaShiftKeyMask)) {
NSBeginInformationalAlertSheet(@"Modifier keys Caps Lock detected", nil, nil, nil, [NSApp mainWindow], self, nil, nil, nil,
@"You sneaky thing!");
}
if ((flags & NSFunctionKeyMask)) {
NSBeginInformationalAlertSheet(@"Modifier keys fn detected", nil, nil, nil, [NSApp mainWindow], self, nil, nil, nil,
@"You sneaky thing!");
}
NSApp.currentEvent
是最可靠的解决方案,特别是在混合鼠标和键盘(例如 Option-click)时。 - Ky -这里是处理Swift 3.0.1关键事件的代码,经过Xcode 8.2.1和macOS 10.12.2测试。
override func keyDown(with event: NSEvent) {
var handled = false
if event.keyCode == 53 { // ESC, same as `CMD + .`
handled = true
print("ESC")
}
if event.modifierFlags.contains(.command) { // .shift, .option, .control ...
if let chars = event.charactersIgnoringModifiers {
handled = true // likely we are interested with that key
switch chars {
case "r":
print("CMD + r")
case ",":
print("CMD + ,")
case "/":
print("CMD + /")
default:
handled = false
}
}
}
if !handled {
super.keyDown(with: event) // let system handle it(may contains sound)
}
}
NSShiftKeyMask
之外,以前还有一个NSAlphaShiftKeyMask
(请参见https://developer.apple.com/reference/appkit/nseventmodifierflags)-- 我正在用.shift
替换前者,但后者呢?是否有Swift 3的等效物。 - wcochran@available(OSX, introduced: 10.0, deprecated: 10.12, renamed: "NSEventModifierFlags.capsLock") public let NSAlphaShiftKeyMask: NSEventModifierFlags
因此请使用 .capsLock
。 - longkaiGetKeyState(VK_SHIFT)
获取这个状态。而在macOS上,相应的方法是什么?NSEvent.modifierFlags
类方法可以在任何时候返回当前修改键状态。但是我找不到一个清晰的方式来订阅这个变量的更改。 - beefonpublic class KeyboardHelper
{
public static var optionKeyIsDown: Bool
{
let flags = NSEvent.modifierFlags
return flags.contains(.option)
}
public static var shiftKeyIsDown: Bool
{
let flags = NSEvent.modifierFlags
return flags.contains(.shift)
}
}
`所以,我只需要 KeyboardHelper.shiftKeyIsDown
- Paul Stevenson如果用户按下特殊键,而不管同时是否按下任何普通键,您想要查看此操作。在Swift 5中,您可以在AppDelegate中使用override func实现。
新的Swift项目中的占位符应该如下所示:
override func flagsChanged (with theEvent: NSEvent)
{
// ...
}
override func flagsChanged (with theEvent: NSEvent)
{
let mods: Int = (Int(theEvent.modifierFlags.rawValue)) >> 16
let t_KeyCapsLockPressed = (bitand(mods, 1) != 0)
let t_KeyShiftPressed = (bitand(mods, 2) != 0)
let t_KeyControlPressed = (bitand(mods, 4) != 0)
let t_KeyOptionPressed = (bitand(mods, 8) != 0)
let t_KeyCommandPressed = (bitand(mods, 16) != 0)
// let t_KeyNumericPadPressed = (bitand(mods, 32) != 0) // Not used here
// let t_KeyHelpPressed = (bitand(mods, 64) != 0) // Not used here
let t_KeyFnPressed = (bitand(mods, 128) != 0)
print("flagsChanged: t_KeyShiftPressed = \(Int(t_KeyShiftPressed))")
print("flagsChanged: t_KeyControlPressed = \(Int(t_KeyControlPressed))")
print("flagsChanged: t_KeyOptionPressed = \(Int(t_KeyOptionPressed))")
print("flagsChanged: t_KeyCommandPressed = \(Int(t_KeyCommandPressed))")
// and so on...
}
每次按下或释放特殊键时都会调用该函数。因此,您可以随心所欲地进行操作。如果您将变量声明为全局变量,则可以实时从任何地方访问它们:
// In the header of your program:
var t_KeyCapsLockPressed: Bool = false
var t_KeyShiftPressed: Bool = false
var t_KeyControlPressed: Bool = false
var t_KeyOptionPressed: Bool = false
var t_KeyCommandPressed: Bool = false
var t_KeyFnPressed: Bool = false
var t_KeyFlagsHaveChanged: Bool = false
// In the AppDelegate:
override func flagsChanged (with theEvent: NSEvent)
{
let mods: Int = (Int(theEvent.modifierFlags.rawValue)) >> 16
t_KeyCapsLockPressed = (bitand(mods, 1) != 0)
t_KeyShiftPressed = (bitand(mods, 2) != 0)
t_KeyControlPressed = (bitand(mods, 4) != 0)
t_KeyOptionPressed = (bitand(mods, 8) != 0)
t_KeyCommandPressed = (bitand(mods, 16) != 0)
t_KeyFnPressed = (bitand(mods, 128) != 0)
t_KeyFlagsHaveChanged = true
}
// In your Main program:
func keyCheck ()
{
if t_KeyFlagsHaveChanged
{
print("flagsChanged: t_KeyShiftPressed = \(Int(t_KeyShiftPressed))")
print("flagsChanged: t_KeyControlPressed = \(Int(t_KeyControlPressed))")
print("flagsChanged: t_KeyOptionPressed = \(Int(t_KeyOptionPressed))")
print("flagsChanged: t_KeyCommandPressed = \(Int(t_KeyCommandPressed))")
// and so on...
t_KeyFlagsHaveChanged = false
}
}
检查是否按下:
-(void)keyDown:(NSEvent *)theEvent
{
if ([theEvent modifierFlags] & NSShiftKeyMask)
{
NSLog("Shift key was pressed");
}
}
检查发布版本:
-(void)keyUp:(NSEvent *)theEvent
{
if(!([theEvent modifierFlags] & NSShiftKeyMask))
{
NSLog("Shift key was released");
}
}
需要注意的是,只有在按下SHIFT键以及其他某个键时,才会调用NSLog函数。
希望这对你有所帮助!
NSView
(从NSResponder
继承)中的keyDown
方法,但当我按下Shift键时该方法根本没有被调用。(我更新了我的问题以反映这一点;现在我看到它可能是混淆的一个来源。) - zneak