mirror of
https://github.com/labwc/labwc.git
synced 2026-06-13 14:33:18 -04:00
Merge 13a487fb35 into 579e532908
This commit is contained in:
commit
52cc5e64d6
4 changed files with 155 additions and 4 deletions
|
|
@ -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 */
|
||||||
|
|
|
||||||
150
src/action.c
150
src/action.c
|
|
@ -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)) {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue