Split view management out of NJDeviceController. Right now this probably just makes...
[enjoyable.git] / Classes / NJKeyInputField.m
index 2bdbfc6..791911b 100644 (file)
 
 enum {
     kVK_RightCommand = kVK_Command - 1,
+    kVK_Insert = 0x72,
+    kVK_Power = 0x7f,
+    kVK_ApplicationMenu = 0x6e,
     kVK_MAX = 0xFFFF,
 };
 
 const CGKeyCode NJKeyInputFieldEmpty = kVK_MAX;
 
-@implementation NJKeyInputField
+@implementation NJKeyInputField {
+    NSTextField *field;
+    NSImageView *warning;
+}
 
 - (id)initWithFrame:(NSRect)frameRect {
     if ((self = [super initWithFrame:frameRect])) {
-        self.alignment = NSCenterTextAlignment;
-        self.editable = NO;
-        self.selectable = NO;
+        field = [[NSTextField alloc] initWithFrame:self.bounds];
+        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;
-    if ([self.delegate respondsToSelector:@selector(keyInputFieldDidClear:)])
         [self.delegate keyInputFieldDidClear:self];
     [self resignIfFirstResponder];
 }
@@ -173,8 +194,17 @@ const CGKeyCode NJKeyInputFieldEmpty = kVK_MAX;
             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 @"";
         default:
@@ -189,18 +219,18 @@ const CGKeyCode NJKeyInputFieldEmpty = kVK_MAX;
 }
 
 - (BOOL)becomeFirstResponder {
-    self.backgroundColor = NSColor.selectedTextBackgroundColor;
+    field.backgroundColor = NSColor.selectedTextBackgroundColor;
     return [super becomeFirstResponder];
 }
 
 - (BOOL)resignFirstResponder {
-    self.backgroundColor = NSColor.textBackgroundColor;
+    field.backgroundColor = NSColor.textBackgroundColor;
     return [super resignFirstResponder];
 }
 
 - (void)setKeyCode:(CGKeyCode)keyCode {
     _keyCode = keyCode;
-    self.stringValue = [NJKeyInputField stringForKeyCode:keyCode];
+    field.stringValue = [NJKeyInputField stringForKeyCode:keyCode];
 }
 
 - (void)keyDown:(NSEvent *)event {
@@ -209,22 +239,59 @@ const CGKeyCode NJKeyInputFieldEmpty = kVK_MAX;
         if ((event.modifierFlags & IGNORE) && event.keyCode == kVK_Delete) {
             // Allow Alt/Command+Delete to clear the field.
             self.keyCode = NJKeyInputFieldEmpty;
-            if ([self.delegate respondsToSelector:@selector(keyInputFieldDidClear:)])
-                [self.delegate keyInputFieldDidClear:self];
+            [self.delegate keyInputFieldDidClear:self];
         } else if (!(event.modifierFlags & IGNORE)) {
             self.keyCode = event.keyCode;
-            if ([self.delegate respondsToSelector:@selector(keyInputField:didChangeKey:)])
-                [self.delegate keyInputField:self didChangeKey:self.keyCode];
+            [self.delegate keyInputField:self didChangeKey:self.keyCode];
         }
         [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;
+    long code = 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 {
@@ -234,19 +301,11 @@ const CGKeyCode NJKeyInputFieldEmpty = kVK_MAX;
     // 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;
-        if ([self.delegate respondsToSelector:@selector(keyInputField:didChangeKey:)])
-            [self.delegate keyInputField:self didChangeKey:_keyCode];
+        [self.delegate keyInputField:self didChangeKey:_keyCode];
     }
 }
 
-- (void)setDelegate:(id<NJKeyInputFieldDelegate, NSTextFieldDelegate>)delegate {
-    [super setDelegate:delegate];
-}
-
-- (id <NJKeyInputFieldDelegate, NSTextFieldDelegate>)delegate {
-    return (id)[super delegate];
-}
-
 @end