Cocoa Keyboard Shortcuts in Dialog without an Edit Menu

前端 未结 16 1254
Happy的楠姐
Happy的楠姐 2020-12-04 07:28

I have an LSUIElement application that displays a menubar status item. The application can display a dialog window that contains a text field.

If the u

相关标签:
16条回答
  • 2020-12-04 08:01

    Improving on that CocoaRocket solution:

    The following saves having to subclass NSTextField and remembering to use the subclass throughout your application; it will also enable copy, paste and friends for other responders that handle them, eg. NSTextView.

    Put this in a subclass of NSApplication and alter the principal class in your Info.plist accordingly.

    - (void) sendEvent:(NSEvent *)event {
        if ([event type] == NSKeyDown) {
            if (([event modifierFlags] & NSDeviceIndependentModifierFlagsMask) == NSCommandKeyMask) {
                if ([[event charactersIgnoringModifiers] isEqualToString:@"x"]) {
                    if ([self sendAction:@selector(cut:) to:nil from:self])
                        return;
                }
                else if ([[event charactersIgnoringModifiers] isEqualToString:@"c"]) {
                    if ([self sendAction:@selector(copy:) to:nil from:self])
                        return;
                }
                else if ([[event charactersIgnoringModifiers] isEqualToString:@"v"]) {
                    if ([self sendAction:@selector(paste:) to:nil from:self])
                        return;
                }
                else if ([[event charactersIgnoringModifiers] isEqualToString:@"z"]) {
                    if ([self sendAction:@selector(undo:) to:nil from:self])
                        return;
                }
                else if ([[event charactersIgnoringModifiers] isEqualToString:@"a"]) {
                    if ([self sendAction:@selector(selectAll:) to:nil from:self])
                        return;
                }
            }
            else if (([event modifierFlags] & NSDeviceIndependentModifierFlagsMask) == (NSCommandKeyMask | NSShiftKeyMask)) {
                if ([[event charactersIgnoringModifiers] isEqualToString:@"Z"]) {
                    if ([self sendAction:@selector(redo:) to:nil from:self])
                        return;
                }
            }
        }
        [super sendEvent:event];
    }
    
    // Blank Selectors to silence Xcode warnings: 'Undeclared selector undo:/redo:'
    - (IBAction)undo:(id)sender {}
    - (IBAction)redo:(id)sender {}
    
    0 讨论(0)
  • 2020-12-04 08:01

    Here's a quick step-by-step guide for swift, based on the excellent answers by @Adrian, Travis B and Thomas Kilian.

    The goal will be to subclass the NSApplication, instead of the NSTextField. Once you have created this class, do link it in your "principal Class" setting of the Info.plist, as stated by Adrian. As opposed to the Objective-C folks, we swiftlers will have to add an additional prefix to the principalClass configuration. So, because my Project is called "Foo", I am going to set "Principal Class" to "Foo.MyApplication". You will get an "Class MyApplication not found" runtime error otherwise.

    The contents of MyApplication read as follows (copied and adapted from all the answers given so far)

    import Cocoa
    
    class MyApplication: NSApplication {
        override func sendEvent(event: NSEvent) {
            if event.type == NSEventType.KeyDown {
                if (event.modifierFlags & NSEventModifierFlags.DeviceIndependentModifierFlagsMask == NSEventModifierFlags.CommandKeyMask) {
                    switch event.charactersIgnoringModifiers!.lowercaseString {
                    case "x":
                        if NSApp.sendAction(Selector("cut:"), to:nil, from:self) { return }
                    case "c":
                        if NSApp.sendAction(Selector("copy:"), to:nil, from:self) { return }
                    case "v":
                        if NSApp.sendAction(Selector("paste:"), to:nil, from:self) { return }
                    case "z":
                        if NSApp.sendAction(Selector("undo:"), to:nil, from:self) { return }
                    case "a":
                        if NSApp.sendAction(Selector("selectAll:"), to:nil, from:self) { return }
                    default:
                        break
                    }
                }
                else if (event.modifierFlags & NSEventModifierFlags.DeviceIndependentModifierFlagsMask == (NSEventModifierFlags.CommandKeyMask | NSEventModifierFlags.ShiftKeyMask)) {
                    if event.charactersIgnoringModifiers == "Z" {
                        if NSApp.sendAction(Selector("redo:"), to:nil, from:self) { return }
                    }
                }
            }
            return super.sendEvent(event)
        }
    
    }
    
    0 讨论(0)
  • 2020-12-04 08:01

    I explain what worked for me in XCode 8 / Swift 3.

    I created MyApplication.swift inside my project folder MyApp:

    import Foundation
    import Cocoa
    
    class MyApplication: NSApplication {
        override func sendEvent(_ event: NSEvent) {
            if event.type == NSEventType.keyDown {
    
                if (event.modifierFlags.contains(NSEventModifierFlags.command)) {
                    switch event.charactersIgnoringModifiers!.lowercased() {
                    case "x":
                        if NSApp.sendAction(#selector(NSText.cut(_:)), to:nil, from:self) { return }
                    case "c":
                        if NSApp.sendAction(#selector(NSText.copy(_:)), to:nil, from:self) { return }
                    case "v":
                        if NSApp.sendAction(#selector(NSText.paste(_:)), to:nil, from:self) { return }
                    case "a":
                        if NSApp.sendAction(#selector(NSText.selectAll(_:)), to:nil, from:self) { return }
                    default:
                        break
                    }
                }
            }
            return super.sendEvent(event)
        }
    
    }
    

    Then change the Info.plist Principal class to MyApp.MyApplication. Build, and run to validate that my text fields and text views have support for Cmd + X, Cmd + C, Cmd + V and Cmd + A.

    0 讨论(0)
  • 2020-12-04 08:01

    Just about 1 hour ago I stumbled upon the same problem. You don't need to code anything. I could do this in Interface Builder:

    • Create a menu (e.g. "Edit") which contains your Cut / Copy / Paste menu items
    • Add the KeyEquivalent for the CMD key to your "Edit" menu (don't know, if this is really needed, I just copied the structure from another project)
    • Add the KeyEquivalents to these menu items (CMD + X and so on)
    • Link the FirstResponder's cut:, copy: and paste: functions to your corresponding menu items

    That worked for me. Unfortunately this (default) behavior doesn't seem to work when you hide the "Edit" menu (just tried it).

    0 讨论(0)
提交回复
热议问题