查看解释KeyEvents:但是将不需要的事件传递到响应者链上?

发布于 2025-01-02 10:50:21 字数 394 浏览 1 评论 0原文

我真的很希望我的自定义视图能够与 -moveLeft:-deleteForward:-selectAll: 等一起使用,但我'我还想将我不关心的任何密钥传递到响应者链上。现在我正在覆盖 -keyDown: 来调用 [selfterpretKeyEvents:[NSArray arrayWithObject:event]];,但这似乎占用了所有关键事件,甚至是那些关键事件我的观点没有得到回应。

有没有什么方法可以将不需要的事件传递到链上,但仍然响应 -moveLeft: 等?或者我是否需要在 -keyDown: 中实现我自己的所有操作,以便我知道我做了什么和没有响应?

I'd really like my custom view to work with -moveLeft:, -deleteForward:, -selectAll:, etc., but I'd also like to pass any keys I didn't care about onward up the responder chain. Right now I'm overriding -keyDown: to call [self interpretKeyEvents:[NSArray arrayWithObject:event]];, but this seems to hog all the key events, even ones my view doesn't respond to.

Is there any way to pass unwanted events up the chain, but still respond to -moveLeft:, etc.? Or do I need to implement all my own actions in -keyDown: so that I know what I did and did not respond to?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

青巷忧颜 2025-01-09 10:50:21

遇到这个问题试图找到同样问题的解决方案。从来没有在网上找到任何东西,但我想出了一些到目前为止似乎运作良好的东西。这就是我正在做的:

子类化您的 NSTextView (或您正在使用的任何内容)并创建一个实例变量来临时存储 key down event 。 。 。

@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 事件。

Came across this trying to find a solution to this same problem. Never found anything online, but I came up with something that seems to work well so far. Here's what I'm doing:

Subclass your NSTextView (or whatever you're using) and create an instance variable to temporarily store the key down event . . .

@interface MyTextView : NSTextView {
    NSEvent* _keyDownEvent;
}

@end

Then define your view's methods like so (take out the retain/release junk if you're using automatic reference counting):

@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

Here's how I arrived at this. When a key press isn't handled, you hear a beeping tone. So, I set a breakpoint on NSBeep(), and when the program broke, I spit out a stack trace in 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

What's happening is this: When the key down event isn't used for text input, a "noop" command is sent up the response chain. By default this triggers a beep when it falls off the response chain. In my solution, the NSTextView subclass catches the noop command and instead throws the original keyDown event down the response chain. Then your NSWindow or other views will get any unused keyDown events as normal.

日暮斜阳 2025-01-09 10:50:21

这是我对 @daxninto 答案的快速实现,并且似乎有效:

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
    }

}

This is my swift implementation of @daxnitro's answer, and seems to work:

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
    }

}
孤千羽 2025-01-09 10:50:21

我遇到了与 NSTableView 中的自定义 NSTextView 密切相关的问题。我希望能够在 NSTextView 中按住 Shift 键选择文本,但是当选择所有文本后,将响应者链上的 Shift-Select 传递到 NSTableView

我的解决方案只是在我的 NSTextView 上覆盖 responds(to:) 并决定是否要在那里处理它。

override func responds(to aSelector: Selector!) -> Bool  {
  if aSelector == #selector(moveUpAndModifySelection(_:)) {
    return selectedRange().location != 0
  }
            
  return super.responds(to: aSelector)
}

I had a closely related issue with a custom NSTextView in an NSTableView. I wanted to be able to shift-select text in the NSTextView, but when all the text was selected, pass the shift-select up the responder chain to the NSTableView.

My solution was simply to override responds(to:) on my NSTextView and decide whether I wanted to handle it there.

override func responds(to aSelector: Selector!) -> Bool  {
  if aSelector == #selector(moveUpAndModifySelection(_:)) {
    return selectedRange().location != 0
  }
            
  return super.responds(to: aSelector)
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文