Browse Source

readme updates. Uncaptured tinkering

master
dirkson 1 month ago
parent
commit
2e8e903dae
5 changed files with 1231 additions and 16732 deletions
  1. +18
    -3
      README.md
  2. +882
    -1013
      dict
  3. +0
    -15691
      res/freq-en
  4. +309
    -15
      src/dict.c
  5. +22
    -10
      src/kbd.c

+ 18
- 3
README.md View File

@@ -1,9 +1,24 @@
# kbd

So, stenograghy is awesomely fast, right? But the downside of it is that you need to learn a whole new keyboard layout in order to use it AND you need to learn every single word you'd like to type.
Stenograghy is awesomely fast - Proficient users can type as quickly as most people can speak. But the downside of it is that you need to learn a whole new keyboard layout in order to use it AND you need to learn a new 'spelling' for every single word you'd like to type.

kbd aims to be a middle road, exposing a suite of chorded keyboard shortcuts on top of your existing keyboard layout. RightGui+t becomes 'the '. RightGui+u becomes 'you '. You get to use your existing keyboad and layout unchanged, AND each new chord you learn instantly speeds up your current typing.

The current version is a prototype, only working on linux.

# building

You'll need gcc, clang, or other C complier, and 'tup', a build system.

```
tup init
tup
```

# usage

kbd /dev/input/by-id/your-keyboard-here

## todo

* Add smart backspace and punctuation
@@ -13,5 +28,5 @@ kbd aims to be a middle road, exposing a suite of chorded keyboard shortcuts on
* Make loading detect duplicate chords in dictionary
* Create a way to learn chords
* Add a qwerty-oriented dictionary (current assumes colemak)
* Add windows version
* Add windows version - Requires an entirely separate program
* Add in-keyboard version via QMK. Dict in header.

+ 882
- 1013
dict
File diff suppressed because it is too large
View File


+ 0
- 15691
res/freq-en
File diff suppressed because it is too large
View File


+ 309
- 15
src/dict.c View File

@@ -1,16 +1,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>

/* char colemak[10][3] = {
{ 'q', 'a', 'z' }, //0 a
{ 'w', 'r', 'x' }, //1 b
{ 'f', 's', 'c' }, //2 c
{ 'p', 't', 'v' }, //3 d
{ 'g', 'd', 'b' }, //4 d
{ 'j', 'h', 'k' }, //5 e
{ 'l', 'n', 'm' }, //6 e
{ 'u', 'e', ',' }, //7 f
{ 'y', 'i', '.' }, //8 g
{ ';', 'o', '/' }, //9 h
}; */
#include "jsmn.h"

#define GRP_1 1
#define GRP_2 2
@@ -21,7 +15,73 @@
#define GRP_7 64
#define GRP_8 128

unsigned short int colemak[26] = {
#define DICT_MAX_WORD_SIZE 64
#define DICT_MAX_WORD_NUM 3000
#define DICT_SWITCH_NUM 2000

#define dict_err(str) { perror("err: "str); exit(EXIT_FAILURE); }

char en_letter_freq[27] = {
2, //a
19, //b
12, //c
9, //d
0, //e
14, //f
17, //g
8, //h
4, //i
24, //j
21, //k
10, //l
13, //m
5, //n
3, //o
18, //p
23, //q
7, //r
6, //s
1, //t
11, //u
20, //v
16, //w
22, //x
15, //y
25, //z
26, //'
};

char en_letter_use[27] = {
0, //a
1, //b
1, //c
1, //d
0, //e
1, //f
1, //g
1, //h
0, //i
1, //j
1, //k
1, //l
1, //m
1, //n
0, //o
1, //p
1, //q
1, //r
1, //s
1, //t
0, //u
1, //v
1, //w
1, //x
1, //y
1, //z
0, //'
};

unsigned short int colemak[27] = {
GRP_1, //a
GRP_4, //b
GRP_3, //c
@@ -48,21 +108,255 @@ unsigned short int colemak[26] = {
GRP_2, //x
GRP_7, //y
GRP_1, //z
GRP_8, //'
};

typedef struct kbd_chord_tree_t
{
char *str;
char *result;
int len;
struct kbd_chord_tree_t *next;
} kbd_chord_tree_t;

void kbd_load_json(kbd_chord_tree_t *root)
//give it a character, it'll return an index into the array, or -1 on err
char kbd_char_conv(char c)
{
if (c == '\'')
return 26;
char res = tolower(c);
if (!islower(res))
return -1;
else
return res - 97;
}

char kbd_index_conv(char c)
{
if (c == 26)
return '\'';
else
return c + 97;
}

int dict_letter_sort (const void * a, const void * b)
{
return en_letter_freq[(int)*(char*)a] < en_letter_freq[(int)*(char*)b];
}

int dict_add_chord(kbd_chord_tree_t *node, int depth, char *key, int keylen, char *result, int resultlen)
{
if (node->result == NULL)
{
//printf("Stored: %s \n", result);
node->result = strndup(result, resultlen);
node->len = resultlen;
if (depth == resultlen)
return -depth;
else
return depth;
}

//if (node->result != NULL)
if (depth == keylen)
{
//printf("Collision: %s > %s \n", node->result, result);
return -depth;
}

if (node->next == NULL)
node->next = calloc(27, sizeof(kbd_chord_tree_t));

return dict_add_chord(&node->next[(int)key[depth]], depth+1, key, keylen, result, resultlen);
}

void dict_trim_key(char *key, char *rawkey, int oldlen, int *j, unsigned short int * layout, char useall)
{
int i;
char flags = 0;
*j = 0;

/*
printf("%i: ", useall);
for (i=0; i < oldlen; i++)
printf("%c", kbd_index_conv(rawkey[i]));
printf("\n");
*/

for (i = 0; i < oldlen; i++)
{
if ((useall || en_letter_use[(int)rawkey[i]]) && !(flags & layout[(int)rawkey[i]]))
{
flags = flags | layout[(int)rawkey[i]];
key[*j] = rawkey[i];
(*j)++;
}
}

key[*j] = '\0';

/*
printf("%i: ", useall);
for (i=0; i < *j; i++)
printf("%c", kbd_index_conv(key[i]));
printf("\n\n");
*/

}
void dict_write_word(FILE *f, char *key, char *str, int len)
{
int i;
char keyp[DICT_MAX_WORD_SIZE];

if (len < 0)
len = -len;

for (i=0; i < len; i++)
keyp[i] = kbd_index_conv(key[i]);
keyp[len] = '\0';

if (fprintf(f, "%s:%s\n", keyp, str) == -1) dict_err("failed to write");

}

void dict_load_freq(kbd_chord_tree_t *root, char *file, char *out)
{
char *str = NULL;
char key[DICT_MAX_WORD_SIZE];
char rawkey[DICT_MAX_WORD_SIZE];
size_t size = 0;
size_t num;
int keylen;
int i;
int chordlen;

int words = 0;

FILE *fp = fopen(file, "r");
if (fp == NULL) dict_err("failed to open freq");

FILE *fo = fopen(out, "w");
if (fo == NULL) dict_err("failed to open dict");

FILE *fc = fopen("fail", "w");
if (fo == NULL) dict_err("failed to open failures file");

//skip first line
//if (getline(&str, &size, fp) == -1) dict_err("failed to read first line of input file");

//if (fprintf(fo, "{\n") == -1) dict_err("failed to write to output file");

while ((num = getline(&str, &size, fp)) != -1)
{
//chop off newline
num = num - 1;
str[num] = '\0';
//printf("\n");
//printf("|%s|%i|%i\n", str, (int)num, (int)strlen(str));
//weed out bad words
if (num > DICT_MAX_WORD_SIZE)
continue;

//figure out key from word
for (i=0; i < num; i++)
{
rawkey[i] = kbd_char_conv(str[i]);
if (rawkey[i] == -1)
{
i = 0;
break;
}
}
if (i == 0)
continue;

//if (words > DICT_SWITCH_NUM)
//qsort(key, num, sizeof(char), dict_letter_sort);

dict_trim_key(key, rawkey, num, &keylen, colemak, 1);

/*
printf("Raw:\n");
for (i=0; i < num; i++)
printf("%i ", kbd_char_conv(str[i]));
printf("\n");
for (i=0; i < num; i++)
printf("%i ", key[i]);
printf("\n");
printf("freq:\n");
for (i=0; i < num; i++)
printf("%i ", en_letter_freq[(int)kbd_char_conv(str[i])]);
printf("\n");
for (i=0; i < num; i++)
printf("%i ", en_letter_freq[(int)key[i]]);
printf("\n");
printf("orig:\n");
for (i=0; i < num; i++)
printf("%c", (str[i]));
printf("\n");
for (i=0; i < num; i++)
printf("%c", kbd_index_conv(key[i]));
printf("\n");
*/

//add word
if ((chordlen = dict_add_chord(root, 0, key, keylen, str, num)) > 0)
{
dict_write_word(fo, key, str, chordlen);
}
else
{
dict_trim_key(key, rawkey, num, &keylen, colemak, 0);
if ((chordlen = dict_add_chord(root, 0, key, keylen, str, num)) > 0)
dict_write_word(fo, key, str, chordlen);
else
{
qsort(rawkey, num, sizeof(char), dict_letter_sort);
dict_trim_key(key, rawkey, num, &keylen, colemak, 1);
if ((chordlen = dict_add_chord(root, 0, key, keylen, str, num)) > 0)
dict_write_word(fo, key, str, chordlen);
else
{
dict_trim_key(key, rawkey, num, &keylen, colemak, 0);
if ((chordlen = dict_add_chord(root, 0, key, keylen, str, num)) > 0)
dict_write_word(fo, key, str, chordlen);
else
{
printf("Collision: %s \n", str);
dict_write_word(fc, key, str, chordlen);
}
}
}
}
words++;
if (words > DICT_MAX_WORD_NUM)
break;
}

//if (fprintf(fo, "}\n") == -1) dict_err("failed to write to output file");
fclose(fc);
fclose(fp);
fclose(fo);
if (str)
free(str);
}

void dict_write_all(kbd_chord_tree_t *root, char *file)
{
}

int main(int argc, char* argv[])
{

if(argc != 3) dict_err("Usage: dict [input] [output]");

kbd_chord_tree_t root = {0};
root.result = "null";
dict_load_freq(&root, argv[1], argv[2]);

//dict_write_all(&root, argv[2]);

printf("Done\n");

return 0;
}


+ 22
- 10
src/kbd.c View File

@@ -83,7 +83,7 @@ void kbd_add_chord(kbd_chord_tree_t *node, int depth, char *chord, int chordlen,


int loc = tolower(chord[depth]);
if (!islower(loc)) kbd_err("Found a symbol in a chord that I don't recognize")
if (!islower(loc)) return; //kbd_err("Found a symbol in a chord that I don't recognize")
loc = loc - 97; //a==0

if (node->next == NULL)
@@ -146,11 +146,10 @@ void kbd_load_json(kbd_chord_tree_t *root)
if (fp == NULL) kbd_err("failed to open dict");

//skip first {
if ((read = getline(&str, &len, fp)) == -1) kbd_err("failed to read dict initially");
//if ((read = getline(&str, &len, fp)) == -1) kbd_err("failed to read dict initially");

if ((read = getline(&str, &len, fp)) == -1) kbd_err("failed to read dict");

while (str[0] != '}')
while ((read = getline(&str, &len, fp)) != -1)
{
jsmn_init(&p);
switch (jsmn_parse(&p, str, read, t, KBD_DICT_LINE_SIZE)) {
@@ -171,7 +170,7 @@ void kbd_load_json(kbd_chord_tree_t *root)
break;
}

if (t[0].type != JSMN_STRING || t[1].type != JSMN_STRING) kbd_err("json type other than string detected");
if (t[0].type != JSMN_PRIMITIVE || t[1].type != JSMN_PRIMITIVE) kbd_err("json type other than primitive detected");

if (str[t[0].start] != '?')
{
@@ -183,7 +182,6 @@ void kbd_load_json(kbd_chord_tree_t *root)
//printf("Found one! \n");
}

if ((read = getline(&str, &len, fp)) == -1) kbd_err("failed to read dict");
}

fclose(fp);
@@ -275,7 +273,7 @@ void kbd_init(int *letters, int *fdo, int *fdi, int *ftty, char *str, kbd_chord_
if(ioctl(*fdi, EVIOCGRAB, 1) < 0) kbd_err("eviocgrab failed");
}

void kbd_event(int *letters, struct input_event ev, int fdo, int ftty, kbd_state_t *kbd_state, kbd_chord_tree_t *root)
void kbd_event(int *letters, struct input_event ev, int fdo, int ftty, kbd_state_t *kbd_state, kbd_chord_tree_t *root, int *backspace)
{
char *result;
int resultlen;
@@ -290,6 +288,17 @@ void kbd_event(int *letters, struct input_event ev, int fdo, int ftty, kbd_state
//{
switch (ev.code)
{
case KEY_BACKSPACE:
if (ev.value != 0)
{
for (i = *backspace; i > 0; i--)
{
kbd_tapkey(fdo, KEY_BACKSPACE);
sleep_us(5000);
}
*backspace = 1;
}
break;
case KEY_RIGHTMETA:
if (ev.value == 1)
{
@@ -349,6 +358,7 @@ void kbd_event(int *letters, struct input_event ev, int fdo, int ftty, kbd_state
default:
if (kbd_state->chord == 0)
{
*backspace = 1;
if(write(fdo, &ev, sizeof(struct input_event)) < 0) kbd_err("cannot write to fake keyboard");
kbd_emit(fdo, EV_SYN, SYN_REPORT, 0);
}
@@ -392,6 +402,7 @@ void kbd_event(int *letters, struct input_event ev, int fdo, int ftty, kbd_state
for (j = 1; j < resultlen; j++)
kbd_tapkey(fdo, letters[(int)(tolower(result[j])-97)]);
kbd_tapkey(fdo, KEY_SPACE);
*backspace = resultlen+1;
if (kbd_state->lshift)
kbd_presskey(fdo, KEY_LEFTSHIFT);
if (kbd_state->rshift)
@@ -424,14 +435,15 @@ void kbd_main_loop(int *letters, int fdi, int fdo, int ftty, kbd_chord_tree_t *r
struct input_event ev;
kbd_state_t kbd_state;


memset(&ev, 0, sizeof(struct input_event));
memset(&kbd_state, 0, sizeof(kbd_state_t));

int backspace = 1;

while(1)
{
read(fdi, &ev, sizeof(struct input_event));
kbd_event(letters, ev, fdo, ftty, &kbd_state, root);
kbd_event(letters, ev, fdo, ftty, &kbd_state, root, &backspace);
}
}

@@ -453,7 +465,7 @@ int main(int argc, char* argv[])
{
int letters[26];
int fdo, fdi, ftty;
kbd_chord_tree_t root;
kbd_chord_tree_t root = {0};





Loading…
Cancel
Save