2012-02-05 33 views
5

Mi piacerebbe molto che la mia vista personalizzata funzionasse con -moveLeft:, -deleteForward:, -selectAll:, ecc., Ma vorrei anche passare tutte le chiavi a cui non interessava più la catena di risposta. In questo momento sto ignorando lo[self interpretKeyEvents:[NSArray arrayWithObject:event]];, ma questo sembra incasinare tutti gli eventi chiave, anche quelli a cui la mia vista non risponde.Visualizza interpretKeyEvents: ma passa quelli indesiderati nella catena di risposta?

C'è un modo per passare eventi indesiderati lungo la catena, ma rispondere comunque a -moveLeft:, ecc.? O devo implementare tutte le mie azioni in -keyDown: in modo che io sappia cosa ho fatto e non ho risposto?

+0

Prova il mio [soluzione] (http://stackoverflow.com/a/23897022/1067147) – WINSergey

risposta

6

Si è imbattuto in questo tentativo di trovare una soluzione a questo stesso problema. Non ho mai trovato nulla online, ma mi è venuto in mente qualcosa che sembra funzionare bene finora. Ecco quello che sto facendo:

sottoclasse tua NSTextView (o qualsiasi altra cosa che si sta utilizzando) e creare una variabile di istanza per memorizzare temporaneamente il tasto basso evento. . .

@interface MyTextView : NSTextView { 
    NSEvent* _keyDownEvent; 
} 

@end 

quindi definire i metodi del vostro vista in questo modo (estrarre il mantenere/spazzatura rilascio se si sta utilizzando Automatic Reference Counting):

@implementation MyTextView 

- (id)initWithFrame:(NSRect)frame { 
    if (self = [super initWithFrame:frame]) { 
     _keyDownEvent = nil; 
    } 

    return self; 
} 

- (void)keyDown:(NSEvent*)event { 
    [_keyDownEvent release]; 
    _keyDownEvent = [event retain]; 
    [super keyDown:event]; 
} 

- (void)doCommandBySelector:(SEL)selector { 
    if (_keyDownEvent && selector == @selector(noop:)) { 
     if ([self nextResponder]) { 
      [[self nextResponder] keyDown:[_keyDownEvent autorelease]]; 
     } else { 
      [_keyDownEvent release]; 
     } 
     _keyDownEvent = nil; 
    } else { 
     [super doCommandBySelector:selector]; 
    } 
} 

- (void)dealloc { 
    [_keyDownEvent release]; 

    [super dealloc]; 
} 

@end 

Ecco come sono arrivato a questo. Quando un tasto non viene gestita, viene emesso un segnale acustico. Così, ho impostato un punto di interruzione NSBeep(), e quando il programma è rotto, ho sputato fuori una traccia dello stack in GDB:

#0 0x00007fff96eb1c2d in NSBeep() 
#1 0x00007fff96e6d739 in -[NSResponder doCommandBySelector:]() 
#2 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:]() 
#3 0x00007fff96fda826 in -[NSWindow doCommandBySelector:]() 
#4 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:]() 
#5 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:]() 
#6 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:]() 
#7 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:]() 
#8 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:]() 
#9 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:]() 
#10 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:]() 
#11 0x00007fff96f486ce in -[NSTextView doCommandBySelector:]() 
#12 0x00007fff96da1c93 in -[NSKeyBindingManager(NSKeyBindingManager_MultiClients) interpretEventAsCommand:forClient:]() 
#13 0x00007fff970f5382 in -[NSTextInputContext handleEvent:]() 
#14 0x00007fff96fbfd2a in -[NSView interpretKeyEvents:]() 
#15 0x00007fff96f38a25 in -[NSTextView keyDown:]() 
#16 0x0000000100012889 in -[MyTextView keyDown:] (self=0x1004763a0, _cmd=0x7fff972b0234, event=0x100197320) at /path/MyTextView.m:24 
#17 0x00007fff96a16b44 in -[NSWindow sendEvent:]() 
#18 0x00007fff969af16d in -[NSApplication sendEvent:]() 
#19 0x00007fff969451f2 in -[NSApplication run]() 
#20 0x00007fff96bc3b88 in NSApplicationMain() 
#21 0x00000001000015e2 in main (argc=3, argv=0x7fff5fbff8f0) at /path/main.m:12 

Quello che sta succedendo è questo: quando l'evento chiave verso il basso non viene utilizzato per l'immissione di testo , un comando "noop" viene inviato sulla catena di risposta. Di default questo fa scattare un segnale acustico quando cade dalla catena di risposta. Nella mia soluzione, la sottoclasse NSTextView prende il comando noop e invece lancia l'evento keyDown originale lungo la catena di risposta. Quindi la NSWindow o altre viste otterranno normalmente gli eventi keyDown inutilizzati.

3

Questa è la mia risposta rapida attuazione di @ daxnitro, e sembra funzionare:

import Cocoa 

class EditorTextView: NSTextView { 

    private var keyDownEvent: NSEvent? 

    required init?(coder aCoder: NSCoder) { 
     super.init(coder: aCoder) 
    } 

    override init() { 
     super.init() 
    } 

    override init(frame frameRect: NSRect, textContainer aTextContainer: NSTextContainer!) { 
     super.init(frame: frameRect, textContainer: aTextContainer) 
    } 

    override func keyDown(event: NSEvent) { 
     keyDownEvent = event 
     super.keyDown(event) 
    } 

    override func doCommandBySelector(aSelector: Selector) { 
     if aSelector != NSSelectorFromString("noop:") { 
      super.doCommandBySelector(aSelector) 
     } else if keyDownEvent != nil { 
      self.nextResponder?.keyDown(keyDownEvent!) 
     } 
     keyDownEvent = nil 
    } 

}