array based actions for chords instead of switch-case
This commit is contained in:
parent
76cbc6888f
commit
f806133f9c
1 changed files with 99 additions and 201 deletions
300
smol_gkos.ino
300
smol_gkos.ino
|
@ -23,17 +23,7 @@ const byte PIN_BALL_SDA = 18;
|
|||
const byte PIN_BALL_SCL = 19;
|
||||
const byte PIN_BALL_INT = 11;
|
||||
|
||||
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;
|
||||
|
||||
enum Button { A, B, C, D, E, F, MouseUL, MouseUR, MouseDL, MouseDR };
|
||||
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
|
||||
|
@ -41,12 +31,50 @@ const int button_pins[10] = {
|
|||
const int debounce_time = 400;
|
||||
int button_timers[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
// TODO: differentiate between GKOS modifiers and keyboard modifiers somehow
|
||||
// different actions that the keyboard can take
|
||||
// - print a single character
|
||||
// - press (and release) a key
|
||||
// - toggle a modifier
|
||||
enum ActionType { PrintCharacter, PressKey, ToggleModifier };
|
||||
|
||||
/*
|
||||
backspace, space (keep those two first since they overlap with the rest )
|
||||
g, k, o, s, w, native
|
||||
*/
|
||||
const byte modifiers[8] = { 7, 56, 24, 48, 3, 6, 40, 5 };
|
||||
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',
|
||||
' ', ' ', ' ', ' '
|
||||
};
|
||||
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
|
||||
};
|
||||
|
||||
/*
|
||||
dash, backslash, slash, apostrophe, comma, exclamation point, question mark,
|
||||
|
@ -57,10 +85,6 @@ 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,
|
||||
|
@ -68,11 +92,14 @@ const int special_action_targets[22] = {
|
|||
KEY_ESC, Modifier::Control, Modifier::Alt, KEY_DELETE, KEY_INSERT,
|
||||
KEY_TAB, KEY_ENTER
|
||||
};
|
||||
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 modifier_used = false;
|
||||
bool modified_pressed = false;
|
||||
bool chord_used = false;
|
||||
bool chorded_pressed = false;
|
||||
|
||||
void setup() {
|
||||
pinMode(PIN_A, INPUT_PULLUP);
|
||||
|
@ -121,8 +148,8 @@ void loop() {
|
|||
if (key_pressed == 0) {
|
||||
key_pressed_total = 0;
|
||||
// clear flags
|
||||
modifier_used = false;
|
||||
modified_pressed = false;
|
||||
chord_used = false;
|
||||
chorded_pressed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -145,229 +172,100 @@ void key_released(byte key) {
|
|||
}
|
||||
}
|
||||
|
||||
if (is_special && !modifier_used) {
|
||||
if (is_special && !chord_used) {
|
||||
// only register a special keypress when all keys have been released
|
||||
if (key_pressed != 0)
|
||||
return;
|
||||
|
||||
switch (special_action_types[special]) {
|
||||
case SpecialType::PrintCharacter:
|
||||
switch (special_action_target_types[special]) {
|
||||
case ActionType::PrintCharacter:
|
||||
Keyboard.print((char)special_action_targets[special]);
|
||||
return;
|
||||
case SpecialType::PressKey:
|
||||
case ActionType::PressKey:
|
||||
Keyboard.press(special_action_targets[special]);
|
||||
Keyboard.release(special_action_targets[special]);
|
||||
return;
|
||||
case SpecialType::ToggleModifier:
|
||||
case ActionType::ToggleModifier:
|
||||
// TODO
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
MODIFIERS
|
||||
CHORDS
|
||||
*/
|
||||
bool is_modifier = false;
|
||||
byte modifier = 0;
|
||||
bool is_chord = false;
|
||||
byte chord = 0;
|
||||
for (byte b = 0; b < 8; b++) {
|
||||
if ((key_pressed_total & modifiers[b]) == modifiers[b]) {
|
||||
is_modifier = true;
|
||||
modifier = b;
|
||||
modifier_used = true;
|
||||
if ((key_pressed_total & chords[b]) == chords[b]) {
|
||||
is_chord = true;
|
||||
chord = b;
|
||||
chord_used = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
if (is_chord) {
|
||||
// chord on its own
|
||||
if (!chorded_pressed && key_pressed == 0 &&
|
||||
key_pressed_total == chords[chord]) {
|
||||
switch (chord_target_types[chord * 4]) {
|
||||
case ActionType::PrintCharacter:
|
||||
Keyboard.print((char)chord_targets[chord * 4]);
|
||||
return;
|
||||
}
|
||||
if (key == BUTTON_D || key == BUTTON_E) {
|
||||
Keyboard.press(KEY_LEFT);
|
||||
Keyboard.release(KEY_LEFT);
|
||||
key_pressed_total &= ~(1 << key);
|
||||
modified_pressed = true;
|
||||
case ActionType::PressKey:
|
||||
Keyboard.press(chord_targets[chord * 4]);
|
||||
Keyboard.release(chord_targets[chord * 4]);
|
||||
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;
|
||||
}
|
||||
// keys that can be chorded with
|
||||
for (byte b = 0; b < 3; b++) {
|
||||
if (key == chord_buttons[chord * 3 + b]) {
|
||||
Serial.print(chord);
|
||||
Serial.println(" pressed");
|
||||
// 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)chord_targets[chord * 4 + 1 + b]);
|
||||
return;
|
||||
case ActionType::PressKey:
|
||||
Keyboard.press(chord_targets[chord * 4 + 1 + b]);
|
||||
Keyboard.release(chord_targets[chord * 4 + 1 + b]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
REGULAR KEYS
|
||||
*/
|
||||
switch (key) {
|
||||
case BUTTON_A:
|
||||
case Button::A:
|
||||
Keyboard.print('a');
|
||||
return;
|
||||
case BUTTON_B:
|
||||
case Button::B:
|
||||
Keyboard.print('b');
|
||||
return;
|
||||
case BUTTON_C:
|
||||
case Button::C:
|
||||
Keyboard.print('c');
|
||||
return;
|
||||
case BUTTON_D:
|
||||
case Button::D:
|
||||
Keyboard.print('d');
|
||||
return;
|
||||
case BUTTON_E:
|
||||
case Button::E:
|
||||
Keyboard.print('e');
|
||||
return;
|
||||
case BUTTON_F:
|
||||
case Button::F:
|
||||
Keyboard.print('f');
|
||||
return;
|
||||
default:
|
||||
Serial.print("unknown key ");
|
||||
Serial.println(key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue