summaryrefslogtreecommitdiff
path: root/src/input.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/input.c')
-rw-r--r--src/input.c238
1 files changed, 238 insertions, 0 deletions
diff --git a/src/input.c b/src/input.c
index d53e7ed..633145a 100644
--- a/src/input.c
+++ b/src/input.c
@@ -1,7 +1,67 @@
#include <string.h>
#include <engine/input.h>
+#include <engine/dltools.h>
#include <engine/logging.h>
+/* Lazy binds, used internally. They are similar to BindAction and friends.
+ * The only difference is that we set callbacks and such to NULL, but populate
+ * the function name strings such that can be reloaded. */
+#define BindActionLazy(key, altkey, action_str) \
+ (binding_t){\
+ .action = (action_t){.action = {\
+ .type = InputType_action,\
+ .callback = NULL,\
+ .callback_str = strdup( action_str ),\
+ }},\
+ .scancode = key,\
+ .scancode_alt = altkey,\
+ .since_last_activation = 0\
+}
+
+#define BindStateLazy(key, altkey, _activate_str , _deactivate_str) \
+ (binding_t){\
+ .action = (action_t){.state = {\
+ .type = InputType_state,\
+ .activate = NULL,\
+ .deactivate = NULL,\
+ .activate_str = strdup( _activate_str ),\
+ .deactivate_str = strdup( _deactivate_str ),\
+ }},\
+ .scancode = key,\
+ .scancode_alt = altkey,\
+ .since_last_activation = 0\
+}
+
+void binding_t_free(binding_t* b) {
+ switch (b->action.type) {
+ case InputType_error:
+ ERROR("Cannot free binding of type InputType_error");
+ break;
+ case InputType_action:
+ free(b->action.action.callback_str);
+ return;
+
+ case InputType_state:
+ free(b->action.state.activate_str);
+ free(b->action.state.deactivate_str);
+ break;
+
+ case InputType_range:
+ ERROR("Cannot free binding of type InputType_rage");
+ break;
+
+ default:
+ ERROR("Unknown bindings type");
+ break;
+ }
+ exit(EXIT_FAILURE);
+}
+
+void i_ctx_t_free(i_ctx* c) {
+ for (isize i = 0; i < c->len; i++) {
+ binding_t_free(&c->bindings[i]);
+ }
+}
bool binding_action_cmp(binding_t *restrict a, binding_t *restrict b) {
InputType t = a->action.type;
@@ -92,3 +152,181 @@ action_t i_get_action(const i_ctx *restrict ctx, u32 time, scancode_t scancode)
return (action_t){.type = InputType_error};
}
+
+bool state_refresh_input_ctx(void *lib, i_ctx **ctx, usize ctx_len) {
+ if (ctx == NULL) return true;
+ if (ctx_len > 0 && ctx[0] == NULL) return false;
+ if (lib == NULL) return false;
+
+ for (usize c = 0; c < ctx_len; c++) {
+ LOG("ctx[%d]->len = %d", c, ctx[c]->len);
+ for (isize b = 0; b < ctx[c]->len; b++) {
+ switch (ctx[c]->bindings[b].action.type) {
+ case InputType_error:
+ break;
+ case InputType_action:
+ if (strcmp("NULL", ctx[c]->bindings[b].action.action.callback_str) != 0) {
+
+ ctx[c]->bindings[b].action.action.callback =
+ (input_callback_t*)dynamic_library_get_symbol(lib, ctx[c]->bindings[b].action.action.callback_str);
+
+ if (ctx[c]->bindings[b].action.action.callback == NULL) {
+ ERROR("Failed to get binding for %s: %s",
+ ctx[c]->bindings[b].action.action.callback_str,
+ dynamic_library_get_error());
+ return false;
+ }
+ }
+ break;
+ case InputType_state:
+ if (strcmp("NULL", ctx[c]->bindings[b].action.state.activate_str) != 0) {
+
+ ctx[c]->bindings[b].action.state.activate =
+ (input_callback_t*)dynamic_library_get_symbol(lib, ctx[c]->bindings[b].action.state.activate_str);
+
+ if (ctx[c]->bindings[b].action.state.activate == NULL) {
+ ERROR("Failed to get binding for %s: %s",
+ ctx[c]->bindings[b].action.state.activate_str,
+ dynamic_library_get_error());
+ return false;
+ }
+ }
+
+ if (strcmp("NULL", ctx[c]->bindings[b].action.state.deactivate_str) != 0) {
+
+ ctx[c]->bindings[b].action.state.deactivate =
+ (input_callback_t*)dynamic_library_get_symbol(lib, ctx[c]->bindings[b].action.state.deactivate_str);
+
+ if (ctx[c]->bindings[b].action.state.deactivate == NULL) {
+ ERROR("Failed to get binding for %s: %s",
+ ctx[c]->bindings[b].action.state.deactivate_str,
+ dynamic_library_get_error());
+ return false;
+ }
+ }
+ break;
+ case InputType_range:
+ default:
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+/* Make a lazy duplication of a binding. See comments on BindActionLazy and
+ * friends above. */
+i_ctx* i_ctx_dup(i_ctx **ctx, usize ctx_len) {
+ usize num_binds = 0;
+ for (usize c = 0; c < ctx_len; c++) {
+ num_binds += ctx[c]->len;
+ }
+
+ binding_t *bb = calloc(num_binds, sizeof(binding_t));
+ i_ctx *ret = calloc(ctx_len, sizeof(i_ctx));
+
+ usize cumsum = 0;
+ for (usize c = 0; c < ctx_len; c++) {
+ binding_t *b = ctx[c]->bindings;
+ ret[c].len = ctx[c]->len;
+ ret[c].bindings = &bb[cumsum];
+
+ for (isize i = 0; i < ctx[c]->len; i++) {
+ switch (b[i].action.type) {
+ case InputType_error:
+ break;
+ case InputType_action:
+ bb[cumsum] = BindActionLazy(
+ b[i].scancode,
+ b[i].scancode_alt,
+ strdup(b[i].action.action.callback_str));
+ break;
+ case InputType_state:
+ bb[cumsum] = BindStateLazy(
+ b[i].scancode,
+ b[i].scancode_alt,
+ strdup(b[i].action.state.activate_str),
+ strdup(b[i].action.state.deactivate_str));
+ break;
+ case InputType_range:
+ default:
+ break;
+ }
+ cumsum++;
+ }
+ }
+ return ret;
+}
+
+/* Returns a pointer to a binding in c with .action == a.
+ * Returns NULL if not found. */
+binding_t *get_action(i_ctx *c, action_t *a) {
+ for (isize i = 0; i < c->len; i++) {
+ if (c->bindings[i].action.type != a->type) continue;
+
+ switch (c->bindings[i].action) {
+ case InputType_error:
+ return NULL;
+
+ case InputType_action:
+ if (!strcmp(c->bindings[i].action.action.callback_str, a->action.callback_str)) {
+ return &c->bindings[i];
+ }
+ break;
+
+ case InputType_state:
+ if (!strcmp(c->bindings[i].action.state.activate_str, a->state.activate_str)
+ && !strcmp(c->bindings[i].action.state.deactivate_str, a->state.deactivate_str)) {
+ return &c->bindings[i];
+ }
+ break;
+
+ case InputType_range:
+ default:
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+void i_bind_ctx(i_ctx *c, scancode_t s, action_t *a) {
+ binding_t* b = get_action(c, a);
+
+ if (b == NULL) {
+ WARN("Failed to update keybinding");
+ return;
+ }
+
+ b->scancode = s;
+}
+
+void i_bind_ctx_alt(i_ctx *c, scancode_t s, action_t *a) {
+ binding_t* b = get_action(c, a);
+
+ if (b == NULL) {
+ WARN("Failed to update keybinding");
+ return;
+ }
+
+ b->scancode_alt = s;
+}
+
+void i_bind(binding_t *b, scancode_t s) {
+ if (b == NULL) {
+ WARN("Failed to update keybinding");
+ return;
+ }
+
+ b->scancode = s;
+}
+
+void i_bind_alt(binding_t *b, scancode_t s) {
+ if (b == NULL) {
+ WARN("Failed to update keybinding");
+ return;
+ }
+
+ b->scancode_alt = s;
+}