Rewrite KeyInputTextView into NJKeyInputField. New class communicates using a proper...
[enjoyable.git] / NJKeyInputField.m
diff --git a/NJKeyInputField.m b/NJKeyInputField.m
new file mode 100644 (file)
index 0000000..13aa138
--- /dev/null
@@ -0,0 +1,209 @@
+//
+//  NJKeyInputField.h
+//  Enjoyable
+//
+//  Copyright 2013 Joe Wreschnig.
+//
+
+#import "NJKeyInputField.h"
+
+CGKeyCode NJKeyInputFieldEmpty = 0xFFFF;
+
+@implementation NJKeyInputField
+
+- (id)initWithFrame:(NSRect)frameRect {
+    if ((self = [super initWithFrame:frameRect])) {
+        self.alignment = NSCenterTextAlignment;
+        [self setEditable:NO];
+        [self setSelectable:NO];
+    }
+    return self;
+}
+
+- (void)clear {
+    self.keyCode = NJKeyInputFieldEmpty;
+    [self.keyDelegate keyInputFieldDidClear:self];
+    [self resignIfFirstResponder];
+}
+
+- (BOOL)hasKeyCode {
+    return self.keyCode >= 0;
+}
+
++ (NSString *)stringForKeyCode:(CGKeyCode)keyCode {
+    switch (keyCode) {
+        case 0xffff: return @"";
+        case 0x7a: return @"F1";
+        case 0x78: return @"F2";
+        case 0x63: return @"F3";
+        case 0x76: return @"F4";
+        case 0x60: return @"F5";
+        case 0x61: return @"F6";
+        case 0x62: return @"F7";
+        case 0x64: return @"F8";
+        case 0x65: return @"F9";
+        case 0x6d: return @"F10";
+        case 0x67: return @"F11";
+        case 0x6f: return @"F12";
+        case 0x69: return @"F13";
+        case 0x6b: return @"F14";
+        case 0x71: return @"F15";
+        case 0x6a: return @"F16";
+        case 0x40: return @"F17";
+        case 0x4f: return @"F18";
+        case 0x50: return @"F19";
+            
+        case 0x35: return @"Esc";
+        case 0x32: return @"`";
+            
+        case 0x12: return @"1";
+        case 0x13: return @"2";
+        case 0x14: return @"3";
+        case 0x15: return @"4";
+        case 0x17: return @"5";
+        case 0x16: return @"6";
+        case 0x1a: return @"7";
+        case 0x1c: return @"8";
+        case 0x19: return @"9";
+        case 0x1d: return @"0";
+        case 0x1b: return @"-";
+        case 0x18: return @"=";
+            
+        case 0x3f: return @"Fn";
+        case 0x36: return @"Right Command";
+        case 0x37: return @"Left Command";
+        case 0x38: return @"Left Shift";
+        case 0x39: return @"Caps Lock";
+        case 0x3a: return @"Left Option";
+        case 0x3b: return @"Left Control";
+        case 0x3c: return @"Right Shift";
+        case 0x3d: return @"Right Option";
+        case 0x3e: return @"Right Control";
+            
+        case 0x73: return @"Home";
+        case 0x74: return @"Page Up";
+        case 0x75: return @"Delete";
+        case 0x77: return @"End";
+        case 0x79: return @"Page Down";
+            
+        case 0x30: return @"Tab";
+        case 0x33: return @"Backspace";
+        case 0x24: return @"Return";
+        case 0x31: return @"Space";
+            
+        case 0x0c: return @"Q";
+        case 0x0d: return @"W";
+        case 0x0e: return @"E";
+        case 0x0f: return @"R";
+        case 0x11: return @"T";
+        case 0x10: return @"Y";
+        case 0x20: return @"U";
+        case 0x22: return @"I";
+        case 0x1f: return @"O";
+        case 0x23: return @"P";
+        case 0x21: return @"[";
+        case 0x1e: return @"]";
+        case 0x2a: return @"\\";
+        case 0x00: return @"A";
+        case 0x01: return @"S";
+        case 0x02: return @"D";
+        case 0x03: return @"F";
+        case 0x05: return @"G";
+        case 0x04: return @"H";
+        case 0x26: return @"J";
+        case 0x28: return @"K";
+        case 0x25: return @"L";
+        case 0x29: return @";";
+        case 0x27: return @"'";
+        case 0x06: return @"Z";
+        case 0x07: return @"X";
+        case 0x08: return @"C";
+        case 0x09: return @"V";
+        case 0x0b: return @"B";
+        case 0x2d: return @"N";
+        case 0x2e: return @"M";
+        case 0x2b: return @",";
+        case 0x2f: return @".";
+        case 0x2c: return @"/";
+            
+        case 0x47: return @"Clear";
+        case 0x51: return @"Keypad =";
+        case 0x4b: return @"Keypad /";
+        case 0x43: return @"Keypad *";
+        case 0x59: return @"Keypad 7";
+        case 0x5b: return @"Keypad 8";
+        case 0x5c: return @"Keypad 9";
+        case 0x4e: return @"Keypad -";
+        case 0x56: return @"Keypad 4";
+        case 0x57: return @"Keypad 5";
+        case 0x58: return @"Keypad 6";
+        case 0x45: return @"Keypad +";
+        case 0x53: return @"Keypad 1";
+        case 0x54: return @"Keypad 2";
+        case 0x55: return @"Keypad 3";
+        case 0x52: return @"Keypad 0";
+        case 0x41: return @"Keypad .";
+        case 0x4c: return @"Enter";
+            
+        case 0x7e: return @"Up";
+        case 0x7d: return @"Down";
+        case 0x7b: return @"Left";
+        case 0x7c: return @"Right";
+        default:
+            return [[NSString alloc] initWithFormat:@"Key 0x%x", keyCode];
+    }
+}
+
+- (BOOL)acceptsFirstResponder {
+    return self.isEnabled;
+}
+
+- (BOOL)becomeFirstResponder {
+    self.backgroundColor = NSColor.selectedTextBackgroundColor;
+    return [super becomeFirstResponder];
+}
+
+- (BOOL)resignFirstResponder {
+    self.backgroundColor = NSColor.textBackgroundColor;
+    return [super resignFirstResponder];
+}
+
+- (void)setKeyCode:(CGKeyCode)keyCode {
+    _keyCode = keyCode;
+    self.stringValue = [NJKeyInputField stringForKeyCode:keyCode];
+}
+
+- (void)keyDown:(NSEvent *)theEvent {
+    if (!theEvent.isARepeat) {
+        if ((theEvent.modifierFlags & NSAlternateKeyMask)
+            && theEvent.keyCode == 0x35) {
+            // Allow Alt+Escape to clear the field.
+            self.keyCode = NJKeyInputFieldEmpty;
+            [self.keyDelegate keyInputFieldDidClear:self];
+        } else {
+            self.keyCode = theEvent.keyCode;
+            [self.keyDelegate keyInputField:self didChangeKey:_keyCode];
+        }
+        [self resignIfFirstResponder];
+    }
+}
+
+- (void)mouseDown:(NSEvent *)theEvent {
+    if (self.acceptsFirstResponder)
+        [self.window makeFirstResponder:self];
+}
+
+- (void)flagsChanged:(NSEvent *)theEvent {
+    // Many keys are only available on MacBook keyboards by using the
+    // Fn modifier key (e.g. Fn+Left for Home), so delay processing
+    // modifiers until the up event is received in order to let the
+    // 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)) {
+        self.keyCode = theEvent.keyCode;
+        [self.keyDelegate keyInputField:self didChangeKey:_keyCode];
+    }
+}
+
+@end