Index: src/hid_cfg_input.c =================================================================== --- src/hid_cfg_input.c (revision 1455) +++ src/hid_cfg_input.c (revision 1456) @@ -36,26 +36,37 @@ /* split value into a list of '-' separated words; examine each word and set the bitmask of modifiers */ -static hid_cfg_mod_t parse_mods(const char *value) +static hid_cfg_mod_t parse_mods(const char *value, const char **last, unsigned int vlen) { hid_cfg_mod_t m = 0; int press = 0; + const char *next; + while(isspace(*value)) value++; + + if (*value != '<') { for(;;) { - if (strncmp(value, "shift", 5) == 0) m |= M_Shift; - else if (strncmp(value, "ctrl", 4) == 0) m |= M_Ctrl; - else if (strncmp(value, "alt", 3) == 0) m |= M_Alt; - else if (strncmp(value, "release", 7) == 0) m |= M_Release; - else if (strncmp(value, "press", 5) == 0) press = 1; + if ((vlen >= 5) && (strncasecmp(value, "shift", 5) == 0)) m |= M_Shift; + else if ((vlen >= 4) && (strncasecmp(value, "ctrl", 4) == 0)) m |= M_Ctrl; + else if ((vlen >= 3) && (strncasecmp(value, "alt", 3) == 0)) m |= M_Alt; + else if ((vlen >= 7) && (strncasecmp(value, "release", 7) == 0)) m |= M_Release; + else if ((vlen >= 5) && (strncasecmp(value, "press", 5) == 0)) press = 1; else Message("Unkown modifier: %s\n", value); /* skip to next word */ - value = strchr(value, '-'); - if (value == NULL) + next = strpbrk(value, "<-"); + if (next == NULL) break; - value++; + if (*next == '<') + break; + vlen -= (next - value); + value = next+1; } + } + if (last != NULL) + *last = value; + if (press && (m & M_Release)) Message("Bogus modifier: both press and release\n"); @@ -117,7 +128,7 @@ continue; } for(m = btn->data.list.first; m != NULL; m = m->next) { - hid_cfg_mod_t mod_mask = parse_mods(m->name); + hid_cfg_mod_t mod_mask = parse_mods(m->name, NULL, -1); htip_set(mouse->mouse_mask, btn_mask|mod_mask, m); } } @@ -164,12 +175,17 @@ htip_uninit(&km->keys); } -hid_cfg_keyseq_t *hid_cfg_keys_add_under(hid_cfg_keys_t *km, hid_cfg_keyseq_t *parent, hid_cfg_mod_t mods, short int key_char, int terminal) +hid_cfg_keyseq_t *hid_cfg_keys_add_under(hid_cfg_keys_t *km, hid_cfg_keyseq_t *parent, hid_cfg_mod_t mods, unsigned short int key_char, int terminal) { hid_cfg_keyseq_t *ns; hid_cfg_keyhash_t addr; htip_t *phash = (parent == NULL) ? &km->keys : &parent->seq_next; + /* do not grow the tree under actions */ + if ((parent != NULL) && (parent->action_node != NULL)) + return NULL; + + addr.details.mods = mods; addr.details.key_char = key_char; @@ -187,7 +203,158 @@ return ns; } -int hid_cfg_keys_add_by_desc(hid_cfg_keys_t *km, const char *keydesc, hid_cfg_keyseq_t **out_seq, int out_seq_len) +const hid_cfg_keytrans_t hid_cfg_key_default_trans[] = { + { "semicolon", ';' }, + { "return", '\r' }, + { "enter", '\r' }, + { "space", ' ' }, +/* { "backspace", '\b' },*/ +/* { "tab", '\t' },*/ + { NULL, 0 }, +}; + +static unsigned short int translate_key(hid_cfg_keys_t *km, const char *desc, int len) { + char tmp[256]; + if ((km->auto_chr) && (len == 1)) + return *desc; + + if (len > sizeof(tmp)-1) { + Message("key sym name too long\n"); + return 0; + } + strncpy(tmp, desc, len); + tmp[len] = '\0'; + + if (km->auto_tr != NULL) { + const hid_cfg_keytrans_t *t; + for(t = km->auto_tr; t->name != NULL; t++) { + if (strcasecmp(tmp, t->name) == 0) { + tmp[0] = t->sym; + tmp[1] = '\0'; + len = 1; + break; + } + } + } + + return km->translate_key(tmp, len); } + + +int hid_cfg_keys_add_by_desc(hid_cfg_keys_t *km, const char *keydesc, lht_node_t *action_node, hid_cfg_keyseq_t **out_seq, int out_seq_len) +{ + const char *curr, *next, *last, *k; + hid_cfg_mod_t mods[HIDCFG_MAX_KEYSEQ_LEN]; + unsigned short int key_chars[HIDCFG_MAX_KEYSEQ_LEN]; + int n, slen, len; + hid_cfg_keyseq_t *lasts; + + slen = 0; + curr = keydesc; + do { + if (slen >= HIDCFG_MAX_KEYSEQ_LEN) + return -1; + while(isspace(*curr)) curr++; + if (*curr == '\0') + break; + next = strchr(curr, ';'); + if (next != NULL) { + len = next - curr; + while(*next == ';') next++; + } + else + len = strlen(curr); + + mods[slen] = parse_mods(curr, &last, len); + + k = strchr(last, '<'); + if (k == NULL) { + Message("Missing in the key description: '%s'\n", keydesc); + return -1; + } + len -= k-last; + k++; len--; + if ((strncmp(k, "key>", 4) != 0) && (strncmp(k, "Key>", 4) != 0)) { + Message("Missing in the key description"); + return -1; + } + k+=4; len-=4; + key_chars[slen] = translate_key(km, k, len); + + if (key_chars[slen] == 0) { + Message("Unrecognised key symbol in key description"); + return -1; + } + + + slen++; + curr = next; + } while(curr != NULL); + + if ((out_seq != NULL) && (slen >= out_seq_len)) + return -1; + + printf("KEY insert\n"); + + lasts = NULL; + for(n = 0; n < slen; n++) { + hid_cfg_keyseq_t *s; + int terminal = (n == slen-1); + + printf(" mods=%x sym=%x\n", mods[n], key_chars[n]); + + s = hid_cfg_keys_add_under(km, lasts, mods[n], key_chars[n], terminal); + if (s == NULL) { + printf(" ERROR\n"); +#warning TODO: free stuff? + return -1; + } + if (terminal) + s->action_node = action_node; + + if (out_seq != NULL) + out_seq[n] = s; + lasts = s; + } + + return slen; +} + +int hid_cfg_keys_input(hid_cfg_keys_t *km, hid_cfg_mod_t mods, unsigned short int key_char, hid_cfg_keyseq_t **seq, int *seq_len) +{ + hid_cfg_keyseq_t *ns; + hid_cfg_keyhash_t addr; + htip_t *phash = (*seq_len == 0) ? &km->keys : &(seq[*seq_len])->seq_next; + + addr.details.mods = mods; + addr.details.key_char = key_char; + + /* already in the tree */ + ns = htip_get(phash, addr.hash); + if (ns == NULL) + return -1; + + seq[*seq_len] = ns; + (*seq_len)++; + + /* found a terminal node with an action */ + if (ns->action_node != NULL) { + int len = *seq_len; + *seq_len = 0; + return len; + } + + return 0; +} + +int hid_cfg_keys_action(hid_cfg_keyseq_t **seq, int seq_len) +{ + if (seq_len < 1) + return -1; + + hid_cfg_action(seq[seq_len-1]->action_node); +#warning TODO: + return 0; +} Index: src/hid_cfg_input.h =================================================================== --- src/hid_cfg_input.h (revision 1455) +++ src/hid_cfg_input.h (revision 1456) @@ -40,11 +40,12 @@ /************************** KEYBOARD ***************************/ +#define HIDCFG_MAX_KEYSEQ_LEN 32 typedef union hid_cfg_keyhash_u { /* integer hash key */ unsigned long hash; struct { - short int mods; /* of hid_cfg_mod_t */ - short int key_char; + unsigned short int mods; /* of hid_cfg_mod_t */ + unsigned short int key_char; } details; } hid_cfg_keyhash_t; @@ -53,15 +54,33 @@ struct hid_cfg_keyseq_s { unsigned long int keysym; /* optional 32 bit long storage the GUI hid should cast to whatever the GUI backend supports */ - lht_node_t *node; /* terminal node: end of sequence, run actions */ + lht_node_t *action_node; /* terminal node: end of sequence, run actions */ htip_t seq_next; /* ... or if node is NULL, a hash for each key that may follow the current one */ hid_cfg_keyseq_t *parent; }; +/* Translate symbolic name to single-char keysym before processing; useful + for shortcuts like "Return -> '\r'" which are otherwise hard to describe + in text format */ +typedef struct hid_cfg_keytrans_s { + char *name; + char sym; +} hid_cfg_keytrans_t; + +extern const hid_cfg_keytrans_t hid_cfg_key_default_trans[]; + /* A complete tree of keyboard shortcuts/hotkeys */ typedef struct hid_cfg_keys_s { htip_t keys; + + /* translate key sym description (the portion after ) to key_char; + desc is a \0 terminated string, len is only a hint. Should return 0 + on error. */ + unsigned short int (*translate_key)(char *desc, int len); + + int auto_chr; /* if non-zero: don't call translate_key() for 1-char symbols, handle the default way */ + const hid_cfg_keytrans_t *auto_tr; /* apply this table before calling translate_key() */ } hid_cfg_keys_t; @@ -74,7 +93,7 @@ int hid_cfg_keys_uninit(hid_cfg_keys_t *km); #warning TODO: desc -hid_cfg_keyseq_t *hid_cfg_keys_add_under(hid_cfg_keys_t *km, hid_cfg_keyseq_t *parent, hid_cfg_mod_t mods, short int key_char, int terminal); +hid_cfg_keyseq_t *hid_cfg_keys_add_under(hid_cfg_keys_t *km, hid_cfg_keyseq_t *parent, hid_cfg_mod_t mods, unsigned short int key_char, int terminal); /* Add a new key using a description (read from a lihata file usually) If out_seq is not NULL, load the array with pointers pointing to each @@ -81,12 +100,12 @@ key in the sequence, up to out_seq_len. Returns -1 on failure or the length of the sequence. */ -int hid_cfg_keys_add_by_desc(hid_cfg_keys_t *km, const char *keydesc, hid_cfg_keyseq_t **out_seq, int out_seq_len); +int hid_cfg_keys_add_by_desc(hid_cfg_keys_t *km, const char *keydesc, lht_node_t *action_node, hid_cfg_keyseq_t **out_seq, int out_seq_len); /* Process next input key stroke. Seq and seq_len must not be NULL as they are the internal state of multi-key processing. Load seq array with pointers pointing to each key in the - sequence, up to seq_len_max. + sequence, up to seq_len. Returns: -1 if the key stroke or sequence is invalid 0 if more characters needed to complete the sequence @@ -93,11 +112,11 @@ + a positive integer means the lookup succeeded and the return value is the length of the resulting sequence. */ -int hid_cfg_keys_input(hid_cfg_keys_t *km, hid_cfg_mod_t mods, short int key_char, hid_cfg_keyseq_t **seq, int *seq_len, int seq_len_max); +int hid_cfg_keys_input(hid_cfg_keys_t *km, hid_cfg_mod_t mods, unsigned short int key_char, hid_cfg_keyseq_t **seq, int *seq_len); /* Run the action for a key sequence looked up by hid_cfg_keys_input(). Returns: the result of the action or -1 on error */ -int hid_cfg_keys_action(hid_cfg_keyseq_t *seq, int seq_len); +int hid_cfg_keys_action(hid_cfg_keyseq_t **seq, int seq_len); #endif