NSTextView:如何禁用单击,但仍允许选择复制和粘贴?

时间:2016-03-21 18:11:34

标签: cocoa nstextview nsevent

我有基于NSTextView的组件,我想禁用它上面的单击,这样它的插入点不受这些单击的影响,但仍然能够选择文本片段进行复制和粘贴工作:

  1. 单击无效
  2. 可以复制并粘贴,但不会影响插入点
  3. 我想要的是我们在默认的终端应用程序中所拥有的:有插入点,无法通过鼠标点击更改它,但仍然可以选择文本进行复制和粘贴。

    我尝试过查看- (void)mouseDown:(NSEvent *)theEvent方法,但没有找到任何有用的方法。

1 个答案:

答案 0 :(得分:1)

我找到了hacky解决方法来实现这种行为。我创建了demo project,相关的课程有TerminalLikeTextView。这个解决方案工作得很好,但我仍然希望有一个更好的解决方案:减少hacky并减少对NSTextView内部机制的依赖,所以如果有人有这样的请分享。

关键步骤是:

1)在鼠标按下之前将mouseDownFlag设置为YES,在之后设置为NO:

@property (assign, nonatomic) BOOL mouseDownFlag;

- (void)mouseDown:(NSEvent *)theEvent {
    self.mouseDownFlag = YES;

    [super mouseDown:theEvent];

    self.mouseDownFlag = NO;
}

2)防止插入点从updateInsertionPointStateAndRestartTimer方法提前更新返回:

- (void)updateInsertionPointStateAndRestartTimer:(BOOL)flag {
    if (self.mouseDownFlag) {
        return;
    }

    [super updateInsertionPointStateAndRestartTimer:flag];
}

3)前两个步骤会使插入点不随鼠标移动,但selectionRange仍然会被更改,因此我们需要跟踪它:

static const NSUInteger kCursorLocationSnapshotNotExists = NSUIntegerMax;
@property (assign, nonatomic) NSUInteger cursorLocationSnapshot;

#pragma mark - <NSTextViewDelegate>

- (NSRange)textView:(NSTextView *)textView willChangeSelectionFromCharacterRange:(NSRange)oldSelectedCharRange toCharacterRange:(NSRange)newSelectedCharRange {

    if (self.mouseDownFlag && self.cursorLocationSnapshot == kCursorLocationSnapshotNotExists) {
        self.cursorLocationSnapshot = oldSelectedCharRange.location;
    }

    return newSelectedCharRange;
}

4)如果需要,尝试使用密钥打印恢复位置:

- (void)keyDown:(NSEvent *)event {
    NSString *characters = event.characters;

    [self insertTextToCurrentPosition:characters];
}

- (void)insertTextToCurrentPosition:(NSString *)text {
    if (self.cursorLocationSnapshot != kCursorLocationSnapshotNotExists) {
        self.selectedRange = NSMakeRange(self.cursorLocationSnapshot, 0);
        self.cursorLocationSnapshot = kCursorLocationSnapshotNotExists;
    }

    [self insertText:text replacementRange:NSMakeRange(self.selectedRange.location, 0)];
}