diff options
| -rw-r--r-- | src/binding.c | 2 | ||||
| -rw-r--r-- | src/binding.h | 8 | ||||
| -rw-r--r-- | src/keyboard.c | 52 | ||||
| -rw-r--r-- | src/keyboard.h | 9 | ||||
| -rw-r--r-- | src/main.c | 39 |
5 files changed, 65 insertions, 45 deletions
diff --git a/src/binding.c b/src/binding.c index 191bc0d..5147c97 100644 --- a/src/binding.c +++ b/src/binding.c @@ -42,7 +42,7 @@ struct lookup_result lookup_key(struct keymap *keymaps, uint32_t nkeymaps, for (uint32_t bi = 0; bi < keymap->nbindings; ++bi) { struct binding *binding = &keymap->bindings[bi]; - if (key->c == binding->key.c && key->mod == binding->key.mod) { + if (key_equal(key, &binding->key)) { if (binding->type == BindingType_Command) { return (struct lookup_result){ .found = true, diff --git a/src/binding.h b/src/binding.h index 8a703c3..f00efed 100644 --- a/src/binding.h +++ b/src/binding.h @@ -11,14 +11,14 @@ enum binding_type { BindingType_Command, BindingType_Keymap }; #define BINDING(mod_, c_, command_) \ (struct binding) { \ - .key = {.mod = mod_, .c = c_}, .type = BindingType_Command, \ - .command = hash_command_name(command_) \ + .key = {.mod = mod_, .bytes[0] = c_, .nbytes = 1}, \ + .type = BindingType_Command, .command = hash_command_name(command_) \ } #define PREFIX(mod_, c_, keymap_) \ (struct binding) { \ - .key = {.mod = mod_, .c = c_}, .type = BindingType_Keymap, \ - .keymap = keymap_ \ + .key = {.mod = mod_, .bytes[0] = c_, .nbytes = 1}, \ + .type = BindingType_Keymap, .keymap = keymap_ \ } struct binding { diff --git a/src/keyboard.c b/src/keyboard.c index aaeccd2..b4c0c6d 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1,6 +1,7 @@ #include "keyboard.h" #include "reactor.h" #include "stdio.h" +#include "utf8.h" #include <ctype.h> #include <errno.h> @@ -13,31 +14,48 @@ struct keyboard keyboard_create(struct reactor *reactor) { .reactor_event_id = reactor_register_interest(reactor, STDIN_FILENO, ReadInterest), .has_data = false, + .last_key = {0}, }; } void parse_keys(uint8_t *bytes, uint32_t nbytes, struct key *out_keys, - uint32_t *out_nkeys) { + uint32_t *out_nkeys, struct key *previous_key) { uint32_t nkps = 0; + struct key *prevkp = previous_key; for (uint32_t bytei = 0; bytei < nbytes; ++bytei) { uint8_t b = bytes[bytei]; struct key *kp = &out_keys[nkps]; + kp->nbytes = 1; if (b == 0x1b) { // meta kp->mod |= Meta; } else if (b >= 0x00 && b <= 0x1f) { // ctrl char kp->mod |= Ctrl; - kp->c = b | 0x40; - + kp->bytes[0] = b | 0x40; + ++nkps; + prevkp = kp; } else if (b == 0x7f) { // ^? kp->mod |= Ctrl; - kp->c = '?'; - } else { // normal char (or part of char) - kp->c = b; + kp->bytes[0] = '?'; + ++nkps; + prevkp = kp; + } else if (utf8_byte_is_unicode_start((uint8_t)b)) { + kp->bytes[0] = b; + ++nkps; + prevkp = kp; + } else if (utf8_byte_is_unicode_continuation((uint8_t)b)) { + prevkp->bytes[prevkp->nbytes] = b; + ++prevkp->nbytes; + } else { /* ascii char */ + if (prevkp->mod & Meta) { + prevkp->bytes[0] = b; + } else { + kp->bytes[0] = b; + } + ++nkps; + prevkp = kp; } - - ++nkps; } *out_nkeys = nkps; @@ -61,7 +79,7 @@ struct keyboard_update keyboard_update(struct keyboard *kbd, int nbytes = read(STDIN_FILENO, bytes, 32); if (nbytes > 0) { - parse_keys(bytes, nbytes, upd.keys, &upd.nkeys); + parse_keys(bytes, nbytes, upd.keys, &upd.nkeys, &kbd->last_key); } else if (nbytes == EAGAIN) { kbd->has_data = false; } @@ -69,8 +87,13 @@ struct keyboard_update keyboard_update(struct keyboard *kbd, return upd; } -bool key_equal(struct key *key, uint8_t mod, uint8_t c) { - return key->c == c && key->mod == mod; +bool key_equal_char(struct key *key, uint8_t mod, uint8_t c) { + return key->bytes[0] == c && key->mod == mod; +} + +bool key_equal(struct key *key1, struct key *key2) { + return memcmp(key1->bytes, key2->bytes, key1->nbytes) == 0 && + key1->mod == key2->mod && key1->nbytes == key2->nbytes; } void key_name(struct key *key, char *buf, size_t capacity) { @@ -84,5 +107,10 @@ void key_name(struct key *key, char *buf, size_t capacity) { break; } - snprintf(buf, capacity, "%s%c", mod, tolower((char)key->c)); + uint8_t lower[6]; + for (uint32_t bytei = 0; bytei < key->nbytes; ++bytei) { + lower[bytei] = tolower(key->bytes[bytei]); + } + + snprintf(buf, capacity, "%s%.*s", mod, key->nbytes, lower); } diff --git a/src/keyboard.h b/src/keyboard.h index 4078213..18630c3 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -7,16 +7,16 @@ enum modifiers { Meta = 1 << 1, }; -// note that unicode chars are split over multiple keypresses -// TODO: make unicode chars nicer to deal with struct key { - uint8_t c; + uint8_t bytes[6]; + uint8_t nbytes; uint8_t mod; }; struct keyboard { uint32_t reactor_event_id; bool has_data; + struct key last_key; }; struct keyboard_update { @@ -31,5 +31,6 @@ struct keyboard keyboard_create(struct reactor *reactor); struct keyboard_update keyboard_update(struct keyboard *kbd, struct reactor *reactor); -bool key_equal(struct key *key, uint8_t mod, uint8_t c); +bool key_equal_char(struct key *key, uint8_t mod, uint8_t c); +bool key_equal(struct key *key1, struct key *key2); void key_name(struct key *key, char *buf, size_t capacity); @@ -58,13 +58,19 @@ void exit_editor(struct command_ctx ctx, int argc, const char *argv[]) { terminate(); } -static struct command GLOBAL_COMMANDS[] = {{ - .name = "find-file", - .fn = unimplemented_command, - .userdata = (void *)"find-file", - }, - {.name = "abort", .fn = _abort}, - {.name = "exit", .fn = exit_editor}}; +static struct command GLOBAL_COMMANDS[] = { + { + .name = "find-file", + .fn = unimplemented_command, + .userdata = (void *)"find-file", + }, + { + .name = "run-command-interactive", + .fn = unimplemented_command, + .userdata = (void *)"run-command-interactive", + }, + {.name = "abort", .fn = _abort}, + {.name = "exit", .fn = exit_editor}}; uint64_t calc_frame_time_ns(struct timespec *timers, uint32_t num_timer_pairs) { uint64_t total = 0; @@ -151,6 +157,7 @@ int main(int argc, char *argv[]) { struct binding global_binds[] = { PREFIX(Ctrl, 'X', &ctrlx_map), BINDING(Ctrl, 'G', "abort"), + BINDING(Meta, 'x', "run-command-interactive"), }; struct binding ctrlx_bindings[] = { BINDING(Ctrl, 'C', "exit"), @@ -245,9 +252,6 @@ int main(int argc, char *argv[]) { uint32_t nbuffer_keymaps = buffer_keymaps(&curbuf, &local_keymaps); struct keyboard_update kbd_upd = keyboard_update(&kbd, &reactor); - // buffer up chars to handle utf-8 "correctly" - uint8_t chars[kbd_upd.nkeys]; - uint8_t nchars; for (uint32_t ki = 0; ki < kbd_upd.nkeys; ++ki) { struct key *k = &kbd_upd.keys[ki]; @@ -263,10 +267,6 @@ int main(int argc, char *argv[]) { } if (res.found) { - if (nchars > 0) { - buffer_add_text(active_window->buffer, chars, nchars); - nchars = 0; - } switch (res.type) { case BindingType_Command: { execute_command(res.command, active_window->buffer, 0, NULL); @@ -282,21 +282,12 @@ int main(int argc, char *argv[]) { } } } else if (current_keymap != NULL) { - if (nchars > 0) { - buffer_add_text(active_window->buffer, chars, nchars); - nchars = 0; - } minibuffer_echo_timeout(4, "key is not bound!"); current_keymap = NULL; } else { - chars[nchars] = k->c; - ++nchars; + buffer_add_text(active_window->buffer, k->bytes, k->nbytes); } } - if (nchars > 0) { - buffer_add_text(active_window->buffer, chars, nchars); - nchars = 0; - } clock_gettime(CLOCK_MONOTONIC, &keyboard_end); // calculate frame time |
