简体   繁体   中英

How can I get the selection direction of an NSTextView?

I'm trying to get the direction of the selected ranges in an NSTextView . In other words, whether the selected ranges change their location or length when you use shift+leftarrow and shift+rightarrow . My first though was that selectionAffinity represents the direction, but it only seems to apply to multi-line selections.

How can I get the direction of selected ranges?

iOS

Step 1: Declare Property

@property (nonatomic) NSRange lastRange;

Step 2: In TextView Delegate, add this:

- (void) textViewDidChangeSelection:(UITextView *)textView

    NSRange currentRange = NSMakeRange(textView.selectedRange.location, textView.selectedRange.length);

    if (currentRange.length == 0) {
        NSLog(@"Nothing selected");
        _lastRange = currentRange;
    }
    else {
        if (currentRange.location < _lastRange.location) {
            NSLog(@"Selecting LEFT");
        }
        else {
            NSLog(@"Selecting RIGHT");
        }
    }
}

OSX

OSX with all the features requested involved a little bit more work, but here's what I came up with for a working, consistent solution. Renaming is optional, or rather ... encouraged ...

Step 1: Subclass a NSTextView

In your SubClass.h :

#import "TheSelectionizer.h"

- (void)setSelectedRange:(NSRange)charRange affinity:(NSSelectionAffinity)affinity stillSelecting:(BOOL)stillSelectingFlag {

    if (charRange.length == 0) {
        _lastAnchorPoint = charRange;
    }
    [super setSelectedRange:charRange affinity:affinity stillSelecting:stillSelectingFlag];
}

@end

In your SubClass.m

 #import "TheSelectionizer.h" - (void)setSelectedRange:(NSRange)charRange affinity:(NSSelectionAffinity)affinity stillSelecting:(BOOL)stillSelectingFlag { if (charRange.length == 0) { _lastAnchorPoint = charRange; } [super setSelectedRange:charRange affinity:affinity stillSelecting:stillSelectingFlag]; } @end 
Step 2: Implement NSTextViewDelegate
 - (NSRange) textView:(NSTextView *)textView willChangeSelectionFromCharacterRange:(NSRange)oldSelectedCharRange toCharacterRange:(NSRange)newSelectedCharRange { if (newSelectedCharRange.length != 0) { TheSelectionizer * selectionizer = (TheSelectionizer *)textView; int anchorStart = (int)selectionizer.lastAnchorPoint.location; int selectionStart = (int)newSelectedCharRange.location; int selectionLength = (int)newSelectedCharRange.length; /* If mouse selects left, and then a user arrows right, or the opposite, anchor point flips. */ int difference = anchorStart - selectionStart; if (difference > 0 && difference != selectionLength) { if (oldSelectedCharRange.location == newSelectedCharRange.location) { // We were selecting left via mouse, but now we are selecting to the right via arrows anchorStart = selectionStart; } else { // We were selecting right via mouse, but now we are selecting to the left via arrows anchorStart = selectionStart + selectionLength; } selectionizer.lastAnchorPoint = NSMakeRange(anchorStart, 0); } // Evaluate Selection Direction if (anchorStart == selectionStart) { if (oldSelectedCharRange.length < newSelectedCharRange.length) { // Bigger NSLog(@"Will select right in overall right selection"); } else { // Smaller NSLog(@"Will select left in overall right selection"); } } else { if (oldSelectedCharRange.length < newSelectedCharRange.length) { // Bigger NSLog(@"Will select left in overall left selection"); } else { // Smaller NSLog(@"Will select right in overall left selection"); } } } return newSelectedCharRange; } 

I posted a project just in case someone wants to try it or wants to see it.

Full "project" available HERE

Assumed that NSRange yourPreviousRange is declared.

//Check when NSTextView changed its value
@interface delegateAppDelegate : NSObject <NSApplicationDelegate, NSTextViewDelegate> {
    NSWindow *window;
}

-(void)textDidChange:(NSNotification *)notification {
    NSRange yourRange = notification.object.selectedRange;
    if (yourRange.location == yourPreviousRange.location - 1 || yourRange.length == yourPreviousRange.length){
     //left direction  
    } else if (yourRange.location == yourPreviousRange.location || yourRange.length == yourPreviousRange.length + 1){
    //right direction
    }
    yourPreviousRange = yourRange;
}

Use NSTextViewDelegate methods : -textView:willChangeSelectionFromCharacterRange:toCharacterRange: or -textView:willChangeSelectionFromCharacterRanges:toCharacterRanges: if you want multi-selections support.

Note that if you only implements -textView:willChangeSelectionFromCharacterRange:toCharacterRange: the multi-selections will be disallowed.

For example without multi-selections :

- (NSRange)textView:(NSTextView *)aTextView willChangeSelectionFromCharacterRange:(NSRange)oldSelectedCharRange toCharacterRange:(NSRange)newSelectedCharRange
{
    if (newSelectedCharRange.length == 0 && oldSelectedCharRange.length == 0) 
    {
        /* move the insertion point */

        if (newSelectedCharRange.location < oldSelectedCharRange.location)
            NSLog(@"insertion point move left");
        else
            NSLog(@"insertion point move right");
    }
    else if (newSelectedCharRange.length == 0 && oldSelectedCharRange.length != 0)
    {
        /* end a selection and move insertion point */

        if (newSelectedCharRange.location == oldSelectedCharRange.location)
            NSLog(@"insertion point at start from previous selection");
        else if (newSelectedCharRange.location < oldSelectedCharRange.location)
            NSLog(@"insertion point move left");
        else
            NSLog(@"insertion point move right");
    }
    else if (oldSelectedCharRange.length == 0 && newSelectedCharRange.length != 0)
    {
        /* start a selection */

        if (newSelectedCharRange.location == oldSelectedCharRange.location)
            NSLog(@"start a selection at insertion point, move right");
        else if (newSelectedCharRange.location < oldSelectedCharRange.location)
            NSLog(@"start a selection, move left");
        else
            NSLog(@"start a selection, move right");
    }
    else
    {
        if (newSelectedCharRange.location < oldSelectedCharRange.location)
            NSLog(@"selection move left");
        else
            NSLog(@"selection move right");
    }

    return newSelectedCharRange;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM