Сочетания клавиш какао в диалоге без меню редактирования - PullRequest
33 голосов
/ 09 июня 2009

У меня есть приложение LSUIElement, которое отображает элемент состояния меню. Приложение может отображать диалоговое окно, содержащее текстовое поле.

Если пользователь щелкает правой кнопкой мыши / удерживает нажатой клавишу Control текстовое поле, появляется меню, в котором можно вырезать, скопировать, вставить и т. Д. Однако стандартные сочетания клавиш Command-X, Command-C и Command-V не позволяют работа в поле. Я предполагаю, что это потому, что мое приложение не предоставляет меню «Правка» с этими ярлыками.

Я попытался добавить пункт меню «Правка» в меню моего приложения, как это было предложено в блоге Отправка некоторого кода , но это не сработало. Можно использовать пункты меню в меню «Правка», но сочетания клавиш по-прежнему не работают.

Я могу представить несколько способов взломать работу с клавиатурой, но есть ли «рекомендуемый» способ заставить это работать?

(Подробнее о приложении см. Отсчет по меню .)

Смежный вопрос: В модальном окне не работает копирование / вставка

Ответы [ 15 ]

0 голосов
/ 31 января 2019

Спасибо за это решение! Это очень помогло мне, поэтому я решил добавить некоторый код в надежде, что это поможет кому-то еще Предложенное выше решение отлично работает после того, как я преобразовал его в Swift 4.2. Затем я немного переработал код. Я думаю, что это немного чище. Это Swift 4.2 совместимо:

// NSEventExtensions.swift

import AppKit

extension NSEvent {
    func containsKeyModifierFlags(_ flags: NSEvent.ModifierFlags) -> Bool {
        switch modifierFlags.intersection(.deviceIndependentFlagsMask) {
        case [flags]: return true
        default: return false
        }
    }
}

// SearchFiled.swift

import AppKit
import Carbon

final class SearchField: NSSearchField {
    override func performKeyEquivalent(with event: NSEvent) -> Bool {
        switch event.type {
        case .keyDown: return performKeyDownEquivalent(with: event)
        default: return super.performKeyEquivalent(with: event)
        }
    }

    // MARK: - private

    private func performKeyDownEquivalent(with event: NSEvent) -> Bool {
        if event.containsKeyModifierFlags(.command) {
            switch Int(event.keyCode) {
            case kVK_ANSI_X: return NSApp.sendAction(#selector(NSText.cut(_:)), to: nil, from: self)
            case kVK_ANSI_C: return NSApp.sendAction(#selector(NSText.copy(_:)), to: nil, from: self)
            case kVK_ANSI_V: return NSApp.sendAction(#selector(NSText.paste(_:)), to: nil, from: self)
            case kVK_ANSI_Z: return NSApp.sendAction(Selector(("undo:")), to: nil, from: self)
            case kVK_ANSI_A: return NSApp.sendAction(#selector(NSResponder.selectAll(_:)), to: nil, from: self)
            default: break
            }
        } else if event.containsKeyModifierFlags([.command, .shift]) {
            switch Int(event.keyCode) {
            case kVK_ANSI_Z: return NSApp.sendAction(Selector(("redo:")), to: nil, from: self)
            default: break
            }
        }
        return false
    }
}
0 голосов
/ 20 марта 2018

Основываясь на ответе Thomas Kilian, вы можете создать расширение для NSTextField

let commandKey = NSEvent.ModifierFlags.command.rawValue
let commandShiftKey = NSEvent.ModifierFlags.command.rawValue | NSEvent.ModifierFlags.shift.rawValue

extension NSTextField {
    func performEditingKeyEquivalent(with event: NSEvent) -> Bool {
        guard event.type == NSEvent.EventType.keyDown else { return false }

        if (event.modifierFlags.rawValue & NSEvent.ModifierFlags.deviceIndependentFlagsMask.rawValue) == commandKey {
            if let character = event.charactersIgnoringModifiers {
                switch character {
                case "x":
                    if NSApp.sendAction(#selector(NSText.cut(_:)), to: nil, from: self) { return true }
                case "c":
                    if NSApp.sendAction(#selector(NSText.copy(_:)), to: nil, from: self) { return true }
                case "v":
                    if NSApp.sendAction(#selector(NSText.paste(_:)), to: nil, from: self) { return true }
                case "z":
                    if NSApp.sendAction(Selector(("undo:")), to: nil, from: self) { return true }
                case "a":
                    if NSApp.sendAction(#selector(NSResponder.selectAll(_:)), to: nil, from: self) { return true }
                default:
                    break
                }
            }
        } else if (event.modifierFlags.rawValue & NSEvent.ModifierFlags.deviceIndependentFlagsMask.rawValue) == commandShiftKey {
            if event.charactersIgnoringModifiers == "Z" {
                if NSApp.sendAction(Selector(("redo:")), to: nil, from: self) { return true }
            }
        }

        return false
    }
}

В следующем примере можно фактически заменить NSTextField любым из NSTextField наследующих классов (например, NSSearchField, NSSecureTextField), чтобы получить новую функциональность

class SearchField: NSTextField {
    override func performKeyEquivalent(with event: NSEvent) -> Bool {
        if performEditingKeyEquivalent(with: event) {
            return true
        }

        return super.performEditingKeyEquivalent(with: event)
    }
}
0 голосов
/ 25 февраля 2016

Вот ответ Трэвиса как C # для использования с Xamarin.Mac:

    public override bool PerformKeyEquivalent (AppKit.NSEvent e)
    {
        if (e.Type == NSEventType.KeyDown) {
            var inputKey = e.CharactersIgnoringModifiers.ToLower ();
            if (   (e.ModifierFlags & NSEventModifierMask.DeviceIndependentModifierFlagsMask) == NSEventModifierMask.CommandKeyMask
                || (e.ModifierFlags & NSEventModifierMask.DeviceIndependentModifierFlagsMask) == (NSEventModifierMask.CommandKeyMask | NSEventModifierMask.AlphaShiftKeyMask)) {
                switch (inputKey) {
                case "x":
                    NSApplication.SharedApplication.SendAction (new Selector ("cut:"), null, this);
                    return true;
                case "c":
                    NSApplication.SharedApplication.SendAction (new Selector ("copy:"), null, this);
                    return true;
                case "v":
                    NSApplication.SharedApplication.SendAction (new Selector ("paste:"), null, this);
                    return true;
                case "z":
                    NSApplication.SharedApplication.SendAction (new Selector ("undo:"), null, this);
                    return true;
                case "a":
                    NSApplication.SharedApplication.SendAction (new Selector ("selectAll:"), null, this);
                    return true;
                }
            } else if (   (e.ModifierFlags & NSEventModifierMask.DeviceIndependentModifierFlagsMask) == (NSEventModifierMask.CommandKeyMask | NSEventModifierMask.ShiftKeyMask)
                       || (e.ModifierFlags & NSEventModifierMask.DeviceIndependentModifierFlagsMask) == (NSEventModifierMask.CommandKeyMask | NSEventModifierMask.ShiftKeyMask | NSEventModifierMask.AlphaShiftKeyMask)) {
                switch (inputKey) {
                case "z":
                    NSApplication.SharedApplication.SendAction (new Selector ("redo:"), null, this);
                    return true;
                }
            }
        }
        return base.PerformKeyEquivalent(e);
    }
0 голосов
/ 25 марта 2015

Примерно 1 час назад я наткнулся на ту же проблему. Вам не нужно ничего кодировать. Я мог бы сделать это в Интерфейсном Разработчике:

  • Создайте меню (например, «Редактировать»), которое содержит элементы меню Вырезать / Копировать / Вставить
  • Добавьте KeyEquivalent для клавиши CMD в меню «Правка» (не знаю, действительно ли это необходимо, я просто скопировал структуру из другого проекта)
  • Добавить ключевые эквиваленты в эти пункты меню (CMD + X и т. Д.)
  • Свяжите функции FirstResponder cut:, copy: и paste: с соответствующими пунктами меню

Это сработало для меня. К сожалению, это (по умолчанию) поведение не работает, когда вы скрываете меню «Правка» (только что попробовал).

0 голосов
/ 26 января 2015

Решение Адриана хорошо, но лучше, я думаю, использовать оператор switch, а не все эти сравнения строк, например ::100100

    uint const modifierCode = (theEvent.modifierFlags & NSDeviceIndependentModifierFlagsMask);
    BOOL usingModifiers = ( modifierCode != 0 );
    //BOOL const usingShiftKey = ((theEvent.modifierFlags & NSShiftKeyMask) != 0);
    //BOOL const usingCommandKey = ((theEvent.modifierFlags & NSCommandKeyMask) != 0);
    NSString * ch = [theEvent charactersIgnoringModifiers];
    if ( ( usingModifiers ) && ( ch.length == 1 ) ) switch ( [ch characterAtIndex:0] )
    {
        case 'x':
            if ( modifierCode == NSCommandKeyMask ) [m cut]; // <-- m = model
            break;
        case 'c':
            if ( modifierCode == NSCommandKeyMask ) [m copy];
            break;
        case 'v':
            if ( modifierCode == NSCommandKeyMask ) [m paste];
            break;
        case 'z':
            if ( modifierCode == NSCommandKeyMask ) [m undo];
            break;
        case 'Z':
            if ( modifierCode == ( NSCommandKeyMask | NSShiftKeyMask ) ) [m redo];
            break;
        default: // etc.
            break;
    }
    else switch ( theEvent.keyCode ) // <-- for independent keycodes!
    {
        case kVK_Home:
            [m moveToBeginningOfDocument:nil];
            break;
        case kVK_End: // etc!
...