11

I wrote an "Agent" Cocoa app where a TextField is in the status icon's menu. The icon menu is displayed as followed:


(source: ifotos.pl)

The stepper increments or decrements the value by 5. The purpose of the text field is to press the "up" or "down" keys which achieves the same result of the value being incremented or decremented by 5.

I have found out that following code must be used - (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector of NSControlTextEditingDelegate protocol.

The problem I am currently encountering is how to implement the code. My normal approach is use sth.delegate = self;. I attempted to search for an answer but the replies consisted of using to control:textView:.... I was unable to learn how to use the delegate method even with further research.

Thank you in advance!

Community
  • 1
  • 1
radex
  • 6,336
  • 4
  • 30
  • 39

3 Answers3

21

You need to create an object to serve as the text field's delegate. This can be done either in code or, if it seems appropriate, in Interface Builder. You probably already have a controller responsible for this field and the stepper control, so that is a good candidate. This delegate object is what needs to implement the method you mentioned:

- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector

This method will be called whenever the field editor* for the text field is asked to perform one of the NSResponder action messages. The field editor asks its delegate, which is the text field, what it should do, and the field in turn asks its delegate, which is your object.

The commandSelector argument holds the name of the action message. You can therefore test for the messages you are interested in (moveUp: and moveDown: in this case) and intercept them. You perform whatever actions you like and prevent the field editor or the text field from acting on the message.

- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor 
  doCommandBySelector:(SEL)commandSelector {
    if( commandSelector == @selector(moveUp:) ){
        // Your increment code
        return YES;    // We handled this command; don't pass it on
    }
    if( commandSelector == @selector(moveDown:) ){
        // Your decrement code
        return YES;
    }

    return NO;    // Default handling of the command

} 

*Briefly, an NSTextView which handles input on behalf of the text field when the field is active.

jscs
  • 63,694
  • 13
  • 151
  • 195
  • Radex, hope that's more understandable than the docs; let me know if you need clarification. – jscs Jul 11 '11 at 20:24
  • Yes, yes, yes! Thank you. That's way more understandable than the docs. Apple's documentation is so confusing that I haven't even thought that it's _that_ obvious :) – radex Jul 12 '11 at 19:34
2

Try overriding NSResponder message like this:

- (BOOL)performKeyEquivalent:(NSEvent *)theEvent{
    switch ([[theEvent charactersIgnoringModifiers] characterAtIndex:0]) {
        case NSUpArrowFunctionKey:
            // Increase by 5 here
            return YES;
            break;
        case NSDownArrowFunctionKey:;
            // Decrease by 5 here
            return YES;
            break;
        default:
            break;
    }
    return [super performKeyEquivalent:theEvent];
}
ZhangChn
  • 3,154
  • 21
  • 41
  • One weird thing I discovered about this method: performKeyEquivalent doesn't limit itself to the responder chain. Any view that implements this can be called, regardless of whether it has focus, and if it returns YES it can keep the current first responder from receiving the key event. If you use this to catch arrow keys presses in an NSTextField subclass, first check that it's the current first responder: if ( [[self window] firstResponder] != self ) return [super performKeyEquivalent:event]; – davehayden Jun 26 '14 at 04:07
1

if you want to capture shortcuts, you can also use code like this:

- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector {

NSEvent *currentEvent = [[NSApplication sharedApplication]currentEvent];
if ((currentEvent.modifierFlags & NSCommandKeyMask) && (currentEvent.keyCode == kVK_Return)) {  //command + enter to confirm
    //do what you want
    return YES;
}
return NO;
}
holybiner
  • 61
  • 2