mirror of
https://github.com/DreamMaoMao/maomaowm.git
synced 2026-07-06 00:06:43 -04:00
feat: add per keyboard layouts
This commit is contained in:
parent
ce32e929b9
commit
7b36f7990d
5 changed files with 142 additions and 2 deletions
|
|
@ -83,6 +83,10 @@ repeat_delay=600
|
||||||
numlockon=0
|
numlockon=0
|
||||||
xkb_rules_layout=us
|
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
|
# Trackpad
|
||||||
# need relogin to make it apply
|
# need relogin to make it apply
|
||||||
disable_trackpad=0
|
disable_trackpad=0
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@ c_args = [
|
||||||
'-g',
|
'-g',
|
||||||
'-Wno-unused-function',
|
'-Wno-unused-function',
|
||||||
'-DWLR_USE_UNSTABLE',
|
'-DWLR_USE_UNSTABLE',
|
||||||
|
'-D_GNU_SOURCE',
|
||||||
'-D_POSIX_C_SOURCE=200809L',
|
'-D_POSIX_C_SOURCE=200809L',
|
||||||
'-DVERSION="@0@"'.format(version_with_hash),
|
'-DVERSION="@0@"'.format(version_with_hash),
|
||||||
'-DSYSCONFDIR="@0@"'.format('/etc'),
|
'-DSYSCONFDIR="@0@"'.format('/etc'),
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,15 @@ typedef struct {
|
||||||
int32_t noanim;
|
int32_t noanim;
|
||||||
} ConfigLayerRule;
|
} ConfigLayerRule;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *name;
|
||||||
|
char *xkb_rules;
|
||||||
|
char *xkb_model;
|
||||||
|
char *xkb_layout;
|
||||||
|
char *xkb_variant;
|
||||||
|
char *xkb_options;
|
||||||
|
} ConfigKeyboardRule;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int32_t animations;
|
int32_t animations;
|
||||||
int32_t layer_animations;
|
int32_t layer_animations;
|
||||||
|
|
@ -334,6 +343,9 @@ typedef struct {
|
||||||
ConfigLayerRule *layer_rules; // 动态数组
|
ConfigLayerRule *layer_rules; // 动态数组
|
||||||
int32_t layer_rules_count; // 数量
|
int32_t layer_rules_count; // 数量
|
||||||
|
|
||||||
|
ConfigKeyboardRule *keyboard_rules;
|
||||||
|
int32_t keyboard_rules_count;
|
||||||
|
|
||||||
ConfigWinRule *window_rules;
|
ConfigWinRule *window_rules;
|
||||||
int32_t window_rules_count;
|
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);
|
struct wlr_output_state *state, int vrr, int custom);
|
||||||
bool monitor_matches_rule(Monitor *m, const ConfigMonitorRule *rule);
|
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
|
// Helper function to trim whitespace from start and end of a string
|
||||||
void trim_whitespace(char *str) {
|
void trim_whitespace(char *str) {
|
||||||
if (str == NULL || *str == '\0')
|
if (str == NULL || *str == '\0')
|
||||||
|
|
@ -2240,6 +2264,67 @@ bool parse_option(Config *config, char *key, char *value) {
|
||||||
|
|
||||||
config->layer_rules_count++;
|
config->layer_rules_count++;
|
||||||
return !parse_error;
|
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) {
|
} else if (strcmp(key, "windowrule") == 0) {
|
||||||
config->window_rules =
|
config->window_rules =
|
||||||
realloc(config->window_rules,
|
realloc(config->window_rules,
|
||||||
|
|
@ -3261,6 +3346,27 @@ void free_config(void) {
|
||||||
config.layer_rules_count = 0;
|
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
|
// 释放 env
|
||||||
if (config.env) {
|
if (config.env) {
|
||||||
for (int32_t i = 0; i < config.env_count; i++) {
|
for (int32_t i = 0; i < config.env_count; i++) {
|
||||||
|
|
|
||||||
|
|
@ -1041,6 +1041,8 @@ int32_t switch_keyboard_layout(const Arg *arg) {
|
||||||
if (id->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) {
|
if (id->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (id->has_custom_keymap)
|
||||||
|
continue;
|
||||||
|
|
||||||
struct wlr_keyboard *tkb = (struct wlr_keyboard *)id->device_data;
|
struct wlr_keyboard *tkb = (struct wlr_keyboard *)id->device_data;
|
||||||
|
|
||||||
|
|
|
||||||
27
src/mango.c
27
src/mango.c
|
|
@ -274,6 +274,7 @@ typedef struct {
|
||||||
struct libinput_device *libinput_device;
|
struct libinput_device *libinput_device;
|
||||||
struct wl_listener destroy_listener;
|
struct wl_listener destroy_listener;
|
||||||
void *device_data;
|
void *device_data;
|
||||||
|
bool has_custom_keymap;
|
||||||
} InputDevice;
|
} InputDevice;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -3043,6 +3044,7 @@ void createidleinhibitor(struct wl_listener *listener, void *data) {
|
||||||
void createkeyboard(struct wlr_keyboard *keyboard) {
|
void createkeyboard(struct wlr_keyboard *keyboard) {
|
||||||
|
|
||||||
struct libinput_device *device = NULL;
|
struct libinput_device *device = NULL;
|
||||||
|
bool has_custom = false;
|
||||||
|
|
||||||
if (wlr_input_device_is_libinput(&keyboard->base) &&
|
if (wlr_input_device_is_libinput(&keyboard->base) &&
|
||||||
(device = wlr_libinput_get_device_handle(&keyboard->base))) {
|
(device = wlr_libinput_get_device_handle(&keyboard->base))) {
|
||||||
|
|
@ -3057,8 +3059,31 @@ void createkeyboard(struct wlr_keyboard *keyboard) {
|
||||||
&input_dev->destroy_listener);
|
&input_dev->destroy_listener);
|
||||||
|
|
||||||
wl_list_insert(&inputdevices, &input_dev->link);
|
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 */
|
/* Set the keymap to match the group keymap */
|
||||||
wlr_keyboard_set_keymap(keyboard, kb_group->wlr_group->keyboard.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) {
|
if (id->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (id->has_custom_keymap)
|
||||||
|
continue;
|
||||||
|
|
||||||
struct wlr_keyboard *tkb = (struct wlr_keyboard *)id->device_data;
|
struct wlr_keyboard *tkb = (struct wlr_keyboard *)id->device_data;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue