summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlbert Cervin <albert@acervin.com>2022-12-18 21:20:19 +0100
committerAlbert Cervin <albert@acervin.com>2022-12-18 21:20:19 +0100
commita817e01bfe2356fdd860010d46db4e4361f343a6 (patch)
treef6e34056d236b1df6e6a62573d4f9adf602b0dc7
parent3deb7c91056779d1f1b2be112e727bc9999ac21d (diff)
downloaddged-a817e01bfe2356fdd860010d46db4e4361f343a6.tar.gz
dged-a817e01bfe2356fdd860010d46db4e4361f343a6.tar.xz
dged-a817e01bfe2356fdd860010d46db4e4361f343a6.zip
Fixup utf-8 and meta handling in input
-rw-r--r--src/binding.c2
-rw-r--r--src/binding.h8
-rw-r--r--src/keyboard.c52
-rw-r--r--src/keyboard.h9
-rw-r--r--src/main.c39
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);
diff --git a/src/main.c b/src/main.c
index a1d26e5..dc7cf63 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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