-
Notifications
You must be signed in to change notification settings - Fork 11
Quick addition of generalized keyboard commands #59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
5239c85
More generalized keyboard commands and their respective tests
Real-Septicake 37b8163
Formatting... you'd think I'd remember to do this by now
Real-Septicake 846543a
Remove macro and move all previous usages to use to get clang-forma…
Real-Septicake 0c4d573
Implement changes suggested by Trevor
Real-Septicake f3415ef
Added missing static
Real-Septicake File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| loop test starting | ||
| loop test completed | ||
| nesting test starting | ||
| nesting test completed | ||
| char table test starting | ||
| char table test completed | ||
| word test starting | ||
| word test completed | ||
| complex word test starting | ||
| complex word test completed | ||
| test_kb_cmd done |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,231 @@ | ||
| #ifndef KB_CMD_H | ||
| #define KB_CMD_H | ||
|
|
||
| #include "device/keyboard.h" | ||
| #include "device/ps2.h" | ||
| #include "test_helper.h" | ||
|
|
||
| // Returns 0 if executed successfully, non-zero otherwise | ||
| typedef int (*CmdFunc)(void); | ||
|
|
||
| struct LoopNode { | ||
| int idx; | ||
| int remaining; | ||
| }; | ||
|
|
||
| // if you have more than 8 nested loops then what the fuck | ||
| static struct LoopNode loopStack[8]; | ||
| static int current = -1; | ||
|
|
||
| typedef enum { | ||
| // A singular key press | ||
| CMD_KEY_PRESS, | ||
|
|
||
| // Types the entire provided word | ||
| CMD_TYPE_WORD, | ||
|
|
||
| // Signifies the start of a command loop | ||
| CMD_LOOP_START, | ||
|
|
||
| // Signifies the end of the most recent loop command | ||
| CMD_LOOP_END, | ||
|
|
||
| // Runs a function | ||
| CMD_FUNC, | ||
|
|
||
| // End of command list | ||
| CMD_END | ||
| } CMD; | ||
|
|
||
| struct KbCmd { | ||
| CMD cmd; | ||
| union { | ||
| // key to press | ||
| struct PS2Buf_t kb; | ||
|
|
||
| // null terminated string | ||
| char *w; | ||
|
|
||
| // loop count | ||
| int loops; | ||
|
|
||
| // function to execute | ||
| CmdFunc func; | ||
| } data; | ||
| }; | ||
|
|
||
| struct KeyData { | ||
| enum KeyCode c; | ||
| uint8_t mods; | ||
| }; | ||
|
|
||
| #define keyDataStruct(code, modifiers) \ | ||
| (struct KeyData) { \ | ||
| code, modifiers \ | ||
| } | ||
|
|
||
| #define keyAndShifted(unshiftedChar, shiftedChar, key) \ | ||
| [unshiftedChar] = keyDataStruct(key, 0), [shiftedChar] = keyDataStruct( \ | ||
| key, KEY_MOD_SHIFT) | ||
|
|
||
| // clang-format off | ||
| static const struct KeyData charToPressCMD[] = { | ||
| // Row 1 | ||
| keyAndShifted('`', '~', Key_grave), | ||
| keyAndShifted('1', '!', Key_1), | ||
| keyAndShifted('2', '@', Key_2), | ||
| keyAndShifted('3', '#', Key_3), | ||
| keyAndShifted('4', '$', Key_4), | ||
| keyAndShifted('5', '%', Key_5), | ||
| keyAndShifted('6', '^', Key_6), | ||
| keyAndShifted('7', '&', Key_7), | ||
| keyAndShifted('8', '*', Key_8), | ||
| keyAndShifted('9', '(', Key_9), | ||
| keyAndShifted('0', ')', Key_0), | ||
| keyAndShifted('-', '_', Key_minus), | ||
| keyAndShifted('=', '+', Key_equal), | ||
|
|
||
| // Row 2 | ||
| keyAndShifted('q', 'Q', Key_q), | ||
| keyAndShifted('w', 'W', Key_w), | ||
| keyAndShifted('e', 'E', Key_e), | ||
| keyAndShifted('r', 'R', Key_r), | ||
| keyAndShifted('t', 'T', Key_t), | ||
| keyAndShifted('y', 'Y', Key_y), | ||
| keyAndShifted('u', 'U', Key_u), | ||
| keyAndShifted('i', 'I', Key_i), | ||
| keyAndShifted('o', 'O', Key_o), | ||
| keyAndShifted('p', 'P', Key_p), | ||
| keyAndShifted('[', '{', Key_openSquare), | ||
| keyAndShifted(']', '}', Key_closeSquare), | ||
| keyAndShifted('\\', '|', Key_backSlash), | ||
|
|
||
| // Row 3 | ||
| keyAndShifted('a', 'A', Key_a), | ||
| keyAndShifted('s', 'S', Key_s), | ||
| keyAndShifted('d', 'D', Key_d), | ||
| keyAndShifted('f', 'F', Key_f), | ||
| keyAndShifted('g', 'G', Key_g), | ||
| keyAndShifted('h', 'H', Key_h), | ||
| keyAndShifted('j', 'J', Key_j), | ||
| keyAndShifted('k', 'K', Key_k), | ||
| keyAndShifted('l', 'L', Key_l), | ||
| keyAndShifted(';', ':', Key_semicolon), | ||
| keyAndShifted('\'', '"', Key_apostrophe), | ||
|
|
||
| // Row 4 | ||
| keyAndShifted('z', 'Z', Key_z), | ||
| keyAndShifted('x', 'X', Key_x), | ||
| keyAndShifted('c', 'C', Key_c), | ||
| keyAndShifted('v', 'V', Key_v), | ||
| keyAndShifted('b', 'B', Key_b), | ||
| keyAndShifted('n', 'N', Key_n), | ||
| keyAndShifted('m', 'M', Key_m), | ||
| keyAndShifted(',', '<', Key_comma), | ||
| keyAndShifted('.', '>', Key_period), | ||
| keyAndShifted('/', '?', Key_slash), | ||
|
|
||
| // Row 5 | ||
| [' '] = keyDataStruct(Key_space, 0) | ||
| }; | ||
| // clang-format on | ||
| // clang-format can you please not butcher the readability of the code? | ||
|
|
||
| #undef keyPressStruct | ||
| #undef keyAndShifted | ||
| #undef keyAndCapital | ||
|
|
||
| static struct KbCmd keyPressCMD(enum KeyCode code, enum KeyState event, | ||
| uint8_t modifiers) { | ||
| KeyPress kp = (KeyPress){0, code, event, modifiers}; | ||
| struct PS2Buf_t b = (struct PS2Buf_t){PS2_KEY_EVENT, {.keyEvent = kp}}; | ||
| return (struct KbCmd){CMD_KEY_PRESS, {.kb = b}}; | ||
| } | ||
|
|
||
| static struct KbCmd keyPressCMDFromData(struct KeyData data) { | ||
| return (keyPressCMD(data.c, KeyPressed, data.mods)); | ||
| } | ||
|
|
||
| static struct KbCmd typeWordCMD(char *word) { | ||
| return (struct KbCmd){CMD_TYPE_WORD, {.w = word}}; | ||
| } | ||
|
|
||
| // `loops` must be greater than 0 | ||
| static struct KbCmd loopStartCMD(int loops) { | ||
| return (struct KbCmd){CMD_LOOP_START, {.loops = loops}}; | ||
| } | ||
|
|
||
| static struct KbCmd loopEndCMD() { | ||
| return (struct KbCmd){CMD_LOOP_END, {}}; | ||
| } | ||
|
|
||
| static struct KbCmd funcCMD(CmdFunc func) { | ||
| return (struct KbCmd){CMD_FUNC, {.func = func}}; | ||
| } | ||
|
|
||
| static struct KbCmd endCMD() { | ||
| return (struct KbCmd){CMD_END, {}}; | ||
| } | ||
|
|
||
| // Returns 0 when exiting normally, and anything else when things go wrong | ||
| typedef void (*KeyPressHandler)(struct PS2Buf_t); | ||
| typedef int (*ExecFunc)(struct KbCmd, int *, KeyPressHandler); | ||
|
|
||
| static void baseKeyHandler(struct PS2Buf_t kb) { | ||
| vgaEditor(kb); | ||
| } | ||
|
|
||
| static int baseExec(struct KbCmd cmd, int *idx, KeyPressHandler kp) { | ||
| switch (cmd.cmd) { | ||
| case CMD_KEY_PRESS: | ||
| kp(cmd.data.kb); | ||
| break; | ||
| case CMD_TYPE_WORD: | ||
| for (char *c = cmd.data.w; *c != 0; c++) { | ||
| kp(keyPressCMDFromData(charToPressCMD[(int)*c]).data.kb); | ||
| } | ||
| break; | ||
| case CMD_LOOP_START: | ||
| if (cmd.data.loops < 1) { | ||
| FAIL_M("Loop count must be greater than 0, got %i", cmd.data.loops); | ||
| return 1; | ||
| } | ||
| if (current == -1 || loopStack[current].idx != *idx) { | ||
| current++; | ||
| loopStack[current] = (struct LoopNode){*idx, cmd.data.loops}; | ||
| } | ||
| loopStack[current].remaining--; | ||
| break; | ||
| case CMD_LOOP_END: | ||
| if (loopStack[current].remaining) { | ||
| // subtract 1 because idx is incremented after command completes | ||
| // this was a surprisingly annoying issue to track down | ||
| *idx = loopStack[current].idx - 1; | ||
Sploder12 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } else { | ||
| current--; | ||
| } | ||
| break; | ||
| case CMD_FUNC: | ||
| return cmd.data.func(); | ||
| case CMD_END: | ||
| break; | ||
| default: | ||
| FAIL_M("Unexpected command type: %i", cmd.cmd); | ||
| return 1; | ||
| } | ||
| return 0; | ||
| } | ||
|
|
||
| static int execList(struct KbCmd *cmds, ExecFunc f, KeyPressHandler kp) { | ||
| for (int i = 0; cmds[i].cmd != CMD_END; i++) { | ||
| if (f(cmds[i], &i, kp)) { | ||
| char buff[32]; | ||
| int len = snprintf(buff, sizeof(buff), "Command %i failed", i); | ||
| serialWrite(COM1, (uint8_t *)buff, len); | ||
| return 1; | ||
| } | ||
| } | ||
| return 0; | ||
| } | ||
|
|
||
| #endif | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,147 @@ | ||
| #include "kb_cmd.h" | ||
| #include "string.h" | ||
|
|
||
| #define testStart(name, print) \ | ||
| int name##Start() { \ | ||
| char text[] = print " starting\n"; \ | ||
| serialWrite(COM1, (uint8_t *)(text), sizeof(text) - 1); \ | ||
| return 0; \ | ||
| } | ||
|
|
||
| #define testEnd(name, print) \ | ||
| int name##End() { \ | ||
| char text[] = print " completed\n"; \ | ||
| serialWrite(COM1, (uint8_t *)(text), sizeof(text) - 1); \ | ||
| return 0; \ | ||
| } | ||
|
|
||
| char buff[64]; | ||
| int buffIdx = 0; | ||
|
|
||
| int resetBuff() { | ||
| memset(buff, 0, sizeof(buff)); | ||
| buffIdx = 0; | ||
| return 0; | ||
| } | ||
|
|
||
| void testKeyHandler(struct PS2Buf_t buf) { | ||
| buff[buffIdx++] = keyPressToASCII(buf.keyEvent); | ||
| } | ||
|
|
||
| // clang-format off | ||
|
|
||
| // Loop prints | ||
| testStart(loopTest, "loop test") | ||
| testEnd(loopTest, "loop test") | ||
|
|
||
| // Nesting prints | ||
| testStart(nestingTest, "nesting test") | ||
| testEnd(nestingTest, "nesting test") | ||
|
|
||
| // Char table prints | ||
| testStart(charTableTest, "char table test") | ||
| testEnd(charTableTest, "char table test") | ||
|
|
||
| // Word prints | ||
| testStart(wordTest, "word test") | ||
| testEnd(wordTest, "word test") | ||
|
|
||
| // Complex word prints | ||
| testStart(complexWordTest, "complex word test") | ||
| testEnd(complexWordTest, "complex word test") | ||
|
|
||
| // Loop testing | ||
| int v = 0; | ||
|
|
||
| // clang-format on | ||
|
|
||
| int vReset() { | ||
| v = 0; | ||
| return 0; | ||
| } | ||
|
|
||
| int vInc() { | ||
| v++; | ||
| return 0; | ||
| } | ||
|
|
||
| int testSingleLoop() { | ||
| ASSERT_M(v == 4, "Expected to loop 4 times, looped %i time(s) instead", v); | ||
| return 0; | ||
| } | ||
|
|
||
| int testNestedLoop() { | ||
| ASSERT_M(v == 6, "Expected to loop 6 times, looped %i time(s) instead", v); | ||
| return 0; | ||
| } | ||
|
|
||
| // Char table testing | ||
| int capitalShiftTest() { | ||
| ASSERT(Key_a == charToPressCMD['a'].c); | ||
| ASSERT(0 == charToPressCMD['a'].mods); | ||
| ASSERT(Key_a == charToPressCMD['A'].c); | ||
| ASSERT(KEY_MOD_SHIFT == charToPressCMD['A'].mods) | ||
| return 0; | ||
| } | ||
|
|
||
| int shiftTest() { | ||
| ASSERT(Key_grave == charToPressCMD['`'].c) | ||
| ASSERT(0 == charToPressCMD['`'].mods) | ||
| ASSERT(Key_grave == charToPressCMD['~'].c) | ||
| ASSERT(KEY_MOD_SHIFT == charToPressCMD['~'].mods) | ||
| return 0; | ||
| } | ||
|
|
||
| // Word type testing | ||
| int wordTest() { | ||
| ASSERT(strncmp("test", buff, 5)) | ||
| return 0; | ||
| } | ||
Sploder12 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| int complexWordTest() { | ||
| ASSERT(strncmp("This is a very Loong word$%@^@\\", buff, 32)) | ||
| return 0; | ||
| } | ||
|
|
||
| void test_main() { | ||
| struct KbCmd list[] = { | ||
| // Single loop test | ||
| funcCMD(loopTestStart), | ||
| loopStartCMD(4), | ||
| funcCMD(vInc), | ||
| loopEndCMD(), | ||
| funcCMD(testSingleLoop), | ||
| funcCMD(loopTestEnd), | ||
|
|
||
| funcCMD(vReset), | ||
| // Nested loop test | ||
| funcCMD(nestingTestStart), | ||
| loopStartCMD(2), | ||
| loopStartCMD(3), | ||
| funcCMD(vInc), | ||
| loopEndCMD(), | ||
| loopEndCMD(), | ||
| funcCMD(testNestedLoop), | ||
| funcCMD(nestingTestEnd), | ||
|
|
||
| // Char table values test | ||
| funcCMD(charTableTestStart), | ||
| funcCMD(capitalShiftTest), | ||
| funcCMD(shiftTest), | ||
| funcCMD(charTableTestEnd), | ||
|
|
||
| // Word type test | ||
| funcCMD(wordTestStart), | ||
| typeWordCMD("test"), | ||
| funcCMD(wordTestEnd), | ||
|
|
||
| funcCMD(complexWordTestStart), | ||
| typeWordCMD("This is a very Loong word$%@^@\\"), | ||
| funcCMD(complexWordTestEnd), | ||
|
|
||
| endCMD(), | ||
| }; | ||
| execList(list, baseExec, testKeyHandler); | ||
| char done[] = "test_kb_cmd done\n"; | ||
| serialWrite(COM1, (uint8_t *)(done), sizeof(done) - 1); | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.