This commit is contained in:
elviosak 2026-06-08 15:08:54 +00:00 committed by GitHub
commit 52cc5e64d6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 155 additions and 4 deletions

View file

@ -45,6 +45,7 @@ bool keybind_the_same(struct keybind *a, struct keybind *b);
bool keybind_contains_keycode(struct keybind *keybind, xkb_keycode_t keycode); bool keybind_contains_keycode(struct keybind *keybind, xkb_keycode_t keycode);
bool keybind_contains_keysym(struct keybind *keybind, xkb_keysym_t keysym); bool keybind_contains_keysym(struct keybind *keybind, xkb_keysym_t keysym);
bool keybind_contains_any_keysym(struct keybind *keybind, const xkb_keysym_t *syms, int nr_syms);
void keybind_update_keycodes(void); void keybind_update_keycodes(void);
#endif /* LABWC_KEYBIND_H */ #endif /* LABWC_KEYBIND_H */

View file

@ -8,6 +8,7 @@
#include <unistd.h> #include <unistd.h>
#include <wlr/types/wlr_cursor.h> #include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_scene.h> #include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "action-prompt-codes.h" #include "action-prompt-codes.h"
#include "common/buf.h" #include "common/buf.h"
@ -18,6 +19,7 @@
#include "common/spawn.h" #include "common/spawn.h"
#include "common/string-helpers.h" #include "common/string-helpers.h"
#include "config/rcxml.h" #include "config/rcxml.h"
#include "config/keybind.h"
#include "cycle.h" #include "cycle.h"
#include "debug.h" #include "debug.h"
#include "input/keyboard.h" #include "input/keyboard.h"
@ -139,6 +141,7 @@ struct action_arg_list {
X(TOGGLE_SHOW_DESKTOP, "ToggleShowDesktop") \ X(TOGGLE_SHOW_DESKTOP, "ToggleShowDesktop") \
X(WARP_CURSOR, "WarpCursor") \ X(WARP_CURSOR, "WarpCursor") \
X(HIDE_CURSOR, "HideCursor") \ X(HIDE_CURSOR, "HideCursor") \
X(SEND_KEY, "SendKey") \
X(DEBUG_TOGGLE_KEY_STATE_INDICATOR, "DebugToggleKeyStateIndicator") X(DEBUG_TOGGLE_KEY_STATE_INDICATOR, "DebugToggleKeyStateIndicator")
/* /*
@ -535,6 +538,12 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char
goto cleanup; goto cleanup;
} }
break; break;
case ACTION_TYPE_SEND_KEY:
if (!strcasecmp(argument, "identifier") || !strcasecmp(argument, "key")) {
action_arg_add_str(action, argument, content);
goto cleanup;
}
break;
case ACTION_TYPE_IF: case ACTION_TYPE_IF:
if (!strcmp(argument, "message.prompt")) { if (!strcmp(argument, "message.prompt")) {
action_arg_add_str(action, "message.prompt", content); action_arg_add_str(action, "message.prompt", content);
@ -652,6 +661,9 @@ action_is_valid(struct action *action)
case ACTION_TYPE_SNAP_TO_REGION: case ACTION_TYPE_SNAP_TO_REGION:
arg_name = "region"; arg_name = "region";
break; break;
case ACTION_TYPE_SEND_KEY:
arg_name = "identifier";
break;
case ACTION_TYPE_IF: case ACTION_TYPE_IF:
case ACTION_TYPE_FOR_EACH: case ACTION_TYPE_FOR_EACH:
return action_branches_are_valid(action); return action_branches_are_valid(action);
@ -1054,6 +1066,141 @@ warp_cursor(struct view *view, const char *to, const char *x, const char *y)
cursor_update_focus(); cursor_update_focus();
} }
static void
action_key_update_keycodes_iter(struct xkb_keymap *keymap, xkb_keycode_t key, void *data)
{
struct keybind *keybind = (struct keybind *)data;
const xkb_keysym_t *syms;
xkb_layout_index_t layouts = xkb_keymap_num_layouts(keymap);
for (xkb_layout_index_t layout = 0; layout < layouts; layout++) {
int nr_syms = xkb_keymap_key_get_syms_by_level(keymap, key, layout, 0, &syms);
if (!nr_syms) {
continue;
}
if (keybind->keycodes_layout >= 0
&& (xkb_layout_index_t)keybind->keycodes_layout != layout) {
/* Prevent storing keycodes from multiple layouts */
continue;
}
if (keybind_contains_any_keysym(keybind, syms, nr_syms)) {
if (keybind_contains_keycode(keybind, key)) {
/* Prevent storing the same keycode twice */
continue;
}
if (keybind->keycodes_len == MAX_KEYCODES) {
wlr_log(WLR_ERROR,
"Already stored %lu keycodes for keybind",
keybind->keycodes_len);
continue;
}
keybind->keycodes[keybind->keycodes_len++] = key;
keybind->keycodes_layout = layout;
}
}
}
static void
action_key_update_keycodes(struct keybind *keybind, struct xkb_keymap *keymap)
{
keybind->keycodes_len = 0;
keybind->keycodes_layout = -1;
xkb_keymap_key_for_each(keymap, action_key_update_keycodes_iter, keybind);
}
static bool
action_key_parse(const char *key, struct wlr_keyboard_modifiers *modifiers,
uint32_t *keycodes, size_t *num_keycodes)
{
struct wlr_keyboard *kb = wlr_seat_get_keyboard(server.seat.wlr_seat);
if (!kb) {
return false;
}
if (!key) {
*modifiers = kb->modifiers;
*num_keycodes = kb->num_keycodes > MAX_KEYCODES ? MAX_KEYCODES : kb->num_keycodes;
for (size_t i = 0; i < *num_keycodes; ++i) {
keycodes[i] = kb->keycodes[i];
}
return true;
}
if (!kb->keymap) {
return false;
}
struct keybind *k = NULL;
k = keybind_create(key);
if (!k) {
return false;
}
action_key_update_keycodes(k, kb->keymap);
modifiers->depressed = k->modifiers;
*num_keycodes = k->keycodes_len;
for (size_t i = 0; i < *num_keycodes; ++i) {
if (k->keycodes[i] < 8) {
keybind_destroy(k);
return false;
}
keycodes[i] = k->keycodes[i] - 8;
}
keybind_destroy(k);
if (modifiers->depressed == 0 && *num_keycodes == 0) {
return false;
}
return true;
}
static void
action_send_key(struct action *action, struct view *view)
{
struct view *target_view;
struct wlr_seat *wlr_seat = server.seat.wlr_seat;
struct wlr_keyboard *kb = wlr_seat_get_keyboard(server.seat.wlr_seat);
if (!kb) {
return;
}
struct timespec now = {0};
clock_gettime(CLOCK_MONOTONIC, &now);
uint64_t time_msec = now.tv_sec * 1000 + now.tv_nsec / 1000000;
const char *identifier = action_get_str(action, "identifier", NULL);
if (!identifier) {
return;
}
uint32_t *sent_keycodes = key_state_pressed_sent_keycodes();
int num_sent_keycodes = key_state_nr_pressed_sent_keycodes();
const char *key = action_get_str(action, "key", NULL);
struct wlr_keyboard_modifiers modifiers = {0};
uint32_t keycodes[MAX_KEYCODES];
size_t num_keycodes = 0;
if (!action_key_parse(key, &modifiers, keycodes, &num_keycodes)) {
wlr_log(WLR_ERROR, "Failed to parse key: %s", key);
return;
}
bool sent = false;
for_each_view(target_view, &server.views, LAB_VIEW_CRITERIA_NONE) {
if (target_view->surface && !strcasecmp(target_view->app_id, identifier)) {
wlr_seat_keyboard_notify_enter(wlr_seat, target_view->surface,
sent_keycodes, num_sent_keycodes, &modifiers);
wlr_seat_keyboard_notify_modifiers(wlr_seat, &modifiers);
for (size_t i = 0; i < num_keycodes; i++) {
wlr_seat_keyboard_notify_key(wlr_seat, (uint32_t)time_msec,
keycodes[i], WL_KEYBOARD_KEY_STATE_PRESSED);
}
for (size_t i = num_keycodes; i > 0; i--) {
wlr_seat_keyboard_notify_key(wlr_seat, (uint32_t)time_msec,
keycodes[i-1], WL_KEYBOARD_KEY_STATE_RELEASED);
}
sent = true;
}
}
if (sent && view && view->surface) {
wlr_seat_keyboard_notify_enter(wlr_seat, view->surface,
sent_keycodes, num_sent_keycodes, &kb->modifiers);
wlr_seat_keyboard_notify_modifiers(wlr_seat, &kb->modifiers);
}
}
static void static void
run_action(struct view *view, struct action *action, run_action(struct view *view, struct action *action,
struct cursor_context *ctx) struct cursor_context *ctx)
@ -1447,6 +1594,9 @@ run_action(struct view *view, struct action *action,
} }
break; break;
} }
case ACTION_TYPE_SEND_KEY:
action_send_key(action, view);
break;
case ACTION_TYPE_IF: { case ACTION_TYPE_IF: {
/* At least one of the queries was matched or there was no query */ /* At least one of the queries was matched or there was no query */
if (action_get_str(action, "message.prompt", NULL)) { if (action_get_str(action, "message.prompt", NULL)) {

View file

@ -7,7 +7,6 @@
#include <string.h> #include <string.h>
#include <wlr/types/wlr_keyboard_group.h> #include <wlr/types/wlr_keyboard_group.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "common/list.h"
#include "common/mem.h" #include "common/mem.h"
#include "config/rcxml.h" #include "config/rcxml.h"
#include "labwc.h" #include "labwc.h"
@ -72,7 +71,7 @@ keybind_contains_keysym(struct keybind *keybind, xkb_keysym_t keysym)
return false; return false;
} }
static bool bool
keybind_contains_any_keysym(struct keybind *keybind, keybind_contains_any_keysym(struct keybind *keybind,
const xkb_keysym_t *syms, int nr_syms) const xkb_keysym_t *syms, int nr_syms)
{ {
@ -205,7 +204,6 @@ keybind_create(const char *keybind)
if (!k) { if (!k) {
return NULL; return NULL;
} }
wl_list_append(&rc.keybinds, &k->link);
k->keysyms = xmalloc(k->keysyms_len * sizeof(xkb_keysym_t)); k->keysyms = xmalloc(k->keysyms_len * sizeof(xkb_keysym_t));
memcpy(k->keysyms, keysyms, k->keysyms_len * sizeof(xkb_keysym_t)); memcpy(k->keysyms, keysyms, k->keysyms_len * sizeof(xkb_keysym_t));
wl_list_init(&k->actions); wl_list_init(&k->actions);

View file

@ -593,6 +593,8 @@ fill_keybind(xmlNode *node)
keybind = keybind_create(keyname); keybind = keybind_create(keyname);
if (!keybind) { if (!keybind) {
wlr_log(WLR_ERROR, "Invalid keybind: %s", keyname); wlr_log(WLR_ERROR, "Invalid keybind: %s", keyname);
} else {
wl_list_append(&rc.keybinds, &keybind->link);
} }
} }
if (!keybind) { if (!keybind) {
@ -1617,7 +1619,7 @@ load_default_key_bindings(void)
if (!k) { if (!k) {
continue; continue;
} }
wl_list_append(&rc.keybinds, &k->link);
action = action_create(current->action); action = action_create(current->action);
wl_list_append(&k->actions, &action->link); wl_list_append(&k->actions, &action->link);