Compare commits

..

No commits in common. "c7de79c4e5416fd8174e995609ad9e96143e68cc" and "76cbc6888f0460a3b57ecec4e726d3350773ebfd" have entirely different histories.

View file

@ -23,7 +23,17 @@ const byte PIN_BALL_SDA = 18;
const byte PIN_BALL_SCL = 19; const byte PIN_BALL_SCL = 19;
const byte PIN_BALL_INT = 11; 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] = { const int button_pins[10] = {
PIN_A, PIN_B, PIN_C, PIN_D, PIN_E, PIN_F, PIN_A, PIN_B, PIN_C, PIN_D, PIN_E, PIN_F,
PIN_MOUSE_UL, PIN_MOUSE_UR, PIN_MOUSE_DL, PIN_MOUSE_DR 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; const int debounce_time = 400;
int button_timers[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int button_timers[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
// different actions that the keyboard can take // TODO: differentiate between GKOS modifiers and keyboard modifiers somehow
// - 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' };
/* /*
backspace, space (keep those two first since they overlap with the rest ) backspace, space (keep those two first since they overlap with the rest )
g, k, o, s, w, native g, k, o, s, w, native
*/ */
const byte chords[8] = { 7, 56, 24, 48, 3, 6, 40, 5 }; const byte modifiers[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
};
/* /*
dash, backslash, slash, apostrophe, comma, exclamation point, question mark, 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, 17, 51, 30, 10, 20, 12, 33, 34, 9, 36, 27,
54, 18, 45, 63, 31, 47, 55, 62, 43, 61, 59 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 }; enum Modifier { Shift, SymbolShift, Keyset, Control, Alt };
const int special_action_targets[22] = { const int special_action_targets[22] = {
'-', '\\', '/', '\'', ',', '!', '?', '/', KEY_UP, KEY_DOWN, KEY_PAGE_UP, '-', '\\', '/', '\'', ',', '!', '?', '/', 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_ESC, Modifier::Control, Modifier::Alt, KEY_DELETE, KEY_INSERT,
KEY_TAB, KEY_ENTER 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 = 0;
byte key_pressed_total = 0; byte key_pressed_total = 0;
bool chord_used = false; bool modifier_used = false;
bool chorded_pressed = false; bool modified_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;
void setup() { void setup() {
pinMode(PIN_A, INPUT_PULLUP); pinMode(PIN_A, INPUT_PULLUP);
@ -184,15 +117,12 @@ void loop() {
if (b < 6) { if (b < 6) {
key_pressed &= ~(1 << b); key_pressed &= ~(1 << b);
// gkos key was released, check if it completed a chord // gkos key was released, check if it completed a chord
// clear temporary modifiers if a keypress was completed key_released(b);
if (key_released(b))
mod_shift = mod_symbol = mod_control = mod_alt = false;
update_leds();
if (key_pressed == 0) { if (key_pressed == 0) {
key_pressed_total = 0; key_pressed_total = 0;
// clear flags // clear flags
chord_used = false; modifier_used = false;
chorded_pressed = false; modified_pressed = false;
} }
} }
} }
@ -201,10 +131,7 @@ void loop() {
} }
} }
// returns true if a keypress was completed void key_released(byte key) {
bool key_released(byte key) {
int target = 0;
/* /*
SPECIALS 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 // only register a special keypress when all keys have been released
if (key_pressed != 0) if (key_pressed != 0)
return false; return;
target = special_action_targets[special]; switch (special_action_types[special]) {
if (mod_shift || mod_shift_lock || mod_symbol || mod_symbol_lock) { case SpecialType::PrintCharacter:
if (special_action_targets_symbol[special] != 0) Keyboard.print((char)special_action_targets[special]);
target = special_action_targets_symbol[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; bool is_modifier = false;
byte chord = 0; byte modifier = 0;
for (byte b = 0; b < 8; b++) { for (byte b = 0; b < 8; b++) {
if ((key_pressed_total & chords[b]) == chords[b]) { if ((key_pressed_total & modifiers[b]) == modifiers[b]) {
is_chord = true; is_modifier = true;
chord = b; modifier = b;
chord_used = true; modifier_used = true;
break; break;
} }
} }
if (is_chord) { if (is_modifier) {
// chord on its own switch (modifier) {
if (!chorded_pressed && key_pressed == 0 && case 0: // backspace
key_pressed_total == chords[chord]) { if (!modified_pressed && key_pressed == 0 &&
target = chord_targets[chord * 4]; key_pressed_total == modifiers[modifier]) {
if (mod_shift || mod_shift_lock) Keyboard.press(KEY_BACKSPACE);
target = chord_targets_shifted[chord * 4]; Keyboard.release(KEY_BACKSPACE);
else if (mod_symbol || mod_symbol_lock) return;
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; if (key == BUTTON_D || key == BUTTON_E) {
} Keyboard.press(KEY_LEFT);
// keys that can be chorded with Keyboard.release(KEY_LEFT);
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); key_pressed_total &= ~(1 << key);
chorded_pressed = true; modified_pressed = true;
switch (chord_target_types[chord * 4 + 1 + b]) { return;
case ActionType::PrintCharacter: } else if (key == BUTTON_F) {
Keyboard.print((char)target); Keyboard.press(KEY_HOME);
return true; Keyboard.release(KEY_HOME);
case ActionType::PressKey: key_pressed_total &= ~(1 << key);
Keyboard.press(target); modified_pressed = true;
Keyboard.release(target); return;
return true;
} }
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 REGULAR KEYS
*/ */
if (mod_shift || mod_shift_lock) switch (key) {
Keyboard.print(button_characters_shifted[key]); case BUTTON_A:
else if (mod_symbol || mod_symbol_lock) Keyboard.print('a');
Keyboard.print(button_characters_symbol[key]); return;
else case BUTTON_B:
Keyboard.print(button_characters[key]); Keyboard.print('b');
return true; return;
} case BUTTON_C:
Keyboard.print('c');
void update_leds() { return;
digitalWrite(PIN_LED1, mod_shift || mod_shift_lock); case BUTTON_D:
digitalWrite(PIN_LED2, mod_symbol || mod_symbol_lock); Keyboard.print('d');
digitalWrite(PIN_LED3, mod_control || mod_alt); return;
case BUTTON_E:
Keyboard.print('e');
return;
case BUTTON_F:
Keyboard.print('f');
return;
default:
Serial.print("unknown key ");
Serial.println(key);
return;
}
} }