This commit is contained in:
Reza 2026-07-05 01:56:41 +00:00 committed by GitHub
commit 3734d5f54b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 142 additions and 2 deletions

View file

@ -83,6 +83,10 @@ repeat_delay=600
numlockon=0
xkb_rules_layout=us
# per-device keyboard rules: override xkb layout for specific keyboards
# keyboardrule=name:ErgoDox EZ,xkb_layout:us,xkb_variant:colemak
# keyboardrule=name:Keychron,xkb_rules:evdev,xkb_layout:us,xkb_variant:dvorak
# Trackpad
# need relogin to make it apply
disable_trackpad=0

View file

@ -68,6 +68,7 @@ c_args = [
'-g',
'-Wno-unused-function',
'-DWLR_USE_UNSTABLE',
'-D_GNU_SOURCE',
'-D_POSIX_C_SOURCE=200809L',
'-DVERSION="@0@"'.format(version_with_hash),
'-DSYSCONFDIR="@0@"'.format('/etc'),

View file

@ -180,6 +180,15 @@ typedef struct {
int32_t noanim;
} ConfigLayerRule;
typedef struct {
char *name;
char *xkb_rules;
char *xkb_model;
char *xkb_layout;
char *xkb_variant;
char *xkb_options;
} ConfigKeyboardRule;
typedef struct {
int32_t animations;
int32_t layer_animations;
@ -334,6 +343,9 @@ typedef struct {
ConfigLayerRule *layer_rules; // 动态数组
int32_t layer_rules_count; // 数量
ConfigKeyboardRule *keyboard_rules;
int32_t keyboard_rules_count;
ConfigWinRule *window_rules;
int32_t window_rules_count;
@ -400,6 +412,18 @@ bool apply_rule_to_state(Monitor *m, const ConfigMonitorRule *rule,
struct wlr_output_state *state, int vrr, int custom);
bool monitor_matches_rule(Monitor *m, const ConfigMonitorRule *rule);
// Find matching keyboard rule by device name (substring match, case-insensitive)
static inline ConfigKeyboardRule *find_keyboard_rule(Config *cfg, const char *device_name) {
if (!device_name || !cfg->keyboard_rules)
return NULL;
for (int32_t i = 0; i < cfg->keyboard_rules_count; i++) {
if (cfg->keyboard_rules[i].name &&
strcasestr(device_name, cfg->keyboard_rules[i].name))
return &cfg->keyboard_rules[i];
}
return NULL;
}
// Helper function to trim whitespace from start and end of a string
void trim_whitespace(char *str) {
if (str == NULL || *str == '\0')
@ -2240,6 +2264,67 @@ bool parse_option(Config *config, char *key, char *value) {
config->layer_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));
char *saveptr;
char *param = strtok_r(value, ",", &saveptr);
bool parse_error = false;
while (param != NULL) {
trim_whitespace(param);
char *eq = strchr(param, ':');
if (eq != NULL) {
*eq = '\0';
char *sub_key = param;
char *sub_value = eq + 1;
trim_whitespace(sub_key);
trim_whitespace(sub_value);
if (strcmp(sub_key, "name") == 0) {
rule->name = strdup(sub_value);
} else if (strcmp(sub_key, "xkb_rules") == 0) {
rule->xkb_rules = strdup(sub_value);
} else if (strcmp(sub_key, "xkb_model") == 0) {
rule->xkb_model = strdup(sub_value);
} else if (strcmp(sub_key, "xkb_layout") == 0) {
rule->xkb_layout = strdup(sub_value);
} else if (strcmp(sub_key, "xkb_variant") == 0) {
rule->xkb_variant = strdup(sub_value);
} else if (strcmp(sub_key, "xkb_options") == 0) {
rule->xkb_options = strdup(sub_value);
} else {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Unknown keyboardrule "
"parameter: %s\n", sub_key);
}
*eq = ':';
} else {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Malformed keyboardrule "
"parameter: %s\n", param);
parse_error = true;
}
param = strtok_r(NULL, ",", &saveptr);
}
if (rule->name == NULL) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m keyboardrule requires name\n");
parse_error = true;
}
config->keyboard_rules_count++;
return !parse_error;
} else if (strcmp(key, "windowrule") == 0) {
config->window_rules =
realloc(config->window_rules,
@ -3261,6 +3346,27 @@ void free_config(void) {
config.layer_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].xkb_rules)
free((void *)config.keyboard_rules[i].xkb_rules);
if (config.keyboard_rules[i].xkb_model)
free((void *)config.keyboard_rules[i].xkb_model);
if (config.keyboard_rules[i].xkb_layout)
free((void *)config.keyboard_rules[i].xkb_layout);
if (config.keyboard_rules[i].xkb_variant)
free((void *)config.keyboard_rules[i].xkb_variant);
if (config.keyboard_rules[i].xkb_options)
free((void *)config.keyboard_rules[i].xkb_options);
}
free(config.keyboard_rules);
config.keyboard_rules = NULL;
config.keyboard_rules_count = 0;
}
// 释放 env
if (config.env) {
for (int32_t i = 0; i < config.env_count; i++) {

View file

@ -1041,6 +1041,8 @@ int32_t switch_keyboard_layout(const Arg *arg) {
if (id->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) {
continue;
}
if (id->has_custom_keymap)
continue;
struct wlr_keyboard *tkb = (struct wlr_keyboard *)id->device_data;

View file

@ -274,6 +274,7 @@ typedef struct {
struct libinput_device *libinput_device;
struct wl_listener destroy_listener;
void *device_data;
bool has_custom_keymap;
} InputDevice;
typedef struct {
@ -3043,6 +3044,7 @@ void createidleinhibitor(struct wl_listener *listener, void *data) {
void createkeyboard(struct wlr_keyboard *keyboard) {
struct libinput_device *device = NULL;
bool has_custom = false;
if (wlr_input_device_is_libinput(&keyboard->base) &&
(device = wlr_libinput_get_device_handle(&keyboard->base))) {
@ -3057,8 +3059,31 @@ void createkeyboard(struct wlr_keyboard *keyboard) {
&input_dev->destroy_listener);
wl_list_insert(&inputdevices, &input_dev->link);
ConfigKeyboardRule *rule =
find_keyboard_rule(&config, libinput_device_get_name(device));
if (rule && (rule->xkb_layout || rule->xkb_variant || rule->xkb_options)) {
struct xkb_rule_names rules = {
.rules = rule->xkb_rules ? rule->xkb_rules : config.xkb_rules.rules,
.model = rule->xkb_model ? rule->xkb_model : config.xkb_rules.model,
.layout = rule->xkb_layout,
.variant = rule->xkb_variant,
.options = rule->xkb_options ? rule->xkb_options : config.xkb_rules.options,
};
struct xkb_context *ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
struct xkb_keymap *custom_keymap =
xkb_keymap_new_from_names(ctx, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (custom_keymap) {
wlr_keyboard_set_keymap(keyboard, custom_keymap);
xkb_keymap_unref(custom_keymap);
has_custom = true;
input_dev->has_custom_keymap = true;
}
xkb_context_unref(ctx);
}
}
if (!has_custom)
/* Set the keymap to match the group keymap */
wlr_keyboard_set_keymap(keyboard, kb_group->wlr_group->keyboard.keymap);
@ -5724,6 +5749,8 @@ void reset_keyboard_layout(void) {
if (id->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) {
continue;
}
if (id->has_custom_keymap)
continue;
struct wlr_keyboard *tkb = (struct wlr_keyboard *)id->device_data;