int termkey_keycmp(TermKey *tk, const TermKeyKey *key1p, const TermKeyKey *key2p) { /* Copy the key structs since we'll be modifying them */ TermKeyKey key1 = *key1p, key2 = *key2p; termkey_canonicalise(tk, &key1); termkey_canonicalise(tk, &key2); if(key1.type != key2.type) return key1.type - key2.type; switch(key1.type) { case TERMKEY_TYPE_UNICODE: if(key1.code.codepoint != key2.code.codepoint) return key1.code.codepoint - key2.code.codepoint; break; case TERMKEY_TYPE_KEYSYM: if(key1.code.sym != key2.code.sym) return key1.code.sym - key2.code.sym; break; case TERMKEY_TYPE_FUNCTION: case TERMKEY_TYPE_UNKNOWN_CSI: if(key1.code.number != key2.code.number) return key1.code.number - key2.code.number; break; case TERMKEY_TYPE_MOUSE: { int cmp = strncmp(key1.code.mouse, key2.code.mouse, 4); if(cmp != 0) return cmp; } break; case TERMKEY_TYPE_POSITION: { int line1, col1, line2, col2; termkey_interpret_position(tk, &key1, &line1, &col1); termkey_interpret_position(tk, &key2, &line2, &col2); if(line1 != line2) return line1 - line2; return col1 - col2; } break; case TERMKEY_TYPE_DCS: case TERMKEY_TYPE_OSC: return key1p - key2p; case TERMKEY_TYPE_MODEREPORT: { int initial1, initial2, mode1, mode2, value1, value2; termkey_interpret_modereport(tk, &key1, &initial1, &mode1, &value1); termkey_interpret_modereport(tk, &key2, &initial2, &mode2, &value2); if(initial1 != initial2) return initial1 - initial2; if(mode1 != mode2) return mode1 - mode2; return value1 - value2; } } return key1.modifiers - key2.modifiers; }
static void emit_codepoint(TermKey *tk, long codepoint, TermKeyKey *key) { if(codepoint == 0) { // ASCII NUL = Ctrl-Space key->type = TERMKEY_TYPE_KEYSYM; key->code.sym = TERMKEY_SYM_SPACE; key->modifiers = TERMKEY_KEYMOD_CTRL; } else if(codepoint < 0x20) { // C0 range key->code.codepoint = 0; key->modifiers = 0; if(!(tk->flags & TERMKEY_FLAG_NOINTERPRET) && tk->c0[codepoint].sym != TERMKEY_SYM_UNKNOWN) { key->code.sym = tk->c0[codepoint].sym; key->modifiers |= tk->c0[codepoint].modifier_set; } if(!key->code.sym) { key->type = TERMKEY_TYPE_UNICODE; /* Generically modified Unicode ought not report the SHIFT state, or else * we get into complicationg trying to report Shift-; vs : and so on... * In order to be able to represent Ctrl-Shift-A as CTRL modified * unicode A, we need to call Ctrl-A simply 'a', lowercase */ if(codepoint+0x40 >= 'A' && codepoint+0x40 <= 'Z') // it's a letter - use lowecase instead key->code.codepoint = codepoint + 0x60; else key->code.codepoint = codepoint + 0x40; key->modifiers = TERMKEY_KEYMOD_CTRL; } else { key->type = TERMKEY_TYPE_KEYSYM; } } else if(codepoint == 0x7f && !(tk->flags & TERMKEY_FLAG_NOINTERPRET)) { // ASCII DEL key->type = TERMKEY_TYPE_KEYSYM; key->code.sym = TERMKEY_SYM_DEL; key->modifiers = 0; } else if(codepoint >= 0x20 && codepoint < 0x80) { // ASCII lowbyte range key->type = TERMKEY_TYPE_UNICODE; key->code.codepoint = codepoint; key->modifiers = 0; } else if(codepoint >= 0x80 && codepoint < 0xa0) { // UTF-8 never starts with a C1 byte. So we can be sure of these key->type = TERMKEY_TYPE_UNICODE; key->code.codepoint = codepoint - 0x40; key->modifiers = TERMKEY_KEYMOD_CTRL|TERMKEY_KEYMOD_ALT; } else { // UTF-8 codepoint key->type = TERMKEY_TYPE_UNICODE; key->code.codepoint = codepoint; key->modifiers = 0; } termkey_canonicalise(tk, key); if(key->type == TERMKEY_TYPE_UNICODE) fill_utf8(key); }
const char *termkey_strpkey(TermKey *tk, const char *str, TermKeyKey *key, TermKeyFormat format) { struct modnames *mods = &modnames[!!(format & TERMKEY_FORMAT_LONGMOD) + !!(format & TERMKEY_FORMAT_ALTISMETA) * 2 + !!(format & TERMKEY_FORMAT_LOWERMOD) * 4]; key->modifiers = 0; if((format & TERMKEY_FORMAT_CARETCTRL) && str[0] == '^' && str[1]) { str = termkey_strpkey(tk, str+1, key, format & ~TERMKEY_FORMAT_CARETCTRL); if(!str || key->type != TERMKEY_TYPE_UNICODE || key->code.codepoint < '@' || key->code.codepoint > '_' || key->modifiers != 0) return NULL; if(key->code.codepoint >= 'A' && key->code.codepoint <= 'Z') key->code.codepoint += 0x20; key->modifiers = TERMKEY_KEYMOD_CTRL; fill_utf8(key); return (char *)str; } const char *sep_at; while((sep_at = strchr(str, (format & TERMKEY_FORMAT_SPACEMOD) ? ' ' : '-'))) { size_t n = sep_at - str; if(n == strlen(mods->alt) && strncmp(mods->alt, str, n) == 0) key->modifiers |= TERMKEY_KEYMOD_ALT; else if(n == strlen(mods->ctrl) && strncmp(mods->ctrl, str, n) == 0) key->modifiers |= TERMKEY_KEYMOD_CTRL; else if(n == strlen(mods->shift) && strncmp(mods->shift, str, n) == 0) key->modifiers |= TERMKEY_KEYMOD_SHIFT; else break; str = sep_at + 1; } size_t nbytes; ssize_t snbytes; const char *endstr; if((endstr = termkey_lookup_keyname_format(tk, str, &key->code.sym, format))) { key->type = TERMKEY_TYPE_KEYSYM; str = endstr; } else if(sscanf(str, "F%d%zn", &key->code.number, &snbytes) == 1) { key->type = TERMKEY_TYPE_FUNCTION; str += snbytes; } // Unicode must be last else if(parse_utf8((unsigned const char *)str, strlen(str), &key->code.codepoint, &nbytes) == TERMKEY_RES_KEY) { key->type = TERMKEY_TYPE_UNICODE; fill_utf8(key); str += nbytes; } // TODO: Consider mouse events? else return NULL; termkey_canonicalise(tk, key); return (char *)str; }