summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Swenson <christopher@swenson.org>2022-07-29 22:01:35 -0500
committerGitHub <noreply@github.com>2022-07-29 20:01:35 -0700
commitd1096ad440e046fb44d3ba75c0049065b1dadb60 (patch)
treebbe5e5a20fee2f861553a8d1484f695050fa7b38
parentd2aa8e6bb8171c4af82bce678f098cd38597863e (diff)
[Keymap] Add enigma keymap for contra keyboard (#17829)
-rwxr-xr-xkeyboards/contra/config.h8
-rw-r--r--keyboards/contra/keymaps/enigma/config.h27
-rw-r--r--keyboards/contra/keymaps/enigma/keymap.c625
-rw-r--r--keyboards/contra/keymaps/enigma/readme.md35
-rw-r--r--keyboards/contra/keymaps/enigma/rules.mk2
5 files changed, 689 insertions, 8 deletions
diff --git a/keyboards/contra/config.h b/keyboards/contra/config.h
index 5a21752e1f..7e4fddb59f 100755
--- a/keyboards/contra/config.h
+++ b/keyboards/contra/config.h
@@ -28,11 +28,3 @@
28 28
29/* Locking resynchronize hack */ 29/* Locking resynchronize hack */
30#define LOCKING_RESYNC_ENABLE 30#define LOCKING_RESYNC_ENABLE
31
32#ifdef RGB_DI_PIN
33#define RGBLIGHT_ANIMATIONS
34#define RGBLED_NUM 0
35#define RGBLIGHT_HUE_STEP 8
36#define RGBLIGHT_SAT_STEP 8
37#define RGBLIGHT_VAL_STEP 8
38#endif
diff --git a/keyboards/contra/keymaps/enigma/config.h b/keyboards/contra/keymaps/enigma/config.h
new file mode 100644
index 0000000000..87f0199876
--- /dev/null
+++ b/keyboards/contra/keymaps/enigma/config.h
@@ -0,0 +1,27 @@
1/* Copyright 2022 Christopher Swenson
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#define RGB_DI_PIN F7
20#ifdef RGB_DI_PIN
21 #define RGBLIGHT_EFFECT_RAINBOW_SWIRL
22 #define RGBLIGHT_EFFECT_SNAKE
23 #define RGBLED_NUM 12
24 #define RGBLIGHT_HUE_STEP 8
25 #define RGBLIGHT_SAT_STEP 8
26 #define RGBLIGHT_VAL_STEP 8
27#endif \ No newline at end of file
diff --git a/keyboards/contra/keymaps/enigma/keymap.c b/keyboards/contra/keymaps/enigma/keymap.c
new file mode 100644
index 0000000000..d8779fb063
--- /dev/null
+++ b/keyboards/contra/keymaps/enigma/keymap.c
@@ -0,0 +1,625 @@
1/* Copyright 2022 Christopher Swenson
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include QMK_KEYBOARD_H
18
19enum planck_layers {
20 _ENIGMA,
21 _QWERTY,
22 _FN,
23 _LOWER,
24 _RAISE
25};
26
27enum planck_normal_keycodes {
28 QWERTY = SAFE_RANGE,
29 ENIGMA,
30 EN_A,
31 EN_B,
32 EN_C,
33 EN_D,
34 EN_E,
35 EN_F,
36 EN_G,
37 EN_H,
38 EN_I,
39 EN_J,
40 EN_K,
41 EN_L,
42 EN_M,
43 EN_N,
44 EN_O,
45 EN_P,
46 EN_Q,
47 EN_R,
48 EN_S,
49 EN_T,
50 EN_U,
51 EN_V,
52 EN_W,
53 EN_X,
54 EN_Y,
55 EN_Z,
56 EN_RES,
57 EN_TEST,
58 EN_DIAG,
59 EN_BSPC,
60 EN_SREF,
61 EN_SROT,
62 EN_SPOS,
63 EN_SRIN,
64 EN_SPLU
65};
66
67const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
68 /* Enigma
69 * ,-----------------------------------------------------------------------------------.
70 * | Esc | Q | W | E | R | T | Y | U | I | O | P | Bksp |
71 * |------+------+------+------+------+-------------+------+------+------+------+------|
72 * | Tab | A | S | D | F | G | H | J | K | L | ; | " |
73 * |------+------+------+------+------+------|------+------+------+------+------+------|
74 * | Shift| Z | X | C | V | B | N | M | , | . | / |Enter |
75 * |------+------+------+------+------+------+------+------+------+------+------+------|
76 * | Ctrl | Fn | Alt | GUI |Lower | Space |Raise | Left | Down | Up |Right |
77 * `-----------------------------------------------------------------------------------'
78 */
79 [_ENIGMA] = LAYOUT_planck_mit(
80 QK_GESC, EN_Q, EN_W, EN_E, EN_R, EN_T, EN_Y, EN_U, EN_I, EN_O, EN_P, KC_BSPC,
81 KC_TAB, EN_A, EN_S, EN_D, EN_F, EN_G, EN_H, EN_J, EN_K, EN_L, KC_SCLN, KC_QUOT,
82 KC_LSFT, EN_Z, EN_X, EN_C, EN_V, EN_B, EN_N, EN_M, KC_COMM, KC_DOT, KC_SLSH, KC_ENT,
83 KC_LCTL, MO(_FN), KC_LGUI, KC_LALT, MO(_LOWER), KC_SPC, MO(_RAISE), KC_LEFT, KC_DOWN, KC_UP, KC_RGHT
84 ),
85 /* Qwerty
86 * ,-----------------------------------------------------------------------------------.
87 * | Esc | Q | W | E | R | T | Y | U | I | O | P | Bksp |
88 * |------+------+------+------+------+-------------+------+------+------+------+------|
89 * | Tab | A | S | D | F | G | H | J | K | L | ; | " |
90 * |------+------+------+------+------+------|------+------+------+------+------+------|
91 * | Shift| Z | X | C | V | B | N | M | , | . | / |Enter |
92 * |------+------+------+------+------+------+------+------+------+------+------+------|
93 * | Ctrl | Fn | Alt | GUI |Lower | Space |Raise | Left | Down | Up |Right |
94 * `-----------------------------------------------------------------------------------'
95 */
96 [_QWERTY] = LAYOUT_planck_mit(
97 QK_GESC, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSPC,
98 KC_TAB, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT,
99 KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_ENT,
100 KC_LCTL, MO(_FN), KC_LGUI, KC_LALT, MO(_LOWER), KC_SPC, MO(_RAISE), KC_LEFT, KC_DOWN, KC_UP, KC_RGHT
101 ),
102 /* Function
103 * ,-----------------------------------------------------------------------------------.
104 * | Boot | Reset| Diag | | | | | | | | Test |Revers|
105 * |------+------+------+------+------+-------------+------+------+------+------+------|
106 * | | | | | | | | | | | | |
107 * |------+------+------+------+------+------|------+------+------+------+------+------|
108 * | |Reflec|Rotors|Posn.s|Rings |Plugs | | |Enigma|Qwerty| | |
109 * |------+------+------+------+------+------+------+------+------+------+------+------|
110 * | | | | | | | | | | | |
111 * `-----------------------------------------------------------------------------------'
112 */
113 [_FN] = LAYOUT_planck_mit(
114 QK_BOOT, EN_RES, EN_DIAG, _______, _______, _______, _______, _______, _______, _______, EN_TEST, EN_BSPC,
115 _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
116 _______, EN_SREF, EN_SROT, EN_SPOS, EN_SRIN, EN_SPLU, _______, _______, QWERTY, ENIGMA, _______, _______,
117 _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______
118 ),
119 /* Lower
120 * ,-----------------------------------------------------------------------------------.
121 * | ~ | ! | @ | # | $ | % | ^ | & | * | ( | ) | Bksp |
122 * |------+------+------+------+------+-------------+------+------+------+------+------|
123 * | | | | | | | | _ | + | { | } | | |
124 * |------+------+------+------+------+------|------+------+------+------+------+------|
125 * | Shift| | | | | | | | | | | |
126 * |------+------+------+------+------+------+------+------+------+------+------+------|
127 * | Ctrl | Fn | Alt | GUI |Lower | Space |Raise | Left | Down | Up |Right |
128 * `-----------------------------------------------------------------------------------'
129 */
130 [_LOWER] = LAYOUT_planck_mit(
131 KC_TILD, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_BSPC,
132 _______, _______, _______, _______, _______, _______, _______, KC_UNDS, KC_PLUS, KC_LCBR, KC_RCBR, KC_PIPE,
133 KC_LSFT, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
134 KC_LCTL, _______, KC_LGUI, KC_LALT, _______, KC_SPC, _______, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT
135 ),
136 /* RAISE
137 * ,-----------------------------------------------------------------------------------.
138 * | ` | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | Bksp |
139 * |------+------+------+------+------+-------------+------+------+------+------+------|
140 * | | | | | | | | - | = | [ | ] | \ |
141 * |------+------+------+------+------+------|------+------+------+------+------+------|
142 * | Shift| | | | | | | | | | | |
143 * |------+------+------+------+------+------+------+------+------+------+------+------|
144 * | Ctrl | Fn | Alt | GUI |Lower | Space |Raise | Left | Down | Up |Right |
145 * `-----------------------------------------------------------------------------------'
146 */
147 [_RAISE] = LAYOUT_planck_mit(
148 KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSPC,
149 _______, _______, _______, _______, _______, _______, _______, KC_MINS, KC_EQL, KC_LBRC, KC_RBRC, KC_BSLS,
150 KC_LSFT, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
151 KC_LCTL, _______, KC_LGUI, KC_LALT, _______, KC_SPC, _______, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT
152 ),
153};
154
155char rotor_definitions[5][26] = {
156 "EKMFLGDQVZNTOWYHXUSPAIBRCJ",
157 "AJDKSIRUXBLHWTMCQGZNPYFVOE",
158 "BDFHJLCPRTXVZNYEIWGAKMUSQO",
159 "ESOVPZJAYQUIRHXLNFTGKDCMWB",
160 "VZBRGITYUPSDNHLXAWMJQOFECK"
161};
162
163char reflector_definitions[3][26] = {
164 "EJMZALYXVBWFCRQUONTSPIKHGD",
165 "YRUHQSLDPXNGOKMIEBFZCWVJAT",
166 "FVPJIAOYEDRZXWGCTKUQSBNMHL"
167};
168
169char notch[5] = "QEVJZ";
170
171typedef struct Settings {
172 char rotor_order[3];
173 char rotor_rings[3];
174 char rotor_positions[3];
175 char plugs[25];
176 int plug_count;
177 char reflector;
178} Settings;
179
180typedef struct KeyboardState {
181 bool is_setting_reflector;
182 bool is_setting_rotors;
183 bool is_setting_rotor_positions;
184 bool is_setting_rotor_rings;
185 bool is_setting_plugs;
186 char setting_progress[26];
187 int setting_index;
188 Settings current_settings;
189 Settings default_settings;
190} KeyboardState;
191
192int bound(int letter) {
193 return ((letter % 26) + 26) % 26;
194}
195
196char to_char(int letter) {
197 return 'A' + letter;
198}
199
200int to_int(char letter) {
201 return letter - 'A';
202}
203
204char encipher(char letter, Settings *settings) {
205 int rotor_2_step = settings->rotor_positions[2] == notch[settings->rotor_order[2] - 1];
206 int rotor_1_step = settings->rotor_positions[1] == notch[settings->rotor_order[1] - 1];
207
208 // Advance the third rotor
209 settings->rotor_positions[2]++;
210 if (settings->rotor_positions[2] > 'Z') {
211 settings->rotor_positions[2] -= 26;
212 }
213
214 // Maybe advance the second rotor, including double steps
215 if (rotor_2_step || rotor_1_step) {
216 settings->rotor_positions[1]++;
217 if (settings->rotor_positions[1] > 'Z') {
218 settings->rotor_positions[1] -= 26;
219 }
220 }
221
222 // Maybe advance the first rotor
223 if (rotor_1_step) {
224 settings->rotor_positions[0]++;
225 if (settings->rotor_positions[0] > 'Z') {
226 settings->rotor_positions[0] -= 26;
227 }
228 }
229
230 // Swap letters on plugboard
231 for (int i = 0; i < settings->plug_count * 2; i += 2) {
232 if (letter == settings->plugs[i]) {
233 letter = settings->plugs[i + 1];
234 } else if (letter == settings->plugs[i + 1]) {
235 letter = settings->plugs[i];
236 }
237 }
238
239 // Rotors (right to left)
240 for (int rotor_index = 2; rotor_index >= 0; rotor_index--) {
241 char *rotor_definition = rotor_definitions[settings->rotor_order[rotor_index] - 1];
242 int position = to_int(settings->rotor_positions[rotor_index]);
243 int ring = to_int(settings->rotor_rings[rotor_index]);
244 int char_index = to_int(letter);
245 letter = to_char(bound(
246 to_int(rotor_definition[bound(char_index + position - ring)]) + ring - position
247 ));
248 }
249
250 // Swap via reflector
251 letter = reflector_definitions[to_int(settings->reflector)][to_int(letter)];
252
253 // Rotors in reverse (left to right)
254 for (int rotor_index = 0; rotor_index < 3; rotor_index++) {
255 char *rotor_definition = rotor_definitions[settings->rotor_order[rotor_index] - 1];
256 int position = to_int(settings->rotor_positions[rotor_index]);
257 int ring = to_int(settings->rotor_rings[rotor_index]);
258 int search_index;
259 for (search_index = 0; search_index < 26; search_index++) {
260 if (
261 rotor_definition[search_index]
262 == to_char(bound(to_int(letter) - ring + position))
263 ) {
264 break;
265 }
266 }
267 letter = to_char(bound(search_index - position + ring));
268 }
269
270 // Plugboard again
271 for (int i = 0; i < settings->plug_count * 2; i += 2) {
272 if (letter == settings->plugs[i]) {
273 letter = settings->plugs[i + 1];
274 } else if (letter == settings->plugs[i + 1]) {
275 letter = settings->plugs[i];
276 }
277 }
278
279 return letter;
280}
281
282void init_enigma_default(Settings *settings) {
283 settings->rotor_order[0] = 1;
284 settings->rotor_rings[0] = 'A';
285 settings->rotor_positions[0] = 'A';
286
287 settings->rotor_order[1] = 2;
288 settings->rotor_rings[1] = 'A';
289 settings->rotor_positions[1] = 'A';
290
291 settings->rotor_order[2] = 3;
292 settings->rotor_rings[2] = 'A';
293 settings->rotor_positions[2] = 'A';
294
295 strcpy(settings->plugs, "");
296 settings->plug_count = 0;
297
298 settings->reflector = 'B';
299}
300
301void copy_settings(Settings *from, Settings *to) {
302 to->rotor_order[0] = from->rotor_order[0];
303 to->rotor_rings[0] = from->rotor_rings[0];
304 to->rotor_positions[0] = from->rotor_positions[0];
305
306 to->rotor_order[1] = from->rotor_order[1];
307 to->rotor_rings[1] = from->rotor_rings[1];
308 to->rotor_positions[1] = from->rotor_positions[1];
309
310 to->rotor_order[2] = from->rotor_order[2];
311 to->rotor_rings[2] = from->rotor_rings[2];
312 to->rotor_positions[2] = from->rotor_positions[2];
313
314 strncpy(to->plugs, from->plugs, from->plug_count * 2);
315 to->plug_count = from->plug_count;
316
317 to->reflector = from->reflector;
318}
319
320char *rotor_name(int rotor_number) {
321 if (rotor_number == 1) {
322 return "I";
323 } else if (rotor_number == 2) {
324 return "II";
325 } else if (rotor_number == 3) {
326 return "III";
327 } else if (rotor_number == 4) {
328 return "IV";
329 } else if (rotor_number == 5) {
330 return "V";
331 }
332 return "?";
333}
334
335void rotors_reverse(Settings *settings) {
336 int rotor_2_step = settings->rotor_positions[2]
337 == to_char(bound(to_int(notch[settings->rotor_order[2] - 1]) + 1));
338 int rotor_1_step = settings->rotor_positions[1]
339 == to_char(bound(to_int(notch[settings->rotor_order[1] - 1]) + 1));
340
341 // Reverse third rotor
342 settings->rotor_positions[2]--;
343 if (settings->rotor_positions[2] < 'A') {
344 settings->rotor_positions[2] += 26;
345 }
346
347 // Maybe reverse second rotor (including double steps)
348 if (rotor_2_step || rotor_1_step) {
349 settings->rotor_positions[1]--;
350 if (settings->rotor_positions[1] < 'A') {
351 settings->rotor_positions[1] += 26;
352 }
353 }
354
355 // Maybe recerse first rotor
356 if (rotor_1_step) {
357 settings->rotor_positions[0]--;
358 if (settings->rotor_positions[0] < 'A') {
359 settings->rotor_positions[0] += 26;
360 }
361 }
362}
363
364void reset_settings(KeyboardState *state) {
365 copy_settings(&state->default_settings, &state->current_settings);
366}
367
368void set_layer(uint8_t default_layer) {
369 default_layer_set((layer_state_t)1 << default_layer);
370}
371
372void set_backlight(uint8_t mode, uint8_t hue, uint8_t sat, uint8_t val) {
373 #ifdef RGBLIGHT_ENABLE
374 rgblight_enable_noeeprom();
375 rgblight_mode_noeeprom(mode);
376 rgblight_sethsv_noeeprom(hue, sat, val);
377 #endif
378}
379
380void clear_working_settings(KeyboardState *state) {
381 state->is_setting_reflector = false;
382 state->is_setting_rotors = false;
383 state->is_setting_rotor_positions = false;
384 state->is_setting_rotor_rings = false;
385 state->is_setting_plugs = false;
386 state->setting_index = 0;
387 set_layer(_ENIGMA);
388 set_backlight(RGBLIGHT_MODE_STATIC_LIGHT, HSV_RED);
389}
390
391void send_settings_string(Settings *settings) {
392 send_char(settings->reflector);
393 send_string(". ");
394 send_string(rotor_name(settings->rotor_order[0]));
395 send_char(settings->rotor_rings[0]);
396 send_string("-");
397 send_string(rotor_name(settings->rotor_order[1]));
398 send_char(settings->rotor_rings[1]);
399 send_string("-");
400 send_string(rotor_name(settings->rotor_order[2]));
401 send_char(settings->rotor_rings[2]);
402 send_string(" (");
403 send_char(settings->rotor_positions[0]);
404 send_string(", ");
405 send_char(settings->rotor_positions[1]);
406 send_string(", ");
407 send_char(settings->rotor_positions[2]);
408 send_string(") ");
409 for (int i = 0; i < settings->plug_count; i++) {
410 send_char(settings->plugs[i * 2]);
411 send_char(settings->plugs[i * 2 + 1]);
412 send_string(" ");
413 }
414 send_string("\n");
415}
416
417void perform_test(Settings *settings) {
418 for (int i = 0; i < 1000; i++) {
419 send_char(encipher('A', settings) - ('A' - 'a'));
420 }
421}
422
423void commit_plug_settings(KeyboardState *state) {
424 state->default_settings.plug_count = state->setting_index / 2;
425 for (int i = 0; i < state->default_settings.plug_count; i++) {
426 state->default_settings.plugs[i * 2] = state->setting_progress[i * 2];
427 state->default_settings.plugs[i * 2 + 1] = state->setting_progress[i * 2 + 1];
428 }
429 reset_settings(state);
430 clear_working_settings(state);
431}
432
433void handle_set_reflector(char letter, KeyboardState *state) {
434 if (letter >= 'A' && letter <= 'C') {
435 state->default_settings.reflector = letter;
436 reset_settings(state);
437 clear_working_settings(state);
438 }
439}
440
441bool handle_set_rotor(char letter, KeyboardState *state) {
442 bool is_valid = letter >= 'A' && letter <= 'E' && state->setting_index < 3;
443 if (is_valid) {
444 state->setting_progress[state->setting_index] = to_int(letter) + 1;
445 state->setting_index += 1;
446 if (state->setting_index == 3) {
447 state->default_settings.rotor_order[0] = state->setting_progress[0];
448 state->default_settings.rotor_order[1] = state->setting_progress[1];
449 state->default_settings.rotor_order[2] = state->setting_progress[2];
450 reset_settings(state);
451 clear_working_settings(state);
452 }
453 }
454 return is_valid;
455}
456
457bool handle_set_rotor_position(char letter, KeyboardState *state) {
458 bool is_valid = state->setting_index < 3; // Guaranteed to be A-Z already
459 if (is_valid) {
460 state->setting_progress[state->setting_index] = letter;
461 state->setting_index += 1;
462 if (state->setting_index == 3) {
463 state->default_settings.rotor_positions[0] = state->setting_progress[0];
464 state->default_settings.rotor_positions[1] = state->setting_progress[1];
465 state->default_settings.rotor_positions[2] = state->setting_progress[2];
466 reset_settings(state);
467 clear_working_settings(state);
468 }
469 }
470 return is_valid;
471}
472
473bool handle_set_rotor_ring(char letter, KeyboardState *state) {
474 bool is_valid = state->setting_index < 3;
475 if (is_valid) {
476 state->setting_progress[state->setting_index] = letter;
477 state->setting_index += 1;
478 if (state->setting_index == 3) {
479 state->default_settings.rotor_rings[0] = state->setting_progress[0];
480 state->default_settings.rotor_rings[1] = state->setting_progress[1];
481 state->default_settings.rotor_rings[2] = state->setting_progress[2];
482 reset_settings(state);
483 clear_working_settings(state);
484 }
485 }
486 return is_valid;
487}
488
489bool handle_set_plug(char letter, KeyboardState *state) {
490 bool is_valid = state->setting_index < 26;
491 if (is_valid) {
492 state->setting_progress[state->setting_index] = letter;
493 state->setting_index += 1;
494 }
495 return is_valid;
496}
497
498void handle_enigma_keypress(char letter, bool any_mods, KeyboardState *state) {
499 bool settings_valid = true;
500 if (letter) {
501 if (any_mods) {
502 tap_code(KC_A + to_int(letter));
503 } else if (state->is_setting_reflector) {
504 handle_set_reflector(letter, state);
505 } else if (state->is_setting_rotors) {
506 settings_valid = handle_set_rotor(letter, state);
507 } else if (state->is_setting_rotor_positions) {
508 settings_valid = handle_set_rotor_position(letter, state);
509 } else if (state->is_setting_rotor_rings) {
510 settings_valid = handle_set_rotor_ring(letter, state);
511 } else if (state->is_setting_plugs) {
512 settings_valid = handle_set_plug(letter, state);
513 } else {
514 char c2 = encipher(letter, &state->current_settings);
515 send_char(c2 - ('A' - 'a'));
516 }
517 }
518 if (!settings_valid) {
519 clear_working_settings(state);
520 }
521}
522
523KeyboardState STATE;
524
525void keyboard_pre_init_user(void) {
526 init_enigma_default(&STATE.default_settings);
527 init_enigma_default(&STATE.current_settings);
528 clear_working_settings(&STATE);
529}
530
531bool process_record_user(uint16_t keycode, keyrecord_t *record) {
532 uint8_t letter_index;
533 bool letter_found = false;
534 if (record->event.pressed) {
535 switch (keycode) {
536 case QWERTY:
537 set_layer(_QWERTY);
538 set_backlight(RGBLIGHT_MODE_RAINBOW_SWIRL + 4, HSV_PURPLE);
539 break;
540 case ENIGMA:
541 set_layer(_ENIGMA);
542 set_backlight(RGBLIGHT_MODE_STATIC_LIGHT, HSV_RED);
543 break;
544 case EN_SREF:
545 reset_settings(&STATE);
546 STATE.is_setting_reflector = true;
547 set_layer(_ENIGMA);
548 set_backlight(RGBLIGHT_MODE_SNAKE, HSV_RED);
549 break;
550 case EN_SROT:
551 reset_settings(&STATE);
552 STATE.is_setting_rotors = true;
553 STATE.setting_index = 0;
554 set_layer(_ENIGMA);
555 set_backlight(RGBLIGHT_MODE_SNAKE, 10, 255, 255);
556 break;
557 case EN_SPOS:
558 reset_settings(&STATE);
559 STATE.is_setting_rotor_positions = true;
560 STATE.setting_index = 0;
561 set_layer(_ENIGMA);
562 set_backlight(RGBLIGHT_MODE_SNAKE, HSV_ORANGE);
563 break;
564 case EN_SRIN:
565 reset_settings(&STATE);
566 STATE.is_setting_rotor_rings = true;
567 STATE.setting_index = 0;
568 set_layer(_ENIGMA);
569 set_backlight(RGBLIGHT_MODE_SNAKE, HSV_GREEN);
570 break;
571 case EN_SPLU:
572 reset_settings(&STATE);
573 STATE.is_setting_plugs = true;
574 STATE.setting_index = 0;
575 set_layer(_ENIGMA);
576 set_backlight(RGBLIGHT_MODE_SNAKE, HSV_BLUE);
577 break;
578 case QK_GESC:
579 if (
580 STATE.is_setting_reflector
581 || STATE.is_setting_rotors
582 || STATE.is_setting_rotor_positions
583 || STATE.is_setting_rotor_rings
584 || STATE.is_setting_plugs
585 ) {
586 clear_working_settings(&STATE);
587 return false;
588 }
589 break;
590 case KC_ENT:
591 if (STATE.is_setting_plugs) {
592 commit_plug_settings(&STATE);
593 return false;
594 }
595 break;
596 case EN_A ... EN_Z:
597 letter_index = keycode - EN_A;
598 letter_found = true;
599 break;
600 case EN_RES:
601 reset_settings(&STATE);
602 break;
603 case EN_TEST:
604 perform_test(&STATE.current_settings);
605 break;
606 case EN_DIAG:
607 send_settings_string(&STATE.current_settings);
608 break;
609 case EN_BSPC:
610 rotors_reverse(&STATE.current_settings);
611 tap_code(KC_BSPC);
612 break;
613 }
614 }
615 char letter = letter_found ? 'A' + letter_index : 0;
616 uint8_t mods = get_mods();
617 bool any_mods = (mods & MOD_MASK_CTRL) || (mods & MOD_MASK_ALT) || (mods & MOD_MASK_GUI);
618 handle_enigma_keypress(letter, any_mods, &STATE);
619 return true;
620}
621
622void keyboard_post_init_user(void) {
623 set_layer(_QWERTY);
624 set_backlight(RGBLIGHT_MODE_RAINBOW_SWIRL + 4, HSV_PURPLE);
625}
diff --git a/keyboards/contra/keymaps/enigma/readme.md b/keyboards/contra/keymaps/enigma/readme.md
new file mode 100644
index 0000000000..9bc69b3980
--- /dev/null
+++ b/keyboards/contra/keymaps/enigma/readme.md
@@ -0,0 +1,35 @@
1# A Contra Layout with an Enigma Emulator
2
3```
4
5,-----------------------------------------------------------------------------------.
6| Esc | Q | W | E | R | T | Y | U | I | O | P | Bksp |
7|------+------+------+------+------+-------------+------+------+------+------+------|
8| Tab | A | S | D | F | G | H | J | K | L | ; | " |
9|------+------+------+------+------+------|------+------+------+------+------+------|
10| Shift| Z | X | C | V | B | N | M | , | . | / |Enter |
11|------+------+------+------+------+------+------+------+------+------+------+------|
12| Ctrl | Fn | Alt | GUI |Lower | Space |Raise | Left | Down | Up |Right |
13`-----------------------------------------------------------------------------------'
14```
15
16By default, this layout functions like a normal QWERTY layout. But it also has an in-built Enigma machine emulator.
17To enable the emulator, press `Fn+.`, and to go back to QWERTY, press `FN+,`.
18
19A demonstration video can be found [here](https://youtu.be/p8kBjP1DCzo).
20
21When Enigma mode is enabled, all letters A-Z will be enciphered using the Enigma emulator. Other keycodes will not be modified. Shift will be sent as normal, so you can choose whether to capitalize the output. If any other modifier (Ctrl, Alt, or Gui) are being pressed, the normal letter will come through.
22
23There are a few key combinations for configuring and diagnosing the Enigma emulator:
24
25* `Fn+Q` resets the emulator to the last-configured settings
26* `Fn+W` types out the current Enigma settings, e.g. `B. IA-IIA-IIIA (A, A, A) QW` (meaning reflector B; rotors I, II, and III all at ring setting A; all at position A, and with Q and W swapped on the plugboard)
27* `Fn+P` types out 1000 enciphered As, for testing
28* `Fn+Backspace` back-rotates the rotors one step, for fixing typos without having to re-type a whole message
29* `Fn+Z` followed by A, B, or C is used to set the reflector
30* `Fn+X` followed by three characters A-E is used to set the rotors
31* `Fn+C` followed by three characters A-Z is used to set the rotor positions
32* `Fn+V` followed by three characters A-Z is used to set the ring settings
33* `Fn+B` followed by up to 13 pairs of characters A-Z (one at a time, not simulaneously) then the Enter key is used to set the plugboard
34
35
diff --git a/keyboards/contra/keymaps/enigma/rules.mk b/keyboards/contra/keymaps/enigma/rules.mk
new file mode 100644
index 0000000000..261e59922a
--- /dev/null
+++ b/keyboards/contra/keymaps/enigma/rules.mk
@@ -0,0 +1,2 @@
1RGBLIGHT_ENABLE = yes
2RGBLIGHT_SUPPORTED = yes \ No newline at end of file