1
0
mirror of https://codeberg.org/vyivel/dulcepan/ synced 2025-03-12 10:49:15 +02:00

config: allow to bind multiple keys to the same action

Allows for both Space and Enter to save the selection, for example.
This commit is contained in:
Kirill Primak 2025-01-30 22:24:10 +03:00
parent 51f744c876
commit 9879f3ad69
5 changed files with 70 additions and 14 deletions

View File

@ -40,6 +40,7 @@ persistence = true
# PNG (zlib) compression level, 0-9 # PNG (zlib) compression level, 0-9
png-compression = 6 png-compression = 6
# Key bindings # Key bindings. Each binding is a comma-separated list of key names; empty names
# are ignored. A binding may be empty.
quit-key = Escape quit-key = Escape
save-key = Space save-key = Space,Enter

View File

@ -15,6 +15,21 @@ static inline void bytes_to_color(uint8_t bytes[static 4], float out[static 4])
} }
} }
static void keybinding_init(struct dp_keybinding *kb, xkb_keysym_t *syms, size_t n_syms) {
*kb = (struct dp_keybinding){
.syms = dp_zalloc(sizeof(*kb->syms) * n_syms),
.n_syms = n_syms,
};
for (size_t i = 0; i < n_syms; i++) {
xkb_keysym_t sym = syms[i];
kb->syms[i] = sym;
}
}
static void keybinding_finish(struct dp_keybinding *kb) {
free(kb->syms);
}
static void load_color(char *value, int line_idx, float out[static 4]) { static void load_color(char *value, int line_idx, float out[static 4]) {
size_t len = strlen(value); size_t len = strlen(value);
@ -78,19 +93,31 @@ static void load_bool(char *value, int line_idx, bool *out) {
} }
} }
static void load_key(char *value, int line_idx, xkb_keysym_t *out) { static void load_key(char *value, int line_idx, struct dp_keybinding *out) {
*out = xkb_keysym_from_name(value, XKB_KEYSYM_CASE_INSENSITIVE); size_t n_syms = 0;
if (*out == XKB_KEY_NoSymbol) { xkb_keysym_t syms[32];
dp_log_fatal("Config: unknown key %s on line %d", value, line_idx);
char *save_ptr = NULL;
for (char *name; (name = strtok_r(value, ",", &save_ptr)) != NULL; value = NULL) {
if (n_syms == sizeof(syms) / sizeof(*syms)) {
// chill out
dp_log_fatal("Config: too many keys on line %d", line_idx);
}
xkb_keysym_t sym = xkb_keysym_from_name(name, XKB_KEYSYM_CASE_INSENSITIVE);
if (sym == XKB_KEY_NoSymbol) {
dp_log_fatal("Config: unknown key \"%s\" on line %d", name, line_idx);
}
syms[n_syms++] = sym;
} }
keybinding_finish(out);
keybinding_init(out, syms, n_syms);
} }
void dp_config_load(struct dp_state *state, const char *user_path) { void dp_config_load(struct dp_state *state, const char *user_path) {
struct dp_config *config = &state->config; struct dp_config *config = &state->config;
*config = (struct dp_config){ *config = (struct dp_config){
.quit_key = XKB_KEY_Escape,
.save_key = XKB_KEY_space,
.border_size = 2, .border_size = 2,
.border_gradient = DP_BORDER_GRADIENT_NONE, .border_gradient = DP_BORDER_GRADIENT_NONE,
.gradient_angle = 45, .gradient_angle = 45,
@ -100,11 +127,15 @@ void dp_config_load(struct dp_state *state, const char *user_path) {
.quick_select = false, .quick_select = false,
.persistence = true, .persistence = true,
}; };
bytes_to_color((uint8_t[]){0xff, 0xff, 0xff, 0x40}, config->unselected_color); bytes_to_color((uint8_t[]){0xff, 0xff, 0xff, 0x40}, config->unselected_color);
bytes_to_color((uint8_t[]){0x00, 0x00, 0x00, 0x00}, config->selected_color); bytes_to_color((uint8_t[]){0x00, 0x00, 0x00, 0x00}, config->selected_color);
bytes_to_color((uint8_t[]){0xff, 0xff, 0xff, 0xff}, config->border_color); bytes_to_color((uint8_t[]){0xff, 0xff, 0xff, 0xff}, config->border_color);
bytes_to_color((uint8_t[]){0x00, 0x00, 0x00, 0xff}, config->border_secondary_color); bytes_to_color((uint8_t[]){0x00, 0x00, 0x00, 0xff}, config->border_secondary_color);
keybinding_init(&config->quit_kb, (xkb_keysym_t[]){XKB_KEY_Escape}, 1);
keybinding_init(&config->save_kb, (xkb_keysym_t[]){XKB_KEY_space, XKB_KEY_Return}, 2);
FILE *fp = NULL; FILE *fp = NULL;
if (user_path != NULL) { if (user_path != NULL) {
fp = fopen(user_path, "r"); fp = fopen(user_path, "r");
@ -215,9 +246,9 @@ void dp_config_load(struct dp_state *state, const char *user_path) {
} else if (strcmp(key, "persistence") == 0) { } else if (strcmp(key, "persistence") == 0) {
load_bool(value, line_idx, &config->persistence); load_bool(value, line_idx, &config->persistence);
} else if (strcmp(key, "quit-key") == 0) { } else if (strcmp(key, "quit-key") == 0) {
load_key(value, line_idx, &config->quit_key); load_key(value, line_idx, &config->quit_kb);
} else if (strcmp(key, "save-key") == 0) { } else if (strcmp(key, "save-key") == 0) {
load_key(value, line_idx, &config->save_key); load_key(value, line_idx, &config->save_kb);
} else { } else {
dp_log_error("Config: unknown key %s on line %d", key, line_idx); dp_log_error("Config: unknown key %s on line %d", key, line_idx);
} }
@ -226,3 +257,10 @@ void dp_config_load(struct dp_state *state, const char *user_path) {
fclose(fp); fclose(fp);
} }
void dp_config_finish(struct dp_state *state) {
struct dp_config *config = &state->config;
keybinding_finish(&config->quit_kb);
keybinding_finish(&config->save_kb);
}

View File

@ -141,6 +141,11 @@ enum dp_border_gradient {
DP_BORDER_GRADIENT_LOOP, DP_BORDER_GRADIENT_LOOP,
}; };
struct dp_keybinding {
xkb_keysym_t *syms;
size_t n_syms;
};
struct dp_config { struct dp_config {
// RGBA, not premultiplied // RGBA, not premultiplied
float unselected_color[4]; float unselected_color[4];
@ -148,8 +153,8 @@ struct dp_config {
float border_color[4]; float border_color[4];
float border_secondary_color[4]; float border_secondary_color[4];
xkb_keysym_t quit_key; struct dp_keybinding quit_kb;
xkb_keysym_t save_key; struct dp_keybinding save_kb;
int border_size; // 0 if disabled int border_size; // 0 if disabled
enum dp_border_gradient border_gradient; enum dp_border_gradient border_gradient;
@ -204,6 +209,7 @@ struct dp_state {
}; };
void dp_config_load(struct dp_state *state, const char *user_path); void dp_config_load(struct dp_state *state, const char *user_path);
void dp_config_finish(struct dp_state *state);
// When done, data must be unmapped // When done, data must be unmapped
struct wl_buffer *dp_buffer_create(struct dp_state *state, int32_t width, int32_t height, struct wl_buffer *dp_buffer_create(struct dp_state *state, int32_t width, int32_t height,

View File

@ -278,6 +278,8 @@ int main(int argc, char **argv) {
run(&state); run(&state);
dp_config_finish(&state);
cairo_pattern_destroy(state.border_pattern); cairo_pattern_destroy(state.border_pattern);
xkb_context_unref(state.xkb_context); xkb_context_unref(state.xkb_context);

View File

@ -50,6 +50,15 @@ static void keyboard_handle_leave(
// Ignored // Ignored
} }
static bool match_keybinding(struct dp_keybinding *kb, uint32_t sym) {
for (size_t i = 0; i < kb->n_syms; i++) {
if (sym == kb->syms[i]) {
return true;
}
}
return false;
}
static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
uint32_t time_msec, uint32_t keycode, enum wl_keyboard_key_state key_state) { uint32_t time_msec, uint32_t keycode, enum wl_keyboard_key_state key_state) {
struct dp_seat *seat = data; struct dp_seat *seat = data;
@ -62,9 +71,9 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, uin
struct dp_state *state = seat->state; struct dp_state *state = seat->state;
struct dp_config *config = &state->config; struct dp_config *config = &state->config;
if (keysym == config->quit_key) { if (match_keybinding(&config->quit_kb, keysym)) {
state->status = DP_STATUS_QUIT; state->status = DP_STATUS_QUIT;
} else if (keysym == config->save_key) { } else if (match_keybinding(&config->save_kb, keysym)) {
state->status = DP_STATUS_SAVED; state->status = DP_STATUS_SAVED;
} }
} }