2073d8de7f162a011594581768a5c8d60b2120b6
[enjoyable.git] / Classes / NJKeyInputField.m
1 //
2 // NJKeyInputField.h
3 // Enjoyable
4 //
5 // Copyright 2013 Joe Wreschnig.
6 //
7
8 #import "NJKeyInputField.h"
9
10 const CGKeyCode NJKeyInputFieldEmpty = 0xFFFF;
11
12 @implementation NJKeyInputField
13
14 - (id)initWithFrame:(NSRect)frameRect {
15 if ((self = [super initWithFrame:frameRect])) {
16 self.alignment = NSCenterTextAlignment;
17 self.editable = NO;
18 self.selectable = NO;
19 }
20 return self;
21 }
22
23 - (void)clear {
24 self.keyCode = NJKeyInputFieldEmpty;
25 if ([self.delegate respondsToSelector:@selector(keyInputFieldDidClear:)])
26 [self.delegate keyInputFieldDidClear:self];
27 [self resignIfFirstResponder];
28 }
29
30 - (BOOL)hasKeyCode {
31 return self.keyCode != NJKeyInputFieldEmpty;
32 }
33
34 + (NSString *)stringForKeyCode:(CGKeyCode)keyCode {
35 switch (keyCode) {
36 case 0x7a: return @"F1";
37 case 0x78: return @"F2";
38 case 0x63: return @"F3";
39 case 0x76: return @"F4";
40 case 0x60: return @"F5";
41 case 0x61: return @"F6";
42 case 0x62: return @"F7";
43 case 0x64: return @"F8";
44 case 0x65: return @"F9";
45 case 0x6d: return @"F10";
46 case 0x67: return @"F11";
47 case 0x6f: return @"F12";
48 case 0x69: return @"F13";
49 case 0x6b: return @"F14";
50 case 0x71: return @"F15";
51 case 0x6a: return @"F16";
52 case 0x40: return @"F17";
53 case 0x4f: return @"F18";
54 case 0x50: return @"F19";
55
56 case 0x35: return @"⎋";
57 case 0x32: return @"`";
58
59 case 0x12: return @"1";
60 case 0x13: return @"2";
61 case 0x14: return @"3";
62 case 0x15: return @"4";
63 case 0x17: return @"5";
64 case 0x16: return @"6";
65 case 0x1a: return @"7";
66 case 0x1c: return @"8";
67 case 0x19: return @"9";
68 case 0x1d: return @"0";
69 case 0x1b: return @"-";
70 case 0x18: return @"=";
71
72 case 0x3f: return @"Fn";
73 case 0x36: return NSLocalizedString(@"Right ⌘", @"keyboard key");
74 case 0x37: return NSLocalizedString(@"Left ⌘", @"keyboard key");
75 case 0x38: return NSLocalizedString(@"Left ⇧", @"keyboard key");
76 case 0x39: return @"⇪";
77 case 0x3a: return NSLocalizedString(@"Left ⌥", @"keyboard key");
78 case 0x3b: return NSLocalizedString(@"Left ⌃", @"keyboard key");
79 case 0x3c: return NSLocalizedString(@"Right ⇧", @"keyboard key");
80 case 0x3d: return NSLocalizedString(@"Right ⌃", @"keyboard key");
81 case 0x3e: return NSLocalizedString(@"Right ⌥", @"keyboard key");
82
83 case 0x73: return @"↖";
84 case 0x74: return @"⇞";
85 case 0x77: return @"↘";
86 case 0x79: return @"⇟";
87
88 case 0x75: return @"⌦";
89 case 0x33: return @"⌫";
90
91 case 0x30: return @"⇥";
92 case 0x24: return @"↩";
93 case 0x31: return @"␣";
94
95 case 0x0c: return @"Q";
96 case 0x0d: return @"W";
97 case 0x0e: return @"E";
98 case 0x0f: return @"R";
99 case 0x11: return @"T";
100 case 0x10: return @"Y";
101 case 0x20: return @"U";
102 case 0x22: return @"I";
103 case 0x1f: return @"O";
104 case 0x23: return @"P";
105 case 0x21: return @"[";
106 case 0x1e: return @"]";
107 case 0x2a: return @"\\";
108 case 0x00: return @"A";
109 case 0x01: return @"S";
110 case 0x02: return @"D";
111 case 0x03: return @"F";
112 case 0x05: return @"G";
113 case 0x04: return @"H";
114 case 0x26: return @"J";
115 case 0x28: return @"K";
116 case 0x25: return @"L";
117 case 0x29: return @";";
118 case 0x27: return @"'";
119 case 0x06: return @"Z";
120 case 0x07: return @"X";
121 case 0x08: return @"C";
122 case 0x09: return @"V";
123 case 0x0b: return @"B";
124 case 0x2d: return @"N";
125 case 0x2e: return @"M";
126 case 0x2b: return @",";
127 case 0x2f: return @".";
128 case 0x2c: return @"/";
129
130 case 0x47: return @"⌧";
131 case 0x51: return NSLocalizedString(@"Key Pad =", @"numeric pad key");
132 case 0x4b: return NSLocalizedString(@"Key Pad /", @"numeric pad key");
133 case 0x43: return NSLocalizedString(@"Key Pad *", @"numeric pad key");
134 case 0x59: return NSLocalizedString(@"Key Pad 7", @"numeric pad key");
135 case 0x5b: return NSLocalizedString(@"Key Pad 8", @"numeric pad key");
136 case 0x5c: return NSLocalizedString(@"Key Pad 9", @"numeric pad key");
137 case 0x4e: return NSLocalizedString(@"Key Pad -", @"numeric pad key");
138 case 0x56: return NSLocalizedString(@"Key Pad 4", @"numeric pad key");
139 case 0x57: return NSLocalizedString(@"Key Pad 5", @"numeric pad key");
140 case 0x58: return NSLocalizedString(@"Key Pad 6", @"numeric pad key");
141 case 0x45: return NSLocalizedString(@"Key Pad +", @"numeric pad key");
142 case 0x53: return NSLocalizedString(@"Key Pad 1", @"numeric pad key");
143 case 0x54: return NSLocalizedString(@"Key Pad 2", @"numeric pad key");
144 case 0x55: return NSLocalizedString(@"Key Pad 3", @"numeric pad key");
145 case 0x52: return NSLocalizedString(@"Key Pad 0", @"numeric pad key");
146 case 0x41: return NSLocalizedString(@"Key Pad .", @"numeric pad key");
147 case 0x4c: return @"⌤";
148
149 case 0x7e: return @"↑";
150 case 0x7d: return @"↓";
151 case 0x7b: return @"←";
152 case 0x7c: return @"→";
153 case 0xffff: // NJKeyInputFieldEmpty
154 return @"";
155 default:
156 return [[NSString alloc] initWithFormat:
157 NSLocalizedString(@"key 0x%x", @"unknown key code"),
158 keyCode];
159 }
160 }
161
162 - (BOOL)acceptsFirstResponder {
163 return self.isEnabled;
164 }
165
166 - (BOOL)becomeFirstResponder {
167 self.backgroundColor = NSColor.selectedTextBackgroundColor;
168 return [super becomeFirstResponder];
169 }
170
171 - (BOOL)resignFirstResponder {
172 self.backgroundColor = NSColor.textBackgroundColor;
173 return [super resignFirstResponder];
174 }
175
176 - (void)setKeyCode:(CGKeyCode)keyCode {
177 _keyCode = keyCode;
178 self.stringValue = [NJKeyInputField stringForKeyCode:keyCode];
179 }
180
181 - (void)keyDown:(NSEvent *)event {
182 static const NSUInteger IGNORE = NSAlternateKeyMask | NSCommandKeyMask;
183 if (!event.isARepeat) {
184 if ((event.modifierFlags & IGNORE) && event.keyCode == 0x33) {
185 // Allow Alt/Command+Backspace to clear the field.
186 self.keyCode = NJKeyInputFieldEmpty;
187 if ([self.delegate respondsToSelector:@selector(keyInputFieldDidClear:)])
188 [self.delegate keyInputFieldDidClear:self];
189 } else if (!(event.modifierFlags & IGNORE)) {
190 self.keyCode = event.keyCode;
191 if ([self.delegate respondsToSelector:@selector(keyInputField:didChangeKey:)])
192 [self.delegate keyInputField:self didChangeKey:self.keyCode];
193 }
194 [self resignIfFirstResponder];
195 }
196 }
197
198 - (void)mouseDown:(NSEvent *)theEvent {
199 if (self.window.firstResponder == self)
200 [self.window makeFirstResponder:nil];
201 else if (self.acceptsFirstResponder)
202 [self.window makeFirstResponder:self];
203 }
204
205 - (void)flagsChanged:(NSEvent *)theEvent {
206 // Many keys are only available on MacBook keyboards by using the
207 // Fn modifier key (e.g. Fn+Left for Home), so delay processing
208 // modifiers until the up event is received in order to let the
209 // user type these virtual keys. However, there is no actual event
210 // for modifier key up - so detect it by checking to see if any
211 // modifiers are still down.
212 if (!(theEvent.modifierFlags & NSDeviceIndependentModifierFlagsMask)) {
213 self.keyCode = theEvent.keyCode;
214 if ([self.delegate respondsToSelector:@selector(keyInputField:didChangeKey:)])
215 [self.delegate keyInputField:self didChangeKey:_keyCode];
216 }
217 }
218
219 - (void)setDelegate:(id<NJKeyInputFieldDelegate, NSTextFieldDelegate>)delegate {
220 [super setDelegate:delegate];
221 }
222
223 - (id <NJKeyInputFieldDelegate, NSTextFieldDelegate>)delegate {
224 return (id)[super delegate];
225 }
226
227 @end