From a2b6ab3e54ecebd2d77437676d3d515ec98c2fd4 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 11 Feb 2026 11:59:08 +0800 Subject: [PATCH] kbl --- src/config/parse_config.h | 134 +++++++++++++++++++++++++++++++++++++ src/ext-protocol/dwl-ipc.h | 10 +-- src/fetch/common.h | 4 +- src/mango.c | 58 +++++++++++++++- 4 files changed, 196 insertions(+), 10 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 556fc352..ea019018 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -111,6 +111,13 @@ typedef struct { int32_t vrr; // variable refresh rate } ConfigMonitorRule; +typedef struct { + const char *name; + int32_t vendor, product; + struct xkb_keymap *keymap; + struct xkb_context *ctx; +} ConfigKeyboardRule; + // 修改后的宏定义 #define CHVT(n) \ { \ @@ -321,6 +328,9 @@ typedef struct { ConfigMonitorRule *monitor_rules; // 动态数组 int32_t monitor_rules_count; // 条数 + ConfigKeyboardRule *keyboard_rules; // 动态数组 + int32_t keyboard_rules_count; // 条数 + KeyBinding *key_bindings; int32_t key_bindings_count; @@ -1840,6 +1850,113 @@ bool parse_option(Config *config, char *key, char *value) { config->monitor_rules_count++; return !parse_error; + } else if (strcmp(key, "keyboardrule") == 0) { + config->keyboard_rules = + realloc(config->keyboard_rules, (config->keyboard_rules_count + 1) * + sizeof(ConfigKeyboardRule)); + if (!config->keyboard_rules) { + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for keyboard rules\n"); + return false; + } + + ConfigKeyboardRule *rule = + &config->keyboard_rules[config->keyboard_rules_count]; + memset(rule, 0, sizeof(ConfigKeyboardRule)); + + // 设置默认值 + rule->vendor = -1; + rule->product = -1; + rule->keymap = NULL; + + char rule_xkb_rules_rules[256]; + char rule_xkb_rules_model[256]; + char rule_xkb_rules_layout[256]; + char rule_xkb_rules_variant[256]; + char rule_xkb_rules_options[256]; + + strcpy(rule_xkb_rules_rules, xkb_rules_rules); + strcpy(rule_xkb_rules_model, xkb_rules_model); + strcpy(rule_xkb_rules_layout, xkb_rules_layout); + strcpy(rule_xkb_rules_variant, xkb_rules_variant); + strcpy(rule_xkb_rules_options, xkb_rules_options); + + bool parse_error = false; + char *token = strtok(value, ","); + while (token != NULL) { + char *colon = strchr(token, ':'); + if (colon != NULL) { + *colon = '\0'; + char *key = token; + char *val = colon + 1; + + trim_whitespace(key); + trim_whitespace(val); + + if (strcmp(key, "vendor") == 0) { + rule->vendor = atoi(val); + } else if (strcmp(key, "product") == 0) { + rule->product = atoi(val); + } else if (strcmp(key, "name") == 0) { + rule->name = strdup(val); + } else if (strcmp(key, "xkb_rules_rules") == 0) { + strcpy(rule_xkb_rules_rules, val); + rule_xkb_rules_rules[sizeof(rule_xkb_rules_rules) - 1] = + '\0'; // 确保字符串以 null 结尾 + } else if (strcmp(key, "xkb_rules_model") == 0) { + strcpy(rule_xkb_rules_model, val); + rule_xkb_rules_model[sizeof(rule_xkb_rules_model) - 1] = + '\0'; // 确保字符串以 null 结尾 + } else if (strcmp(key, "xkb_rules_layout") == 0) { + strcpy(rule_xkb_rules_layout, val); + rule_xkb_rules_layout[sizeof(rule_xkb_rules_layout) - 1] = + '\0'; // 确保字符串以 null 结尾 + } else if (strcmp(key, "xkb_rules_variant") == 0) { + strcpy(rule_xkb_rules_variant, val); + rule_xkb_rules_variant[sizeof(rule_xkb_rules_variant) - 1] = + '\0'; // 确保字符串以 null 结尾 + } else if (strcmp(key, "xkb_rules_options") == 0) { + strcpy(rule_xkb_rules_options, val); + rule_xkb_rules_options[sizeof(rule_xkb_rules_options) - 1] = + '\0'; // 确保字符串以 null 结尾 + } else { + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown " + "keyboard rule " + "option:\033[1m\033[31m %s\n", + key); + parse_error = true; + } + } + token = strtok(NULL, ","); + } + + struct xkb_rule_names rule_xkb_rules = { + .rules = (rule_xkb_rules_rules[0] == '\0') ? NULL : rule_xkb_rules_rules, + .model = (rule_xkb_rules_model[0] == '\0') ? NULL : rule_xkb_rules_model, + .layout = (rule_xkb_rules_layout[0] == '\0') ? NULL : rule_xkb_rules_layout, + .variant = (rule_xkb_rules_variant[0] == '\0') ? NULL : rule_xkb_rules_variant, + .options = (rule_xkb_rules_options[0] == '\0') ? NULL : rule_xkb_rules_options, + }; + + rule->ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + rule->keymap = xkb_keymap_new_from_names(rule->ctx, &rule_xkb_rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + +// 添加调试信息 +fprintf(stderr, "\033[1m\033[32m[DEBUG]:\033[0m Created keymap: %p\n", (void*)rule->keymap); +if (rule->keymap) { + fprintf(stderr, " Keymap created successfully.\n"); +} else { + fprintf(stderr, " Failed to create keymap.\n"); + // 可以尝试获取更多错误信息 + // xkb_context_get_log_string(rule->ctx) 可能会提供错误信息 +} + + + config->keyboard_rules_count++; + return !parse_error; } else if (strcmp(key, "tagrule") == 0) { config->tag_rules = realloc(config->tag_rules, @@ -2976,6 +3093,21 @@ void free_config(void) { config.monitor_rules_count = 0; } + // 释放 keyboard_rules + if (config.keyboard_rules) { + for (int32_t i = 0; i < config.keyboard_rules_count; i++) { + if (config.keyboard_rules[i].name) + free((void *)config.keyboard_rules[i].name); + if (config.keyboard_rules[i].ctx) + xkb_context_unref(config.keyboard_rules[i].ctx); + if (config.keyboard_rules[i].keymap) + xkb_keymap_unref(config.keyboard_rules[i].keymap); + } + free(config.keyboard_rules); + config.keyboard_rules = NULL; + config.keyboard_rules_count = 0; + } + // 释放 layer_rules if (config.layer_rules) { for (int32_t i = 0; i < config.layer_rules_count; i++) { @@ -3443,6 +3575,8 @@ bool parse_config(void) { config.window_rules_count = 0; config.monitor_rules = NULL; config.monitor_rules_count = 0; + config.keyboard_rules = NULL; + config.keyboard_rules_count = 0; config.key_bindings = NULL; config.key_bindings_count = 0; config.mouse_bindings = NULL; diff --git a/src/ext-protocol/dwl-ipc.h b/src/ext-protocol/dwl-ipc.h index 90e6dd6b..07267ebf 100644 --- a/src/ext-protocol/dwl-ipc.h +++ b/src/ext-protocol/dwl-ipc.h @@ -150,20 +150,20 @@ void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output) { } active_kb = get_active_keyboard_device(); - if(active_kb) { - sprintf(active_kb_name, "vendor:%d,product:%d,name:%s", active_kb->vendor, active_kb->product, active_kb->name); + if (active_kb) { + sprintf(active_kb_name, "vendor:%d,product:%d,name:%s", + active_kb->vendor, active_kb->product, active_kb->name); } else { sprintf(active_kb_name, "-1 -1 unknown"); } - - keyboard = active_kb ? (struct wlr_keyboard*)active_kb->device_data: &kb_group->wlr_group->keyboard; + keyboard = active_kb ? (struct wlr_keyboard *)active_kb->device_data + : &kb_group->wlr_group->keyboard; current = xkb_state_serialize_layout(keyboard->xkb_state, XKB_STATE_LAYOUT_EFFECTIVE); get_layout_abbr(kb_layout, xkb_keymap_layout_get_name(keyboard->keymap, current)); - zdwl_ipc_output_v2_send_layout( ipc_output->resource, monitor->pertag->ltidxs[monitor->pertag->curtag] - layouts); diff --git a/src/fetch/common.h b/src/fetch/common.h index 087bdd7f..2a67ba5f 100644 --- a/src/fetch/common.h +++ b/src/fetch/common.h @@ -129,13 +129,13 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, *pl = l; } -InputDevice * get_active_keyboard_device(void) { +InputDevice *get_active_keyboard_device(void) { InputDevice *id; wl_list_for_each(id, &inputdevices, link) { if (id->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) { continue; } - + if (id->isactivate) { return id; } diff --git a/src/mango.c b/src/mango.c index 9361a74d..630ab201 100644 --- a/src/mango.c +++ b/src/mango.c @@ -786,7 +786,9 @@ static Client *get_scroll_stack_head(Client *c); static bool client_only_in_one_tag(Client *c); static Client *get_focused_stack_client(Client *sc); static bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc); -static InputDevice * get_active_keyboard_device(void); +static InputDevice *get_active_keyboard_device(void); +static bool apply_keyboard_rules(InputDevice *id, + struct wlr_keyboard *keyboard); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -2560,9 +2562,52 @@ void createidleinhibitor(struct wl_listener *listener, void *data) { checkidleinhibitor(NULL); } +bool apply_keyboard_rules(InputDevice *id, struct wlr_keyboard *keyboard) { + int ji = 0; + ConfigKeyboardRule *r; + bool match_rule = true; + + if (id->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) { + return false; + } + + for (ji = 0; ji < config.keyboard_rules_count; ji++) { + if (config.keyboard_rules_count < 1) + break; + + r = &config.keyboard_rules[ji]; + + if (r->vendor != -1) { + if (r->vendor != id->vendor) { + match_rule = false; + } + } + + if (r->product != -1) { + if (r->product != id->product) { + match_rule = false; + } + } + + if (r->name != NULL) { + if (strcmp(r->name, id->name) != 0) { + match_rule = false; + } + } + + if (match_rule) { + wlr_keyboard_set_keymap(keyboard, r->keymap); + return true; + } + } + + return false; +} + void createkeyboard(struct wlr_keyboard *keyboard) { struct libinput_device *device = NULL; + bool hit_rule = false; if (wlr_input_device_is_libinput(&keyboard->base) && (device = wlr_libinput_get_device_handle(&keyboard->base))) { @@ -2592,10 +2637,13 @@ void createkeyboard(struct wlr_keyboard *keyboard) { wl_signal_add(&keyboard->events.key, &input_dev->source_keyboard_key); wl_list_insert(&inputdevices, &input_dev->link); + + hit_rule = apply_keyboard_rules(input_dev, keyboard); } /* Set the keymap to match the group keymap */ - wlr_keyboard_set_keymap(keyboard, kb_group->wlr_group->keyboard.keymap); + if (!hit_rule) + wlr_keyboard_set_keymap(keyboard, kb_group->wlr_group->keyboard.keymap); wlr_keyboard_notify_modifiers(keyboard, 0, 0, locked_mods, 0); @@ -5084,7 +5132,11 @@ void reset_keyboard_layout(void) { struct wlr_keyboard *tkb = (struct wlr_keyboard *)id->device_data; - wlr_keyboard_set_keymap(tkb, keyboard->keymap); + bool hit_rules = apply_keyboard_rules(id, tkb); + + if (!hit_rules) + wlr_keyboard_set_keymap(tkb, keyboard->keymap); + wlr_keyboard_notify_modifiers(tkb, depressed, latched, locked, 0); tkb->modifiers.group = 0;