diff --git a/smol_gkos.ino b/smol_gkos.ino index 6fd3864..262d64b 100644 --- a/smol_gkos.ino +++ b/smol_gkos.ino @@ -23,7 +23,17 @@ const byte PIN_BALL_SDA = 18; const byte PIN_BALL_SCL = 19; const byte PIN_BALL_INT = 11; -enum Button { A, B, C, D, E, F, MouseUL, MouseUR, MouseDL, MouseDR }; +const byte BUTTON_A = 0; +const byte BUTTON_B = 1; +const byte BUTTON_C = 2; +const byte BUTTON_D = 3; +const byte BUTTON_E = 4; +const byte BUTTON_F = 5; +const byte BUTTON_MOUSE_UL = 6; +const byte BUTTON_MOUSE_UR = 7; +const byte BUTTON_MOUSE_DL = 8; +const byte BUTTON_MOUSE_DR = 9; + const int button_pins[10] = { PIN_A, PIN_B, PIN_C, PIN_D, PIN_E, PIN_F, PIN_MOUSE_UL, PIN_MOUSE_UR, PIN_MOUSE_DL, PIN_MOUSE_DR @@ -31,76 +41,12 @@ const int button_pins[10] = { const int debounce_time = 400; int button_timers[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -// different actions that the keyboard can take -// - print a single character -// - press (and release) a key -// - toggle a modifier -enum ActionType { PrintCharacter, PressKey, ToggleModifier }; - -const char button_characters[6] = { 'a', 'b', 'c', 'd', 'e', 'f' }; -const char button_characters_shifted[6] = { 'A', 'B', 'C', 'D', 'E', 'F' }; -const char button_characters_symbol[6] = { '1', '2', '3', '4', '5', '6' }; - +// TODO: differentiate between GKOS modifiers and keyboard modifiers somehow /* backspace, space (keep those two first since they overlap with the rest ) g, k, o, s, w, native */ -const byte chords[8] = { 7, 56, 24, 48, 3, 6, 40, 5 }; -// buttons that can be combined with a chord for a keypress -const byte chord_buttons[24] = { - Button::D, Button::E, Button::F, - Button::A, Button::B, Button::C, - Button::A, Button::B, Button::C, - Button::A, Button::B, Button::C, - Button::D, Button::E, Button::F, - Button::D, Button::E, Button::F, - Button::A, Button::B, Button::C, - Button::D, Button::E, Button::F, -}; -// keypresses for chords in sets of 4 -// index 0 is the chord on its own, 1-3 correspond to chord_buttons -const int chord_targets[32] = { - KEY_BACKSPACE, KEY_LEFT, KEY_LEFT, KEY_HOME, - KEY_SPACE, KEY_RIGHT, KEY_RIGHT, KEY_END, - 'g', 'h', 'i', 'j', - 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', - 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z', - 0, 0, 0, 0 -}; -const int chord_targets_shifted[32] = { - KEY_BACKSPACE, KEY_LEFT, KEY_LEFT, KEY_HOME, - KEY_SPACE, KEY_RIGHT, KEY_RIGHT, KEY_END, - 'G', 'H', 'I', 'J', - 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', - 'S', 'T', 'U', 'V', - 'W', 'X', 'Y', 'Z', - 0, 0, 0, 0 -}; -// TODO: check that all the symbols work -// TODO: match symbols to keypresses in the keyboard layout -const int chord_targets_symbol[32] = { - KEY_BACKSPACE, KEY_LEFT, KEY_LEFT, KEY_HOME, - KEY_SPACE, KEY_RIGHT, KEY_RIGHT, KEY_END, - '0', '7', '8', '9', - '#', '@', '½', '&', - '+', '%', '=', '^', - '*', '$', '€', '£', - '(', '[', '<', '{', - ')', ']', '>', '}' -}; -const byte chord_target_types[32] = { - 1, 1, 1, 1, - 1, 1, 1, 1, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0 -}; +const byte modifiers[8] = { 7, 56, 24, 48, 3, 6, 40, 5 }; /* dash, backslash, slash, apostrophe, comma, exclamation point, question mark, @@ -111,6 +57,10 @@ const byte specials[22] = { 17, 51, 30, 10, 20, 12, 33, 34, 9, 36, 27, 54, 18, 45, 63, 31, 47, 55, 62, 43, 61, 59 }; +enum SpecialType { PrintCharacter, PressKey, ToggleModifier }; +const byte special_action_types[22] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 1, 1, 1, 1 +}; enum Modifier { Shift, SymbolShift, Keyset, Control, Alt }; const int special_action_targets[22] = { '-', '\\', '/', '\'', ',', '!', '?', '/', KEY_UP, KEY_DOWN, KEY_PAGE_UP, @@ -118,28 +68,11 @@ const int special_action_targets[22] = { KEY_ESC, Modifier::Control, Modifier::Alt, KEY_DELETE, KEY_INSERT, KEY_TAB, KEY_ENTER }; -const int special_action_targets_symbol[22] = { - '_', '\`', 0, '\"', ';', '|', '~', ':', 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0 -}; -const byte special_action_target_types[22] = { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 1, 1, 1, 1 -}; byte key_pressed = 0; byte key_pressed_total = 0; -bool chord_used = false; -bool chorded_pressed = false; - -bool mod_shift = false; -bool mod_shift_lock = false; -bool mod_symbol = false; -bool mod_symbol_lock = false; -// TODO: control and alt modifiers -bool mod_control = false; -bool mod_alt = false; +bool modifier_used = false; +bool modified_pressed = false; void setup() { pinMode(PIN_A, INPUT_PULLUP); @@ -184,15 +117,12 @@ void loop() { if (b < 6) { key_pressed &= ~(1 << b); // gkos key was released, check if it completed a chord - // clear temporary modifiers if a keypress was completed - if (key_released(b)) - mod_shift = mod_symbol = mod_control = mod_alt = false; - update_leds(); + key_released(b); if (key_pressed == 0) { key_pressed_total = 0; // clear flags - chord_used = false; - chorded_pressed = false; + modifier_used = false; + modified_pressed = false; } } } @@ -201,10 +131,7 @@ void loop() { } } -// returns true if a keypress was completed -bool key_released(byte key) { - int target = 0; - +void key_released(byte key) { /* SPECIALS */ @@ -218,133 +145,229 @@ bool key_released(byte key) { } } - if (is_special && !chord_used) { + if (is_special && !modifier_used) { // only register a special keypress when all keys have been released if (key_pressed != 0) - return false; + return; - target = special_action_targets[special]; - if (mod_shift || mod_shift_lock || mod_symbol || mod_symbol_lock) { - if (special_action_targets_symbol[special] != 0) - target = special_action_targets_symbol[special]; + switch (special_action_types[special]) { + case SpecialType::PrintCharacter: + Keyboard.print((char)special_action_targets[special]); + return; + case SpecialType::PressKey: + Keyboard.press(special_action_targets[special]); + Keyboard.release(special_action_targets[special]); + return; + case SpecialType::ToggleModifier: + // TODO + return; } - - switch (special_action_target_types[special]) { - case ActionType::PrintCharacter: - Keyboard.print((char)target); - return true; - case ActionType::PressKey: - Keyboard.press(target); - Keyboard.release(target); - return true; - case ActionType::ToggleModifier: - switch (target) { - case Modifier::Shift: - mod_symbol = mod_symbol_lock = false; - if (mod_shift_lock) { - mod_shift_lock = false; - } else if (mod_shift) { - mod_shift = false; - mod_shift_lock = true; - } else { - mod_shift = true; - } - return false; - case Modifier::SymbolShift: - mod_shift = mod_shift_lock = mod_symbol_lock = false; - mod_symbol = !mod_symbol; - return false; - case Modifier::Keyset: - mod_shift = mod_shift_lock = mod_symbol = false; - mod_symbol_lock = !mod_symbol_lock; - return false; - case Modifier::Control: - mod_control = !mod_control; - return false; - case Modifier::Alt: - mod_alt = !mod_alt; - return false; - } - } - return false; } /* - CHORDS + MODIFIERS */ - bool is_chord = false; - byte chord = 0; + bool is_modifier = false; + byte modifier = 0; for (byte b = 0; b < 8; b++) { - if ((key_pressed_total & chords[b]) == chords[b]) { - is_chord = true; - chord = b; - chord_used = true; + if ((key_pressed_total & modifiers[b]) == modifiers[b]) { + is_modifier = true; + modifier = b; + modifier_used = true; break; } } - if (is_chord) { - // chord on its own - if (!chorded_pressed && key_pressed == 0 && - key_pressed_total == chords[chord]) { - target = chord_targets[chord * 4]; - if (mod_shift || mod_shift_lock) - target = chord_targets_shifted[chord * 4]; - else if (mod_symbol || mod_symbol_lock) - target = chord_targets_symbol[chord * 4]; - - switch (chord_target_types[chord * 4]) { - case ActionType::PrintCharacter: - Keyboard.print((char)target); - return true; - case ActionType::PressKey: - Keyboard.press(target); - Keyboard.release(target); - return true; - } - return false; - } - // keys that can be chorded with - for (byte b = 0; b < 3; b++) { - if (key == chord_buttons[chord * 3 + b]) { - target = chord_targets[chord * 4 + 1 + b]; - if (mod_shift || mod_shift_lock) - target = chord_targets_shifted[chord * 4 + 1 + b]; - else if (mod_symbol || mod_symbol_lock) - target = chord_targets_symbol[chord * 4 + 1 + b]; - - // erase key from total so you can hold the chord down for - // multiple chorded keypresses - key_pressed_total &= ~(1 << key); - chorded_pressed = true; - switch (chord_target_types[chord * 4 + 1 + b]) { - case ActionType::PrintCharacter: - Keyboard.print((char)target); - return true; - case ActionType::PressKey: - Keyboard.press(target); - Keyboard.release(target); - return true; + if (is_modifier) { + switch (modifier) { + case 0: // backspace + if (!modified_pressed && key_pressed == 0 && + key_pressed_total == modifiers[modifier]) { + Keyboard.press(KEY_BACKSPACE); + Keyboard.release(KEY_BACKSPACE); + return; } - } + if (key == BUTTON_D || key == BUTTON_E) { + Keyboard.press(KEY_LEFT); + Keyboard.release(KEY_LEFT); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } else if (key == BUTTON_F) { + Keyboard.press(KEY_HOME); + Keyboard.release(KEY_HOME); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } + return; + case 1: // space + if (!modified_pressed && key_pressed == 0 && + key_pressed_total == modifiers[modifier]) { + Keyboard.press(KEY_SPACE); + Keyboard.release(KEY_SPACE); + return; + } + if (key == BUTTON_A || key == BUTTON_B) { + Keyboard.press(KEY_RIGHT); + Keyboard.release(KEY_RIGHT); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } else if (key == BUTTON_C) { + Keyboard.press(KEY_END); + Keyboard.release(KEY_END); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } + return; + case 2: // G + if (!modified_pressed && key_pressed == 0 && + key_pressed_total == modifiers[modifier]) { + Keyboard.print('g'); + return; + } + if (key == BUTTON_A) { + Keyboard.print('h'); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } else if (key == BUTTON_B) { + Keyboard.print('i'); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } else if (key == BUTTON_C) { + Keyboard.print('j'); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } + return; + case 3: // K + if (!modified_pressed && key_pressed == 0 && + key_pressed_total == modifiers[modifier]) { + Keyboard.print('k'); + return; + } + if (key == BUTTON_A) { + Keyboard.print('l'); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } else if (key == BUTTON_B) { + Keyboard.print('m'); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } else if (key == BUTTON_C) { + Keyboard.print('n'); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } + return; + case 4: // O + if (!modified_pressed && key_pressed == 0 && + key_pressed_total == modifiers[modifier]) { + Keyboard.print('o'); + return; + } + if (key == BUTTON_D) { + Keyboard.print('p'); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } else if (key == BUTTON_E) { + Keyboard.print('q'); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } else if (key == BUTTON_F) { + Keyboard.print('r'); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } + return; + case 5: // S + if (!modified_pressed && key_pressed == 0 && + key_pressed_total == modifiers[modifier]) { + Keyboard.print('s'); + return; + } + if (key == BUTTON_D) { + Keyboard.print('t'); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } else if (key == BUTTON_E) { + Keyboard.print('u'); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } else if (key == BUTTON_F) { + Keyboard.print('v'); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } + return; + case 6: // W + if (!modified_pressed && key_pressed == 0 && + key_pressed_total == modifiers[modifier]) { + Keyboard.print('w'); + return; + } + if (key == BUTTON_A) { + Keyboard.print('x'); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } else if (key == BUTTON_B) { + Keyboard.print('y'); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } else if (key == BUTTON_C) { + Keyboard.print('z'); + key_pressed_total &= ~(1 << key); + modified_pressed = true; + return; + } + return; + case 7: // native + // TODO + return; } - return false; } /* REGULAR KEYS */ - if (mod_shift || mod_shift_lock) - Keyboard.print(button_characters_shifted[key]); - else if (mod_symbol || mod_symbol_lock) - Keyboard.print(button_characters_symbol[key]); - else - Keyboard.print(button_characters[key]); - return true; -} - -void update_leds() { - digitalWrite(PIN_LED1, mod_shift || mod_shift_lock); - digitalWrite(PIN_LED2, mod_symbol || mod_symbol_lock); - digitalWrite(PIN_LED3, mod_control || mod_alt); + switch (key) { + case BUTTON_A: + Keyboard.print('a'); + return; + case BUTTON_B: + Keyboard.print('b'); + return; + case BUTTON_C: + Keyboard.print('c'); + return; + case BUTTON_D: + Keyboard.print('d'); + return; + case BUTTON_E: + Keyboard.print('e'); + return; + case BUTTON_F: + Keyboard.print('f'); + return; + default: + Serial.print("unknown key "); + Serial.println(key); + return; + } }