Посмотреть interpretKeyEvents: но передать ненужные вверх по цепочке респондента? - PullRequest
4 голосов
/ 05 февраля 2012

Мне бы очень хотелось, чтобы мой пользовательский вид работал с -moveLeft:, -deleteForward:, -selectAll: и т. Д., Но я также хотел бы передать любые ключи, которые меня не волновали, вверх по цепочке респондента , Прямо сейчас я переопределяю -keyDown: для вызова [self interpretKeyEvents:[NSArray arrayWithObject:event]];, но это похоже на все ключевые события, даже те, на которые мой взгляд не реагирует.

Есть ли способ передать нежелательные события вверх по цепочке, но при этом ответить на -moveLeft: и т. Д.? Или мне нужно реализовать все свои собственные действия в -keyDown:, чтобы я знал, что я сделал и не ответил?

Ответы [ 2 ]

5 голосов
/ 05 марта 2012

Наткнулся на это, пытаясь найти решение этой же проблемы. Никогда ничего не находил в Интернете, но я придумал что-то, что, кажется, работает хорошо до сих пор. Вот что я делаю:

Создайте подкласс вашего NSTextView (или того, что вы используете) и создайте переменную экземпляра для временного хранения события нажатия клавиши. , .

@interface MyTextView : NSTextView {
    NSEvent* _keyDownEvent;
}

@end

Затем определите методы вашего представления следующим образом (уберите мусорное хранилище / освобождение, если вы используете автоматический подсчет ссылок):

@implementation MyTextView

- (id)initWithFrame:(NSRect)frame {
    if (self = [super initWithFrame:frame]) {
        _keyDownEvent = nil;
    }

    return self;
}

- (void)keyDown:(NSEvent*)event {
    [_keyDownEvent release];
    _keyDownEvent = [event retain];
    [super keyDown:event];
}

- (void)doCommandBySelector:(SEL)selector {
    if (_keyDownEvent && selector == @selector(noop:)) {
        if ([self nextResponder]) {
            [[self nextResponder] keyDown:[_keyDownEvent autorelease]];
        } else {
            [_keyDownEvent release];
        }
        _keyDownEvent = nil;
    } else {
        [super doCommandBySelector:selector];
    }
}

- (void)dealloc {
    [_keyDownEvent release];

    [super dealloc];
}

@end

Вот как я пришел к этому. Когда нажатие клавиши не обрабатывается, вы слышите звуковой сигнал. Итак, я установил точку останова на NSBeep (), и когда программа сломалась, я выплюнул трассировку стека в GDB:

#0  0x00007fff96eb1c2d in NSBeep ()
#1  0x00007fff96e6d739 in -[NSResponder doCommandBySelector:] ()
#2  0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#3  0x00007fff96fda826 in -[NSWindow doCommandBySelector:] ()
#4  0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#5  0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#6  0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#7  0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#8  0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#9  0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#10 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#11 0x00007fff96f486ce in -[NSTextView doCommandBySelector:] ()
#12 0x00007fff96da1c93 in -[NSKeyBindingManager(NSKeyBindingManager_MultiClients) interpretEventAsCommand:forClient:] ()
#13 0x00007fff970f5382 in -[NSTextInputContext handleEvent:] ()
#14 0x00007fff96fbfd2a in -[NSView interpretKeyEvents:] ()
#15 0x00007fff96f38a25 in -[NSTextView keyDown:] ()
#16 0x0000000100012889 in -[MyTextView keyDown:] (self=0x1004763a0, _cmd=0x7fff972b0234, event=0x100197320) at /path/MyTextView.m:24
#17 0x00007fff96a16b44 in -[NSWindow sendEvent:] ()
#18 0x00007fff969af16d in -[NSApplication sendEvent:] ()
#19 0x00007fff969451f2 in -[NSApplication run] ()
#20 0x00007fff96bc3b88 in NSApplicationMain ()
#21 0x00000001000015e2 in main (argc=3, argv=0x7fff5fbff8f0) at /path/main.m:12

Вот что происходит: когда событие нажатия клавиши не используется для ввода текста, в цепочку ответов отправляется команда «noop». По умолчанию это вызывает звуковой сигнал, когда он падает с цепочки ответов. В моем решении подкласс NSTextView ловит команду noop и вместо этого выбрасывает исходное событие keyDown по цепочке ответов. Тогда ваше NSWindow или другие представления получат любые неиспользованные события keyDown как обычно.

3 голосов
/ 19 января 2015

Это моя быстрая реализация ответа @ daxnitro, и, похоже, работает:

import Cocoa

class EditorTextView: NSTextView {

    private var keyDownEvent: NSEvent?

    required init?(coder aCoder: NSCoder) {
        super.init(coder: aCoder)
    }

    override init() {
        super.init()
    }

    override init(frame frameRect: NSRect, textContainer aTextContainer: NSTextContainer!) {
        super.init(frame: frameRect, textContainer: aTextContainer)
    }

    override func keyDown(event: NSEvent) {
        keyDownEvent = event
        super.keyDown(event)
    }

    override func doCommandBySelector(aSelector: Selector) {
        if aSelector != NSSelectorFromString("noop:") {
            super.doCommandBySelector(aSelector)
        } else if  keyDownEvent != nil {
            self.nextResponder?.keyDown(keyDownEvent!)
        }
        keyDownEvent = nil
    }

}
...