diff --git a/README.md b/README.md index df722f6..19916dd 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ See below for more features. - height : type-num(0-9999) - isterm : type-num(0 or 1) it will be swallowed by the sub window - noswallow: type-num(0 or 1) don't swallow the isterm window +- globalkeybinding: type-string(for example-- alt-l or alt+super-l) # some special feature - hycov like overview diff --git a/config.conf b/config.conf index fcba18b..7a3cf3a 100644 --- a/config.conf +++ b/config.conf @@ -103,6 +103,7 @@ tags=id:9,layout_name:tile # height : type-num(0-9999) # isterm : type-num (0 or 1) -- when new window open, will replace it, and will restore after the sub window exit # nnoswallow : type-num(0 or 1) -- if enable, this window wll not replace isterm window when it was open by isterm window +# globalkeybinding: type-string(for example-- alt-l or alt+super-l) # example # windowrule=isfloating:1,appid:yesplaymusic @@ -113,6 +114,9 @@ tags=id:9,layout_name:tile # windowrule=isfloating:1,appid:wofi # windowrule=isnoborder:1,appid:wofi # windowrule=animation_type_open:zoom,appid:wofi +# windowrule=globalkeybinding:ctrl+alt-o,appid:com.obsproject.Studio +# windowrule=globalkeybinding:ctrl+alt-n,appid:com.obsproject.Studio + # open in specific tag # windowrule=tags:4,appid:Google-chrome diff --git a/maomao.c b/maomao.c index 5b068f3..dcc0e05 100644 --- a/maomao.c +++ b/maomao.c @@ -457,6 +457,7 @@ static void inputdevice(struct wl_listener *listener, void *data); static int keybinding(uint32_t mods, xkb_keysym_t sym); static void keypress(struct wl_listener *listener, void *data); static void keypressmod(struct wl_listener *listener, void *data); +static bool keypressglobal(struct wlr_surface *last_surface, struct wlr_keyboard *keyboard, struct wlr_keyboard_key_event *event, uint32_t mods, xkb_keysym_t keysym); static void locksession(struct wl_listener *listener, void *data); static void maplayersurfacenotify(struct wl_listener *listener, void *data); static void mapnotify(struct wl_listener *listener, void *data); @@ -3285,6 +3286,62 @@ keybinding(uint32_t mods, xkb_keysym_t sym) { return handled; } +bool +keypressglobal(struct wlr_surface *last_surface, struct wlr_keyboard *keyboard, struct wlr_keyboard_key_event *event, uint32_t mods, xkb_keysym_t keysym) +{ + Client *c = NULL, *lastc = focustop(selmon); + uint32_t keycodes[32] = {0}; + int reset = false; + const char *appid = NULL; + const char *title = NULL; + int appid_len,title_len,ji; + const ConfigWinRule *r; + + for (ji = 0; ji < config.window_rules_count; ji++) { + if (config.window_rules_count < 1) + break; + r = &config.window_rules[ji]; + + if(!r->globalkeybinding.mod || !r->globalkeybinding.keysym ) + continue; + + + /* match key only (case insensitive) ignoring mods */ + if (r->globalkeybinding.keysym == keysym && r->globalkeybinding.mod == mods) { + wl_list_for_each(c, &clients, link) { + if (c && c != lastc) { + appid = client_get_appid(c); + title = client_get_title(c); + if (appid && r->id) { + appid_len = strlen(appid); + if(strncmp(appid, r->id, appid_len) == 0) { + reset = true; + wlr_seat_keyboard_enter(seat, client_surface(c), keycodes, 0, &keyboard->modifiers); + wlr_seat_keyboard_send_key(seat, event->time_msec, event->keycode, event->state); + goto done; + } + } + + if (title && r->title) { + title_len = strlen(title); + if(strncmp(title, r->title, title_len) == 0) { + reset = true; + wlr_seat_keyboard_enter(seat, client_surface(c), keycodes, 0, &keyboard->modifiers); + wlr_seat_keyboard_send_key(seat, event->time_msec, event->keycode, event->state); + goto done; + } + } + } + } + } + } + +done: + if (reset) + wlr_seat_keyboard_enter(seat, last_surface, keycodes, 0, &keyboard->modifiers); + return reset; +} + void // 17 keypress(struct wl_listener *listener, void *data) { int i; @@ -3292,6 +3349,14 @@ keypress(struct wl_listener *listener, void *data) { Keyboard *kb = wl_container_of(listener, kb, key); struct wlr_keyboard_key_event *event = data; + struct wlr_surface *last_surface = seat->keyboard_state.focused_surface; + struct wlr_xdg_surface *xdg_surface = last_surface ? wlr_xdg_surface_try_from_wlr_surface(last_surface) : NULL; + int pass = 0; + bool hit_global = false; +#ifdef XWAYLAND + struct wlr_xwayland_surface *xsurface = last_surface ? wlr_xwayland_surface_try_from_wlr_surface(last_surface) : NULL; +#endif + /* Translate libinput keycode -> xkbcommon */ uint32_t keycode = event->keycode + 8; /* Get a list of keysyms based on the keymap for this keyboard */ @@ -3344,6 +3409,21 @@ keypress(struct wl_listener *listener, void *data) { if (handled) return; + /* don't pass when popup is focused + * this is better than having popups (like fuzzel or wmenu) closing while typing in a passed keybind */ + pass = (xdg_surface && xdg_surface->role != WLR_XDG_SURFACE_ROLE_POPUP) || !last_surface +#ifdef XWAYLAND + || xsurface +#endif + ; + /* passed keys don't get repeated */ + if (pass && syms) + hit_global = keypressglobal(last_surface, kb->wlr_keyboard, event, mods, syms[0]); + + if(hit_global) { + return; + } + #ifdef IM /* if there is a keyboard grab, we send the key there */ struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(kb); diff --git a/parse_config.h b/parse_config.h index 8d0850a..2541765 100644 --- a/parse_config.h +++ b/parse_config.h @@ -7,6 +7,13 @@ #define SYSCONFDIR "/etc" #endif +typedef struct { + uint32_t mod; + xkb_keysym_t keysym; + void (*func)(const Arg *); + Arg arg; +} KeyBinding; + typedef struct { const char *id; const char *title; @@ -22,6 +29,9 @@ typedef struct { int height; int isterm; int noswallow; + uint32_t passmod; + xkb_keysym_t keysym; + KeyBinding globalkeybinding; } ConfigWinRule; typedef struct { @@ -36,13 +46,6 @@ typedef struct { int noswallow; } ConfigMonitorRule; -typedef struct { - uint32_t mod; - xkb_keysym_t keysym; - void (*func)(const Arg *); - Arg arg; -} KeyBinding; - // 定义一个宏来简化默认按键绑定的添加 #define CHVT(n) \ { \ @@ -802,6 +805,7 @@ void parse_config_line(Config *config, const char *line) { rule->id = NULL; rule->title = NULL; rule->tags = 0; + rule->globalkeybinding = (KeyBinding){0}; char *token = strtok(value, ","); while (token != NULL) { @@ -839,6 +843,11 @@ void parse_config_line(Config *config, const char *line) { rule->scroller_proportion = atof(val); } else if (strcmp(key, "isfullscreen") == 0) { rule->isfullscreen = atoi(val); + } else if (strcmp(key, "globalkeybinding") == 0) { + char mod_str[256], keysym_str[256]; + sscanf(val, "%[^-]-%[a-zA-Z]", mod_str, keysym_str); + rule->globalkeybinding.mod = parse_mod(mod_str); + rule->globalkeybinding.keysym = parse_keysym(keysym_str); } } token = strtok(NULL, ",");