diff --git a/src/backend/x11/backend.c b/src/backend/x11/backend.c index a9b81b1..926b82d 100644 --- a/src/backend/x11/backend.c +++ b/src/backend/x11/backend.c @@ -185,6 +185,9 @@ void backend_destroy(backend_t *backend) { p_delete(&backend->kill.windows); p_clear(&backend->kill, 1); + xcb_key_symbols_free(backend->key_symbols); + backend->key_symbols = nullptr; + xcb_disconnect(backend->conn); backend->conn = nullptr; free(backend); diff --git a/src/backend/x11/event.c b/src/backend/x11/event.c index 1d9fbde..b50333c 100644 --- a/src/backend/x11/event.c +++ b/src/backend/x11/event.c @@ -5,9 +5,11 @@ #include #include #include +#include #include #include "backend/x11/window.h" +#include "base/macros.h" #include "base/memory.h" #include "core/backend.h" #include "core/types.h" @@ -198,6 +200,47 @@ static bool handle_configure_request( return true; } +static modifier_mask_t get_modifiers(uint16_t mask) { + typedef struct modifier_map_t { + modifier_bit_t modifier; + xcb_mod_mask_t mask; + } modifier_map_t; + static constexpr modifier_map_t modifier_map[] = { + {ZDWM_MOD_SHIFT, XCB_MOD_MASK_SHIFT}, + {ZDWM_MOD_CONTROL, XCB_MOD_MASK_CONTROL}, + {ZDWM_MOD_1, XCB_MOD_MASK_1}, + {ZDWM_MOD_2, XCB_MOD_MASK_2}, + {ZDWM_MOD_3, XCB_MOD_MASK_3}, + {ZDWM_MOD_4, XCB_MOD_MASK_4}, + {ZDWM_MOD_5, XCB_MOD_MASK_5}, + }; + + auto mods = ZDWM_MOD_NONE; + for (size_t i = 0; i < countof(modifier_map); ++i) { + auto item = &modifier_map[i]; + if (mask & item->mask) mods |= item->modifier; + } + return mods; +} + +static bool handle_key_press( + backend_t *backend, + event_t *event, + const xcb_key_press_event_t *xcb_event +) { + auto keycode = xcb_event->detail; + + /* keysym without any modifiers */ + auto keysym = xcb_key_symbols_get_keysym(backend->key_symbols, keycode, 0); + + event->type = ZDWM_EVENT_KEY_PRESS; + event->as.key_press.keycode = keycode; + event->as.key_press.keysym = keysym; + event->as.key_press.modifiers = get_modifiers(xcb_event->state); + + return true; +} + bool backend_next_event(backend_t *backend, event_t *event) { if (!backend || !backend->conn || !event) return false; @@ -221,6 +264,7 @@ bool backend_next_event(backend_t *backend, event_t *event) { EVENT(XCB_UNMAP_NOTIFY, handle_unmap_notify); EVENT(XCB_DESTROY_NOTIFY, handle_destroy_notify); EVENT(XCB_CONFIGURE_REQUEST, handle_configure_request); + EVENT(XCB_KEY_PRESS, handle_key_press); #undef EVENT diff --git a/src/backend/x11/window.h b/src/backend/x11/window.h index 43e463e..95451db 100644 --- a/src/backend/x11/window.h +++ b/src/backend/x11/window.h @@ -7,7 +7,6 @@ #include #include "core/backend.h" -#include "core/plan.h" #include "internal.h" typedef struct atoms_t atoms_t; diff --git a/src/config/defaults.c b/src/config/defaults.c index d7449c0..3313456 100644 --- a/src/config/defaults.c +++ b/src/config/defaults.c @@ -58,9 +58,6 @@ bool config_defaults_build( auto default_mode = api->add_mode(builder, "default"); - zdwm_action_arg_t launcher_arg = {.str = launcher}; - api->bind(builder, default_mode, "Mod4+r", spawn, &launcher_arg); - #define BIND(mode, key, fn, arg) \ api->bind(builder, mode, key, fn, &(zdwm_action_arg_t)arg) diff --git a/src/core/binding.c b/src/core/binding.c index 5813e53..d472944 100644 --- a/src/core/binding.c +++ b/src/core/binding.c @@ -14,14 +14,6 @@ #include "base/memory.h" #include "core/types.h" -typedef struct key_binding_t { - const char *key_str; - modifier_mask_t modifiers; - xkb_keysym_t keysym; - zdwm_action_fn *fn; - zdwm_action_arg_t *arg; -} key_binding_t; - typedef struct binding_mode_t { zdwm_binding_mode_id_t id; const char *name; @@ -271,3 +263,12 @@ bool binding_table_cycle_mode(binding_table_t *table, int delta) { return true; } + +const key_binding_t * +binding_table_get_current_bindings(binding_table_t *table, size_t *count) { + auto mode = binding_table_get_mode(table, table->current_mode); + if (!mode || !mode->count) return nullptr; + + *count = mode->count; + return mode->items; +} diff --git a/src/core/binding.h b/src/core/binding.h index 277ed30..91be9fd 100644 --- a/src/core/binding.h +++ b/src/core/binding.h @@ -1,10 +1,21 @@ #pragma once +#include #include #include +#include "core/types.h" + typedef struct binding_table_t binding_table_t; +typedef struct key_binding_t { + const char *key_str; + modifier_mask_t modifiers; + keysym_t keysym; + zdwm_action_fn *fn; + zdwm_action_arg_t *arg; +} key_binding_t; + /** * @brief 添加新的模式 * @@ -84,3 +95,18 @@ bool binding_table_set_current_mode( * @return 无法切换返回 false 否则返回 true */ bool binding_table_cycle_mode(binding_table_t *table, int delta); + +/** + * @brief 获取当前按键绑定列表 + * + * @param table 按键绑定表 + * @param count 保存按键个数的指针 + * + * @return 返回当前按键列表的头指针,调用方仅只读访问,不持有对应的内存。 + * + * @notice + * 1. count 指针不能为 nullptr ,若 count 传 nullptr 视为调用方错误 + * 2. 调用方需判断返回的指针是否为 nullptr + */ +const key_binding_t * +binding_table_get_current_bindings(binding_table_t *table, size_t *count); diff --git a/src/core/plan.h b/src/core/plan.h index cb9fcf0..122cb4b 100644 --- a/src/core/plan.h +++ b/src/core/plan.h @@ -49,11 +49,6 @@ typedef struct effect_window_list_t { size_t count; } effect_window_list_t; -typedef struct key_bind_t { - modifier_mask_t modifiers; - keysym_t keysym; -} key_bind_t; - typedef struct effect_bind_key_t { const key_bind_t *keys; size_t count; diff --git a/src/core/policy.c b/src/core/policy.c index 87a46e0..8cc50f0 100644 --- a/src/core/policy.c +++ b/src/core/policy.c @@ -4,6 +4,7 @@ #include #include "base/macros.h" +#include "core/binding.h" #include "core/command.h" #include "core/command_buffer.h" #include "core/event.h" @@ -14,6 +15,23 @@ #include "core/window.h" #include "core/wm_desc.h" +static void route_key_press( + binding_table_t *binding_table, + const zdwm_action_ctx_t *action_ctx, + const key_press_event_t *e +) { + size_t count = 0; + auto bindings = binding_table_get_current_bindings(binding_table, &count); + if (!bindings) return; + + for (size_t i = 0; i < count; ++i) { + auto binding = &bindings[i]; + if (binding->modifiers == e->modifiers && binding->keysym == e->keysym) { + binding->fn(action_ctx, binding->arg); + } + } +} + static workspace_id_t derive_window_workspace(const state_t *state) { return state->outputs[state->current_output_index].current_workspace_id; } @@ -115,6 +133,9 @@ void policy_route_event( ) { auto state = ctx->state; switch (event->type) { + case ZDWM_EVENT_KEY_PRESS: + route_key_press(ctx->bind_table, &ctx->action_ctx, &event->as.key_press); + break; case ZDWM_EVENT_WINDOW_MAP_REQUEST: route_map_request(state, ctx->rules, &event->as.window_map_request, out); break; diff --git a/src/core/policy.h b/src/core/policy.h index 26d6a10..6c9e82b 100644 --- a/src/core/policy.h +++ b/src/core/policy.h @@ -1,6 +1,8 @@ #pragma once #include + +#include "core/binding.h" #include "core/command_buffer.h" #include "core/event.h" #include "core/plan.h" @@ -8,6 +10,7 @@ #include "core/state.h" typedef struct policy_context_t { + binding_table_t *bind_table; state_t *state; const rules_t *rules; const zdwm_action_ctx_t action_ctx; diff --git a/src/core/runtime.c b/src/core/runtime.c index 7f56906..e3f6908 100644 --- a/src/core/runtime.c +++ b/src/core/runtime.c @@ -1,6 +1,7 @@ #include "core/runtime.h" #include +#include #include "action.h" #include "base/memory.h" @@ -13,6 +14,7 @@ #include "core/policy.h" #include "core/rules.h" #include "core/state.h" +#include "core/types.h" #include "core/wm_desc.h" static bool runtime_workspace_desc_has_valid_layouts( @@ -112,6 +114,32 @@ void runtime_shutdown(runtime_t *runtime) { runtime->config_module_handle = nullptr; } +void runtime_setup(runtime_t *runtime) { + size_t bind_count = 0; + auto bindings = + binding_table_get_current_bindings(runtime->binding_table, &bind_count); + if (!bindings) return; + + auto backend = runtime->backend; + auto plan = &runtime->plan; + + plan_reset(plan); + + auto keys = p_new(key_bind_t, bind_count); + for (size_t i = 0; i < bind_count; ++i) { + keys[i].keysym = bindings[i].keysym; + keys[i].modifiers = bindings[i].modifiers; + } + effect_t effect_bind_key = { + .type = ZDWM_EFFECT_BIND_KEY, + .as.bind_key = {.count = bind_count, .keys = keys}, + }; + plan_push_effect(plan, &effect_bind_key); + + backend_apply_effect(backend, plan->effects, plan->count); + plan_reset(plan); +} + void runtime_run(runtime_t *runtime) { runtime->running = true; @@ -120,6 +148,7 @@ void runtime_run(runtime_t *runtime) { plan_t *plan = &runtime->plan; policy_context_t ctx = { + .bind_table = runtime->binding_table, .state = &runtime->state, .rules = &runtime->rules, .action_ctx = { diff --git a/src/core/runtime.h b/src/core/runtime.h index 2bfeae0..a5799f8 100644 --- a/src/core/runtime.h +++ b/src/core/runtime.h @@ -40,4 +40,5 @@ typedef struct runtime_t { bool runtime_init(runtime_t *runtime, runtime_init_desc_t *desc); void runtime_init_desc_cleanup(runtime_init_desc_t *desc); void runtime_shutdown(runtime_t *runtime); +void runtime_setup(runtime_t *runtime); void runtime_run(runtime_t *runtime); diff --git a/src/core/types.h b/src/core/types.h index 4a80689..9a89402 100644 --- a/src/core/types.h +++ b/src/core/types.h @@ -62,3 +62,8 @@ typedef enum modifier_bit_t { ZDWM_MOD_4 = 1u << 5, ZDWM_MOD_5 = 1u << 6, } modifier_bit_t; + +typedef struct key_bind_t { + modifier_mask_t modifiers; + keysym_t keysym; +} key_bind_t; diff --git a/tests/core/main.c b/tests/core/main.c index 6e0866f..dfc5074 100644 --- a/tests/core/main.c +++ b/tests/core/main.c @@ -36,6 +36,7 @@ int main(void) { runtime_t runtime = {0}; bootstrap(&runtime); + runtime_setup(&runtime); runtime_run(&runtime); runtime_shutdown(&runtime);