gBoards Common (#8921)
Co-Authored-By: Drashna Jaelre <drashna@live.com>
This commit is contained in:
parent
6f30b402a2
commit
15e84f79f1
57 changed files with 11774 additions and 0 deletions
0
keyboards/gboards/engine/config.h
Normal file
0
keyboards/gboards/engine/config.h
Normal file
458
keyboards/gboards/engine/engine.c
Normal file
458
keyboards/gboards/engine/engine.c
Normal file
|
@ -0,0 +1,458 @@
|
|||
/* This is a stripped down version of the Georgi engine meant for use with
|
||||
* Ginni. As such serial-Steno features are disabled, chords are 16bits and
|
||||
* crap is removed where possible
|
||||
*
|
||||
* Do not use this on anything other then Ginny if you want to be sane
|
||||
*/
|
||||
#include "engine.h"
|
||||
|
||||
// Chord state
|
||||
C_SIZE cChord = 0; // Current Chord
|
||||
int chordIndex = 0; // Keys in previousachord
|
||||
C_SIZE pressed = 0; // number of held keys
|
||||
C_SIZE chordState[32]; // Full Chord history
|
||||
#define QWERBUF 24 // Size of chords to buffer for output
|
||||
|
||||
bool repeatFlag = false; // Should we repeat?
|
||||
C_SIZE pChord = 0; // Previous Chord
|
||||
C_SIZE stickyBits = 0; // Or'd with every incoming press
|
||||
int pChordIndex = 0; // Keys in previousachord
|
||||
C_SIZE pChordState[32]; // Previous chord sate
|
||||
|
||||
// Key Dicts
|
||||
extern const struct keyEntry keyDict[];
|
||||
extern const struct comboEntry cmbDict[];
|
||||
extern const struct funcEntry funDict[];
|
||||
extern const struct stringEntry strDict[];
|
||||
extern const struct specialEntry spcDict[];
|
||||
extern size_t specialLen;
|
||||
extern size_t stringLen;
|
||||
extern size_t funcsLen;
|
||||
extern size_t keyLen;
|
||||
extern size_t comboLen;
|
||||
|
||||
// Mode state
|
||||
enum MODE { STENO = 0, QWERTY, COMMAND };
|
||||
enum MODE pMode;
|
||||
enum MODE cMode = QWERTY;
|
||||
|
||||
// Command State
|
||||
#define MAX_CMD_BUF 20
|
||||
uint8_t CMDLEN = 0;
|
||||
uint8_t CMDBUF[MAX_CMD_BUF];
|
||||
|
||||
// Key Repeat state
|
||||
bool inChord = false;
|
||||
bool repEngaged = false;
|
||||
uint16_t repTimer = 0;
|
||||
#define REP_INIT_DELAY 750
|
||||
#define REP_DELAY 25
|
||||
|
||||
// Mousekeys state
|
||||
bool inMouse = false;
|
||||
int8_t mousePress;
|
||||
|
||||
// All processing done at chordUp goes through here
|
||||
void processKeysUp() {
|
||||
// Check for mousekeys, this is release
|
||||
#ifdef MOUSEKEY_ENABLE
|
||||
if (inMouse) {
|
||||
inMouse = false;
|
||||
mousekey_off(mousePress);
|
||||
mousekey_send();
|
||||
}
|
||||
#endif
|
||||
|
||||
// handle command mode
|
||||
if (cChord == COMMAND_MODE) {
|
||||
#ifndef NO_DEBUG
|
||||
uprintf("COMMAND Toggle\n");
|
||||
#endif
|
||||
if (cMode != COMMAND) { // Entering Command Mode
|
||||
CMDLEN = 0;
|
||||
pMode = cMode;
|
||||
cMode = COMMAND;
|
||||
} else { // Exiting Command Mode
|
||||
cMode = pMode;
|
||||
|
||||
// Press all and release all
|
||||
for (int i = 0; i < CMDLEN; i++) {
|
||||
register_code(CMDBUF[i]);
|
||||
}
|
||||
clear_keyboard();
|
||||
}
|
||||
}
|
||||
|
||||
// Process and reset state
|
||||
processChord();
|
||||
cChord = pressed;
|
||||
inChord = false;
|
||||
chordIndex = 0;
|
||||
clear_keyboard();
|
||||
repEngaged = false;
|
||||
for (int i = 0; i < 32; i++) chordState[i] = 0xFFFF;
|
||||
}
|
||||
|
||||
// Update Chord State
|
||||
bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
|
||||
// Everything happens in here when steno keys come in.
|
||||
// Bail on keyup
|
||||
|
||||
// Update key repeat timers
|
||||
repTimer = timer_read();
|
||||
bool pr = record->event.pressed;
|
||||
// Switch on the press adding to chord
|
||||
switch (keycode) {
|
||||
ENGINE_CONFIG
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle any postprocessing
|
||||
|
||||
// All keys up, send it!
|
||||
if (inChord && !pr && (pressed & IN_CHORD_MASK) == 0) {
|
||||
processKeysUp();
|
||||
return false;
|
||||
}
|
||||
if (pressed == 0 && !pr) {
|
||||
processKeysUp();
|
||||
return false;
|
||||
}
|
||||
|
||||
cChord |= pressed;
|
||||
cChord = process_engine_post(cChord, keycode, record);
|
||||
inChord = (cChord & IN_CHORD_MASK) != 0;
|
||||
|
||||
// Store previous state for fastQWER
|
||||
if (pr) {
|
||||
chordState[chordIndex] = cChord;
|
||||
chordIndex++;
|
||||
}
|
||||
|
||||
#ifndef NO_DEBUG
|
||||
uprintf("Chord: %u\n", cChord);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
void matrix_scan_user(void) {
|
||||
// We abuse this for early sending of key
|
||||
// Key repeat only on QWER/SYMB layers
|
||||
if (cMode != QWERTY || !inChord) return;
|
||||
|
||||
// Check timers
|
||||
#ifndef NO_HOLD
|
||||
if (!repEngaged && timer_elapsed(repTimer) > REP_INIT_DELAY) {
|
||||
// Process Key for report
|
||||
processChord();
|
||||
|
||||
// Send report to host
|
||||
send_keyboard_report();
|
||||
repEngaged = true;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
// Try and match cChord
|
||||
C_SIZE mapKeys(C_SIZE chord, bool lookup) {
|
||||
lookup = lookup || repEngaged;
|
||||
#ifndef NO_DEBUG
|
||||
if (!lookup) uprint("SENT!\n");
|
||||
#endif
|
||||
// Single key chords
|
||||
for (int i = 0; i < keyLen; i++) {
|
||||
if (keyDict[i].chord == chord) {
|
||||
if (!lookup) SEND(keyDict[i].key);
|
||||
return chord;
|
||||
}
|
||||
}
|
||||
|
||||
// strings
|
||||
for (int i = 0; i < stringLen; i++) {
|
||||
struct stringEntry fromPgm;
|
||||
memcpy_P(&fromPgm, &strDict[i], sizeof(stringEntry_t));
|
||||
if (fromPgm.chord == chord) {
|
||||
if (!lookup) {
|
||||
if (get_mods() & (MOD_LSFT | MOD_RSFT)) {
|
||||
set_mods(get_mods() & ~(MOD_LSFT | MOD_RSFT));
|
||||
set_oneshot_mods(MOD_LSFT);
|
||||
}
|
||||
send_string_P((PGM_P)(fromPgm.str));
|
||||
}
|
||||
return chord;
|
||||
}
|
||||
}
|
||||
|
||||
// combos
|
||||
for (int i = 0; i < comboLen; i++) {
|
||||
struct comboEntry fromPgm;
|
||||
memcpy_P(&fromPgm, &cmbDict[i], sizeof(comboEntry_t));
|
||||
if (fromPgm.chord == chord) {
|
||||
#ifndef NO_DEBUG
|
||||
uprintf("%d found combo\n", i);
|
||||
#endif
|
||||
|
||||
if (!lookup) {
|
||||
uint8_t comboKeys[COMBO_MAX];
|
||||
memcpy_P(&comboKeys, fromPgm.keys, sizeof(uint8_t) * COMBO_MAX);
|
||||
for (int j = 0; j < COMBO_MAX; j++)
|
||||
#ifndef NO_DEBUG
|
||||
uprintf("Combo [%u]: %u\n", j, comboKeys[j]);
|
||||
#endif
|
||||
|
||||
for (int j = 0; (j < COMBO_MAX) && (comboKeys[j] != COMBO_END); j++) {
|
||||
#ifndef NO_DEBUG
|
||||
uprintf("Combo [%u]: %u\n", j, comboKeys[j]);
|
||||
#endif
|
||||
SEND(comboKeys[j]);
|
||||
}
|
||||
}
|
||||
return chord;
|
||||
}
|
||||
}
|
||||
|
||||
// functions
|
||||
for (int i = 0; i < funcsLen; i++) {
|
||||
if (funDict[i].chord == chord) {
|
||||
if (!lookup) funDict[i].act();
|
||||
return chord;
|
||||
}
|
||||
}
|
||||
|
||||
// Special handling
|
||||
for (int i = 0; i < specialLen; i++) {
|
||||
if (spcDict[i].chord == chord) {
|
||||
if (!lookup) {
|
||||
uint16_t arg = spcDict[i].arg;
|
||||
switch (spcDict[i].action) {
|
||||
case SPEC_STICKY:
|
||||
SET_STICKY(arg);
|
||||
break;
|
||||
case SPEC_REPEAT:
|
||||
REPEAT();
|
||||
break;
|
||||
case SPEC_CLICK:
|
||||
CLICK_MOUSE((uint8_t)arg);
|
||||
break;
|
||||
case SPEC_SWITCH:
|
||||
SWITCH_LAYER(arg);
|
||||
break;
|
||||
default:
|
||||
SEND_STRING("Invalid Special in Keymap");
|
||||
}
|
||||
}
|
||||
return chord;
|
||||
}
|
||||
}
|
||||
|
||||
if ((chord & IN_CHORD_MASK) && (chord & IN_CHORD_MASK) != chord && mapKeys((chord & IN_CHORD_MASK), true) == (chord & IN_CHORD_MASK)) {
|
||||
#ifndef NO_DEBUG
|
||||
uprintf("Try with ignore mask:%u\n", (chord & IN_CHORD_MASK));
|
||||
#endif
|
||||
mapKeys((chord & ~IN_CHORD_MASK), lookup);
|
||||
mapKeys((chord & IN_CHORD_MASK), lookup);
|
||||
return chord;
|
||||
}
|
||||
#ifndef NO_DEBUG
|
||||
uprintf("Reached end\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
// Traverse the chord history to a given point
|
||||
// Returns the mask to use
|
||||
void processChord(void) {
|
||||
// Save the clean chord state
|
||||
C_SIZE savedChord = cChord;
|
||||
|
||||
// Apply Stick Bits if needed
|
||||
if (stickyBits != 0) {
|
||||
cChord |= stickyBits;
|
||||
for (int i = 0; i <= chordIndex; i++) chordState[i] |= stickyBits;
|
||||
}
|
||||
|
||||
// First we test if a whole chord was passsed
|
||||
// If so we just run it handling repeat logic
|
||||
if (mapKeys(cChord, true) == cChord) {
|
||||
mapKeys(cChord, false);
|
||||
// Repeat logic
|
||||
if (repeatFlag) {
|
||||
#ifndef NO_DEBUG
|
||||
uprintf("repeating?\n");
|
||||
#endif
|
||||
restoreState();
|
||||
repeatFlag = false;
|
||||
processChord();
|
||||
} else {
|
||||
saveState(cChord);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
C_SIZE next = process_chord_getnext(cChord);
|
||||
if (next && next != cChord) {
|
||||
#ifndef NO_DEBUG
|
||||
uprintf("Trying next candidate: %u\n", next);
|
||||
#endif
|
||||
if (mapKeys(next, true) == next) {
|
||||
mapKeys(next, false);
|
||||
// Repeat logic
|
||||
if (repeatFlag) {
|
||||
#ifndef NO_DEBUG
|
||||
uprintf("repeating?\n");
|
||||
#endif
|
||||
restoreState();
|
||||
repeatFlag = false;
|
||||
processChord();
|
||||
} else {
|
||||
saveState(cChord);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NO_DEBUG
|
||||
uprintf("made it past the maw\n");
|
||||
#endif
|
||||
|
||||
// Iterate through chord picking out the individual
|
||||
// and longest chords
|
||||
C_SIZE bufChords[QWERBUF];
|
||||
int bufLen = 0;
|
||||
C_SIZE mask = 0;
|
||||
|
||||
// We iterate over it multiple times to catch the longest
|
||||
// chord. Then that gets addded to the mask and re run.
|
||||
while (savedChord != mask) {
|
||||
C_SIZE test = 0;
|
||||
C_SIZE longestChord = 0;
|
||||
|
||||
for (int i = 0; i <= chordIndex; i++) {
|
||||
cChord = chordState[i] & ~mask;
|
||||
if (cChord == 0) continue;
|
||||
|
||||
test = mapKeys(cChord, true);
|
||||
if (test != 0) {
|
||||
longestChord = test;
|
||||
}
|
||||
}
|
||||
|
||||
mask |= longestChord;
|
||||
bufChords[bufLen] = longestChord;
|
||||
bufLen++;
|
||||
|
||||
// That's a loop of sorts, halt processing
|
||||
if (bufLen >= QWERBUF) {
|
||||
#ifndef NO_DEBUG
|
||||
uprintf("looped. exiting");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Now that the buffer is populated, we run it
|
||||
for (int i = 0; i < bufLen; i++) {
|
||||
cChord = bufChords[i];
|
||||
#ifndef NO_DEBUG
|
||||
uprintf("sending: %u\n", cChord);
|
||||
#endif
|
||||
mapKeys(cChord, false);
|
||||
}
|
||||
|
||||
// Save state in case of repeat
|
||||
if (!repeatFlag) {
|
||||
saveState(savedChord);
|
||||
}
|
||||
|
||||
// Restore cChord for held repeat
|
||||
cChord = savedChord;
|
||||
return;
|
||||
}
|
||||
void saveState(C_SIZE cleanChord) {
|
||||
pChord = cleanChord;
|
||||
pChordIndex = chordIndex;
|
||||
for (int i = 0; i < 32; i++) pChordState[i] = chordState[i];
|
||||
}
|
||||
void restoreState() {
|
||||
cChord = pChord;
|
||||
chordIndex = pChordIndex;
|
||||
for (int i = 0; i < 32; i++) chordState[i] = pChordState[i];
|
||||
}
|
||||
|
||||
// Macros for calling from keymap.c
|
||||
void SEND(uint8_t kc) {
|
||||
// Send Keycode, Does not work for Quantum Codes
|
||||
if (cMode == COMMAND && CMDLEN < MAX_CMD_BUF) {
|
||||
#ifndef NO_DEBUG
|
||||
uprintf("CMD LEN: %d BUF: %d\n", CMDLEN, MAX_CMD_BUF);
|
||||
#endif
|
||||
CMDBUF[CMDLEN] = kc;
|
||||
CMDLEN++;
|
||||
}
|
||||
|
||||
if (cMode != COMMAND) register_code(kc);
|
||||
return;
|
||||
}
|
||||
void REPEAT(void) {
|
||||
if (cMode != QWERTY) return;
|
||||
|
||||
repeatFlag = true;
|
||||
return;
|
||||
}
|
||||
void SET_STICKY(C_SIZE stick) {
|
||||
stickyBits ^= stick;
|
||||
return;
|
||||
}
|
||||
void CLICK_MOUSE(uint8_t kc) {
|
||||
#ifdef MOUSEKEY_ENABLE
|
||||
mousekey_on(kc);
|
||||
mousekey_send();
|
||||
|
||||
// Store state for later use
|
||||
inMouse = true;
|
||||
mousePress = kc;
|
||||
#endif
|
||||
}
|
||||
void SWITCH_LAYER(int layer) {
|
||||
#ifndef NO_ACTION_LAYER
|
||||
if (keymapsCount >= layer) layer_on(layer);
|
||||
#endif
|
||||
}
|
||||
uint8_t bitpop_v(C_SIZE val) {
|
||||
#if C_SIZE == uint8_t
|
||||
return bitpop(val);
|
||||
#elif C_SIZE == uint16_t
|
||||
return bitpop16(val);
|
||||
#elif C_SIZE == uint32_t
|
||||
return bitpop32(val);
|
||||
#elif C_SIZE == uint64_t
|
||||
uint8_t n = 0;
|
||||
if (bits >> 32) {
|
||||
bits >>= 32;
|
||||
n += 32;
|
||||
}
|
||||
if (bits >> 16) {
|
||||
bits >>= 16;
|
||||
n += 16;
|
||||
}
|
||||
if (bits >> 8) {
|
||||
bits >>= 8;
|
||||
n += 8;
|
||||
}
|
||||
if (bits >> 4) {
|
||||
bits >>= 4;
|
||||
n += 4;
|
||||
}
|
||||
if (bits >> 2) {
|
||||
bits >>= 2;
|
||||
n += 2;
|
||||
}
|
||||
if (bits >> 1) {
|
||||
bits >>= 1;
|
||||
n += 1;
|
||||
}
|
||||
return n;
|
||||
#else
|
||||
# error unsupported C_SIZE
|
||||
#endif
|
||||
}
|
||||
__attribute__((weak)) C_SIZE process_engine_post(C_SIZE cur_chord, uint16_t keycode, keyrecord_t *record) { return cur_chord; }
|
104
keyboards/gboards/engine/engine.h
Normal file
104
keyboards/gboards/engine/engine.h
Normal file
|
@ -0,0 +1,104 @@
|
|||
/* 2019, g Heavy Industries
|
||||
Blessed mother of Christ, please keep this readable
|
||||
and protect us from segfaults. For thine is the clock,
|
||||
the slave and the master. Until we return from main.
|
||||
|
||||
Amen.
|
||||
|
||||
This is a stripped down version of the Georgi engine meant for use with
|
||||
. As such serial-Steno features are disabled, chords are 16bits and
|
||||
crap is removed where possible
|
||||
*/
|
||||
|
||||
#include QMK_KEYBOARD_H
|
||||
#pragma once
|
||||
#include "keymap.h"
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "config_engine.h"
|
||||
#include <avr/pgmspace.h>
|
||||
#include "wait.h"
|
||||
|
||||
// Maximum values for combos
|
||||
#define COMBO_END 0x00
|
||||
|
||||
// In memory chord datatypes
|
||||
enum specialActions {
|
||||
SPEC_STICKY,
|
||||
SPEC_REPEAT,
|
||||
SPEC_CLICK,
|
||||
SPEC_SWITCH,
|
||||
};
|
||||
struct funcEntry {
|
||||
C_SIZE chord;
|
||||
void (*act)(void);
|
||||
} funcEntry_t;
|
||||
struct stringEntry {
|
||||
C_SIZE chord;
|
||||
PGM_P str;
|
||||
} stringEntry_t;
|
||||
struct comboEntry {
|
||||
C_SIZE chord;
|
||||
PGM_P keys;
|
||||
} comboEntry_t;
|
||||
struct keyEntry {
|
||||
C_SIZE chord;
|
||||
uint8_t key;
|
||||
} keyEntry_t;
|
||||
struct specialEntry {
|
||||
C_SIZE chord;
|
||||
enum specialActions action;
|
||||
uint16_t arg;
|
||||
} specialEntry_t;
|
||||
|
||||
// Chord Temps
|
||||
extern C_SIZE cChord;
|
||||
extern C_SIZE test;
|
||||
|
||||
// Function defs
|
||||
void processKeysUp(void);
|
||||
void processChord(void);
|
||||
C_SIZE processQwerty(bool lookup);
|
||||
C_SIZE processFakeSteno(bool lookup);
|
||||
void saveState(C_SIZE cChord);
|
||||
void restoreState(void);
|
||||
uint8_t bitpop_v(C_SIZE val);
|
||||
|
||||
// Macros for use in keymap.c
|
||||
void SEND(uint8_t kc);
|
||||
void REPEAT(void);
|
||||
void SET_STICKY(C_SIZE);
|
||||
void SWITCH_LAYER(int);
|
||||
void CLICK_MOUSE(uint8_t);
|
||||
C_SIZE process_engine_post(C_SIZE cur_chord, uint16_t keycode, keyrecord_t *record);
|
||||
C_SIZE process_chord_getnext(C_SIZE cur_chord);
|
||||
|
||||
// Keymap helpers
|
||||
// New Approach, multiple structures
|
||||
#define P_KEYMAP(chord, keycode) {chord, keycode},
|
||||
|
||||
#define K_KEYMAP(chord, name, ...) {chord, (PGM_P)&name},
|
||||
#define K_ACTION(chord, name, ...) const uint8_t name[] PROGMEM = __VA_ARGS__;
|
||||
|
||||
#define S_KEYMAP(chord, name, string) {chord, (PGM_P)&name},
|
||||
#define S_ACTION(chord, name, string) const char name[] PROGMEM = string;
|
||||
|
||||
#define X_KEYMAP(chord, name, func) {chord, name},
|
||||
#define X_ACTION(chord, name, func) \
|
||||
void name(void) { func }
|
||||
|
||||
#define Z_KEYMAP(chord, act, arg) {chord, act, arg},
|
||||
|
||||
#define TEST_COLLISION(chord, ...) \
|
||||
case chord: \
|
||||
break;
|
||||
#define BLANK(...)
|
||||
|
||||
// Shift to internal representation
|
||||
// i.e) S(teno)R(ight)F
|
||||
#define STN(n) ((C_SIZE)1 << n)
|
||||
#define ENGINE_HOOK(keycode, chord) \
|
||||
case keycode: \
|
||||
pr ? (pressed |= (chord)) : (pressed &= ~(chord)); \
|
||||
break;
|
121
keyboards/gboards/engine/keymap_engine.h
Normal file
121
keyboards/gboards/engine/keymap_engine.h
Normal file
|
@ -0,0 +1,121 @@
|
|||
/* If for some reason you're still here, maybe due to horror, shock or
|
||||
* some other godforsaken reason. Meet X Macros.
|
||||
*
|
||||
* The we abuse the include system to generate data structures that are
|
||||
* used by the internal chording engine. The alternative to this is
|
||||
* using a external generator (Like is done for the ASETNIOP base keymaps)
|
||||
* With this disgusting bodge, you can just edit your .defs and compile!
|
||||
*/
|
||||
|
||||
// Clear all X Macros
|
||||
#define PRES BLANK
|
||||
#define KEYS BLANK
|
||||
#define SUBS BLANK
|
||||
#define EXEC BLANK
|
||||
#define SPEC BLANK
|
||||
|
||||
// Process single key pushes
|
||||
#undef PRES
|
||||
#define PRES P_KEYMAP
|
||||
const struct keyEntry keyDict[] = {
|
||||
#include "dicts.def"
|
||||
};
|
||||
#undef PRES
|
||||
#define PRES BLANK
|
||||
|
||||
// Process Combos
|
||||
#undef KEYS
|
||||
#define KEYS K_ACTION
|
||||
#include "dicts.def"
|
||||
#undef KEYS
|
||||
#define KEYS BLANK
|
||||
|
||||
#undef KEYS
|
||||
#define KEYS K_KEYMAP
|
||||
const struct comboEntry PROGMEM cmbDict[] = {
|
||||
#include "dicts.def"
|
||||
};
|
||||
#undef KEYS
|
||||
#define KEYS BLANK
|
||||
|
||||
// Process String stubs
|
||||
#undef SUBS
|
||||
#define SUBS S_ACTION
|
||||
#include "dicts.def"
|
||||
#undef SUBS
|
||||
#define SUBS BLANK
|
||||
|
||||
// Generate dict for strings
|
||||
#undef SUBS
|
||||
#define SUBS S_KEYMAP
|
||||
const struct stringEntry PROGMEM strDict[] = {
|
||||
#include "dicts.def"
|
||||
};
|
||||
#undef SUBS
|
||||
#define SUBS BLANK
|
||||
|
||||
// Generate function stubs
|
||||
#undef EXEC
|
||||
#define EXEC X_ACTION
|
||||
#include "dicts.def"
|
||||
#undef EXEC
|
||||
#define EXEC BLANK
|
||||
|
||||
// Process the function structure
|
||||
#undef EXEC
|
||||
#define EXEC X_KEYMAP
|
||||
const struct funcEntry funDict[] = {
|
||||
#include "dicts.def"
|
||||
};
|
||||
#undef EXEC
|
||||
#define EXEC BLANK
|
||||
|
||||
// Handle Special calls
|
||||
#undef SPEC
|
||||
#define SPEC Z_KEYMAP
|
||||
const struct specialEntry spcDict[] = {
|
||||
#include "dicts.def"
|
||||
};
|
||||
#undef SPEC
|
||||
#define SPEC BLANK
|
||||
|
||||
// Test for collisions!
|
||||
// Switch statement will explode on duplicate
|
||||
// chords. This will be optimized out
|
||||
#undef PRES
|
||||
#undef KEYS
|
||||
#undef SUBS
|
||||
#undef EXEC
|
||||
#undef SPEC
|
||||
#define PRES TEST_COLLISION
|
||||
#define KEYS TEST_COLLISION
|
||||
#define SUBS TEST_COLLISION
|
||||
#define EXEC TEST_COLLISION
|
||||
#define SPEC TEST_COLLISION
|
||||
void testCollisions(void) {
|
||||
C_SIZE bomb = 0;
|
||||
switch (bomb) {
|
||||
#include "dicts.def"
|
||||
}
|
||||
}
|
||||
|
||||
// Test for unexpected input
|
||||
// Should return blank lines for all valid input
|
||||
#undef PRES
|
||||
#undef KEYS
|
||||
#undef SUBS
|
||||
#undef EXEC
|
||||
#undef SPEC
|
||||
#define PRES BLANK
|
||||
#define KEYS BLANK
|
||||
#define SUBS BLANK
|
||||
#define EXEC BLANK
|
||||
#define SPEC BLANK
|
||||
#include "dicts.def"
|
||||
|
||||
// Get size data back into the engine
|
||||
size_t funcsLen = sizeof(funDict) / sizeof(funDict[0]);
|
||||
size_t stringLen = sizeof(strDict) / sizeof(strDict[0]);
|
||||
size_t keyLen = sizeof(keyDict) / sizeof(keyDict[0]);
|
||||
size_t comboLen = sizeof(cmbDict) / sizeof(cmbDict[0]);
|
||||
size_t specialLen = sizeof(spcDict) / sizeof(spcDict[0]);
|
1
keyboards/gboards/engine/rules.mk
Normal file
1
keyboards/gboards/engine/rules.mk
Normal file
|
@ -0,0 +1 @@
|
|||
SRC += engine.c
|
Loading…
Add table
Add a link
Reference in a new issue