I have NSTextView-based component and I would like to disable single clicks on it, so that its insertion point is not affected by these single clicks, but still to be able to select pieces of text for copy-and-paste work:
What I want is exactly what we have in default Terminal app: there is insertion point and it is not possible to change it via mouse click, but still selection of text for copy-and-paste is possible.
I have tried looking at - (void)mouseDown:(NSEvent *)theEvent
method but didn't find anything helpful.
I have found hacky workaround to achieve this kind of behavior. I have created demo project, the relevant class there is TerminalLikeTextView. This solution works perfectly but I would still like to have a better solution: less hacky and less dependent on internal mechanics of NSTextView so if anyone has such please share.
The key steps are:
1) Set mouseDownFlag to YES before mouse down and to NO after:
@property (assign, nonatomic) BOOL mouseDownFlag;
- (void)mouseDown:(NSEvent *)theEvent {
self.mouseDownFlag = YES;
[super mouseDown:theEvent];
self.mouseDownFlag = NO;
}
2) To prevent insertion point from updating return early from updateInsertionPointStateAndRestartTimer
method:
- (void)updateInsertionPointStateAndRestartTimer:(BOOL)flag {
if (self.mouseDownFlag) {
return;
}
[super updateInsertionPointStateAndRestartTimer:flag];
}
3) First two steps will make insertion point to not move with mouse however the selectionRange
will still be changed so we need to keep track of it:
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) Attempt to print using keys restores location if needed:
- (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)];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With