feat(backend): 支持鼠标抓取功能

This commit is contained in:
2026-06-20 01:04:00 +08:00
parent 7a47f4d44d
commit b8cd40df9f
12 changed files with 178 additions and 54 deletions

View File

@@ -522,6 +522,22 @@ backend_bind_key(backend_t *backend, const effect_bind_key_t *bind_key) {
window_grab_keys(backend, root, bind_key->keys, bind_key->count);
}
static void backend_grab_button(
backend_t *backend,
const effect_grab_button_t *grab_button
) {
auto conn = backend->conn;
auto window = grab_button->window;
xcb_ungrab_button(conn, XCB_BUTTON_INDEX_ANY, window, XCB_MOD_MASK_ANY);
auto buttons = grab_button->buttons;
for (size_t i = 0; i < grab_button->count; ++i) {
auto button = buttons[i].button;
auto modifiers = buttons[i].modifiers;
window_grab_button(backend, window, button, modifiers);
}
}
static void backend_merge_effects(
backend_t *backend,
const effect_t *effects,
@@ -601,6 +617,8 @@ static void backend_merge_effects(
case ZDWM_EFFECT_BIND_KEY:
backend_bind_key(backend, &e->as.bind_key);
break;
case ZDWM_EFFECT_GRAB_BUTTON:
backend_grab_button(backend, &e->as.grab_button);
}
}
}

71
src/backend/x11/common.c Normal file
View File

@@ -0,0 +1,71 @@
#include "common.h"
#include <stddef.h>
#include <stdint.h>
#include <xcb/xproto.h>
#include "base/macros.h"
#include "core/types.h"
typedef struct modifier_map_t {
modifier_bit_t modifier;
xcb_mod_mask_t mask;
} modifier_map_t;
static constexpr modifier_map_t modifier_map[] = {
{ZDWM_MOD_SHIFT, XCB_MOD_MASK_SHIFT},
{ZDWM_MOD_CONTROL, XCB_MOD_MASK_CONTROL},
{ZDWM_MOD_1, XCB_MOD_MASK_1},
{ZDWM_MOD_2, XCB_MOD_MASK_2},
{ZDWM_MOD_3, XCB_MOD_MASK_3},
{ZDWM_MOD_4, XCB_MOD_MASK_4},
{ZDWM_MOD_5, XCB_MOD_MASK_5},
};
modifier_mask_t modifiers_xcb_to_zdwm(uint16_t mask) {
modifier_mask_t mods = ZDWM_MOD_NONE;
for (size_t i = 0; i < countof(modifier_map); ++i) {
auto item = &modifier_map[i];
if (mask & item->mask) mods |= item->modifier;
}
return mods;
}
uint16_t modifiers_zdwm_to_xcb(modifier_mask_t mask) {
uint16_t mods = 0U;
for (size_t i = 0; i < countof(modifier_map); ++i) {
auto item = &modifier_map[i];
if (mask & item->modifier) mods |= item->mask;
}
return mods;
}
typedef struct button_map_t {
button_t zdwm_button;
xcb_button_index_t xcb_button;
} button_map_t;
static constexpr button_map_t button_map[] = {
{ZDWM_BUTTON_LEFT, XCB_BUTTON_INDEX_1},
{ZDWM_BUTTON_RIGHT, XCB_BUTTON_INDEX_3},
{ZDWM_BUTTON_MIDDLE, XCB_BUTTON_INDEX_2},
/* TODO: 后续可以考虑加上鼠标滚轮事件 */
};
button_t button_xcb_to_zdwm(xcb_button_t button) {
for (size_t i = 0; i < countof(button_map); ++i) {
auto item = &button_map[i];
if (button == item->xcb_button) return item->zdwm_button;
}
return ZDWM_BUTTON_NONE;
}
xcb_button_t button_zdwm_to_xcb(button_t button) {
for (size_t i = 0; i < countof(button_map); ++i) {
auto item = &button_map[i];
if (button == item->zdwm_button) return item->xcb_button;
}
return XCB_BUTTON_INDEX_ANY;
}

12
src/backend/x11/common.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include <stdint.h>
#include <xcb/xproto.h>
#include "core/types.h"
modifier_mask_t modifiers_xcb_to_zdwm(uint16_t mask);
uint16_t modifiers_zdwm_to_xcb(modifier_mask_t mask);
button_t button_xcb_to_zdwm(xcb_button_t button);
xcb_button_t button_zdwm_to_xcb(button_t button);

View File

@@ -9,8 +9,8 @@
#include <xcb/xcb_keysyms.h>
#include <xcb/xproto.h>
#include "backend/x11/common.h"
#include "backend/x11/window.h"
#include "base/macros.h"
#include "base/memory.h"
#include "core/backend.h"
#include "core/types.h"
@@ -233,29 +233,6 @@ static bool handle_configure_request(
return true;
}
static modifier_mask_t get_modifiers(uint16_t mask) {
typedef struct modifier_map_t {
modifier_bit_t modifier;
xcb_mod_mask_t mask;
} modifier_map_t;
static constexpr modifier_map_t modifier_map[] = {
{ZDWM_MOD_SHIFT, XCB_MOD_MASK_SHIFT},
{ZDWM_MOD_CONTROL, XCB_MOD_MASK_CONTROL},
{ZDWM_MOD_1, XCB_MOD_MASK_1},
{ZDWM_MOD_2, XCB_MOD_MASK_2},
{ZDWM_MOD_3, XCB_MOD_MASK_3},
{ZDWM_MOD_4, XCB_MOD_MASK_4},
{ZDWM_MOD_5, XCB_MOD_MASK_5},
};
auto mods = ZDWM_MOD_NONE;
for (size_t i = 0; i < countof(modifier_map); ++i) {
auto item = &modifier_map[i];
if (mask & item->mask) mods |= item->modifier;
}
return mods;
}
static bool handle_key_press(
backend_t *backend,
event_t *event,
@@ -269,39 +246,18 @@ static bool handle_key_press(
event->type = ZDWM_EVENT_KEY_PRESS;
event->as.key_press.keycode = keycode;
event->as.key_press.keysym = keysym;
event->as.key_press.modifiers = get_modifiers(xcb_event->state);
event->as.key_press.modifiers = modifiers_xcb_to_zdwm(xcb_event->state);
return true;
}
static bool get_button(xcb_button_t button_detail, uint32_t *button) {
assert(button != nullptr);
switch (button_detail) {
case XCB_BUTTON_INDEX_1:
*button = ZDWM_BUTTON_LEFT;
return true;
case XCB_BUTTON_INDEX_2:
*button = ZDWM_BUTTON_RIGHT;
return true;
case XCB_BUTTON_INDEX_3:
*button = ZDWM_BUTTON_MIDDLE;
return true;
case XCB_BUTTON_INDEX_4:
case XCB_BUTTON_INDEX_5:
/* TODO: 后续可以考虑加上鼠标滚轮事件 */
default:
return false;
}
}
static bool fill_button_event(
const xcb_button_press_event_t *xcb_event,
pointer_button_event_t *data
) {
uint32_t button = 0;
if (!get_button(xcb_event->detail, &button)) return false;
auto button = button_xcb_to_zdwm(xcb_event->detail);
data->modifiers = get_modifiers(xcb_event->state);
data->modifiers = modifiers_xcb_to_zdwm(xcb_event->state);
data->button = button;
data->window = xcb_event->event;
data->root = (point_t){.x = xcb_event->root_x, .y = xcb_event->root_y};

View File

@@ -8,6 +8,7 @@
#include <xcb/xcb_keysyms.h>
#include <xcb/xproto.h>
#include "backend/x11/common.h"
#include "backend/x11/cursor.h"
#include "base/macros.h"
#include "base/memory.h"
@@ -463,3 +464,26 @@ void window_change_cursor(
xcb_params_cw_t params = {.cursor = cursor_get_xcb_cursor(backend, cursor)};
xcb_aux_change_window_attributes(conn, window, XCB_CW_CURSOR, &params);
}
void window_grab_button(
backend_t *backend,
xcb_window_t window,
button_t button,
modifier_mask_t modifiers
) {
auto xcb_button = button_zdwm_to_xcb(button);
if (xcb_button == XCB_BUTTON_INDEX_ANY) return;
xcb_grab_button(
backend->conn,
false, /* 事件仅发送给抓取者,不发送给其他窗口 */
window,
XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE,
XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_SYNC,
XCB_WINDOW_NONE,
XCB_CURSOR_NONE,
xcb_button,
modifiers_zdwm_to_xcb(modifiers)
);
}

View File

@@ -124,3 +124,10 @@ void window_change_cursor(
xcb_window_t window,
cursor_t cursor
);
void window_grab_button(
backend_t *backend,
xcb_window_t window,
button_t button,
modifier_mask_t modifiers
);