implement keybind parsing

This commit is contained in:
Akos Horvath 2024-03-16 19:55:34 +01:00
parent 01e8c16e8b
commit 58bc1089f2
2 changed files with 210 additions and 27 deletions

View File

@ -2,8 +2,6 @@
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <assert.h> #include <assert.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h>
#include <stdint.h>
#include <errno.h> #include <errno.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
@ -17,11 +15,50 @@
#include "config.h" #include "config.h"
#include "wm.h" #include "wm.h"
static const KeybindFunctionCommand __wm_keybind_commands[] = {
(KeybindFunctionCommand) {
.command = "spawn",
.function = &wm_kb_spawn
},
(KeybindFunctionCommand) {
.command = "focus",
.function = &wm_kb_focus_dir
},
(KeybindFunctionCommand) {
.command = "move",
.function = &wm_kb_move_dir
},
(KeybindFunctionCommand) {
.command = "switch_ws",
.function = &wm_kb_switch_ws
},
(KeybindFunctionCommand) {
.command = "move_to_ws",
.function = &wm_kb_move_client_ws
},
(KeybindFunctionCommand) {
.command = "quit",
.function = &wm_kb_exit
},
(KeybindFunctionCommand) {
.command = "quit_client",
.function = &wm_kb_kill
},
(KeybindFunctionCommand) {
.command = "split_vertical",
.function = &wm_kb_switch_split_mode
},
(KeybindFunctionCommand) {
.command = "split_horizontal",
.function = &wm_kb_switch_split_mode
},
};
void wm_cfg_init_def(Config *config) void wm_cfg_init_def(Config *config)
{ {
config->ms_p = 0.5; config->ms_p = 0.5;
config->border_col = "#222222"; strncpy(config->border_col, "#222222", CONFIG_COLOR_MAX);
config->focused_border_col = "#444444"; strncpy(config->focused_border_col, "#444444", CONFIG_COLOR_MAX);
config->border_width = 2; config->border_width = 2;
config->focus_on_motion = true; config->focus_on_motion = true;
@ -165,6 +202,14 @@ void wm_keybinds_init_def(Config *config)
memcpy(config->keybinds, k, size); memcpy(config->keybinds, k, size);
} }
void wm_keybinds_free(Config *config)
{
for (size_t i = 0; i < config->kb_count; i++) {
if (config->keybinds[i].function == &wm_kb_spawn)
free(config->keybinds[i].args.sl);
}
}
void wm_configfile_init(ConfigFile *config, const char *filename) void wm_configfile_init(ConfigFile *config, const char *filename)
{ {
assert(config); assert(config);
@ -175,23 +220,23 @@ void wm_configfile_init(ConfigFile *config, const char *filename)
ConfigCommand commands[] = { ConfigCommand commands[] = {
(ConfigCommand) {.string = "border_color", .arg_count = 1, (ConfigCommand) {.string = "border_color", .arg_count = 1,
.cfg_var_offset[0] = offsetof(Config, border_col), .cfg_var_offset[0] = offsetof(Config, border_col),
.argc = 0}, .argc = 0, .arg_type = TYPE_STRING},
(ConfigCommand) {.string = "focused_border_color", .arg_count = 1, (ConfigCommand) {.string = "focused_border_color", .arg_count = 1,
.cfg_var_offset[0] = offsetof(Config, focused_border_col), .cfg_var_offset[0] = offsetof(Config, focused_border_col),
.argc = 0}, .argc = 0, .arg_type = TYPE_STRING},
(ConfigCommand) {.string = "border_width", .arg_count = 1, (ConfigCommand) {.string = "border_width", .arg_count = 1,
.cfg_var_offset[0] = offsetof(Config, border_width), .cfg_var_offset[0] = offsetof(Config, border_width),
.argc = 0}, .argc = 0, .arg_type = TYPE_UNSIGNED_INTEGER},
(ConfigCommand) {.string = "keybind", .arg_count = 0, (ConfigCommand) {.string = "keybind", .arg_count = 0,
.cfg_var_offset[0] = -1, .cfg_var_offset[0] = -1,
.argc = 0}, .argc = 0, .arg_type = TYPE_KEYBIND},
(ConfigCommand) {.string = "focus_on_motion", .arg_count = 1, (ConfigCommand) {.string = "focus_on_motion", .arg_count = 1,
.cfg_var_offset[0] = offsetof(Config, focus_on_motion), .cfg_var_offset[0] = offsetof(Config, focus_on_motion),
.argc = 0}, .argc = 0, .arg_type = TYPE_BOOL},
}; };
config->command_count = sizeof(commands) / sizeof (commands[0]); config->command_count = sizeof(commands) / sizeof (commands[0]);
@ -210,6 +255,8 @@ void wm_configfile_free(ConfigFile *config)
for (size_t i = 0; i < config->command_count; i++) { for (size_t i = 0; i < config->command_count; i++) {
wm_configcommand_free(&config->available_commands[i]); wm_configcommand_free(&config->available_commands[i]);
} }
free(config->available_commands);
} }
void wm_configfile_read(ConfigFile *cfile, Config *config) void wm_configfile_read(ConfigFile *cfile, Config *config)
@ -253,31 +300,31 @@ void wm_config_apply_command(Config *config, ConfigCommand *command)
switch (command->arg_type) { switch (command->arg_type) {
case TYPE_INTEGER: case TYPE_INTEGER:
for (size_t i = 0; i < command->argc; i++) { for (size_t i = 0; i < command->argc; i++) {
*(int*)((char*)config + (command->cfg_var_offset[i])) = command->args[i].i; *(int*)(((char*)config) + (command->cfg_var_offset[i])) = command->args[i].i;
} }
return; return;
case TYPE_UNSIGNED_INTEGER: case TYPE_UNSIGNED_INTEGER:
for (size_t i = 0; i < command->argc; i++) { for (size_t i = 0; i < command->argc; i++) {
*(unsigned int*)((char*)config + (command->cfg_var_offset[i])) = command->args[i].ui; *(unsigned int*)(((char*)config) + (command->cfg_var_offset[i])) = command->args[i].ui;
} }
return; return;
case TYPE_BOOL: case TYPE_BOOL:
for (size_t i = 0; i < command->argc; i++) { for (size_t i = 0; i < command->argc; i++) {
*(bool*)((char*)config + (command->cfg_var_offset[i])) = command->args[i].i; *(bool*)(((char*)config) + (command->cfg_var_offset[i])) = command->args[i].i;
} }
return; return;
case TYPE_KEYBIND: case TYPE_KEYBIND:
// TODO wm_config_replace_keybind(config, &command->keybind);
wm_config_parse_bind_command(command); return;
case TYPE_STRING: case TYPE_STRING:
for (size_t i = 0; i < command->argc; i++) { for (size_t i = 0; i < command->argc; i++) {
size_t len = strnlen(command->argv[i], CONFIG_ARGLEN_MAX); size_t len = strnlen(command->argv[i], CONFIG_ARGLEN_MAX);
memcpy((char*)(config + (command->cfg_var_offset)[i]), command->argv[i], len); memcpy(((char*)(config) + (command->cfg_var_offset)[i]), command->argv[i], len);
} }
return; return;
case TYPE_FLOAT: case TYPE_FLOAT:
for (size_t i = 0; i < command->argc; i++) { for (size_t i = 0; i < command->argc; i++) {
*(float*)((char*)config + (command->cfg_var_offset[i])) = atof(command->argv[i]); *(float*)(((char*)config) + (command->cfg_var_offset[i])) = atof(command->argv[i]);
} }
return; return;
} }
@ -298,6 +345,9 @@ ParserResult wm_configfile_parse_line(const ConfigFile *cfile, Config *config,
if (line[0] == '\n') if (line[0] == '\n')
return (ParserResult) {.success = true, .message = ""}; return (ParserResult) {.success = true, .message = ""};
if (!token)
return (ParserResult) {.success = true, .message = ""};
// try to match command // try to match command
for (size_t i = 0; i < cfile->command_count; i++) { for (size_t i = 0; i < cfile->command_count; i++) {
if (strncmp(cfile->available_commands[i].string, token, if (strncmp(cfile->available_commands[i].string, token,
@ -333,12 +383,15 @@ ParserResult wm_configfile_parse_line(const ConfigFile *cfile, Config *config,
CONFIG_ARGC_MAX); CONFIG_ARGC_MAX);
} }
if (command->argc > command->arg_count) { if (command->argc > command->arg_count && command->arg_type != TYPE_KEYBIND) {
PARSER_RETURN(result, false, "Too many arguments to command %s\n", PARSER_RETURN(result, false, "Too many arguments to command %s\n",
command->string); command->string);
} }
strncpy(command->argv[command->argc-1], token, CONFIG_ARGLEN_MAX); strncpy(command->argv[command->argc-1], token, CONFIG_ARGLEN_MAX);
char *arg = command->argv[command->argc-1];
for (size_t i = 0; i < strnlen(arg, CONFIG_ARGLEN_MAX); i++)
if (arg[i] == '\n') arg[i] = '\0';
} }
// end of args // end of args
@ -419,8 +472,8 @@ void wm_configcommand_argv_parse(ConfigCommand *command)
} }
return; return;
case TYPE_KEYBIND: case TYPE_KEYBIND:
// todo command->keybind = wm_config_parse_bind_command(command);
wm_config_parse_bind_command(command); return;
case TYPE_STRING: case TYPE_STRING:
for (size_t i = 0; i < command->argc; i++) { for (size_t i = 0; i < command->argc; i++) {
size_t len = strnlen(command->argv[i], CONFIG_ARGLEN_MAX); size_t len = strnlen(command->argv[i], CONFIG_ARGLEN_MAX);
@ -474,6 +527,99 @@ bool atobool(char *arr)
return false; return false;
} }
Arg wm_keybind_argv_to_args(Keybind kb, ConfigCommand command)
{
DEBUG_PRINT("%s\n", __func__);
Arg ret;
if (kb.function == &wm_kb_spawn) {
ret.sl = calloc(command.argc - 2, sizeof(char*));
for (size_t i = 2; i < command.argc; i++) {
ret.sl[i] = calloc(CONFIG_ARGLEN_MAX, 1);
strncpy(ret.sl[i], command.argv[i], CONFIG_ARGLEN_MAX);
}
return ret;
}
if (kb.function == &wm_kb_focus_dir) {
assert(command.argc == 3);
ret.i = wm_string_to_direction(command.argv[command.argc - 1]);
return ret;
}
if (kb.function == &wm_kb_move_dir) {
assert(command.argc == 3);
ret.i = wm_string_to_direction(command.argv[command.argc - 1]);
return ret;
}
if (kb.function == &wm_kb_switch_ws) {
assert(command.argc == 3);
ret.i = atoi(command.argv[command.argc - 1]);
return ret;
}
if (kb.function == &wm_kb_move_client_ws) {
assert(command.argc == 3);
ret.i = atoi(command.argv[command.argc - 1]);
return ret;
}
if (kb.function == &wm_kb_switch_split_mode) {
// TODO
}
assert(false);
}
int wm_string_to_direction(const char *str)
{
int ret;
char lower[CONFIG_ARGLEN_MAX];
strncpy(lower, str, CONFIG_ARGLEN_MAX);
for (char *c = lower; *c; c++) *c = tolower(*c);
ret = strncmp(lower, "right", CONFIG_ARGLEN_MAX);
if (ret == 0) return RIGHT;
ret = strncmp(lower, "left", CONFIG_ARGLEN_MAX);
if (ret == 0) return LEFT;
ret = strncmp(lower, "up", CONFIG_ARGLEN_MAX);
if (ret == 0) return UP;
ret = strncmp(lower, "down", CONFIG_ARGLEN_MAX);
if (ret == 0) return DOWN;
fprintf(stderr, "wm: encountered invalid direction \"%s\"\n. exiting.",
str);
abort();
}
KeybindFunction wm_str_to_keybindfunction(const char* str)
{
DEBUG_PRINT("%s %s\n", __func__, str);
char lower[CONFIG_ARGLEN_MAX];
strncpy(lower, str, CONFIG_ARGLEN_MAX);
for (char *c = lower; *c; c++) *c = tolower(*c);
for (size_t i = 0; i < sizeof(__wm_keybind_commands) / sizeof(__wm_keybind_commands[0]); i++) {
if (strncmp(lower, __wm_keybind_commands[i].command, CONFIG_ARGLEN_MAX) == 0)
return __wm_keybind_commands[i].function;
}
fprintf(stderr, "wm: encountered invalid keybind command \"%s\"\n. exiting.",
str);
abort();
}
unsigned int wm_string_to_mask(const char* str) unsigned int wm_string_to_mask(const char* str)
{ {
int ret; int ret;
@ -504,12 +650,12 @@ unsigned int wm_string_to_mask(const char* str)
ret = strncmp(str, "Super", CONFIG_ARGLEN_MAX); ret = strncmp(str, "Super", CONFIG_ARGLEN_MAX);
if (ret == 0) return Mod4Mask; if (ret == 0) return Mod4Mask;
fprintf(stderr, "wm: encountered invalid modifier token %s\n. exiting.", fprintf(stderr, "wm: encountered invalid modifier token \"%s\"\n. exiting.",
str); str);
abort(); abort();
} }
KeySym* wm_keybind_str_to_mask_keysym(const char* kb_argv) KeySym* wm_keybind_string_to_mask_keysym(const char* kb_argv)
{ {
KeySym *ret = calloc(2, sizeof(KeySym)); KeySym *ret = calloc(2, sizeof(KeySym));
char* str = strdup(kb_argv); char* str = strdup(kb_argv);
@ -531,7 +677,7 @@ KeySym* wm_keybind_str_to_mask_keysym(const char* kb_argv)
token = strtok(NULL, "+"); token = strtok(NULL, "+");
} }
DEBUG_PRINT("str: %s token count: %d\n", kb_argv, token_count); DEBUG_PRINT("str: %s, str[0]: %d, token count: %d\n", kb_argv, kb_argv[0], token_count);
ret[0] = wm_string_to_mask(tokens[0]); ret[0] = wm_string_to_mask(tokens[0]);
@ -541,7 +687,7 @@ KeySym* wm_keybind_str_to_mask_keysym(const char* kb_argv)
KeySym keysym = XStringToKeysym(tokens[token_count - 1]); KeySym keysym = XStringToKeysym(tokens[token_count - 1]);
if (keysym == NoSymbol) { if (keysym == NoSymbol) {
fprintf(stderr, "wm: encountered invalid keybind token %s\n. exiting.", fprintf(stderr, "wm: encountered invalid keybind token \"%s\"\n. exiting.",
tokens[token_count-1]); tokens[token_count-1]);
abort(); abort();
} }
@ -553,8 +699,27 @@ KeySym* wm_keybind_str_to_mask_keysym(const char* kb_argv)
return ret; return ret;
} }
// TODO
Keybind wm_config_parse_bind_command(ConfigCommand *command) Keybind wm_config_parse_bind_command(ConfigCommand *command)
{ {
DEBUG_PRINT("%s\n", __func__);
Keybind ret;
KeySym *keysyms = wm_keybind_string_to_mask_keysym(command->argv[0]);
ret.mask = keysyms[0];
ret.keysym = keysyms[1];
free(keysyms);
ret.function = wm_str_to_keybindfunction(command->argv[1]);
ret.args = wm_keybind_argv_to_args(ret, *command);
return ret;
}
void wm_config_replace_keybind(Config *config, const Keybind *keybind)
{
for (size_t i = 0; i < config->kb_count; i++)
if (config->keybinds[i].function == keybind->function) {
config->keybinds[i] = *keybind;
return;
}
} }

View File

@ -11,6 +11,7 @@
#define CONFIG_PARSERRESULT_MAX 1024 #define CONFIG_PARSERRESULT_MAX 1024
#define CONFIG_ARGC_MAX 16 #define CONFIG_ARGC_MAX 16
#define CONFIG_ARGLEN_MAX 256 #define CONFIG_ARGLEN_MAX 256
#define CONFIG_COLOR_MAX 16
#define PARSER_RETURN(result, _success, fmt, ...) \ #define PARSER_RETURN(result, _success, fmt, ...) \
do { (result).success = (_success); \ do { (result).success = (_success); \
@ -42,6 +43,11 @@ struct Keybind {
Arg args; Arg args;
}; };
typedef struct {
const char command[CONFIG_ARGLEN_MAX];
const KeybindFunction function;
} KeybindFunctionCommand;
typedef enum { typedef enum {
TYPE_INTEGER, TYPE_INTEGER,
TYPE_UNSIGNED_INTEGER, TYPE_UNSIGNED_INTEGER,
@ -64,6 +70,7 @@ typedef struct {
size_t argc; size_t argc;
char **argv; char **argv;
Arg *args; Arg *args;
Keybind keybind;
} ConfigCommand; } ConfigCommand;
typedef struct { typedef struct {
@ -74,8 +81,8 @@ typedef struct {
typedef struct { typedef struct {
float ms_p; float ms_p;
char *border_col; char border_col[CONFIG_COLOR_MAX];
char *focused_border_col; char focused_border_col[CONFIG_COLOR_MAX];
unsigned int border_width; unsigned int border_width;
Keybind *keybinds; Keybind *keybinds;
int kb_count; int kb_count;
@ -85,6 +92,7 @@ typedef struct {
void wm_cfg_init_def(Config *config); void wm_cfg_init_def(Config *config);
void wm_keybinds_init_def(Config *config); void wm_keybinds_init_def(Config *config);
void wm_keybinds_free(Config *config);
void wm_configfile_init(ConfigFile *config, const char *path); void wm_configfile_init(ConfigFile *config, const char *path);
void wm_configfile_free(ConfigFile *config); void wm_configfile_free(ConfigFile *config);
void wm_configfile_read(ConfigFile *cfile, Config *config); void wm_configfile_read(ConfigFile *cfile, Config *config);
@ -97,13 +105,23 @@ void wm_configcommand_argv_parse(ConfigCommand *command);
void wm_configcommand_free(ConfigCommand *command); void wm_configcommand_free(ConfigCommand *command);
bool atobool(char *arr); bool atobool(char *arr);
Arg wm_keybind_argv_to_args(Keybind kb, ConfigCommand command);
int wm_string_to_direction(const char *str);
KeybindFunction wm_string_to_keybindfunction(const char* str);
/* Converts string to Key mask (see X.h:218-228). */ /* Converts string to Key mask (see X.h:218-228). */
unsigned int wm_string_to_mask(const char* str); unsigned int wm_string_to_mask(const char* str);
/* The first element is the mask, the second element is the /* The first element is the mask, the second element is the
* key. The returned array needs to be freed. */ * key. The returned array needs to be freed. */
KeySym* wm_keybind_str_to_mask_keysym(const char* kb_argv); KeySym* wm_keybind_string_to_mask_keysym(const char* kb_argv);
Keybind wm_config_parse_bind_command(ConfigCommand *command); Keybind wm_config_parse_bind_command(ConfigCommand *command);
/* Finds a keybind matching the function of the keybind parameter, and
* replaces it. */
void wm_config_replace_keybind(Config *config, const Keybind *keybind);
#endif // CONFIG_H #endif // CONFIG_H