File keyboard.cpp
File List > keyboard > keyboard.cpp
Go to the documentation of this file
#include "keyboard.hpp"
#include "keys.hpp"
uint8_t rows[] = {1, 4, 5, 11, 13};
uint8_t cols[] = {0, 3, 19, 12, 18, 6, 7};
bool lastValue[ROW_COUNT][COL_COUNT];
KeyState keyStates[ROW_COUNT][COL_COUNT];
// Keys wrapped in square brackets require special handling
// default column in functionality.md
// { q, w, [sym], a, [alt], [space], [mic] }
// { e, s, d, p, x, z, [lshift] }
// { r, g, t, [rshift], v, c, f }
// { u, h, y, [enter], b, n, j }
// { o, l, i, [backspace], [$], m, k }
char defaultKeymap[ROW_COUNT][COL_COUNT] = {
{LATIN_SMALL_LETTER_Q, LATIN_SMALL_LETTER_W, NULL, LATIN_SMALL_LETTER_A, NULL, NULL, NULL},
{LATIN_SMALL_LETTER_E, LATIN_SMALL_LETTER_S, LATIN_SMALL_LETTER_D, LATIN_SMALL_LETTER_P, LATIN_SMALL_LETTER_X, LATIN_SMALL_LETTER_Z, NULL},
{LATIN_SMALL_LETTER_R, LATIN_SMALL_LETTER_G, LATIN_SMALL_LETTER_T, NULL, LATIN_SMALL_LETTER_V, LATIN_SMALL_LETTER_C, LATIN_SMALL_LETTER_F},
{LATIN_SMALL_LETTER_U, LATIN_SMALL_LETTER_H, LATIN_SMALL_LETTER_Y, NULL, LATIN_SMALL_LETTER_B, LATIN_SMALL_LETTER_N, LATIN_SMALL_LETTER_J},
{LATIN_SMALL_LETTER_O, LATIN_SMALL_LETTER_L, LATIN_SMALL_LETTER_I, NULL, DOLLAR_SIGN, LATIN_SMALL_LETTER_M, LATIN_SMALL_LETTER_K}
};
// symbol 1 column in functionality.md
// { #, 1, [sym], *, [alt], [space], [0] }
// { 2, 4, 5, @, 8, 7, [lshift] }
// { 3, /, (, [rshift], ?, 9, 6 }
// { _, :, ), [enter], !, ,, ; }
// { +, ", -, [backspace], [¢], ., ' }
char symbolKeymap1[ROW_COUNT][COL_COUNT] = {
{NUMBER_SIGN, DIGIT_ONE, NULL, ASTERISK, NULL, NULL, DIGIT_ZERO},
{DIGIT_TWO, DIGIT_FOUR, DIGIT_FIVE, COMMERCIAL_AT, DIGIT_EIGHT, DIGIT_SEVEN, NULL},
{DIGIT_THREE, SOLIDUS, LEFT_PARENTHESIS, NULL, QUESTION_MARK, DIGIT_NINE, DIGIT_SIX},
{LOW_LINE, COLON, RIGHT_PARENTHESIS, NULL, EXCLAMATION_MARK, COMMA, SEMICOLON},
{PLUS_SIGN, QUOTATION_MARK, HYPHEN_MINUS, NULL, CENT_SIGN, FULL_STOP, APOSTROPHE}
};
// symbol 2 column in functionality.md
// { `, %, [sym], ª, [alt], [space], [NBSP] }
// { &, º, ⌐, =, ∞, µ, [lshift] }
// { £, \, {, [rshift], ¿, ², ¬ }
// { ^, ½, }, [enter], ¡, ∩, ¼ }
// { >, », <, [backspace], [₧], ~, « }
char symbolKeymap2[ROW_COUNT][COL_COUNT] = {
{GRAVE_ACCENT, PERCENT_SIGN, NULL, FEMININE_ORDINAL_INDICATOR, NULL, NULL, NO_BREAK_SPACE},
{AMPERSAND, MASCULINE_ORDINAL_INDICATOR, REVERSED_NOT_SIGN, EQUALS_SIGN, INFINITY, MICRO_SIGN, NULL},
{POUND_SIGN, REVERSE_SOLIDUS, LEFT_CURLY_BRACKET, NULL, INVERTED_QUESTION_MARK, SUPERSCRIPT_TWO, NOT_SIGN},
{CIRCUMFLEX_ACCENT, VULGAR_FRACTION_ONE_HALF, RIGHT_CURLY_BRACKET, NULL, INVERTED_EXCLAMATION_MARK, INTERSECTION, VULGAR_FRACTION_ONE_QUARTER},
{GREATER_THAN_SIGN, RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK, LESS_THAN_SIGN, NULL, PESETA_SIGN, TILDE, LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK}
};
// symbol 3 column in functionality.md
// { ⌠, ⌡, [sym], ≈, [alt], [space], [NULL] }
// { ÷, °, ∙, ≡, NULL, NULL, [lshift] }
// { ¥, √, [, [rshift], NULL, ⁿ, · }
// { ±, \, ], [enter], NULL, NULL, ƒ }
// { ≥, NULL, ≤, [backspace], [NULL], NULL, NULL }
char symbolKeymap3[ROW_COUNT][COL_COUNT] = {
{TOP_HALF_INTEGRAL, BOTTOM_HALF_INTEGRAL, NULL, ALMOST_EQUAL_TO, NULL, NULL, NULL},
{DIVISION_SIGN, DEGREE_SIGN, BULLET_OPERATOR, IDENTICAL_TO, NULL, NULL, NULL},
{YEN_SIGN, SQUARE_ROOT, LEFT_SQUARE_BRACKET, NULL, NULL, SUPERSCRIPT_LATIN_SMALL_LETTER_N, MIDDLE_DOT},
{PLUS_MINUS_SIGN, REVERSE_SOLIDUS, RIGHT_SQUARE_BRACKET, NULL, NULL, NULL, LATIN_SMALL_LETTER_F_WITH_HOOK},
{GREATER_THAN_OR_EQUAL_TO, NULL, LESS_THAN_OR_EQUAL_TO, NULL, NULL, NULL, NULL}
};
// symbol 4 column in functionality.md
// { â, ä, [sym], Ç, [alt], [space], [NULL] }
// { à, ß, é, ç, í, ì, [lshift] }
// { å, ë, á, [rshift], Ñ, ñ, ê }
// { Å, è, Ä, [enter], ô, ö, É }
// { Æ, î, æ, [backspace], [NULL], ò, ï }
char symbolKeymap4[ROW_COUNT][COL_COUNT] = {
{LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX, LATIN_SMALL_LETTER_A_WITH_DIAERESIS, NULL, LATIN_CAPITAL_LETTER_C_WITH_CEDILLA, NULL, NULL, NULL},
{LATIN_SMALL_LETTER_A_WITH_GRAVE, LATIN_SMALL_LETTER_SHARP_S, LATIN_SMALL_LETTER_E_WITH_ACUTE, LATIN_SMALL_LETTER_C_WITH_CEDILLA, LATIN_SMALL_LETTER_I_WITH_ACUTE, LATIN_SMALL_LETTER_I_WITH_GRAVE, NULL},
{LATIN_SMALL_LETTER_A_WITH_RING_ABOVE, LATIN_SMALL_LETTER_E_WITH_DIAERESIS, LATIN_SMALL_LETTER_A_WITH_ACUTE, NULL, LATIN_CAPITAL_LETTER_N_WITH_TILDE, LATIN_SMALL_LETTER_N_WITH_TILDE, LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX},
{LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE, LATIN_SMALL_LETTER_E_WITH_GRAVE, LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS, NULL, LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX, LATIN_SMALL_LETTER_O_WITH_DIAERESIS, LATIN_CAPITAL_LETTER_E_WITH_ACUTE},
{LATIN_CAPITAL_LIGATURE_AE, LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX, LATIN_SMALL_LIGATURE_AE, NULL, NULL, LATIN_SMALL_LETTER_O_WITH_GRAVE, LATIN_SMALL_LETTER_I_WITH_DIAERESIS}
};
// symbol 5 column in functionality.md
// { Ö, ó, [sym], π, [alt], [space], [NULL] }
// { ü, Σ, σ, Γ, NULL, ε, [lshift] }
// { û, Φ, ù, [rshift], NULL, NULL, τ }
// { ú, Θ, Ü, [enter], NULL, NULL, Ω }
// { α, φ, ÿ, [backspace], [NULL], NULL, δ }
char symbolKeymap5[ROW_COUNT][COL_COUNT] = {
{LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS, LATIN_SMALL_LETTER_O_WITH_ACUTE, NULL, GREEK_SMALL_LETTER_PI, NULL, NULL, NULL},
{LATIN_SMALL_LETTER_U_WITH_DIAERESIS, GREEK_CAPITAL_LETTER_SIGMA, GREEK_SMALL_LETTER_SIGMA, GREEK_CAPITAL_LETTER_GAMMA, NULL, GREEK_SMALL_LETTER_EPSILON, NULL},
{LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX, GREEK_CAPITAL_LETTER_PHI, LATIN_SMALL_LETTER_U_WITH_GRAVE, NULL, NULL, NULL, GREEK_SMALL_LETTER_TAU},
{LATIN_SMALL_LETTER_U_WITH_ACUTE, GREEK_CAPITAL_LETTER_THETA, LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS, NULL, NULL, NULL, GREEK_CAPITAL_LETTER_OMEGA},
{GREEK_SMALL_LETTER_ALPHA, GREEK_SMALL_LETTER_PHI, LATIN_SMALL_LETTER_Y_WITH_DIAERESIS, NULL, NULL, NULL, GREEK_SMALL_LETTER_DELTA}
};
// symbol 6 column in functionality.md
// { │, ┤, [sym], ╜, [alt], [space], [NULL] }
// { ╡, ╛, ┐, ╝, ╟, ╞, [lshift] }
// { ╢, ┴, ╖, [rshift], ╔, ╚, └ }
// { ╣, ┬, ╕, [enter], ╩, ╦, ├ }
// { ╗, ┼, ║, [backspace], [═], ╠, ─ }
char symbolKeymap6[ROW_COUNT][COL_COUNT] = {
{BOX_DRAWINGS_LIGHT_VERTICAL, BOX_DRAWINGS_LIGHT_VERTICAL_AND_LEFT, NULL, BOX_DRAWINGS_UP_SINGLE_AND_HORIZONTAL_DOUBLE, NULL, NULL, NULL},
{BOX_DRAWINGS_VERTICAL_SINGLE_AND_LEFT_DOUBLE, BOX_DRAWINGS_UP_SINGLE_AND_HORIZONTAL_DOUBLE, BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT, BOX_DRAWINGS_DOUBLE_UP_AND_LEFT, BOX_DRAWINGS_VERTICAL_DOUBLE_AND_RIGHT_SINGLE, BOX_DRAWINGS_VERTICAL_SINGLE_AND_RIGHT_DOUBLE, NULL},
{BOX_DRAWINGS_VERTICAL_DOUBLE_AND_LEFT_SINGLE, BOX_DRAWINGS_LIGHT_UP_AND_HORIZONTAL, BOX_DRAWINGS_DOWN_DOUBLE_AND_LEFT_SINGLE, NULL, BOX_DRAWINGS_DOUBLE_DOWN_AND_RIGHT, BOX_DRAWINGS_DOUBLE_UP_AND_RIGHT, BOX_DRAWINGS_LIGHT_UP_AND_RIGHT},
{BOX_DRAWINGS_DOUBLE_VERTICAL_AND_LEFT, BOX_DRAWINGS_LIGHT_DOWN_AND_HORIZONTAL, BOX_DRAWINGS_DOWN_SINGLE_AND_LEFT_DOUBLE, NULL, BOX_DRAWINGS_DOUBLE_UP_AND_HORIZONTAL, BOX_DRAWINGS_DOUBLE_DOWN_AND_HORIZONTAL, BOX_DRAWINGS_LIGHT_VERTICAL_AND_RIGHT},
{BOX_DRAWINGS_DOUBLE_DOWN_AND_LEFT, BOX_DRAWINGS_LIGHT_VERTICAL_AND_HORIZONTAL, BOX_DRAWINGS_DOUBLE_VERTICAL, NULL, BOX_DRAWINGS_DOUBLE_HORIZONTAL, BOX_DRAWINGS_DOUBLE_VERTICAL_AND_HORIZONTAL, BOX_DRAWINGS_LIGHT_HORIZONTAL}
};
// symbol 7 column in functionality.md
// { ╬, ╬, [sym], ╪, [alt], [space], [NULL] }
// { ╨, ┘, ┌, ╫, ▒, ░, [lshift] }
// { ╤, ▄, ╥, [rshift], NUL, ▓, █ }
// { ╘, ▌, ╙, [enter], SOH, STX, ▐ }
// { ╓, ■, ╒, [backspace], [EOT], ETX, ▀ }
char symbolKeymap7[ROW_COUNT][COL_COUNT] = {
{BOX_DRAWINGS_DOUBLE_VERTICAL_AND_HORIZONTAL, BOX_DRAWINGS_DOUBLE_VERTICAL_AND_HORIZONTAL, NULL, BOX_DRAWINGS_VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE, NULL, NULL, NULL},
{BOX_DRAWINGS_UP_DOUBLE_AND_HORIZONTAL_SINGLE, BOX_DRAWINGS_LIGHT_UP_AND_LEFT, BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT, BOX_DRAWINGS_VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE, LIGHT_SHADE, MEDIUM_SHADE, NULL},
{BOX_DRAWINGS_DOWN_SINGLE_AND_HORIZONTAL_DOUBLE, LOWER_HALF_BLOCK, BOX_DRAWINGS_DOWN_DOUBLE_AND_HORIZONTAL_SINGLE, NUL_CHAR, NULL, DARK_SHADE, FULL_BLOCK},
{BOX_DRAWINGS_UP_SINGLE_AND_RIGHT_DOUBLE, LEFT_HALF_BLOCK, BOX_DRAWINGS_UP_DOUBLE_AND_RIGHT_SINGLE, NULL, START_OF_HEADING, START_OF_TEXT, RIGHT_HALF_BLOCK},
{BOX_DRAWINGS_DOWN_DOUBLE_AND_RIGHT_SINGLE, BLACK_SQUARE, BOX_DRAWINGS_DOWN_SINGLE_AND_RIGHT_DOUBLE, NULL, END_OF_TRANSMISSION, END_OF_TEXT, UPPER_HALF_BLOCK}
};
// symbol 8 column in functionality.md
// { ENQ, ACK, [sym], SI, [alt], [space], [NULL] }
// { BEL, DLE, DC1, SO, EM, CAN, [lshift] }
// { BS, DC3, TAB, [rshift], ESC, SUB, DC2 }
// { VT, DC4, LF, [enter], FS, GS, NAK }
// { CR, ETB, FF, [backspace], [US], RS, SYN }
char symbolKeymap8[ROW_COUNT][COL_COUNT] = {
{ENQUIRY, ACKNOWLEDGE, NULL, SHIFT_IN, NULL, NULL, NULL},
{BELL, DATA_LINK_ESCAPE, DEVICE_CONTROL_ONE, SHIFT_OUT, END_OF_MEDIUM, CANCEL, NULL},
{BACKSPACE, DEVICE_CONTROL_THREE, HORIZONTAL_TABULATION, NULL, ESCAPE, SUBSTITUTE, DEVICE_CONTROL_TWO},
{VERTICAL_TABULATION, DEVICE_CONTROL_FOUR, LINE_FEED, NULL, FILE_SEPARATOR, GROUP_SEPARATOR, NEGATIVE_ACKNOWLEDGE},
{CARRIAGE_RETURN, END_OF_TRANSMISSION_BLOCK, FORM_FEED, NULL, UNIT_SEPARATOR, RECORD_SEPARATOR, SYNCHRONOUS_IDLE}
};
bool altLock = false;
bool ctrlLock = false;
bool capsLock = false;
bool symbolLock = false;
bool backlightState = true;
bool sendDataFlag = false;
uint8_t keymapIndex = 0; // defaultKeymap = 0, symbolKeymap1 = 1, symbol_keymap2 = 2, etc.
uint8_t keyInfo[KEY_INFO_SIZE] = {0x00, false, false, false, false, false, false}; // key_value, alt, ctrl, shift, sym, mic, speaker
uint8_t sendData[KEY_INFO_SIZE] = {0x00, false, false, false, false, false, false}; // key_value, alt, ctrl, shift, sym, mic, speaker
uint8_t emptyData[KEY_INFO_SIZE] = {0x00, false, false, false, false, false, false}; // empty array to send when no key is pressed
uint8_t currentBrightness = 119; // Default brightness level
unsigned long keyRepeatStart = 0;
void onRequest()
{
if (sendDataFlag) {
Wire.write(sendData, KEY_INFO_SIZE);
sendDataFlag = false;
Serial.print("sendData : ");
for (int i = 0; i < KEY_INFO_SIZE; i++) {
Serial.print(sendData[i]);
Serial.print(" ");
}
Serial.println();
} else {
Wire.write(emptyData, KEY_INFO_SIZE); // Use the temporary array
}
}
void setKeyboardBrightness(uint8_t command)
{
if (command == FUNCTION_TOGGLE) {
if (backlightState) {
currentBrightness = KEYBOARD_BRIGHTNESS_MIN;
} else {
currentBrightness = KEYBOARD_BRIGHTNESS_DEFAULT;
}
} else if (command == FUNCTION_UP) {
if (currentBrightness < KEYBOARD_BRIGHTNESS_MAX) {
if (currentBrightness >= KEYBOARD_BRIGHTNESS_MAX - KEYBOARD_BRIGHTNESS_STEP) {
currentBrightness = KEYBOARD_BRIGHTNESS_MAX;
} else {
currentBrightness += KEYBOARD_BRIGHTNESS_STEP;
}
}
} else if (command == FUNCTION_DOWN) {
if (currentBrightness > KEYBOARD_BRIGHTNESS_MIN) {
if (currentBrightness <= KEYBOARD_BRIGHTNESS_MIN + KEYBOARD_BRIGHTNESS_STEP) {
currentBrightness = KEYBOARD_BRIGHTNESS_MIN;
} else {
currentBrightness -= KEYBOARD_BRIGHTNESS_STEP;
}
}
}
// If the toggle is on/off and the user increments/decrements the brightness then ensure
// the backlight state is set correctly
if (currentBrightness > KEYBOARD_BRIGHTNESS_MIN) {
backlightState = true;
} else {
backlightState = false;
}
ledcWrite(KEYBOARD_BRIGHTNESS_CH, currentBrightness);
}
bool keyReleased(int rowIndex, int colIndex)
{
return keyStates[rowIndex][colIndex] == RELEASED;
}
bool keyHeld(int rowIndex, int colIndex)
{
return keyStates[rowIndex][colIndex] == HELD;
}
bool keyPressed(int rowIndex, int colIndex)
{
return keyStates[rowIndex][colIndex] == PRESSED;
}
bool keyNotPressed(int rowIndex, int colIndex)
{
return keyStates[rowIndex][colIndex] == NOT_PRESSED;
}
bool doesKeyExistInKeymap(int rowIndex, int colIndex, char keymap[ROW_COUNT][COL_COUNT])
{
return keymap[rowIndex][colIndex] != NULL;
}
void printKeyInfo(uint8_t data[KEY_INFO_SIZE])
{
// print all the keyInfo array values
Serial.print("char: ");
Serial.println(data[0]);
Serial.print("alt: ");
Serial.println(data[1]);
Serial.print("ctrl: ");
Serial.println(data[2]);
Serial.print("shift: ");
Serial.println(data[3]);
Serial.print("sym: ");
Serial.println(data[4]);
Serial.print("mic: ");
Serial.println(data[5]);
Serial.print("speaker: ");
Serial.println(data[6]);
Serial.println("************************************");
}
void autoResetKeymapIndex()
{
if (symbolLock == false) {
keymapIndex = MIN_KEYMAP_INDEX;
}
}
void setDefaultCharacter(int rowIndex, int colIndex)
{
// modifiers, alt, ctrl, shift
if (altLock || keyHeld(0, 4)) {
keyInfo[1] = true;
}
if (ctrlLock || keyHeld(2, 3)) {
keyInfo[2] = true;
}
// shift is not applied when caps lock is on unlike the others, this is intended so the host can differentiate between the two
if (keyHeld(1, 6)) {
keyInfo[3] = true;
}
// key value
if (capsLock || keyHeld(1, 6)) {
keyInfo[0] = defaultKeymap[rowIndex][colIndex] - 32;
}
else {
keyInfo[0] = defaultKeymap[rowIndex][colIndex];
}
}
void setSymbolCharacter(int rowIndex, int colIndex)
{
// symbol 1
if ((keymapIndex == 1 || keyHeld(0, 2)) && doesKeyExistInKeymap(rowIndex, colIndex, symbolKeymap1)) {
keyInfo[0] = symbolKeymap1[rowIndex][colIndex];
autoResetKeymapIndex();
}
// symbol 2
else if (keymapIndex == 2 && doesKeyExistInKeymap(rowIndex, colIndex, symbolKeymap2)) {
keyInfo[0] = symbolKeymap2[rowIndex][colIndex];
autoResetKeymapIndex();
}
// symbol 3
else if (keymapIndex == 3 && doesKeyExistInKeymap(rowIndex, colIndex, symbolKeymap3)) {
keyInfo[0] = symbolKeymap3[rowIndex][colIndex];
autoResetKeymapIndex();
}
// symbol 4
else if (keymapIndex == 4 && doesKeyExistInKeymap(rowIndex, colIndex, symbolKeymap4)) {
keyInfo[0] = symbolKeymap4[rowIndex][colIndex];
autoResetKeymapIndex();
}
// symbol 5
else if (keymapIndex == 5 && doesKeyExistInKeymap(rowIndex, colIndex, symbolKeymap5)) {
keyInfo[0] = symbolKeymap5[rowIndex][colIndex];
autoResetKeymapIndex();
}
// symbol 6
else if (keymapIndex == 6 && doesKeyExistInKeymap(rowIndex, colIndex, symbolKeymap6)) {
keyInfo[0] = symbolKeymap6[rowIndex][colIndex];
autoResetKeymapIndex();
}
// symbol 7
else if (keymapIndex == 7 && doesKeyExistInKeymap(rowIndex, colIndex, symbolKeymap7)) {
keyInfo[0] = symbolKeymap7[rowIndex][colIndex];
autoResetKeymapIndex();
}
// symbol 7 special handling for NUL character
else if (keymapIndex == 7 && (keyHeld(2, 4) || keyPressed(2, 4))) {
keyInfo[0] = symbolKeymap7[rowIndex][colIndex];
autoResetKeymapIndex();
keyInfo[4] = true; // set the symbol flag if it is the NUL character (not NULL from an empty space)
}
// symbol 8
else if (keymapIndex == 8 && doesKeyExistInKeymap(rowIndex, colIndex, symbolKeymap8)) {
keyInfo[0] = symbolKeymap8[rowIndex][colIndex];
autoResetKeymapIndex();
}
// set the symbol flag if the character isnt NULL (special handling above for NUL character)
if (keyInfo[0] != NULL) {
keyInfo[4] = true;
}
}
void handleCharacter(int rowIndex, int colIndex) {
// a-z key, alt, ctrl, shift, alt lock, ctrl lock, caps lock, symbol (held)
if ((keymapIndex == MIN_KEYMAP_INDEX || altLock || keyHeld(0, 4) || ctrlLock || keyHeld(2, 3) || capsLock || keyHeld(1, 6) || keyHeld(0, 2)) && doesKeyExistInKeymap(rowIndex, colIndex, defaultKeymap)) {
if (keyHeld(0, 2)) {
setSymbolCharacter(rowIndex, colIndex);
}
else {
setDefaultCharacter(rowIndex, colIndex);
}
}
// symbol
else if (keymapIndex > MIN_KEYMAP_INDEX) {
setSymbolCharacter(rowIndex, colIndex);
}
}
void readKeyMatrix()
{
// iterate the columns
for (int rowIndex = 0; rowIndex < ROW_COUNT; rowIndex++) {
// col: set to output to low
uint8_t curRow = rows[rowIndex];
pinMode(curRow, OUTPUT);
digitalWrite(curRow, LOW);
// row: iterate through the rows
for (int colIndex = 0; colIndex < COL_COUNT; colIndex++) {
uint8_t curCol = cols[colIndex];
pinMode(curCol, INPUT_PULLUP);
delay(1); // arduino is not fast enough to switch input/output modes so wait 1 ms
bool buttonPressed = (digitalRead(curCol) == LOW);
// Debounce logic so keys don't trigger multiple times
if (buttonPressed != lastValue[rowIndex][colIndex]) {
delay(DEBOUNCE_DELAY); // Wait for debounce delay
buttonPressed = (digitalRead(curCol) == LOW); // Read the button state again
}
if (buttonPressed) {
if (keyNotPressed(rowIndex, colIndex) || keyReleased(rowIndex, colIndex)) {
keyStates[rowIndex][colIndex] = PRESSED;
} else {
keyStates[rowIndex][colIndex] = HELD;
}
} else {
if (keyPressed(rowIndex, colIndex) || keyHeld(rowIndex, colIndex)) {
keyStates[rowIndex][colIndex] = RELEASED;
} else {
keyStates[rowIndex][colIndex] = NOT_PRESSED;
}
}
lastValue[rowIndex][colIndex] = buttonPressed;
pinMode(curCol, INPUT);
}
// disable the column
pinMode(curRow, INPUT);
}
}
void sendKeyInfo()
{
memcpy(keyInfo, emptyData, KEY_INFO_SIZE); // clear the keyInfo array
for (int rowIndex = 0; rowIndex < ROW_COUNT; rowIndex++) {
for (int colIndex = 0; colIndex < COL_COUNT; colIndex++) {
// any key released
if (keyPressed(rowIndex, colIndex)) {
keyRepeatStart = millis(); // Set the keyRepeatStart to the current time
// enter
if (keyPressed(3, 3)) {
// backlight down (alt + enter)
if (keyHeld(0, 4)) {
setKeyboardBrightness(FUNCTION_DOWN);
}
// tab (lshift + enter)
else if (keyHeld(1, 6)) {
keyInfo[0] = HORIZONTAL_TABULATION;
}
// cycle symbol backward (sym + enter)
else if (keyHeld(0, 2)) {
if (keymapIndex == MIN_KEYMAP_INDEX) {
keymapIndex = MAX_KEYMAP_INDEX;
}
else {
keymapIndex--;
}
}
// enter
else {
keyInfo[0] = CARRIAGE_RETURN;
}
}
// space
else if (keyPressed(0, 5)) {
// alt lock (alt + space)
if (keyHeld(0, 4)) {
altLock = !altLock;
}
// ctrl lock (rshift + space)
else if (keyHeld(2, 3)) {
ctrlLock = !ctrlLock;
}
// caps lock (lshift + space)
else if (keyHeld(1, 6)) {
capsLock = !capsLock;
}
// symbol lock (sym + space)
else if (keyHeld(0, 2)) {
symbolLock = !symbolLock;
if (keymapIndex > MIN_KEYMAP_INDEX && symbolLock == false) {
keymapIndex = MIN_KEYMAP_INDEX;
}
}
// space
else {
keyInfo[0] = 0x20;
}
}
// backspace
else if (keyPressed(4, 3)) {
// backlight up (alt + backspace)
if (keyHeld(0, 4)) {
setKeyboardBrightness(FUNCTION_UP);
}
// del (lshift + backspace)
else if (keyHeld(1, 6)) {
keyInfo[0] = 0x7F;
}
// cycle symbol forward (sym + backspace)
else if (keyHeld(0, 2)) {
keymapIndex++;
if (keymapIndex > MAX_KEYMAP_INDEX) {
keymapIndex = MIN_KEYMAP_INDEX;
symbolLock = false; // reset symbol lock when all symbol keymaps have been cycled through
}
}
// backspace
else {
keyInfo[0] = BACKSPACE;
}
}
// mic/0
else if (keyPressed(0, 6)) {
// mic toggle (alt + mic)
if (keyHeld(0, 4)) {
keyInfo[0] = FUNCTION_TOGGLE;
keyInfo[5] = true;
}
// mic volume down (lshift + mic)
else if (keyHeld(1, 6)) {
keyInfo[0] = FUNCTION_DOWN;
keyInfo[5] = true;
}
// mic volume up (rshift + mic)
else if (keyHeld(2, 3)) {
keyInfo[0] = FUNCTION_UP;
keyInfo[5] = true;
}
// the below items are contained within the keymaps but appear here as well due to key combination usage
// 0
else if (keymapIndex == 1) {
keyInfo[0] = DIGIT_ZERO;
}
// nbsp
else if (keymapIndex == 2) {
keyInfo[0] = NO_BREAK_SPACE;
}
}
// $/speaker
else if (keyPressed(4, 4)) {
// speaker toggle (alt + $)
if (keyHeld(0, 4)) {
keyInfo[0] = FUNCTION_TOGGLE;
keyInfo[6] = true;
}
// speaker volume down (lshift + $)
else if (keyHeld(1, 6)) {
keyInfo[0] = FUNCTION_DOWN;
keyInfo[6] = true;
}
// speaker volume up (rshift + $)
else if (keyHeld(2, 3)) {
keyInfo[0] = FUNCTION_UP;
keyInfo[6] = true;
}
// the below items are contained within the keymaps but appear here as well due to key combination usage
// $
else if (keymapIndex == 0) {
keyInfo[0] = DOLLAR_SIGN;
}
// ¢
else if (keymapIndex == 1) {
keyInfo[0] = CENT_SIGN;
}
// ₧
else if (keymapIndex == 2) {
keyInfo[0] = PESETA_SIGN;
}
// ═
else if (keymapIndex == 6) {
keyInfo[0] = BOX_DRAWINGS_DOUBLE_HORIZONTAL;
}
// EOT
else if (keymapIndex == 7) {
keyInfo[0] = END_OF_TRANSMISSION;
}
// US
else if (keymapIndex == 8) {
keyInfo[0] = UNIT_SEPARATOR;
}
}
// rshift
else if (keyPressed(2, 3)) {
// backlight toggle (alt + rshift)
if (keyHeld(0, 4)) {
setKeyboardBrightness(FUNCTION_TOGGLE);
}
}
// a-z key, alt, ctrl, shift, alt lock, ctrl lock, caps lock, symbol (held)
else {
handleCharacter(rowIndex, colIndex);
}
}
// a-z key (held), alt, ctrl, shift, alt lock, ctrl lock, caps lock, symbol (held)
else if (keyHeld(rowIndex, colIndex) && (millis() - keyRepeatStart > KEY_REPEAT_DELAY)) {
handleCharacter(rowIndex, colIndex);
}
}
}
// if keyInfo array is not empty, print the data over serial
if (keyInfo[0] != 0x00 || keyInfo[1] != 0x00 || keyInfo[2] != 0x00 || keyInfo[3] != 0x00 || keyInfo[4] != 0x00 || keyInfo[5] != 0x00 || keyInfo[6] != 0x00)
{
printKeyInfo(keyInfo);
sendDataFlag = true;
}
// if the sendDataFlag is true then copy the keyInfo array to the sendData array which gets sent by the onRequest function
if (sendDataFlag) {
memcpy(sendData, keyInfo, KEY_INFO_SIZE);
}
}