I have an NSView that calls interpretKeyEvents
for keyDown
events. For some keys like the letter 'a', pressing and holding the key results in repeated calls to insertText
. For other keys like 'x', insertText
is called once and that is it. I would like press and hold to always call insertText
. I'm guessing press and hold for these keys is interpreted as something else, but I cannot find it. I have implemented doCommandBySelector
as described by the documentation, but that is never called either.
Below is a minimal example program that demonstrates the behaviour.
// clang++ -framework AppKit -o proof-of-concept proof-of-concept.mm
#include <stdio.h>
#import <Cocoa/Cocoa.h>
@interface AppView : NSView<NSTextInputClient>
@end
@implementation AppView
- (void)keyDown:(NSEvent *)event {
printf("keydown\n");
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
}
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange {
printf("insertText\n");
}
- (BOOL)acceptsFirstResponder { return YES; }
- (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange {}
- (void)unmarkText {}
- (NSRange)selectedRange { return NSMakeRange(NSNotFound, 0); }
- (NSRange)markedRange { return NSMakeRange(NSNotFound, 0); }
- (BOOL)hasMarkedText { return NO; }
- (nullable NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range actualRange:(nullable NSRangePointer)actualRange { return nil; }
- (NSArray<NSAttributedStringKey> *)validAttributesForMarkedText { return [NSArray array]; }
- (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(nullable NSRangePointer)actualRange { return NSMakeRect(0, 0, 0, 0); }
- (NSUInteger)characterIndexForPoint:(NSPoint)point { return 0; }
@end
int main(int argc, char **argv, char **envp, char **apple) {
[NSApplication sharedApplication];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
NSRect windowDimensions = NSMakeRect(0, 0, 300, 300);
NSWindow *window = [[NSWindow alloc] initWithContentRect:windowDimensions
styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskResizable
backing:NSBackingStoreBuffered
defer:NO];
AppView *windowView = [[AppView alloc] initWithFrame:windowDimensions];
[window setContentView:windowView];
[window makeKeyAndOrderFront:nil];
[NSApp run];
return 0;
}
Is there an explanation for why interpretKeyEvents
handles some key repeats by calling insertText
and ignores others?
Turns out the issue was with the character accent popover menu. This issue helped me figure it out. No popover was ever displayed for me, hence my confusion. I assume that is because I did not provide any system cursor information therefore the application doesn't know where to display it, however I haven't confirmed this.
Adding [[NSUserDefaults standardUserDefaults] setBool: NO forKey: @"ApplePressAndHoldEnabled"];
disabled the accent popover for my application and solved the problem.