[Keymap] Add enigma keymap for contra keyboard (#17829)

master
Chris Swenson 2022-07-29 22:01:35 -05:00 committed by GitHub
parent d2aa8e6bb8
commit d1096ad440
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 689 additions and 8 deletions

View File

@ -28,11 +28,3 @@
/* Locking resynchronize hack */ /* Locking resynchronize hack */
#define LOCKING_RESYNC_ENABLE #define LOCKING_RESYNC_ENABLE
#ifdef RGB_DI_PIN
#define RGBLIGHT_ANIMATIONS
#define RGBLED_NUM 0
#define RGBLIGHT_HUE_STEP 8
#define RGBLIGHT_SAT_STEP 8
#define RGBLIGHT_VAL_STEP 8
#endif

View File

@ -0,0 +1,27 @@
/* Copyright 2022 Christopher Swenson
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#define RGB_DI_PIN F7
#ifdef RGB_DI_PIN
#define RGBLIGHT_EFFECT_RAINBOW_SWIRL
#define RGBLIGHT_EFFECT_SNAKE
#define RGBLED_NUM 12
#define RGBLIGHT_HUE_STEP 8
#define RGBLIGHT_SAT_STEP 8
#define RGBLIGHT_VAL_STEP 8
#endif

View File

@ -0,0 +1,625 @@
/* Copyright 2022 Christopher Swenson
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include QMK_KEYBOARD_H
enum planck_layers {
_ENIGMA,
_QWERTY,
_FN,
_LOWER,
_RAISE
};
enum planck_normal_keycodes {
QWERTY = SAFE_RANGE,
ENIGMA,
EN_A,
EN_B,
EN_C,
EN_D,
EN_E,
EN_F,
EN_G,
EN_H,
EN_I,
EN_J,
EN_K,
EN_L,
EN_M,
EN_N,
EN_O,
EN_P,
EN_Q,
EN_R,
EN_S,
EN_T,
EN_U,
EN_V,
EN_W,
EN_X,
EN_Y,
EN_Z,
EN_RES,
EN_TEST,
EN_DIAG,
EN_BSPC,
EN_SREF,
EN_SROT,
EN_SPOS,
EN_SRIN,
EN_SPLU
};
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
/* Enigma
* ,-----------------------------------------------------------------------------------.
* | Esc | Q | W | E | R | T | Y | U | I | O | P | Bksp |
* |------+------+------+------+------+-------------+------+------+------+------+------|
* | Tab | A | S | D | F | G | H | J | K | L | ; | " |
* |------+------+------+------+------+------|------+------+------+------+------+------|
* | Shift| Z | X | C | V | B | N | M | , | . | / |Enter |
* |------+------+------+------+------+------+------+------+------+------+------+------|
* | Ctrl | Fn | Alt | GUI |Lower | Space |Raise | Left | Down | Up |Right |
* `-----------------------------------------------------------------------------------'
*/
[_ENIGMA] = LAYOUT_planck_mit(
QK_GESC, EN_Q, EN_W, EN_E, EN_R, EN_T, EN_Y, EN_U, EN_I, EN_O, EN_P, KC_BSPC,
KC_TAB, EN_A, EN_S, EN_D, EN_F, EN_G, EN_H, EN_J, EN_K, EN_L, KC_SCLN, KC_QUOT,
KC_LSFT, EN_Z, EN_X, EN_C, EN_V, EN_B, EN_N, EN_M, KC_COMM, KC_DOT, KC_SLSH, KC_ENT,
KC_LCTL, MO(_FN), KC_LGUI, KC_LALT, MO(_LOWER), KC_SPC, MO(_RAISE), KC_LEFT, KC_DOWN, KC_UP, KC_RGHT
),
/* Qwerty
* ,-----------------------------------------------------------------------------------.
* | Esc | Q | W | E | R | T | Y | U | I | O | P | Bksp |
* |------+------+------+------+------+-------------+------+------+------+------+------|
* | Tab | A | S | D | F | G | H | J | K | L | ; | " |
* |------+------+------+------+------+------|------+------+------+------+------+------|
* | Shift| Z | X | C | V | B | N | M | , | . | / |Enter |
* |------+------+------+------+------+------+------+------+------+------+------+------|
* | Ctrl | Fn | Alt | GUI |Lower | Space |Raise | Left | Down | Up |Right |
* `-----------------------------------------------------------------------------------'
*/
[_QWERTY] = LAYOUT_planck_mit(
QK_GESC, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSPC,
KC_TAB, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_ENT,
KC_LCTL, MO(_FN), KC_LGUI, KC_LALT, MO(_LOWER), KC_SPC, MO(_RAISE), KC_LEFT, KC_DOWN, KC_UP, KC_RGHT
),
/* Function
* ,-----------------------------------------------------------------------------------.
* | Boot | Reset| Diag | | | | | | | | Test |Revers|
* |------+------+------+------+------+-------------+------+------+------+------+------|
* | | | | | | | | | | | | |
* |------+------+------+------+------+------|------+------+------+------+------+------|
* | |Reflec|Rotors|Posn.s|Rings |Plugs | | |Enigma|Qwerty| | |
* |------+------+------+------+------+------+------+------+------+------+------+------|
* | | | | | | | | | | | |
* `-----------------------------------------------------------------------------------'
*/
[_FN] = LAYOUT_planck_mit(
QK_BOOT, EN_RES, EN_DIAG, _______, _______, _______, _______, _______, _______, _______, EN_TEST, EN_BSPC,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, EN_SREF, EN_SROT, EN_SPOS, EN_SRIN, EN_SPLU, _______, _______, QWERTY, ENIGMA, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______
),
/* Lower
* ,-----------------------------------------------------------------------------------.
* | ~ | ! | @ | # | $ | % | ^ | & | * | ( | ) | Bksp |
* |------+------+------+------+------+-------------+------+------+------+------+------|
* | | | | | | | | _ | + | { | } | | |
* |------+------+------+------+------+------|------+------+------+------+------+------|
* | Shift| | | | | | | | | | | |
* |------+------+------+------+------+------+------+------+------+------+------+------|
* | Ctrl | Fn | Alt | GUI |Lower | Space |Raise | Left | Down | Up |Right |
* `-----------------------------------------------------------------------------------'
*/
[_LOWER] = LAYOUT_planck_mit(
KC_TILD, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_BSPC,
_______, _______, _______, _______, _______, _______, _______, KC_UNDS, KC_PLUS, KC_LCBR, KC_RCBR, KC_PIPE,
KC_LSFT, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
KC_LCTL, _______, KC_LGUI, KC_LALT, _______, KC_SPC, _______, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT
),
/* RAISE
* ,-----------------------------------------------------------------------------------.
* | ` | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | Bksp |
* |------+------+------+------+------+-------------+------+------+------+------+------|
* | | | | | | | | - | = | [ | ] | \ |
* |------+------+------+------+------+------|------+------+------+------+------+------|
* | Shift| | | | | | | | | | | |
* |------+------+------+------+------+------+------+------+------+------+------+------|
* | Ctrl | Fn | Alt | GUI |Lower | Space |Raise | Left | Down | Up |Right |
* `-----------------------------------------------------------------------------------'
*/
[_RAISE] = LAYOUT_planck_mit(
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSPC,
_______, _______, _______, _______, _______, _______, _______, KC_MINS, KC_EQL, KC_LBRC, KC_RBRC, KC_BSLS,
KC_LSFT, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
KC_LCTL, _______, KC_LGUI, KC_LALT, _______, KC_SPC, _______, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT
),
};
char rotor_definitions[5][26] = {
"EKMFLGDQVZNTOWYHXUSPAIBRCJ",
"AJDKSIRUXBLHWTMCQGZNPYFVOE",
"BDFHJLCPRTXVZNYEIWGAKMUSQO",
"ESOVPZJAYQUIRHXLNFTGKDCMWB",
"VZBRGITYUPSDNHLXAWMJQOFECK"
};
char reflector_definitions[3][26] = {
"EJMZALYXVBWFCRQUONTSPIKHGD",
"YRUHQSLDPXNGOKMIEBFZCWVJAT",
"FVPJIAOYEDRZXWGCTKUQSBNMHL"
};
char notch[5] = "QEVJZ";
typedef struct Settings {
char rotor_order[3];
char rotor_rings[3];
char rotor_positions[3];
char plugs[25];
int plug_count;
char reflector;
} Settings;
typedef struct KeyboardState {
bool is_setting_reflector;
bool is_setting_rotors;
bool is_setting_rotor_positions;
bool is_setting_rotor_rings;
bool is_setting_plugs;
char setting_progress[26];
int setting_index;
Settings current_settings;
Settings default_settings;
} KeyboardState;
int bound(int letter) {
return ((letter % 26) + 26) % 26;
}
char to_char(int letter) {
return 'A' + letter;
}
int to_int(char letter) {
return letter - 'A';
}
char encipher(char letter, Settings *settings) {
int rotor_2_step = settings->rotor_positions[2] == notch[settings->rotor_order[2] - 1];
int rotor_1_step = settings->rotor_positions[1] == notch[settings->rotor_order[1] - 1];
// Advance the third rotor
settings->rotor_positions[2]++;
if (settings->rotor_positions[2] > 'Z') {
settings->rotor_positions[2] -= 26;
}
// Maybe advance the second rotor, including double steps
if (rotor_2_step || rotor_1_step) {
settings->rotor_positions[1]++;
if (settings->rotor_positions[1] > 'Z') {
settings->rotor_positions[1] -= 26;
}
}
// Maybe advance the first rotor
if (rotor_1_step) {
settings->rotor_positions[0]++;
if (settings->rotor_positions[0] > 'Z') {
settings->rotor_positions[0] -= 26;
}
}
// Swap letters on plugboard
for (int i = 0; i < settings->plug_count * 2; i += 2) {
if (letter == settings->plugs[i]) {
letter = settings->plugs[i + 1];
} else if (letter == settings->plugs[i + 1]) {
letter = settings->plugs[i];
}
}
// Rotors (right to left)
for (int rotor_index = 2; rotor_index >= 0; rotor_index--) {
char *rotor_definition = rotor_definitions[settings->rotor_order[rotor_index] - 1];
int position = to_int(settings->rotor_positions[rotor_index]);
int ring = to_int(settings->rotor_rings[rotor_index]);
int char_index = to_int(letter);
letter = to_char(bound(
to_int(rotor_definition[bound(char_index + position - ring)]) + ring - position
));
}
// Swap via reflector
letter = reflector_definitions[to_int(settings->reflector)][to_int(letter)];
// Rotors in reverse (left to right)
for (int rotor_index = 0; rotor_index < 3; rotor_index++) {
char *rotor_definition = rotor_definitions[settings->rotor_order[rotor_index] - 1];
int position = to_int(settings->rotor_positions[rotor_index]);
int ring = to_int(settings->rotor_rings[rotor_index]);
int search_index;
for (search_index = 0; search_index < 26; search_index++) {
if (
rotor_definition[search_index]
== to_char(bound(to_int(letter) - ring + position))
) {
break;
}
}
letter = to_char(bound(search_index - position + ring));
}
// Plugboard again
for (int i = 0; i < settings->plug_count * 2; i += 2) {
if (letter == settings->plugs[i]) {
letter = settings->plugs[i + 1];
} else if (letter == settings->plugs[i + 1]) {
letter = settings->plugs[i];
}
}
return letter;
}
void init_enigma_default(Settings *settings) {
settings->rotor_order[0] = 1;
settings->rotor_rings[0] = 'A';
settings->rotor_positions[0] = 'A';
settings->rotor_order[1] = 2;
settings->rotor_rings[1] = 'A';
settings->rotor_positions[1] = 'A';
settings->rotor_order[2] = 3;
settings->rotor_rings[2] = 'A';
settings->rotor_positions[2] = 'A';
strcpy(settings->plugs, "");
settings->plug_count = 0;
settings->reflector = 'B';
}
void copy_settings(Settings *from, Settings *to) {
to->rotor_order[0] = from->rotor_order[0];
to->rotor_rings[0] = from->rotor_rings[0];
to->rotor_positions[0] = from->rotor_positions[0];
to->rotor_order[1] = from->rotor_order[1];
to->rotor_rings[1] = from->rotor_rings[1];
to->rotor_positions[1] = from->rotor_positions[1];
to->rotor_order[2] = from->rotor_order[2];
to->rotor_rings[2] = from->rotor_rings[2];
to->rotor_positions[2] = from->rotor_positions[2];
strncpy(to->plugs, from->plugs, from->plug_count * 2);
to->plug_count = from->plug_count;
to->reflector = from->reflector;
}
char *rotor_name(int rotor_number) {
if (rotor_number == 1) {
return "I";
} else if (rotor_number == 2) {
return "II";
} else if (rotor_number == 3) {
return "III";
} else if (rotor_number == 4) {
return "IV";
} else if (rotor_number == 5) {
return "V";
}
return "?";
}
void rotors_reverse(Settings *settings) {
int rotor_2_step = settings->rotor_positions[2]
== to_char(bound(to_int(notch[settings->rotor_order[2] - 1]) + 1));
int rotor_1_step = settings->rotor_positions[1]
== to_char(bound(to_int(notch[settings->rotor_order[1] - 1]) + 1));
// Reverse third rotor
settings->rotor_positions[2]--;
if (settings->rotor_positions[2] < 'A') {
settings->rotor_positions[2] += 26;
}
// Maybe reverse second rotor (including double steps)
if (rotor_2_step || rotor_1_step) {
settings->rotor_positions[1]--;
if (settings->rotor_positions[1] < 'A') {
settings->rotor_positions[1] += 26;
}
}
// Maybe recerse first rotor
if (rotor_1_step) {
settings->rotor_positions[0]--;
if (settings->rotor_positions[0] < 'A') {
settings->rotor_positions[0] += 26;
}
}
}
void reset_settings(KeyboardState *state) {
copy_settings(&state->default_settings, &state->current_settings);
}
void set_layer(uint8_t default_layer) {
default_layer_set((layer_state_t)1 << default_layer);
}
void set_backlight(uint8_t mode, uint8_t hue, uint8_t sat, uint8_t val) {
#ifdef RGBLIGHT_ENABLE
rgblight_enable_noeeprom();
rgblight_mode_noeeprom(mode);
rgblight_sethsv_noeeprom(hue, sat, val);
#endif
}
void clear_working_settings(KeyboardState *state) {
state->is_setting_reflector = false;
state->is_setting_rotors = false;
state->is_setting_rotor_positions = false;
state->is_setting_rotor_rings = false;
state->is_setting_plugs = false;
state->setting_index = 0;
set_layer(_ENIGMA);
set_backlight(RGBLIGHT_MODE_STATIC_LIGHT, HSV_RED);
}
void send_settings_string(Settings *settings) {
send_char(settings->reflector);
send_string(". ");
send_string(rotor_name(settings->rotor_order[0]));
send_char(settings->rotor_rings[0]);
send_string("-");
send_string(rotor_name(settings->rotor_order[1]));
send_char(settings->rotor_rings[1]);
send_string("-");
send_string(rotor_name(settings->rotor_order[2]));
send_char(settings->rotor_rings[2]);
send_string(" (");
send_char(settings->rotor_positions[0]);
send_string(", ");
send_char(settings->rotor_positions[1]);
send_string(", ");
send_char(settings->rotor_positions[2]);
send_string(") ");
for (int i = 0; i < settings->plug_count; i++) {
send_char(settings->plugs[i * 2]);
send_char(settings->plugs[i * 2 + 1]);
send_string(" ");
}
send_string("\n");
}
void perform_test(Settings *settings) {
for (int i = 0; i < 1000; i++) {
send_char(encipher('A', settings) - ('A' - 'a'));
}
}
void commit_plug_settings(KeyboardState *state) {
state->default_settings.plug_count = state->setting_index / 2;
for (int i = 0; i < state->default_settings.plug_count; i++) {
state->default_settings.plugs[i * 2] = state->setting_progress[i * 2];
state->default_settings.plugs[i * 2 + 1] = state->setting_progress[i * 2 + 1];
}
reset_settings(state);
clear_working_settings(state);
}
void handle_set_reflector(char letter, KeyboardState *state) {
if (letter >= 'A' && letter <= 'C') {
state->default_settings.reflector = letter;
reset_settings(state);
clear_working_settings(state);
}
}
bool handle_set_rotor(char letter, KeyboardState *state) {
bool is_valid = letter >= 'A' && letter <= 'E' && state->setting_index < 3;
if (is_valid) {
state->setting_progress[state->setting_index] = to_int(letter) + 1;
state->setting_index += 1;
if (state->setting_index == 3) {
state->default_settings.rotor_order[0] = state->setting_progress[0];
state->default_settings.rotor_order[1] = state->setting_progress[1];
state->default_settings.rotor_order[2] = state->setting_progress[2];
reset_settings(state);
clear_working_settings(state);
}
}
return is_valid;
}
bool handle_set_rotor_position(char letter, KeyboardState *state) {
bool is_valid = state->setting_index < 3; // Guaranteed to be A-Z already
if (is_valid) {
state->setting_progress[state->setting_index] = letter;
state->setting_index += 1;
if (state->setting_index == 3) {
state->default_settings.rotor_positions[0] = state->setting_progress[0];
state->default_settings.rotor_positions[1] = state->setting_progress[1];
state->default_settings.rotor_positions[2] = state->setting_progress[2];
reset_settings(state);
clear_working_settings(state);
}
}
return is_valid;
}
bool handle_set_rotor_ring(char letter, KeyboardState *state) {
bool is_valid = state->setting_index < 3;
if (is_valid) {
state->setting_progress[state->setting_index] = letter;
state->setting_index += 1;
if (state->setting_index == 3) {
state->default_settings.rotor_rings[0] = state->setting_progress[0];
state->default_settings.rotor_rings[1] = state->setting_progress[1];
state->default_settings.rotor_rings[2] = state->setting_progress[2];
reset_settings(state);
clear_working_settings(state);
}
}
return is_valid;
}
bool handle_set_plug(char letter, KeyboardState *state) {
bool is_valid = state->setting_index < 26;
if (is_valid) {
state->setting_progress[state->setting_index] = letter;
state->setting_index += 1;
}
return is_valid;
}
void handle_enigma_keypress(char letter, bool any_mods, KeyboardState *state) {
bool settings_valid = true;
if (letter) {
if (any_mods) {
tap_code(KC_A + to_int(letter));
} else if (state->is_setting_reflector) {
handle_set_reflector(letter, state);
} else if (state->is_setting_rotors) {
settings_valid = handle_set_rotor(letter, state);
} else if (state->is_setting_rotor_positions) {
settings_valid = handle_set_rotor_position(letter, state);
} else if (state->is_setting_rotor_rings) {
settings_valid = handle_set_rotor_ring(letter, state);
} else if (state->is_setting_plugs) {
settings_valid = handle_set_plug(letter, state);
} else {
char c2 = encipher(letter, &state->current_settings);
send_char(c2 - ('A' - 'a'));
}
}
if (!settings_valid) {
clear_working_settings(state);
}
}
KeyboardState STATE;
void keyboard_pre_init_user(void) {
init_enigma_default(&STATE.default_settings);
init_enigma_default(&STATE.current_settings);
clear_working_settings(&STATE);
}
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
uint8_t letter_index;
bool letter_found = false;
if (record->event.pressed) {
switch (keycode) {
case QWERTY:
set_layer(_QWERTY);
set_backlight(RGBLIGHT_MODE_RAINBOW_SWIRL + 4, HSV_PURPLE);
break;
case ENIGMA:
set_layer(_ENIGMA);
set_backlight(RGBLIGHT_MODE_STATIC_LIGHT, HSV_RED);
break;
case EN_SREF:
reset_settings(&STATE);
STATE.is_setting_reflector = true;
set_layer(_ENIGMA);
set_backlight(RGBLIGHT_MODE_SNAKE, HSV_RED);
break;
case EN_SROT:
reset_settings(&STATE);
STATE.is_setting_rotors = true;
STATE.setting_index = 0;
set_layer(_ENIGMA);
set_backlight(RGBLIGHT_MODE_SNAKE, 10, 255, 255);
break;
case EN_SPOS:
reset_settings(&STATE);
STATE.is_setting_rotor_positions = true;
STATE.setting_index = 0;
set_layer(_ENIGMA);
set_backlight(RGBLIGHT_MODE_SNAKE, HSV_ORANGE);
break;
case EN_SRIN:
reset_settings(&STATE);
STATE.is_setting_rotor_rings = true;
STATE.setting_index = 0;
set_layer(_ENIGMA);
set_backlight(RGBLIGHT_MODE_SNAKE, HSV_GREEN);
break;
case EN_SPLU:
reset_settings(&STATE);
STATE.is_setting_plugs = true;
STATE.setting_index = 0;
set_layer(_ENIGMA);
set_backlight(RGBLIGHT_MODE_SNAKE, HSV_BLUE);
break;
case QK_GESC:
if (
STATE.is_setting_reflector
|| STATE.is_setting_rotors
|| STATE.is_setting_rotor_positions
|| STATE.is_setting_rotor_rings
|| STATE.is_setting_plugs
) {
clear_working_settings(&STATE);
return false;
}
break;
case KC_ENT:
if (STATE.is_setting_plugs) {
commit_plug_settings(&STATE);
return false;
}
break;
case EN_A ... EN_Z:
letter_index = keycode - EN_A;
letter_found = true;
break;
case EN_RES:
reset_settings(&STATE);
break;
case EN_TEST:
perform_test(&STATE.current_settings);
break;
case EN_DIAG:
send_settings_string(&STATE.current_settings);
break;
case EN_BSPC:
rotors_reverse(&STATE.current_settings);
tap_code(KC_BSPC);
break;
}
}
char letter = letter_found ? 'A' + letter_index : 0;
uint8_t mods = get_mods();
bool any_mods = (mods & MOD_MASK_CTRL) || (mods & MOD_MASK_ALT) || (mods & MOD_MASK_GUI);
handle_enigma_keypress(letter, any_mods, &STATE);
return true;
}
void keyboard_post_init_user(void) {
set_layer(_QWERTY);
set_backlight(RGBLIGHT_MODE_RAINBOW_SWIRL + 4, HSV_PURPLE);
}

View File

@ -0,0 +1,35 @@
# A Contra Layout with an Enigma Emulator
```
,-----------------------------------------------------------------------------------.
| Esc | Q | W | E | R | T | Y | U | I | O | P | Bksp |
|------+------+------+------+------+-------------+------+------+------+------+------|
| Tab | A | S | D | F | G | H | J | K | L | ; | " |
|------+------+------+------+------+------|------+------+------+------+------+------|
| Shift| Z | X | C | V | B | N | M | , | . | / |Enter |
|------+------+------+------+------+------+------+------+------+------+------+------|
| Ctrl | Fn | Alt | GUI |Lower | Space |Raise | Left | Down | Up |Right |
`-----------------------------------------------------------------------------------'
```
By default, this layout functions like a normal QWERTY layout. But it also has an in-built Enigma machine emulator.
To enable the emulator, press `Fn+.`, and to go back to QWERTY, press `FN+,`.
A demonstration video can be found [here](https://youtu.be/p8kBjP1DCzo).
When 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.
There are a few key combinations for configuring and diagnosing the Enigma emulator:
* `Fn+Q` resets the emulator to the last-configured settings
* `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)
* `Fn+P` types out 1000 enciphered As, for testing
* `Fn+Backspace` back-rotates the rotors one step, for fixing typos without having to re-type a whole message
* `Fn+Z` followed by A, B, or C is used to set the reflector
* `Fn+X` followed by three characters A-E is used to set the rotors
* `Fn+C` followed by three characters A-Z is used to set the rotor positions
* `Fn+V` followed by three characters A-Z is used to set the ring settings
* `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

View File

@ -0,0 +1,2 @@
RGBLIGHT_ENABLE = yes
RGBLIGHT_SUPPORTED = yes