add compose support
This commit is contained in:
parent
b99fab1281
commit
e49414745e
13 changed files with 47771 additions and 2 deletions
8705
keyboards/rkb1/keymaps/simple/XCompose
Normal file
8705
keyboards/rkb1/keymaps/simple/XCompose
Normal file
File diff suppressed because it is too large
Load diff
126
keyboards/rkb1/keymaps/simple/compose.c
Normal file
126
keyboards/rkb1/keymaps/simple/compose.c
Normal file
|
@ -0,0 +1,126 @@
|
|||
#include "compose.h"
|
||||
#include <stdint.h>
|
||||
#include "action.h"
|
||||
#include "keycode.h"
|
||||
#include "neo2.h"
|
||||
#include "print.h"
|
||||
#include "quantum_keycodes.h"
|
||||
#include "unicode/unicode.h"
|
||||
|
||||
static int charsWritten, currentState;
|
||||
|
||||
static void resetState(void) {
|
||||
print("resetState()\n");
|
||||
charsWritten = 0;
|
||||
currentState = 0;
|
||||
}
|
||||
|
||||
static void finishCompose(const char* result) {
|
||||
uprintf("Finishing compose with result: %s (%d chars written)\n", result, charsWritten);
|
||||
while(charsWritten) {
|
||||
tap_code(KC_BACKSPACE);
|
||||
charsWritten--;
|
||||
}
|
||||
send_unicode_string(result);
|
||||
resetState();
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint16_t first_edge_idx;
|
||||
uint16_t edge_count;
|
||||
} compose_node_t;
|
||||
|
||||
typedef struct {
|
||||
const char * value;
|
||||
uint16_t c;
|
||||
uint16_t next_node;
|
||||
} compose_edge_t;
|
||||
|
||||
#include "composeTable.h"
|
||||
|
||||
static void checkComposeState(void) {
|
||||
print("checkComposeState()\n");
|
||||
if(currentState * sizeof(compose_node_t) > sizeof(nodes)) {
|
||||
finishCompose("[error in compose]");
|
||||
}
|
||||
}
|
||||
|
||||
static const compose_edge_t *findEdge(uint16_t keycode) {
|
||||
checkComposeState();
|
||||
uint32_t uc = keystroke_to_unicode(keycode);
|
||||
uprintf("Resolved keycode %d: %ld\n", keycode, uc);
|
||||
|
||||
uint16_t match1 = (uint16_t)uc; // yes only bmp support, keyboard doesn’t have any astral keycodes anyways
|
||||
uint16_t match2 = 0;
|
||||
if(keycode < 256) {
|
||||
match2 = 0xD800 + keycode;
|
||||
print("(low keycode)\n");
|
||||
} else if(keycode == KC_LEAD) {
|
||||
match2 = 0xD800;
|
||||
print("(leader key)\n");
|
||||
}
|
||||
|
||||
for(int i = nodes[currentState].first_edge_idx; i < nodes[currentState].first_edge_idx + nodes[currentState].edge_count; i++) {
|
||||
if(compose_edges[i].c == match1 || compose_edges[i].c == match2) {
|
||||
uprintf("found matching node: %d -> %d\n", currentState, i);
|
||||
return &compose_edges[i];
|
||||
}
|
||||
}
|
||||
print("no matching edge found.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// yes this breaks with emoji
|
||||
static size_t charcount_utf8(const char * s) {
|
||||
size_t n = 0;
|
||||
while(*s)
|
||||
if((*(s++) & 0xC0) != 0x80)
|
||||
n++; // only count non-continuation characters
|
||||
return n;
|
||||
}
|
||||
|
||||
static void transEdge(const compose_edge_t *edge) {
|
||||
uprintf("Transitioning to node %d\n", edge->next_node);
|
||||
if(edge->value) {
|
||||
uprintf("new node has value %s\n", edge->value);
|
||||
finishCompose(edge->value);
|
||||
if(edge->next_node != 0) // not necessarily the final product
|
||||
charsWritten = charcount_utf8(edge->value);
|
||||
}
|
||||
currentState = edge->next_node;
|
||||
checkComposeState();
|
||||
}
|
||||
|
||||
static bool isCombining(uint32_t uc) {
|
||||
// yes it is not all of them, but all of them that matter for us
|
||||
if(uc >= 0x300 && uc < 0x370)
|
||||
return true;
|
||||
if(uc == 0x20d7)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void process_compose(uint16_t keycode, keyrecord_t *record) {
|
||||
if(!record->event.pressed)
|
||||
return;
|
||||
const compose_edge_t * edge = findEdge(keycode);
|
||||
if(edge == NULL) { // no matching edge found, reset and try again
|
||||
print("No matching edge found, reset.\n");
|
||||
resetState();
|
||||
edge = findEdge(keycode);
|
||||
}
|
||||
if(edge == NULL) {
|
||||
print("No compose edge found.\n");
|
||||
return; // nothing found
|
||||
}
|
||||
// before we can advance the compose state, we need to prepare certain keys (dead keys, the leader key) because otherwise our deletion will delete too much (which of course is something we do not want)
|
||||
if(isCombining(keystroke_to_unicode(keycode))) {
|
||||
print("keycode refers to deadkey, writing space\n");
|
||||
tap_code(KC_SPACE);
|
||||
} else if(keycode == KC_LEAD) {
|
||||
print("keycode refers to leader key, writing compose symbol\n");
|
||||
send_unicode_string("♫");
|
||||
}
|
||||
charsWritten++;
|
||||
transEdge(edge);
|
||||
}
|
5
keyboards/rkb1/keymaps/simple/compose.h
Normal file
5
keyboards/rkb1/keymaps/simple/compose.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "action.h"
|
||||
void process_compose(uint16_t keycode, keyrecord_t *record);
|
35660
keyboards/rkb1/keymaps/simple/composeTable.h
Normal file
35660
keyboards/rkb1/keymaps/simple/composeTable.h
Normal file
File diff suppressed because it is too large
Load diff
290
keyboards/rkb1/keymaps/simple/keyToCharGen.py
Normal file
290
keyboards/rkb1/keymaps/simple/keyToCharGen.py
Normal file
|
@ -0,0 +1,290 @@
|
|||
data = {
|
||||
' ': [(1, 'space')],
|
||||
'!': [(3, 'k')],
|
||||
'"': [(3, ',')],
|
||||
'#': [(3, 'ü')],
|
||||
'$': [(2, '6'), (3, 'ö')],
|
||||
'%': [(3, 'm'), (3, 'p0')],
|
||||
'&': [(3, 'q')],
|
||||
"'": [(3, '.')],
|
||||
"(": [(3, 'n')],
|
||||
")": [(3, 'r')],
|
||||
"*": [(1, 'kp_asterisk'), (2, 'kp_asterisk'), (3, 'o'), (4, '0')],
|
||||
"+": [(1, 'kp_plus'), (2, 'kp_plus'), (3, 'b'), (4, 'q')],
|
||||
",": [(1, 'kp_dot'), (3, 'kp_dot'), (4, 'd')],
|
||||
"-": [(1, '-'), (1, 'kp_minus'), (2, 'kp_minus'), (3, 't'), (4, '-')],
|
||||
".": [(1, '.'), (2, 'kp_dot'), (4, 'y')],
|
||||
"/": [(1, 'kp_slash'), (2, 'kp_slash'), (3, 'i'), (4, '9')],
|
||||
"0": [(1, '0'), (1, 'p0'), (4, ' ')],
|
||||
"1": [(1, '1'), (1, 'p1'), (4, 'm')],
|
||||
"2": [(1, '2'), (1, 'p2'), (4, ',')],
|
||||
"3": [(1, '3'), (1, 'p3'), (4, '.')],
|
||||
"4": [(1, '4'), (1, 'p4'), (4, 'n')],
|
||||
"5": [(1, '5'), (1, 'p5'), (4, 'r')],
|
||||
"6": [(1, '6'), (1, 'p6'), (4, 't')],
|
||||
"7": [(1, '7'), (1, 'p7'), (4, 'h')],
|
||||
"8": [(1, '8'), (1, 'p8'), (4, 'g')],
|
||||
"9": [(1, '9'), (1, 'p9'), (4, 'f')],
|
||||
":": [(3, 'd'), (3, 'p5'), (4, 'b')],
|
||||
";": [(3, 'j'), (4, 'j')],
|
||||
"<": [(3, 'h')],
|
||||
"=": [(3, 'f'), (3, 'num_lock')],
|
||||
">": [(3, 'g')],
|
||||
'?': [(3, 's')],
|
||||
'@': [(3, 'y')],
|
||||
'[': [(3, 'l')],
|
||||
'\\': [(3, 'u')],
|
||||
']': [(3, 'c')],
|
||||
'^': [(3, 'w')],
|
||||
'_': [(3, 'v')],
|
||||
'`': [(3, 'z')],
|
||||
'{': [(3, 'a')],
|
||||
'|': [(3, 'ä')],
|
||||
'}': [(3, 'e')],
|
||||
'~': [(3, 'p')],
|
||||
'\u00a0': [(5, ' ')],
|
||||
'¡': [(4, 'k')],
|
||||
'¢': [(3, '6')],
|
||||
'£': [(4, '6')],
|
||||
'¤': [(4, '7')],
|
||||
'¥': [(3, '7')],
|
||||
'§': [(2, '2')],
|
||||
'ª': [(4, '1')],
|
||||
'«': [(2, '5')],
|
||||
'¬': [(6, '1')],
|
||||
'\u00ad': [(6, '-')],
|
||||
'°': [(2, '1')],
|
||||
'±': [(3, 'kp_plus')],
|
||||
'²': [(3, '2')],
|
||||
'³': [(3, '3')],
|
||||
'·': [(4, '5')],
|
||||
'¹': [(3, '1')],
|
||||
'º': [(4, '2')],
|
||||
'»': [(2, '4')],
|
||||
'¿': [(4, 's')],
|
||||
'Ä': [(2, 'ä')],
|
||||
'Ö': [(2, 'ö')],
|
||||
'×': [(4, 'kp_asterisk'), (6, 'k')],
|
||||
'Ü': [(2, 'ü')],
|
||||
'ß': [(1, 'ß')],
|
||||
'ä': [(1, 'ä')],
|
||||
'ö': [(1, 'ö')],
|
||||
'÷': [(3, 'kp_slash')],
|
||||
'ü': [(1, 'ü')],
|
||||
'ſ': [(3, 'ß')],
|
||||
'Γ': [(6, 'g')],
|
||||
'Δ': [(6, 'd')],
|
||||
'Θ': [(6, 'j')],
|
||||
'Λ': [(6, 'l')],
|
||||
'Ξ': [(6, 'x')],
|
||||
'Π': [(6, 'p')],
|
||||
'Σ': [(6, 's')],
|
||||
'Φ': [(6, 'f')],
|
||||
'Ψ': [(6, 'h')],
|
||||
'Ω': [(6, 'w')],
|
||||
'α': [(5, 'a')],
|
||||
'β': [(5, 'b')],
|
||||
'γ': [(5, 'g')],
|
||||
'δ': [(5, 'd')],
|
||||
'ε': [(5, 'e')],
|
||||
'ζ': [(5, 'z')],
|
||||
'η': [(5, 'ä')],
|
||||
'θ': [(5, 'j')],
|
||||
'ι': [(5, 'i')],
|
||||
'κ': [(5, 'k')],
|
||||
'λ': [(5, 'l')],
|
||||
'μ': [(5, 'm')],
|
||||
'ν': [(5, 'n')],
|
||||
'ξ': [(5, 'x')],
|
||||
'ο': [(5, 'o')],
|
||||
'π': [(5, 'p')],
|
||||
'ρ': [(5, 'r')],
|
||||
'τ': [(5, 't')],
|
||||
'ς': [(5, 'ß')],
|
||||
'σ': [(5, 's')],
|
||||
'υ': [(5, 'y')],
|
||||
'φ': [(5, 'f')],
|
||||
'χ': [(5, 'c')],
|
||||
'ψ': [(5, 'h')],
|
||||
'ω': [(5, 'w')],
|
||||
'ϑ': [(5, '.')],
|
||||
'ϕ': [(5, 'q')],
|
||||
'ϰ': [(5, '7')],
|
||||
'ϱ': [(5, ',')],
|
||||
'ϵ': [(5, 'ö')],
|
||||
'ẞ': [(2, 'ß')],
|
||||
'\u2011': [(5, '-')],
|
||||
'\u2013': [(2, ',')],
|
||||
'\u2014': [(2, '-')],
|
||||
'‘': [(3, '9')],
|
||||
'’': [(3, '0')],
|
||||
'‚': [(3, '8')],
|
||||
'“': [(2, '9')],
|
||||
'”': [(2, '0')],
|
||||
'„': [(2, '8')],
|
||||
'†': [(2, 'p9')],
|
||||
'•': [(2, '.')],
|
||||
'‣': [(2, 'p6')],
|
||||
'…': [(3, 'x')],
|
||||
'\u202f': [(6, ' ')],
|
||||
'‰': [(5, 'p0')],
|
||||
'′': [(5, 'kp_dot')],
|
||||
'″': [(6, 'kp_dot')],
|
||||
'‹': [(3, '5')],
|
||||
'›': [(3, '4')],
|
||||
'\u2044': [(4, 'kp_slash')],
|
||||
'₀': [(5, '0')],
|
||||
'₁': [(5, '1')],
|
||||
'₂': [(5, '2')],
|
||||
'₃': [(5, '3')],
|
||||
'€': [(2, '7'), (2, 'p5')],
|
||||
'ℂ': [(6, 'c')],
|
||||
'ℓ': [(2, '3')],
|
||||
'ℕ': [(6, 'n')],
|
||||
'№': [(4, '3')],
|
||||
'ℚ': [(6, 'q')],
|
||||
'ℝ': [(6, 'r')],
|
||||
'ℤ': [(6, 'z')],
|
||||
'ℵ': [(6, 'ä')],
|
||||
'←': [(3, 'p4')],
|
||||
'↑': [(3, 'p8')],
|
||||
'→': [(3, 'p6'), (6, '7')],
|
||||
'↓': [(3, 'p2')],
|
||||
'↔': [(3, 'p1')],
|
||||
'↕': [(3, 'p7')],
|
||||
'↦': [(6, '.')],
|
||||
'⇌': [(3, 'p3')],
|
||||
'⇐': [(6, 'b')],
|
||||
'⇒': [(6, ',')],
|
||||
'⇔': [(6, 'm')],
|
||||
'∀': [(6, 'a')],
|
||||
'∂': [(6, 't')],
|
||||
'∃': [(6, 'e')],
|
||||
'∅': [(6, '0')],
|
||||
'∇': [(6, 'y')],
|
||||
'∈': [(6, 'o')],
|
||||
'\u2212': [(3, 'kp_minus'), (4, 'ß')],
|
||||
'∓': [(4, 'kp_plus')],
|
||||
'∔': [(6, 'kp_plus')],
|
||||
'∖': [(4, 'kp_minus')],
|
||||
'∘': [(6, 'ß')],
|
||||
'√': [(6, 'v')],
|
||||
'∝': [(6, '9')],
|
||||
'∞': [(6, '8')],
|
||||
'∡': [(6, '5')],
|
||||
'\u2223': [(6, 'kp_slash')],
|
||||
'∥': [(6, '6')],
|
||||
'∧': [(6, '3')],
|
||||
'∨': [(6, '2')],
|
||||
'∩': [(5, 'p8'), (6, 'ö')],
|
||||
'∪': [(5, 'p2'), (6, 'ü')],
|
||||
'∫': [(6, 'i')],
|
||||
'∸': [(6, 'kp_minus')],
|
||||
'≈': [(5, 'num_lock')],
|
||||
'≠': [(4, 'num_lock')],
|
||||
'≡': [(6, 'num_lock')],
|
||||
'≤': [(5, 'p1')],
|
||||
'≥': [(5, 'p3')],
|
||||
'≪': [(5, 'p7')],
|
||||
'≫': [(5, 'p9')],
|
||||
'⊂': [(5, 'p4'), (6, 'u')],
|
||||
'⊃': [(5, 'p6')],
|
||||
'⊆': [(6, 'p4')],
|
||||
'⊇': [(6, 'p6')],
|
||||
'⊕': [(5, 'kp_plus')],
|
||||
'⊖': [(5, 'kp_minus')],
|
||||
'⊗': [(6, 'kp_asterisk')],
|
||||
'⊙': [(5, 'kp_asterisk')],
|
||||
'⊥': [(6, '4')],
|
||||
'⊶': [(5, 'p5')],
|
||||
'⊷': [(6, 'p5')],
|
||||
'⋂': [(6, 'p8')],
|
||||
'⋃': [(6, 'p2')],
|
||||
'⋅': [(3, 'kp_asterisk')],
|
||||
'⌀': [(5, 'kp_slash')],
|
||||
'⌈': [(6, 'p7')],
|
||||
'⌉': [(6, 'p9')],
|
||||
'⌊': [(6, 'p1')],
|
||||
'⌋': [(6, 'p3')],
|
||||
'␣': [(2, 'p0')],
|
||||
'□': [(6, 'p0')],
|
||||
'♠': [(2, 'p3')],
|
||||
'♣': [(2, 'p4')],
|
||||
'♥': [(2, 'p2')],
|
||||
'♦': [(2, 'p1')],
|
||||
'♀': [(5, '4')],
|
||||
'♂': [(5, '5')],
|
||||
'⚥': [(5, '6')],
|
||||
'✔': [(2, 'p7')],
|
||||
'✘': [(2, 'p8')],
|
||||
'⟨': [(5, '8')],
|
||||
'⟩': [(5, '9')]
|
||||
}
|
||||
|
||||
for c in range(0x41, 0x5B):
|
||||
c = chr(c)
|
||||
data[c] = [(2, c.lower())]
|
||||
data[c.lower()] = [(1, c.lower())]
|
||||
|
||||
trans = {
|
||||
'x': 'q',
|
||||
'v': 'w',
|
||||
'l': 'e',
|
||||
'c': 'r',
|
||||
'w': 't',
|
||||
'k': 'y',
|
||||
'h': 'u',
|
||||
'g': 'i',
|
||||
'f': 'o',
|
||||
'q': 'p',
|
||||
'ß': 'lbrc',
|
||||
'u': 'a',
|
||||
'i': 's',
|
||||
'a': 'd',
|
||||
'e': 'f',
|
||||
'o': 'g',
|
||||
's': 'h',
|
||||
'n': 'j',
|
||||
'r': 'k',
|
||||
't': 'l',
|
||||
'd': 'scln',
|
||||
'y': 'quot',
|
||||
'ü': 'z',
|
||||
'ö': 'x',
|
||||
'ä': 'c',
|
||||
'p': 'v',
|
||||
'z': 'b',
|
||||
'b': 'n',
|
||||
',': 'comm',
|
||||
'.': 'dot',
|
||||
'j': 'slsh',
|
||||
'-': 'mins',
|
||||
' ': 'space'
|
||||
}
|
||||
|
||||
keys = {}
|
||||
|
||||
|
||||
def insert_key(key, layer, char):
|
||||
if key in trans:
|
||||
key = trans[key]
|
||||
if key not in keys:
|
||||
keys[key] = [0, 0, 0, 0, 0, 0]
|
||||
if keys[key][layer] != 0:
|
||||
raise Exception(f"duplicate key/layer combo: {key},{layer}={char}, current value: {chr(keys[key][layer])}")
|
||||
keys[key][layer] = ord(char)
|
||||
|
||||
|
||||
for (char, value) in data.items():
|
||||
for (layer, key) in value:
|
||||
insert_key(key, layer - 1, char)
|
||||
|
||||
print("const uint16_t keycode_to_char[][6] = {")
|
||||
|
||||
for (key, value) in keys.items():
|
||||
print(f" [KC_{key.upper()}] = {{")
|
||||
for char in value:
|
||||
print(f" {hex(char)},")
|
||||
print(" },")
|
||||
|
||||
print("};")
|
482
keyboards/rkb1/keymaps/simple/keyToCharTable.h
Normal file
482
keyboards/rkb1/keymaps/simple/keyToCharTable.h
Normal file
|
@ -0,0 +1,482 @@
|
|||
const uint16_t keycode_to_char[][6] = {
|
||||
[KC_SPACE] = {
|
||||
0x20,
|
||||
0x0,
|
||||
0x0,
|
||||
0x30,
|
||||
0xa0,
|
||||
0x202f,
|
||||
},
|
||||
[KC_Y] = {
|
||||
0x6b,
|
||||
0x4b,
|
||||
0x21,
|
||||
0xa1,
|
||||
0x3ba,
|
||||
0xd7,
|
||||
},
|
||||
[KC_COMM] = {
|
||||
0x0,
|
||||
0x2013,
|
||||
0x22,
|
||||
0x32,
|
||||
0x3f1,
|
||||
0x21d2,
|
||||
},
|
||||
[KC_Z] = {
|
||||
0xfc,
|
||||
0xdc,
|
||||
0x23,
|
||||
0x0,
|
||||
0x0,
|
||||
0x222a,
|
||||
},
|
||||
[KC_6] = {
|
||||
0x36,
|
||||
0x24,
|
||||
0xa2,
|
||||
0xa3,
|
||||
0x26a5,
|
||||
0x2225,
|
||||
},
|
||||
[KC_X] = {
|
||||
0xf6,
|
||||
0xd6,
|
||||
0x24,
|
||||
0x0,
|
||||
0x3f5,
|
||||
0x2229,
|
||||
},
|
||||
[KC_M] = {
|
||||
0x6d,
|
||||
0x4d,
|
||||
0x25,
|
||||
0x31,
|
||||
0x3bc,
|
||||
0x21d4,
|
||||
},
|
||||
[KC_P0] = {
|
||||
0x30,
|
||||
0x2423,
|
||||
0x25,
|
||||
0x0,
|
||||
0x2030,
|
||||
0x25a1,
|
||||
},
|
||||
[KC_P] = {
|
||||
0x71,
|
||||
0x51,
|
||||
0x26,
|
||||
0x2b,
|
||||
0x3d5,
|
||||
0x211a,
|
||||
},
|
||||
[KC_DOT] = {
|
||||
0x2e,
|
||||
0x2022,
|
||||
0x27,
|
||||
0x33,
|
||||
0x3d1,
|
||||
0x21a6,
|
||||
},
|
||||
[KC_J] = {
|
||||
0x6e,
|
||||
0x4e,
|
||||
0x28,
|
||||
0x34,
|
||||
0x3bd,
|
||||
0x2115,
|
||||
},
|
||||
[KC_K] = {
|
||||
0x72,
|
||||
0x52,
|
||||
0x29,
|
||||
0x35,
|
||||
0x3c1,
|
||||
0x211d,
|
||||
},
|
||||
[KC_KP_ASTERISK] = {
|
||||
0x2a,
|
||||
0x2a,
|
||||
0x22c5,
|
||||
0xd7,
|
||||
0x2299,
|
||||
0x2297,
|
||||
},
|
||||
[KC_G] = {
|
||||
0x6f,
|
||||
0x4f,
|
||||
0x2a,
|
||||
0x0,
|
||||
0x3bf,
|
||||
0x2208,
|
||||
},
|
||||
[KC_0] = {
|
||||
0x30,
|
||||
0x201d,
|
||||
0x2019,
|
||||
0x2a,
|
||||
0x2080,
|
||||
0x2205,
|
||||
},
|
||||
[KC_KP_PLUS] = {
|
||||
0x2b,
|
||||
0x2b,
|
||||
0xb1,
|
||||
0x2213,
|
||||
0x2295,
|
||||
0x2214,
|
||||
},
|
||||
[KC_N] = {
|
||||
0x62,
|
||||
0x42,
|
||||
0x2b,
|
||||
0x3a,
|
||||
0x3b2,
|
||||
0x21d0,
|
||||
},
|
||||
[KC_KP_DOT] = {
|
||||
0x2c,
|
||||
0x2e,
|
||||
0x2c,
|
||||
0x0,
|
||||
0x2032,
|
||||
0x2033,
|
||||
},
|
||||
[KC_SCLN] = {
|
||||
0x64,
|
||||
0x44,
|
||||
0x3a,
|
||||
0x2c,
|
||||
0x3b4,
|
||||
0x394,
|
||||
},
|
||||
[KC_MINS] = {
|
||||
0x2d,
|
||||
0x2014,
|
||||
0x0,
|
||||
0x2d,
|
||||
0x2011,
|
||||
0xad,
|
||||
},
|
||||
[KC_KP_MINUS] = {
|
||||
0x2d,
|
||||
0x2d,
|
||||
0x2212,
|
||||
0x2216,
|
||||
0x2296,
|
||||
0x2238,
|
||||
},
|
||||
[KC_L] = {
|
||||
0x74,
|
||||
0x54,
|
||||
0x2d,
|
||||
0x36,
|
||||
0x3c4,
|
||||
0x2202,
|
||||
},
|
||||
[KC_QUOT] = {
|
||||
0x79,
|
||||
0x59,
|
||||
0x40,
|
||||
0x2e,
|
||||
0x3c5,
|
||||
0x2207,
|
||||
},
|
||||
[KC_KP_SLASH] = {
|
||||
0x2f,
|
||||
0x2f,
|
||||
0xf7,
|
||||
0x2044,
|
||||
0x2300,
|
||||
0x2223,
|
||||
},
|
||||
[KC_S] = {
|
||||
0x69,
|
||||
0x49,
|
||||
0x2f,
|
||||
0x0,
|
||||
0x3b9,
|
||||
0x222b,
|
||||
},
|
||||
[KC_9] = {
|
||||
0x39,
|
||||
0x201c,
|
||||
0x2018,
|
||||
0x2f,
|
||||
0x27e9,
|
||||
0x221d,
|
||||
},
|
||||
[KC_1] = {
|
||||
0x31,
|
||||
0xb0,
|
||||
0xb9,
|
||||
0xaa,
|
||||
0x2081,
|
||||
0xac,
|
||||
},
|
||||
[KC_P1] = {
|
||||
0x31,
|
||||
0x2666,
|
||||
0x2194,
|
||||
0x0,
|
||||
0x2264,
|
||||
0x230a,
|
||||
},
|
||||
[KC_2] = {
|
||||
0x32,
|
||||
0xa7,
|
||||
0xb2,
|
||||
0xba,
|
||||
0x2082,
|
||||
0x2228,
|
||||
},
|
||||
[KC_P2] = {
|
||||
0x32,
|
||||
0x2665,
|
||||
0x2193,
|
||||
0x0,
|
||||
0x222a,
|
||||
0x22c3,
|
||||
},
|
||||
[KC_3] = {
|
||||
0x33,
|
||||
0x2113,
|
||||
0xb3,
|
||||
0x2116,
|
||||
0x2083,
|
||||
0x2227,
|
||||
},
|
||||
[KC_P3] = {
|
||||
0x33,
|
||||
0x2660,
|
||||
0x21cc,
|
||||
0x0,
|
||||
0x2265,
|
||||
0x230b,
|
||||
},
|
||||
[KC_4] = {
|
||||
0x34,
|
||||
0xbb,
|
||||
0x203a,
|
||||
0x0,
|
||||
0x2640,
|
||||
0x22a5,
|
||||
},
|
||||
[KC_P4] = {
|
||||
0x34,
|
||||
0x2663,
|
||||
0x2190,
|
||||
0x0,
|
||||
0x2282,
|
||||
0x2286,
|
||||
},
|
||||
[KC_5] = {
|
||||
0x35,
|
||||
0xab,
|
||||
0x2039,
|
||||
0xb7,
|
||||
0x2642,
|
||||
0x2221,
|
||||
},
|
||||
[KC_P5] = {
|
||||
0x35,
|
||||
0x20ac,
|
||||
0x3a,
|
||||
0x0,
|
||||
0x22b6,
|
||||
0x22b7,
|
||||
},
|
||||
[KC_P6] = {
|
||||
0x36,
|
||||
0x2023,
|
||||
0x2192,
|
||||
0x0,
|
||||
0x2283,
|
||||
0x2287,
|
||||
},
|
||||
[KC_7] = {
|
||||
0x37,
|
||||
0x20ac,
|
||||
0xa5,
|
||||
0xa4,
|
||||
0x3f0,
|
||||
0x2192,
|
||||
},
|
||||
[KC_P7] = {
|
||||
0x37,
|
||||
0x2714,
|
||||
0x2195,
|
||||
0x0,
|
||||
0x226a,
|
||||
0x2308,
|
||||
},
|
||||
[KC_U] = {
|
||||
0x68,
|
||||
0x48,
|
||||
0x3c,
|
||||
0x37,
|
||||
0x3c8,
|
||||
0x3a8,
|
||||
},
|
||||
[KC_8] = {
|
||||
0x38,
|
||||
0x201e,
|
||||
0x201a,
|
||||
0x0,
|
||||
0x27e8,
|
||||
0x221e,
|
||||
},
|
||||
[KC_P8] = {
|
||||
0x38,
|
||||
0x2718,
|
||||
0x2191,
|
||||
0x0,
|
||||
0x2229,
|
||||
0x22c2,
|
||||
},
|
||||
[KC_I] = {
|
||||
0x67,
|
||||
0x47,
|
||||
0x3e,
|
||||
0x38,
|
||||
0x3b3,
|
||||
0x393,
|
||||
},
|
||||
[KC_P9] = {
|
||||
0x39,
|
||||
0x2020,
|
||||
0x0,
|
||||
0x0,
|
||||
0x226b,
|
||||
0x2309,
|
||||
},
|
||||
[KC_O] = {
|
||||
0x66,
|
||||
0x46,
|
||||
0x3d,
|
||||
0x39,
|
||||
0x3c6,
|
||||
0x3a6,
|
||||
},
|
||||
[KC_SLSH] = {
|
||||
0x6a,
|
||||
0x4a,
|
||||
0x3b,
|
||||
0x3b,
|
||||
0x3b8,
|
||||
0x398,
|
||||
},
|
||||
[KC_NUM_LOCK] = {
|
||||
0x0,
|
||||
0x0,
|
||||
0x3d,
|
||||
0x2260,
|
||||
0x2248,
|
||||
0x2261,
|
||||
},
|
||||
[KC_H] = {
|
||||
0x73,
|
||||
0x53,
|
||||
0x3f,
|
||||
0xbf,
|
||||
0x3c3,
|
||||
0x3a3,
|
||||
},
|
||||
[KC_E] = {
|
||||
0x6c,
|
||||
0x4c,
|
||||
0x5b,
|
||||
0x0,
|
||||
0x3bb,
|
||||
0x39b,
|
||||
},
|
||||
[KC_A] = {
|
||||
0x75,
|
||||
0x55,
|
||||
0x5c,
|
||||
0x0,
|
||||
0x0,
|
||||
0x2282,
|
||||
},
|
||||
[KC_R] = {
|
||||
0x63,
|
||||
0x43,
|
||||
0x5d,
|
||||
0x0,
|
||||
0x3c7,
|
||||
0x2102,
|
||||
},
|
||||
[KC_T] = {
|
||||
0x77,
|
||||
0x57,
|
||||
0x5e,
|
||||
0x0,
|
||||
0x3c9,
|
||||
0x3a9,
|
||||
},
|
||||
[KC_W] = {
|
||||
0x76,
|
||||
0x56,
|
||||
0x5f,
|
||||
0x0,
|
||||
0x0,
|
||||
0x221a,
|
||||
},
|
||||
[KC_B] = {
|
||||
0x7a,
|
||||
0x5a,
|
||||
0x60,
|
||||
0x0,
|
||||
0x3b6,
|
||||
0x2124,
|
||||
},
|
||||
[KC_D] = {
|
||||
0x61,
|
||||
0x41,
|
||||
0x7b,
|
||||
0x0,
|
||||
0x3b1,
|
||||
0x2200,
|
||||
},
|
||||
[KC_C] = {
|
||||
0xe4,
|
||||
0xc4,
|
||||
0x7c,
|
||||
0x0,
|
||||
0x3b7,
|
||||
0x2135,
|
||||
},
|
||||
[KC_F] = {
|
||||
0x65,
|
||||
0x45,
|
||||
0x7d,
|
||||
0x0,
|
||||
0x3b5,
|
||||
0x2203,
|
||||
},
|
||||
[KC_V] = {
|
||||
0x70,
|
||||
0x50,
|
||||
0x7e,
|
||||
0x0,
|
||||
0x3c0,
|
||||
0x3a0,
|
||||
},
|
||||
[KC_LBRC] = {
|
||||
0xdf,
|
||||
0x1e9e,
|
||||
0x17f,
|
||||
0x2212,
|
||||
0x3c2,
|
||||
0x2218,
|
||||
},
|
||||
[KC_Q] = {
|
||||
0x78,
|
||||
0x58,
|
||||
0x2026,
|
||||
0x0,
|
||||
0x3be,
|
||||
0x39e,
|
||||
},
|
||||
};
|
|
@ -3,6 +3,8 @@
|
|||
#include QMK_KEYBOARD_H
|
||||
#include "keymap_steno.h"
|
||||
#include "raw_hid.h"
|
||||
#include "neo2.h"
|
||||
#include "compose.h"
|
||||
enum {
|
||||
_MAIN,
|
||||
_NUMPAD,
|
||||
|
@ -144,7 +146,7 @@ static void send_unicode_chunk(const char * data, size_t length) {
|
|||
|
||||
#define UNI_CHUNKSIZE (RAW_EPSIZE - 3)
|
||||
|
||||
void send_unicode_string(const char * str) {
|
||||
/*void send_unicode_string(const char * str) {
|
||||
size_t length = strlen(str);
|
||||
while(length > UNI_CHUNKSIZE) {
|
||||
send_unicode_chunk(str, UNI_CHUNKSIZE);
|
||||
|
@ -152,7 +154,7 @@ void send_unicode_string(const char * str) {
|
|||
length -= UNI_CHUNKSIZE;
|
||||
}
|
||||
send_unicode_chunk(str, length);
|
||||
}
|
||||
}*/
|
||||
|
||||
void register_unicode(uint32_t codepoint) {
|
||||
uint8_t buffer[4];
|
||||
|
@ -184,4 +186,10 @@ void register_unicode(uint32_t codepoint) {
|
|||
}
|
||||
send_unicode_chunk((char *)buffer, size);
|
||||
}
|
||||
|
||||
void post_process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||
track_neo2_modifier_state(keycode, record);
|
||||
process_compose(keycode, record);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
2101
keyboards/rkb1/keymaps/simple/keysymdef.py
Normal file
2101
keyboards/rkb1/keymaps/simple/keysymdef.py
Normal file
File diff suppressed because it is too large
Load diff
250
keyboards/rkb1/keymaps/simple/mkCompose.py
Normal file
250
keyboards/rkb1/keymaps/simple/mkCompose.py
Normal file
|
@ -0,0 +1,250 @@
|
|||
import re
|
||||
from keysymdef import keysymdef
|
||||
import json
|
||||
|
||||
keysym_regex = re.compile("^<([a-zA-Z0-9_]+)>$")
|
||||
unicode_regex = re.compile("^<U([0-9a-fA-F]{4,6})>$")
|
||||
|
||||
keysym_map = {}
|
||||
special_keysyms = {
|
||||
"dead_abovedot": 0x307,
|
||||
"dead_acute": 0x301,
|
||||
"dead_belowdot": 0x323,
|
||||
"dead_caron": 0x30C,
|
||||
"dead_macron": 0x304,
|
||||
"dead_stroke": 0x338,
|
||||
"KP_0": "0xD800 + KC_P0",
|
||||
"KP_1": "0xD800 + KC_P1",
|
||||
"KP_2": "0xD800 + KC_P2",
|
||||
"KP_3": "0xD800 + KC_P3",
|
||||
"KP_4": "0xD800 + KC_P4",
|
||||
"KP_5": "0xD800 + KC_P5",
|
||||
"KP_6": "0xD800 + KC_P6",
|
||||
"KP_7": "0xD800 + KC_P7",
|
||||
"KP_8": "0xD800 + KC_P8",
|
||||
"KP_9": "0xD800 + KC_P9",
|
||||
"KP_Divide": "0xD800 + KC_KP_SLASH",
|
||||
"KP_Add": "0xD800 + KC_KP_PLUS",
|
||||
"KP_Equal": "0xD800 + KC_KP_EQUAL",
|
||||
"KP_Space": 0x20,
|
||||
"KP_Subtract": "0xD800 + KC_KP_MINUS",
|
||||
"KP_Multiply": "0xD800 + KC_KP_ASTERISK",
|
||||
"Multi_key": 0xD800,
|
||||
"dead_abovering": 0x30A,
|
||||
"dead_breve": 0x306,
|
||||
"dead_cedilla": 0x327,
|
||||
"dead_dasia": 0x314,
|
||||
"dead_psili": 0x313,
|
||||
"dead_circumflex": 0x304,
|
||||
"dead_diaeresis": 0x308,
|
||||
"dead_horn": 0x31B,
|
||||
"dead_tilde": 0x303,
|
||||
"dead_belowbreve": 0x32e,
|
||||
"dead_belowcircumflex": 0x32d,
|
||||
"dead_belowcomma": 0x326,
|
||||
"dead_belowdiaeresis": 0x324,
|
||||
"dead_belowmacron": 0x331,
|
||||
"dead_belowring": 0x325,
|
||||
"dead_belowtilde": 0x330,
|
||||
"dead_grave": 0x300,
|
||||
"dead_hook": 0x31b,
|
||||
"underbar": 0x5f,
|
||||
"dead_doubleacute": 0x30B,
|
||||
"dead_doublegrave": 0x30F,
|
||||
"dead_invertedbreve": 0x311,
|
||||
"dead_iota": 0x345,
|
||||
"dead_ogonek": 0x328,
|
||||
"dead_semivoiced_sound": 0x309a,
|
||||
"dead_voiced_sound": 0x3099,
|
||||
"enfilledcircbullet": 0x2022,
|
||||
"leftcaret": 0x3c,
|
||||
"leftshoe": 0x2282,
|
||||
"rightcaret": 0x3e,
|
||||
"rightshoe": 0x2283,
|
||||
"Tab": 9,
|
||||
"hebrew_beth": 0x05D1,
|
||||
"hebrew_daleth": 0x05D3,
|
||||
"hebrew_gimmel": 0x05D2,
|
||||
"hebrew_kuf": 0x5E7,
|
||||
"hebrew_samekh": 0x5E1,
|
||||
"hebrew_taf": 0x5ea,
|
||||
"hebrew_teth": 0x5d8,
|
||||
"hebrew_zadi": 0x5e6,
|
||||
"hebrew_zayin": 0x5d6,
|
||||
}
|
||||
|
||||
nodes = {
|
||||
"children": {}
|
||||
}
|
||||
|
||||
|
||||
def ensure_node(path):
|
||||
if path == ():
|
||||
return nodes
|
||||
parent = ensure_node(path[:-1])
|
||||
if path[-1] not in parent["children"]:
|
||||
parent["children"][path[-1]] = {"children": {}}
|
||||
return parent["children"][path[-1]]
|
||||
|
||||
|
||||
def create_node(path, result):
|
||||
path = tuple(path)
|
||||
node = ensure_node(path)
|
||||
node["result"] = result
|
||||
|
||||
|
||||
def walk_tree(base=None, pre_order=False):
|
||||
if base is None:
|
||||
base = nodes
|
||||
if pre_order:
|
||||
yield base
|
||||
for child in base["children"].values():
|
||||
yield from walk_tree(child, pre_order)
|
||||
if not pre_order:
|
||||
yield base
|
||||
|
||||
def walk_tree_2(base=None):
|
||||
if base is None:
|
||||
base = nodes
|
||||
for k, v in base["children"].items():
|
||||
yield from walk_tree_2(v)
|
||||
yield (base, k, v)
|
||||
|
||||
|
||||
def walk_leaves():
|
||||
for node in walk_tree():
|
||||
if len(node["children"]) == 0:
|
||||
yield node
|
||||
|
||||
|
||||
for (name, _, value) in keysymdef:
|
||||
if value is None:
|
||||
if name in special_keysyms:
|
||||
value = special_keysyms[name]
|
||||
else:
|
||||
continue
|
||||
keysym_map[name] = value
|
||||
|
||||
|
||||
def parse_keysym(keysym: str):
|
||||
unicode_match = unicode_regex.search(keysym)
|
||||
if unicode_match is not None:
|
||||
return int(unicode_match.group(1), 16)
|
||||
normal_match = keysym_regex.search(keysym)
|
||||
if normal_match is not None:
|
||||
return keysym_map[normal_match.group(1)]
|
||||
|
||||
|
||||
with open("keyboards/rkb1/keymaps/simple/XCompose") as fin:
|
||||
for line in fin:
|
||||
line = line.strip()
|
||||
(keysyms, result) = line.split(":", 1)
|
||||
keysyms = keysyms.strip()
|
||||
result = result.strip()
|
||||
keys = [parse_keysym(keysym) for keysym in keysyms.split()]
|
||||
output = eval(result)
|
||||
create_node(keys, output)
|
||||
|
||||
# ensure that every leaf can continue compose sequences
|
||||
#for leaf in walk_leaves():
|
||||
# if "result" not in leaf:
|
||||
# continue
|
||||
# if len(leaf["result"]) != 1:
|
||||
# continue
|
||||
# if ord(leaf["result"]) not in nodes["children"]:
|
||||
# continue
|
||||
# print(f"found recursable leaf {leaf}")
|
||||
# leaf["children"] = nodes["children"][ord(leaf["result"])]["children"]
|
||||
|
||||
|
||||
def freeze_dict(s):
|
||||
kv_pairs = []
|
||||
for key in sorted(s, key=lambda a: str(a)):
|
||||
value = s[key]
|
||||
if isinstance(value, dict):
|
||||
value = freeze_dict(value)
|
||||
kv_pairs.append((key, value))
|
||||
return tuple(kv_pairs)
|
||||
|
||||
|
||||
# merge identical outcomes
|
||||
def merge_identical():
|
||||
seen_nodes = {}
|
||||
|
||||
for parent, key, node in walk_tree_2():
|
||||
frozen_node = freeze_dict(node)
|
||||
if frozen_node in seen_nodes:
|
||||
replacement_node = seen_nodes[frozen_node]
|
||||
parent["children"][key] = replacement_node
|
||||
else:
|
||||
seen_nodes[frozen_node] = node
|
||||
|
||||
|
||||
merge_identical()
|
||||
|
||||
# this flattens the tree
|
||||
flat_nodes = []
|
||||
edges = []
|
||||
relocations = {}
|
||||
seen = set()
|
||||
|
||||
for node in walk_tree(pre_order=True):
|
||||
if len(node["children"]) == 0:
|
||||
continue
|
||||
if id(node) in seen:
|
||||
continue
|
||||
first_edge_idx = len(edges)
|
||||
edge_count = len(node["children"])
|
||||
|
||||
for c, edge in node["children"].items():
|
||||
value = edge["result"] if "result" in edge else None
|
||||
edge_obj = {
|
||||
"value": value,
|
||||
"c": c
|
||||
}
|
||||
if id(edge) in relocations:
|
||||
relocations[id(edge)].append(edge_obj)
|
||||
else:
|
||||
relocations[id(edge)] = [edge_obj]
|
||||
edges.append(edge_obj)
|
||||
flat_nodes.append({
|
||||
"first_edge_idx": first_edge_idx,
|
||||
"edge_count": edge_count,
|
||||
"id": id(node)
|
||||
})
|
||||
seen.add(id(node))
|
||||
|
||||
# fixup relocations
|
||||
for i, node in enumerate(flat_nodes):
|
||||
if node["id"] not in relocations:
|
||||
continue
|
||||
for fixup in relocations[node["id"]]:
|
||||
fixup["next_node"] = i
|
||||
|
||||
print("const static compose_node_t nodes[] = {")
|
||||
for node in flat_nodes:
|
||||
print(" {")
|
||||
print(f" .first_edge_idx = {node['first_edge_idx']},")
|
||||
print(f" .edge_count = {node['edge_count']},")
|
||||
print(" },")
|
||||
print("};")
|
||||
|
||||
|
||||
def escape_str(x):
|
||||
s = ""
|
||||
for c in x.encode("utf-8"):
|
||||
s += f"\\x{(hex(c)[2:]).zfill(2)}"
|
||||
return s
|
||||
|
||||
|
||||
print("const static compose_edge_t compose_edges[] = {")
|
||||
for edge in edges:
|
||||
print(" {")
|
||||
print(f" .c = {edge['c']},")
|
||||
if edge["value"] is not None:
|
||||
escaped = escape_str(edge["value"])
|
||||
print(f" .value = \"{escaped}\",")
|
||||
if "next_node" in edge:
|
||||
print(f" .next_node = {edge['next_node']},")
|
||||
print(" },")
|
||||
print("};")
|
52
keyboards/rkb1/keymaps/simple/neo2.c
Normal file
52
keyboards/rkb1/keymaps/simple/neo2.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
#include "neo2.h"
|
||||
#include "keycode.h"
|
||||
#include "quantum.h"
|
||||
|
||||
static bool pressingLsft, pressingRsft, pressingCaps, pressingNUHS, pressingNUBS, pressingRalt, lockingShift, lockingMod4;
|
||||
|
||||
void track_neo2_modifier_state(uint16_t keycode, keyrecord_t *record) {
|
||||
switch (keycode) {
|
||||
case KC_LEFT_SHIFT:
|
||||
pressingLsft = record->event.pressed;
|
||||
lockingShift ^= pressingLsft && pressingRsft;
|
||||
break;
|
||||
case KC_RIGHT_SHIFT:
|
||||
pressingRsft = record->event.pressed;
|
||||
lockingShift ^= pressingLsft && pressingRsft;
|
||||
break;
|
||||
case KC_CAPS:
|
||||
pressingCaps = record->event.pressed;
|
||||
break;
|
||||
case KC_NUHS:
|
||||
pressingNUHS = record->event.pressed;
|
||||
break;
|
||||
case KC_NUBS:
|
||||
pressingNUBS = record->event.pressed;
|
||||
lockingMod4 ^= pressingNUBS && pressingRalt;
|
||||
break;
|
||||
case KC_RALT:
|
||||
pressingRalt = record->event.pressed;
|
||||
lockingMod4 ^= pressingNUBS && pressingRalt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int getLayer(void) {
|
||||
bool mod2 = lockingShift ^ pressingLsft ^ pressingRsft;
|
||||
bool mod3 = pressingCaps | pressingNUHS;
|
||||
bool mod4 = lockingMod4 ^ pressingNUBS ^ pressingRalt;
|
||||
if (mod4 && mod3) return 5;
|
||||
if (mod4) return 3;
|
||||
if (mod3 && mod2) return 4;
|
||||
if (mod3) return 2;
|
||||
if (mod2) return 1;
|
||||
return 0;
|
||||
}
|
||||
#include "keyToCharTable.h"
|
||||
uint32_t keystroke_to_unicode(uint16_t keycode) {
|
||||
size_t elements = sizeof(keycode_to_char) / (6 * sizeof(uint16_t));
|
||||
if (keycode > elements) {
|
||||
return 0;
|
||||
}
|
||||
return (uint32_t)keycode_to_char[keycode][getLayer()];
|
||||
}
|
7
keyboards/rkb1/keymaps/simple/neo2.h
Normal file
7
keyboards/rkb1/keymaps/simple/neo2.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "quantum/action.h"
|
||||
#include <stdint.h>
|
||||
|
||||
void track_neo2_modifier_state(uint16_t keycode, keyrecord_t *record);
|
||||
uint32_t keystroke_to_unicode(uint16_t keycode);
|
1
keyboards/rkb1/keymaps/simple/rules.mk
Normal file
1
keyboards/rkb1/keymaps/simple/rules.mk
Normal file
|
@ -0,0 +1 @@
|
|||
SRC += neo2.c compose.c
|
82
keyboards/rkb1/keymaps/simple/sparseTable.hpp
Normal file
82
keyboards/rkb1/keymaps/simple/sparseTable.hpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
template <int entries>
|
||||
struct BitSet {
|
||||
BitSet<entries / 2> upper;
|
||||
BitSet<entries / 2> lower;
|
||||
|
||||
bool operator[](size_t index) {
|
||||
if (index < (entries / 2)) return lower[index];
|
||||
return upper[index - (entries / 2)];
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct BitSet<64> {
|
||||
uint64_t data;
|
||||
|
||||
bool operator[](size_t index) const {
|
||||
return (bool)((data >> index) & 1);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct BitSet<32> {
|
||||
uint32_t data;
|
||||
|
||||
bool operator[](size_t index) const {
|
||||
return (bool)((data >> index) & 1);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct BitSet<16> {
|
||||
uint16_t data;
|
||||
|
||||
bool operator[](size_t index) const {
|
||||
return (bool)((data >> index) & 1);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct BitSet<8> {
|
||||
uint8_t data;
|
||||
|
||||
bool operator[](size_t index) const {
|
||||
return (bool)((data >> index) & 1);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct BitSet<1> {
|
||||
bool data;
|
||||
|
||||
bool operator[](size_t index) const {
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, int keyBits, int entryBits>
|
||||
struct SparseTable {
|
||||
BitSet<1 << entryBits> presentEntries;
|
||||
SparseTable<T, keyBits - entryBits, entryBits> entries[0];
|
||||
|
||||
const T *operator[](size_t index) const {
|
||||
size_t subindex = (index >> (keyBits - entryBits)) & ((1 << entryBits) - 1);
|
||||
if (!presentEntries[subindex]) return nullptr;
|
||||
size_t realIndex = 0;
|
||||
for (int i = 0; i < subindex; i++)
|
||||
if (presentEntries[subindex]) realIndex++;
|
||||
return entries[realIndex][index & ((1 << (keyBits - entryBits)) - 1)];
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, int entryBits>
|
||||
struct SparseTable<T, 0, entryBits> {
|
||||
T value;
|
||||
const T *operator[](size_t index) const {
|
||||
return &value;
|
||||
}
|
||||
};
|
Loading…
Reference in a new issue