#include /* KEY_LEFT_CTRL 0x80 128 KEY_LEFT_SHIFT 0x81 129 KEY_LEFT_ALT 0x82 130 KEY_LEFT_GUI 0x83 131 KEY_RIGHT_CTRL 0x84 132 KEY_RIGHT_SHIFT 0x85 133 KEY_RIGHT_ALT 0x86 134 KEY_RIGHT_GUI 0x87 135 KEY_UP_ARROW 0xDA 218 KEY_DOWN_ARROW 0xD9 217 KEY_LEFT_ARROW 0xD8 216 KEY_RIGHT_ARROW 0xD7 215 KEY_BACKSPACE 0xB2 178 KEY_TAB 0xB3 179 KEY_RETURN 0xB0 176 KEY_ESC 0xB1 177 KEY_INSERT 0xD1 209 KEY_DELETE 0xD4 212 KEY_PAGE_UP 0xD3 211 KEY_PAGE_DOWN 0xD6 214 KEY_HOME 0xD2 210 KEY_END 0xD5 213 KEY_CAPS_LOCK 0xC1 193 KEY_F1 0xC2 194 KEY_F2 0xC3 195 KEY_F3 0xC4 196 KEY_F4 0xC5 197 KEY_F5 0xC6 198 KEY_F6 0xC7 199 KEY_F7 0xC8 200 KEY_F8 0xC9 201 KEY_F9 0xCA 202 KEY_F10 0xCB 203 KEY_F11 0xCC 204 KEY_F12 0xCD 205 */ /* KEYBOARD DIAGRAM 0 1 2 3 4 5 6 7 8 9 | | | | | | | | | | 10 ---[ ][ ][ ][ ][ ]---[ ][ ][ ][ ][ ] 11 ---[ ][ ][ ][ ][ ]---[ ][ ][ ][ ][ ] 12 ---[ ][ ][ ][ ][ ]---[ ][ ][ ][ ][ ] 13 --- - - - [ ][ ]---[ ][ ] - - - :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: QUICKEYLANG :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: "L1'moved to layer 1'^L0'moved to layer 0'" This is quickeylang. A simple "codeing language" defined in short strings. The "functions" are read from left to right. Ment to be fast, efficient, human readable, and esoteric. Mechanics --------------------------------------- each key has a... - key function - release function - wait timer (frames the key has been held down) - readIndex when a key is pressed down... 1. run key function when a key is released 1. run release function 2. set the release function to "" 3. set waitTimer to 0 4. set readIndex to 0 key functions are exsexuted when a key is pressed down. release functions are executed only when a key is released. you will be defining key funcitions in the keymap. release functions are dynamic in some ways. Function API ------------------------ ` starts and stops a print increments readIndex as it goes along ex. >>> "'hello world'" <<< will type out "hello world" P for a "Press" 1. makes a key press event from the next charcter IF the release fucntion is undefined. 2. automaticaly appends its coresponding "R" action to the release function. 3. increment readIndex by 2 ex. >>> "P1" <<< >>> "P1^R1" <<< these two functions are the same >>> "P1P2P3" <<< internaly the release function looks like this --> "R1R2R3" >>> "P1^P2" <<< internaly the release function looks like this --> "P2R1R2" releases a key increment readIndex by 2 ^ starts and stops writing to the release function it wasn't writing... ...sets the release function to "" then begins writing to the release function it WAS writing... ...stops writing to the release function continues runing the rest of the function if it is NOT empty... skips to the chracter beyond the next "|" and continues running sets the readIndex as it goes along. these can be used to set the release code for a key ex. >>> "L1^L0" <<< makes for toggle layer W wait does not work inside of release functions changes the whole function of the key if held ment to be used in conjunction with ^ could also make a safty key, you have to hold the key in order for it to enact itself. waits till the waitTimer == waitTime... then, 1. runs the release function 2. sets the release function to "" 3. sets waitTimer to 0 4. increment readIndex by 1 5. continues executing code else... increment the waitTimer by 1 ...stops the key function ex. >>> "'a'WWW'a'WJ6" <<< a manually set up a repeating key with a delayed start ! checks for tapped key releases checks if the waitTimer is less than waitTime... ...if it is it continues exsecuting code ...if NOT the function is stoped intended to be used inside of release functions ex. >>> "^!Pj^WP"+KEY_LEFT_CTRL <<< presses the 'j' key if tapped, the ctrl key if held >>> "^!'A was tapped!^W'A was held down" does not work inside of key functions L 1. switch layers 2. increment readIndex by 2 max of 10 layers(0-9) ex. >>> "L2" J jump and stop function 1. set the readIndex to a spesific value 2. stop the function call does not cause a infinte loop crash does not work inside of release functions M Defines a Midi event ex. >>> "Mn"+0x60+"v"+0x7f */ // sets the speed of the keyboard // the smaller the period the faster the keyboard will check for inputs const unsigned long period = 3; unsigned long prevMillisValue = 0; const char C = KEY_LEFT_CTRL; const char S = KEY_LEFT_SHIFT; const char A = KEY_LEFT_ALT; const char G = KEY_LEFT_GUI; const char BS = KEY_BACKSPACE; const char UA = KEY_UP_ARROW; const char DA = KEY_DOWN_ARROW; const char LA = KEY_LEFT_ARROW; const char RA = KEY_RIGHT_ARROW; const char R = KEY_RETURN; const char ESC = KEY_ESC; const char T = KEY_TAB; const char I = KEY_INSERT; const char D = KEY_DELETE; const char PU = KEY_PAGE_UP; const char PD = KEY_PAGE_DOWN; const char H = KEY_HOME; const char E = KEY_END; const char PS = 0xCE; const char CL = KEY_CAPS_LOCK; const char F1 = KEY_F1; const char F2 = KEY_F2; const char F3 = KEY_F3; const char F4 = KEY_F4; const char F5 = KEY_F5; const char F6 = KEY_F6; const char F7 = KEY_F7; const char F8 = KEY_F8; const char F9 = KEY_F9; const char F10 = KEY_F10; const char F11 = KEY_F11; const char F12 = KEY_F12; const byte countRows = 4; const byte countColumns = 10; const byte maxFunctionLength = 10; const unsigned waitTime = 45; const byte rowPins[countRows] = { 22, 23, 16, 18}; const byte columnPins[countColumns] = { 10, 11, 13, 12, 9, 19, 20, 21, 15, 14}; const char _[maxFunctionLength] = ""; /* BEAKL {"Pq","Ph","Po","Pu","P,", "Pg","Pl","Pr","Pf","Pb"}, {"Pj","Pi","Pe","Pa","Py", "Pd","Pt","Ps","Pn","Pp"}, {"Px","Pk",{0x27,'"'},"'.","''", "Pv","Pm","Pc","Pw","Pz"}, {"","","","' ",{'P',S}, {'P',C},"L1","","",""}, */ /* {"Pp","Py","Po","Pu","P;", "Pv","Pl","Pd","Pf","Pb"}, {"Pc","Pi","Pe","Pa","P,", "Pk","Ph","Pt","Pn","Ps"}, {"P.","P;","P'","P.","P-", "Px","Pm","Pg","Pd","Px"}, {"","","","' ",{'P',S}, "L1","Pr","","",""}, */ /*{"Pb","Pf","Pd","Pl","Pj", "P;","Pu","Po","Py","^!'p^W'q"}, {"Ps","Pn","Pt","Ph","Pk", "P,","Pa","Pe","Pi","Pc"}, {"Pv","Pw","Pg","Pm","Px", "P-","P.","P'",{0x27,R},"P/"}, {"","","", "Pr",{'^','!','L','1','^','W','P',C},{0x27,BS},{'^','!',0x27,' ','^','W','P',S},"","",""}, */ //const char BSKey[maxFunctionLength] = {'^','!',0x27,BS,'^','W','P',S}; //const char ModKey[maxFunctionLength] = {'^','!','L','1','^','W','P',C}; const char keyMap[4][countRows][countColumns][maxFunctionLength] = { { {"^!'p^W'q","Py","Po","Pu","P;", "Pj","Pl","Pd","Pf","Pb"}, { "Pc","Pi","Pe","Pa","P,", "Pk","Ph","Pt","Pn","Ps"}, { "P/",{0x27,R},"P'","P.","P-", "Px","Pm","Pg","Pw","Pv"}, {"","","","' ",{'^','!','L','1','^','W','P',C},{'^','!',0x27,BS,'^','W','P',S},"Pr","","",""}, }, { {{'P',ESC},"'<","',","'>","", "", "'[","':","']",""}, {{'P',T},"'(","L2","')",{'P',G}, "", "'{","L3","'}",""}, { "","","'-","'+","", "'#","'*","'/","'=",""}, {"","","","L0",{'P',C}, {'^','!',0x27,BS,'^','W','P',S},"","","",""}, }, { {"'-","'5","'4","'3","':", {'P',PU},{'P',H}, {'P',UA},{'P',E}, ""}, {"'7","'2","'1","'1","'0", {'P',PD},{'P',LA},{'P',DA},{'P',RA},""}, {"',","'6","'7","'6","", {'P',I},"L2","L3","",{'P',D}}, {"","","","L0",{'^','!','L','1','^','W','P',C}, {'^','!',0x27,BS,'^','W','P',S},"","","",""}, }, { {{'P',ESC},{'P',F1},{'P',F2},{'P',F3},{'P',F10}, {'P',PU},{'P',H}, {'P',UA},{'P',E}, ""}, {"",{'P',F4},{'P',F5},{'P',F6},{'P',F11}, {'P',PD},{'P',LA},{'P',DA},{'P',RA},""}, {"",{'P',F7},{'P',F8},{'P',F9},{'P',F12}, {'P',I},"L2","L3","",{'P',D}}, {"","","","L0",{'^','!','L','1','^','W','P',C}, {'^','!',0x27,BS,'^','W','P',S},"","","",""}, }, }; char releaseMap[countRows][countColumns][maxFunctionLength] = { {"","","","","", "","","","",""}, {"","","","","", "","","","",""}, {"","","","","", "","","","",""}, {"","","","","", "","","","",""}, }; byte writeIndex[countRows][countColumns] = { {0,0,0,0,0, 0,0,0,0,0}, {0,0,0,0,0, 0,0,0,0,0}, {0,0,0,0,0, 0,0,0,0,0}, {0,0,0,0,0, 0,0,0,0,0}, }; unsigned waitTimer[countRows][countColumns] = { {0,0,0,0,0, 0,0,0,0,0}, {0,0,0,0,0, 0,0,0,0,0}, {0,0,0,0,0, 0,0,0,0,0}, {0,0,0,0,0, 0,0,0,0,0}, }; byte readIndex[countRows][countColumns] = { {0,0,0,0,0, 0,0,0,0,0}, {0,0,0,0,0, 0,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 READING = 0; const byte PRINTING = 1; const byte WRITING = 2; byte layer = 0; char pressedKeys[16]; void runFunction(byte r, byte c, bool isKeyFunction) { //Serial.print(">"); char function[maxFunctionLength]; byte index; if (isKeyFunction) { // copy the array to the local function var byte i = maxFunctionLength; // good to 255 elements while ( i-- ) *( function + i ) = *( keyMap[layer][r][c] + i ); // dest and src are your 2 array names index = readIndex[r][c]; } else { // copy the array to the local function var byte i = 5; // good to 255 elements while ( i-- ) *( function + i ) = *( releaseMap[r][c] + i ); // dest and src are your 2 array names // reset the read index to the start of the release code index = 0; } //Serial.println(function); byte state = READING; bool stop = false; while ( index < maxFunctionLength && function[index] != 0 && !stop ) { char byteCode = function[index]; //Serial.print(" "); //Serial.print(index); //Serial.print(": "); //Serial.print(byteCode); //Serial.print(" -> "); char nextByteCode = function[index+1]; byte readDelta = 1; switch (state) { case READING: switch (byteCode) { case 0x27: ////Serial.print("Start printing."); state = PRINTING; break; case 'P': //Serial.print("Press the '"); //Serial.print(nextByteCode); //Serial.print("' key."); Keyboard.press(nextByteCode); if (isKeyFunction) { releaseMap[r][c][writeIndex[r][c]] = 'R'; releaseMap[r][c][writeIndex[r][c]+1] = nextByteCode; } else { function[writeIndex[r][c]] = 'R'; function[writeIndex[r][c]+1] = nextByteCode; } writeIndex[r][c] += 2; readDelta = 2; break; case 'R': //Serial.print("Release the '"); //Serial.print(nextByteCode); //Serial.print("' key."); Keyboard.release(nextByteCode); readDelta = 2; break; case '^': //Serial.print("BEGIN WRITING TO THE RELEASE FUNCTION."); state = WRITING; break; case 'W': if (isKeyFunction == false) { break; } if (waitTimer[r][c] == waitTime) { //Serial.print("Continue, runing code."); runFunction(r, c, false); waitTimer[r][c] = 0; } else { //Serial.print("Wait."); waitTimer[r][c] += 1; stop = true; readDelta = 0; } break; case '!': if (isKeyFunction) { break; } if (waitTimer[r][c] >= waitTime) { stop = true; } break; case 'L': layer = nextByteCode - 0x30; readDelta = 2; break; case 'J': if (isKeyFunction == false) { break; } index = nextByteCode - 0x30; stop = true; readDelta = 0; break; } break; case PRINTING: if (byteCode == 0x27) { state = READING; //Serial.print("STOP PRINTING."); break; } //Serial.print("PRINTING..."); Keyboard.print(byteCode); break; case WRITING: if (byteCode == '^') { //Serial.print("STOP WRITING."); state = READING; break; } //Serial.print("WRITING..."); releaseMap[r][c][writeIndex[r][c]] = byteCode; writeIndex[r][c] += 1; break; } index += readDelta; //Serial.println("<"); } if (isKeyFunction == false) { byte i = writeIndex[r][c]+1; while ( i-- ) *( releaseMap[r][c] + i ) = 0; writeIndex[r][c] = 0; readIndex[r][c] = 0; waitTimer[r][c] = 0; } else { readIndex[r][c] = index; } } // Read the keyboard state void readKeys() { // ? // row scanning for (byte r = 0; r < countRows; r++) { //Keyboard.print(r); // Set row to LOW pinMode(rowPins[r],OUTPUT); digitalWrite(rowPins[r], LOW); // Scan all colums checking for presses for (byte c = 0; c < countColumns; c++) { if (digitalRead(columnPins[c]) == LOW) { // Press detected runFunction(r,c,true); } else { // Check for released keys then release if (releaseMap[r][c] != "") { runFunction(r,c,false); } } } // Return the row to high impedance digitalWrite(rowPins[r], HIGH); pinMode(rowPins[r], INPUT); } } void setup() { Keyboard.begin(); // Serial.begin(1200); // Columns in high impedance for (byte c = 0; c < countColumns; c++) { pinMode(columnPins[c], INPUT_PULLUP); } // Rows in pullup for (byte r = 0; r < countRows; r++) { pinMode(rowPins[r], INPUT); digitalWrite(rowPins[r], HIGH); } delay(2000); } void loop() { if (millis() - prevMillisValue > period) // Non-blocking wait { prevMillisValue = millis(); readKeys(); /* // Set row to LOW pinMode(rowPins[3],OUTPUT); digitalWrite(rowPins[3], LOW); if (digitalRead(columnPins[5]) == LOW) { Keyboard.print('x'); } // Return the row to high impedance digitalWrite(rowPins[3], HIGH); pinMode(rowPins[3], INPUT); */ } }