Re: Advice on restricting/monitoring character input in NSTextView
Re: Advice on restricting/monitoring character input in NSTextView
- Subject: Re: Advice on restricting/monitoring character input in NSTextView
- From: Keith Blount <email@hidden>
- Date: Tue, 7 Feb 2006 05:11:36 -0800 (PST)
You shouldn't need to subclass for this - you were on
the right track in the first place.
The delegate method
-textView:shouldChangeTextInRanges:replacementStrings:
(or you can use the singular version for pre-Tiger or
text views that don't allow multiple selection) will
get called before undo gets set up. So if you restrict
input there, all that will happen is that whenever the
user tries to type something restricted, you have this
method return NO and nothing will happen when the user
types (or you can provide an NSBeep() or a message or
whatever you want within that method.
This method will also get called whenever you try to
paste anything into your text view. This is probably
the sort of thing you want (note that I haven't tested
this code so there may be errors in it - it was just a
quick effort and can definitely be improved):
- (BOOL)textView:(NSTextView *)aTextView
shouldChangeTextInRanges:(NSArray *)affectedRanges
replacementStrings:(NSArray *)replacementStrings
{
if (aTextView != restrictedTextView)
return YES;
if ( ([affectedRanges count] > 0) &&
([replacementStrings count] == 1) )
{
NSString *newString = [replacementStrings
objectAtIndex:0];
NSRange affectedRange = [[affectedRanges
objectAtIndex:0] rangeValue];
// If the new string has a length of one, things are
easy
// (it was probably - but not necessarily - typed
if ([newString length] == 1)
{
// Don't allow tabs!
if ([newString isEqualToString:@"\t"])
{
NSBeep();
return NO;
}
// Don't allow consecutive spaces
if ([newString isEqualToString:@" "])
{
// Is there a space directly before?
int lastCharIndex = affectedRange.location - 1;
if (lastCharIndex >= 0) // Avoid out of bounds
errors
{
NSString *lastChar = [[aTextView string]
substringWithRange:NSMakeRange(lastCharIndex,1)];
if ([lastChar isEqualToString:@" "])
{
NSBeep();
return NO;
}
}
}
// Deal with any other restricted single-character
strings here
}
else if ([newString length] > 1)
{
// If the new string has a length of more than one,
it must have
// been pasted in. Things get more complicated
then... See comments below...
}
}
return YES;
}
That should deal with preventing the user from typing
consecutive spaces or tabs. Dealing with a paste of
multiple characters is more difficult. In that case,
you will need to parse through the string being
pasted, looking for restricted characters. NSString's
-rangeOfString:options:range: would probably be best
for this, although you could also look at NSScanner.
The trouble is, what to do if there is a restricted
character? You could return NO and disallow the paste
entirely, which would be by far the simplest solution.
Otherwise, things get tricky. If your text view is
plain text only, it's not too difficult. You would
just modify the new string and place it in the text
view yourself, still returning NO to the method. (This
is because, unfortunately, the above method allows you
to stop the new string getting entered, but it doesn't
allow you to modify the actual string unless you
insert it yourself.) Google for Andrew Stone's
tutorial on smart quotes for handling this manually.
If you have a rich text view, it's more tricky. In
that case, you would probably want to save the range
of text that has been changed in the above method
(NSMakeRange(affectedRange.location, [newString
length]) ), and then examine and change that range in
-textDidChange:, once the text has been inserted into
the text view. The user might be able to undo back to
a state you don't want in that case, though.
Hope that helps,
Keith
--- ORIGINAL MESSAGE ---
From: Scott Lehman
Subject: Re: Advice on restricting/monitoring
character input in
NSTextView
To: Keith Wilson
Cc: email@hidden
Message-ID:
<email@hidden>
Content-Type: text/plain; charset=iso-8859-1
Well I have to confess that I'm not sure what to do
with that. I thought the docs state that the field
editor is for controls, which made sense to me -
having an NSTextView instance as a field editor for an
NSTextView seems redundant and unecessary. Or is it?
I realize now that while the NSTextStorage delegate
may provide a nice hook, it poses problems for undo.
If I filter out a key stroke, it should be before the
action is registered for undo.
So now I'm thinking subclassing NSTextView might be
the way to go. Is it as simple as:
-Override insertText: to include filtering/processing
(this covers both key press and pastes, correct?)
-Either call [super insertText:aString] with any input
I want, or return immediately if I want to ignore it
?
Thanks,
Scott
--- Keith Wilson wrote:
> I think you need to look at NSWindow's
>
> fieldEditor: forObject:
>
> Keith
>
> On 07/02/2006, at 11:28 AM, Scott Lehman wrote:
>
> > I'm looking to prevent some characters and
> sequences
> > (such as tabs and consecuive spaces for starters)
> from
> > being entered into my NSTextView. After some
> > searching of the list archives, I know to steer
> clear
> > of overriding keyDown: and have the following
> > strategy:
> >
> > For input from the keyboard:
> > -Use the delegate
> > shouldChangeTextInRange(s):replacementString(s)
> > methods (Can I safely assume this is called one
> > character at a time for keyboard input?)
> > -Use delegate textView:doCommandBySelector:
> methods
> > for intercepting special keys (i.e. the insertTab:
> > command, though the previous method can easily
> handle
> > tabs)
> >
> > For input from the pasteboard:
> > -Create a NSTextView subclass to override the
> paste
> > text methods, including some text filtering before
> > inserting any text
> >
> > I think that will work, I would much prefer to
> have
> > the filtering/processing centralized in one place.
> > Are there other strategies to consider that let me
> > catch all text input, be it key presses, the
> > pasteboard, or any other source I'm unaware of?
> >
> >
> > I found the NSTextStorage delegate method
> > textStorageWillProcessEditing: which appears to be
> a
> > good hook to clean up text input. Any issues with
> > using that?
> >
> > Is there anything else earlier in the text input
> chain
> > of command? Is there a safe way to change input
> in a
> > custom text storage class'
> > replaceCharactersInRange:withString:
> implementation?
> >
> > Thanks,
> >
> > Scott
> >
> >
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden