enum {
kVK_RightCommand = kVK_Command - 1,
+ kVK_Insert = 0x72,
+ kVK_Power = 0x7f,
+ kVK_ApplicationMenu = 0x6e,
kVK_MAX = 0xFFFF,
};
const CGKeyCode NJKeyInputFieldEmpty = kVK_MAX;
+@interface NJKeyInputField () <NSTextFieldDelegate>
+@end
+
@implementation NJKeyInputField {
NSTextField *field;
+ NSImageView *warning;
}
- (id)initWithFrame:(NSRect)frameRect {
field.alignment = NSCenterTextAlignment;
field.editable = NO;
field.selectable = NO;
+ field.delegate = self;
[self addSubview:field];
+
+ warning = [[NSImageView alloc] init];
+ warning.image = [NSImage imageNamed:@"NSInvalidDataFreestanding"];
+ CGSize imgSize = warning.image.size;
+ CGRect bounds = self.bounds;
+ warning.frame = CGRectMake(bounds.size.width - (imgSize.width + 4),
+ (bounds.size.height - imgSize.height) / 2,
+ imgSize.width, imgSize.height);
+
+ warning.toolTip = NSLocalizedString(@"invalid key code",
+ @"shown when the user types an invalid key code");
+ warning.hidden = YES;
+ [self addSubview:warning];
}
return self;
}
- (void)clear {
self.keyCode = NJKeyInputFieldEmpty;
- [self.delegate keyInputFieldDidClear:self];
+ [self.delegate keyInputFieldDidClear:self];
[self resignIfFirstResponder];
}
return self.keyCode != NJKeyInputFieldEmpty;
}
-+ (NSString *)stringForKeyCode:(CGKeyCode)keyCode {
++ (NSString *)displayNameForKeyCode:(CGKeyCode)keyCode {
switch (keyCode) {
case kVK_F1: return @"F1";
case kVK_F2: return @"F2";
return NSLocalizedString(@"Key Pad ,", @"numeric pad key");
case kVK_JIS_Eisu: return @"英数";
case kVK_JIS_Kana: return @"かな";
-
+
+ case kVK_Power: return @"⌽";
+ case kVK_VolumeUp: return @"🔊";
+ case kVK_VolumeDown: return @"🔉";
+
+ case kVK_Insert:
+ return NSLocalizedString(@"Insert", "keyboard key");
+ case kVK_ApplicationMenu:
+ return NSLocalizedString(@"Menu", "keyboard key");
case kVK_MAX: // NJKeyInputFieldEmpty
return @"";
- (void)setKeyCode:(CGKeyCode)keyCode {
_keyCode = keyCode;
- field.stringValue = [NJKeyInputField stringForKeyCode:keyCode];
+ field.stringValue = [NJKeyInputField displayNameForKeyCode:keyCode];
}
- (void)keyDown:(NSEvent *)event {
[self resignIfFirstResponder];
}
}
+
+static BOOL isValidKeyCode(long code) {
+ return code < 0xFFFF && code >= 0;
+}
+
+- (void)controlTextDidChange:(NSNotification *)obj {
+ char *error = NULL;
+ long code = strtol(field.stringValue.UTF8String, &error, 16);
+ warning.hidden = (isValidKeyCode(code) && !*error) || !field.stringValue.length;
+}
+
+- (void)controlTextDidEndEditing:(NSNotification *)obj {
+ [field.cell setPlaceholderString:@""];
+ field.editable = NO;
+ field.selectable = NO;
+ warning.hidden = YES;
+ char *error = NULL;
+ const char *s = field.stringValue.UTF8String;
+ short code = (short)strtol(s, &error, 16);
+ if (!*error && isValidKeyCode(code) && field.stringValue.length) {
+ self.keyCode = code;
+ [self.delegate keyInputField:self didChangeKey:self.keyCode];
+ } else {
+ self.keyCode = self.keyCode;
+ }
+}
+
- (void)mouseDown:(NSEvent *)theEvent {
- if (self.window.firstResponder == self)
- [self.window makeFirstResponder:nil];
- else if (self.acceptsFirstResponder)
- [self.window makeFirstResponder:self];
+ if (self.isEnabled) {
+ if (theEvent.modifierFlags & NSCommandKeyMask) {
+ field.editable = YES;
+ field.selectable = YES;
+ field.stringValue = @"";
+ [field.cell setPlaceholderString:
+ NSLocalizedString(@"enter key code",
+ @"shown when user must enter a key code to map to")];
+ [self.window makeFirstResponder:field];
+ } else {
+ if (self.window.firstResponder == self)
+ [self.window makeFirstResponder:nil];
+ else if (self.acceptsFirstResponder)
+ [self.window makeFirstResponder:self];
+ }
+ }
}
- (void)flagsChanged:(NSEvent *)theEvent {
// user type these virtual keys. However, there is no actual event
// for modifier key up - so detect it by checking to see if any
// modifiers are still down.
- if (!(theEvent.modifierFlags & NSDeviceIndependentModifierFlagsMask)) {
+ if (!field.isEditable
+ && !(theEvent.modifierFlags & NSDeviceIndependentModifierFlagsMask)) {
self.keyCode = theEvent.keyCode;
[self.delegate keyInputField:self didChangeKey:_keyCode];
}