mirror of
https://github.com/swaywm/sway.git
synced 2026-04-23 06:46:27 -04:00
input: Add basic pointer gesture support
Passing of gesture events added in #4794 allows to use them in clients but not in sway itself, for example to switch workspaces using three-finger swipes. Add support for binding four basic directional swipes to arbitrary sway commands. Add the necessary handling to default seatops to execute them at the beginning or end of a swipe gesture. This for now responds to all swipes, ignoring the number of fingers used. The former throws up the intrinsic conundrum that we can not know the kind of swipe that's going to happen because it can change all through its lifecylce. Therefore we can only execute bindings on release. Test plan: - add workspace switching to config like so: bindsym --whole-window SWIPE_LEFT workspace prev_on_output bindsym --whole-window SWIPE_RIGHT workspace next_on_output - start sway and open two workspaces - switch back and forth using horizontal three-finger swipes, observing that vertical swipes won't Signed-off-by: Michael Weiser <michael.weiser@gmx.de>
This commit is contained in:
parent
b518870bc1
commit
44a2a60dcd
3 changed files with 195 additions and 6 deletions
|
|
@ -14,6 +14,10 @@
|
||||||
#define SWAY_SCROLL_DOWN KEY_MAX + 2
|
#define SWAY_SCROLL_DOWN KEY_MAX + 2
|
||||||
#define SWAY_SCROLL_LEFT KEY_MAX + 3
|
#define SWAY_SCROLL_LEFT KEY_MAX + 3
|
||||||
#define SWAY_SCROLL_RIGHT KEY_MAX + 4
|
#define SWAY_SCROLL_RIGHT KEY_MAX + 4
|
||||||
|
#define SWAY_SWIPE_UP KEY_MAX + 5
|
||||||
|
#define SWAY_SWIPE_DOWN KEY_MAX + 6
|
||||||
|
#define SWAY_SWIPE_LEFT KEY_MAX + 7
|
||||||
|
#define SWAY_SWIPE_RIGHT KEY_MAX + 8
|
||||||
|
|
||||||
struct sway_cursor {
|
struct sway_cursor {
|
||||||
struct sway_seat *seat;
|
struct sway_seat *seat;
|
||||||
|
|
|
||||||
|
|
@ -1217,6 +1217,31 @@ uint32_t get_mouse_bindsym(const char *name, char **error) {
|
||||||
SWAY_SCROLL_UP, SWAY_SCROLL_DOWN, SWAY_SCROLL_LEFT,
|
SWAY_SCROLL_UP, SWAY_SCROLL_DOWN, SWAY_SCROLL_LEFT,
|
||||||
SWAY_SCROLL_RIGHT, BTN_SIDE, BTN_EXTRA};
|
SWAY_SCROLL_RIGHT, BTN_SIDE, BTN_EXTRA};
|
||||||
return buttons[number - 1];
|
return buttons[number - 1];
|
||||||
|
} else if (strncmp(name, "SWIPE_", strlen("SWIPE_")) == 0) {
|
||||||
|
static const struct {
|
||||||
|
uint32_t button;
|
||||||
|
const char *dir;
|
||||||
|
} swipes[] = {
|
||||||
|
SWAY_SWIPE_UP, "UP",
|
||||||
|
SWAY_SWIPE_DOWN, "DOWN",
|
||||||
|
SWAY_SWIPE_LEFT, "LEFT",
|
||||||
|
SWAY_SWIPE_RIGHT, "RIGHT",
|
||||||
|
0, NULL,
|
||||||
|
}, *sp;
|
||||||
|
|
||||||
|
const char *dir = &name[strlen("SWIPE_")];
|
||||||
|
for (sp = swipes; sp->dir; sp++) {
|
||||||
|
if (strcmp(sp->dir, dir) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sp->dir) {
|
||||||
|
*error = strdup("Unknown swipe type");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sp->button;
|
||||||
} else if (strncmp(name, "BTN_", strlen("BTN_")) == 0) {
|
} else if (strncmp(name, "BTN_", strlen("BTN_")) == 0) {
|
||||||
// Get event code from name
|
// Get event code from name
|
||||||
int code = libevdev_event_code_from_name(EV_KEY, name);
|
int code = libevdev_event_code_from_name(EV_KEY, name);
|
||||||
|
|
@ -1278,6 +1303,14 @@ const char *get_mouse_button_name(uint32_t button) {
|
||||||
name = "SWAY_SCROLL_LEFT";
|
name = "SWAY_SCROLL_LEFT";
|
||||||
} else if (button == SWAY_SCROLL_RIGHT) {
|
} else if (button == SWAY_SCROLL_RIGHT) {
|
||||||
name = "SWAY_SCROLL_RIGHT";
|
name = "SWAY_SCROLL_RIGHT";
|
||||||
|
} else if (button == SWAY_SWIPE_UP) {
|
||||||
|
name = "SWAY_SWIPE_UP";
|
||||||
|
} else if (button == SWAY_SWIPE_DOWN) {
|
||||||
|
name = "SWAY_SWIPE_DOWN";
|
||||||
|
} else if (button == SWAY_SWIPE_LEFT) {
|
||||||
|
name = "SWAY_SWIPE_LEFT";
|
||||||
|
} else if (button == SWAY_SWIPE_RIGHT) {
|
||||||
|
name = "SWAY_SWIPE_RIGHT";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ struct seatop_default_event {
|
||||||
struct sway_node *previous_node;
|
struct sway_node *previous_node;
|
||||||
uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP];
|
uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP];
|
||||||
size_t pressed_button_count;
|
size_t pressed_button_count;
|
||||||
|
bool swiping;
|
||||||
|
double swipe_travel_x, swipe_travel_y;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*-----------------------------------------\
|
/*-----------------------------------------\
|
||||||
|
|
@ -749,14 +751,94 @@ static void handle_pointer_axis(struct sway_seat *seat,
|
||||||
|
|
||||||
static void handle_swipe_begin(struct sway_seat *seat,
|
static void handle_swipe_begin(struct sway_seat *seat,
|
||||||
struct wlr_event_pointer_swipe_begin *event) {
|
struct wlr_event_pointer_swipe_begin *event) {
|
||||||
|
struct sway_input_device *input_device =
|
||||||
|
event->device ? event->device->data : NULL;
|
||||||
struct sway_cursor *cursor = seat->cursor;
|
struct sway_cursor *cursor = seat->cursor;
|
||||||
|
struct seatop_default_event *e = seat->seatop_data;
|
||||||
|
|
||||||
|
// Determine what's under the cursor
|
||||||
|
struct wlr_surface *surface = NULL;
|
||||||
|
double sx, sy;
|
||||||
|
struct sway_node *node = node_at_coords(seat,
|
||||||
|
cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
|
||||||
|
struct sway_container *cont = node && node->type == N_CONTAINER ?
|
||||||
|
node->sway_container : NULL;
|
||||||
|
enum wlr_edges edge = cont ? find_edge(cont, surface, cursor) : WLR_EDGE_NONE;
|
||||||
|
bool on_border = edge != WLR_EDGE_NONE;
|
||||||
|
bool on_titlebar = cont && !on_border && !surface;
|
||||||
|
bool on_contents = cont && !on_border && surface;
|
||||||
|
bool on_workspace = node && node->type == N_WORKSPACE;
|
||||||
|
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
|
// Gather information needed for mouse bindings
|
||||||
|
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
|
||||||
|
uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
|
||||||
|
struct wlr_input_device *device =
|
||||||
|
input_device ? input_device->wlr_device : NULL;
|
||||||
|
char *dev_id = device ? input_device_get_identifier(device) : strdup("*");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle mouse bindings - if there's any swipe bindings for this
|
||||||
|
* context. Here we must swallow all swipes if there's even one
|
||||||
|
* possible binding because we have no way of knowing yet what kind of
|
||||||
|
* swipe this is going to be. It's in the nature of the thing because
|
||||||
|
* the user may turn a left into an upwards swipe mid-way. For the same
|
||||||
|
* reason it makes no sense to execute any binding here. So we defer it
|
||||||
|
* to swipe release. We can break as soon as it's confirmed that there
|
||||||
|
* is at least one binding.
|
||||||
|
*/
|
||||||
|
struct sway_binding *binding = NULL;
|
||||||
|
for (uint32_t button = SWAY_SWIPE_UP; button <= SWAY_SWIPE_RIGHT;
|
||||||
|
button++) {
|
||||||
|
state_add_button(e, button);
|
||||||
|
// check for an on-press binding
|
||||||
|
binding = get_active_mouse_binding(e,
|
||||||
|
config->current_mode->mouse_bindings,
|
||||||
|
modifiers, false, on_titlebar, on_border,
|
||||||
|
on_contents, on_workspace, dev_id);
|
||||||
|
if (!binding) {
|
||||||
|
// see if there's an on-release binding instead
|
||||||
|
binding = get_active_mouse_binding(e,
|
||||||
|
config->current_mode->mouse_bindings,
|
||||||
|
modifiers, true, on_titlebar,
|
||||||
|
on_border, on_contents, on_workspace,
|
||||||
|
dev_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
state_erase_button(e, button);
|
||||||
|
if (binding) {
|
||||||
|
handled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handled) {
|
||||||
|
// mark this as ours and start tracking
|
||||||
|
e->swiping = true;
|
||||||
|
e->swipe_travel_x = 0;
|
||||||
|
e->swipe_travel_y = 0;
|
||||||
|
}
|
||||||
|
free(dev_id);
|
||||||
|
|
||||||
|
if (!handled) {
|
||||||
wlr_pointer_gestures_v1_send_swipe_begin(
|
wlr_pointer_gestures_v1_send_swipe_begin(
|
||||||
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
||||||
event->time_msec, event->fingers);
|
event->time_msec, event->fingers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_swipe_update(struct sway_seat *seat,
|
static void handle_swipe_update(struct sway_seat *seat,
|
||||||
struct wlr_event_pointer_swipe_update *event) {
|
struct wlr_event_pointer_swipe_update *event) {
|
||||||
|
struct seatop_default_event *e = seat->seatop_data;
|
||||||
|
|
||||||
|
// is this ours?
|
||||||
|
if (e->swiping) {
|
||||||
|
e->swipe_travel_x += event->dx;
|
||||||
|
e->swipe_travel_y += event->dy;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
struct sway_cursor *cursor = seat->cursor;
|
struct sway_cursor *cursor = seat->cursor;
|
||||||
wlr_pointer_gestures_v1_send_swipe_update(
|
wlr_pointer_gestures_v1_send_swipe_update(
|
||||||
cursor->pointer_gestures,
|
cursor->pointer_gestures,
|
||||||
|
|
@ -764,12 +846,82 @@ static void handle_swipe_update(struct sway_seat *seat,
|
||||||
event->time_msec, event->dx, event->dy);
|
event->time_msec, event->dx, event->dy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t swipe_to_button(struct seatop_default_event *event) {
|
||||||
|
if (fabs(event->swipe_travel_x) > fabs(event->swipe_travel_y)) {
|
||||||
|
return event->swipe_travel_x > 0 ? SWAY_SWIPE_RIGHT : SWAY_SWIPE_LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return event->swipe_travel_y > 0 ? SWAY_SWIPE_DOWN : SWAY_SWIPE_UP;
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_swipe_end(struct sway_seat *seat,
|
static void handle_swipe_end(struct sway_seat *seat,
|
||||||
struct wlr_event_pointer_swipe_end *event) {
|
struct wlr_event_pointer_swipe_end *event) {
|
||||||
struct sway_cursor *cursor = seat->cursor;
|
struct sway_cursor *cursor = seat->cursor;
|
||||||
|
struct seatop_default_event *e = seat->seatop_data;
|
||||||
|
|
||||||
|
if (!e->swiping) {
|
||||||
wlr_pointer_gestures_v1_send_swipe_end(
|
wlr_pointer_gestures_v1_send_swipe_end(
|
||||||
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
||||||
event->time_msec, event->cancelled);
|
event->time_msec, event->cancelled);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e->swiping = false;
|
||||||
|
|
||||||
|
// can happen when changing finger count mid-swipe or swiping off the
|
||||||
|
// tracking surface (touchpad)
|
||||||
|
if (event->cancelled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sway_input_device *input_device =
|
||||||
|
event->device ? event->device->data : NULL;
|
||||||
|
|
||||||
|
// Determine what's under the cursor
|
||||||
|
struct wlr_surface *surface = NULL;
|
||||||
|
double sx, sy;
|
||||||
|
struct sway_node *node = node_at_coords(seat, cursor->cursor->x,
|
||||||
|
cursor->cursor->y, &surface, &sx, &sy);
|
||||||
|
struct sway_container *cont = node && node->type == N_CONTAINER ?
|
||||||
|
node->sway_container : NULL;
|
||||||
|
enum wlr_edges edge = cont ? find_edge(cont, surface, cursor) :
|
||||||
|
WLR_EDGE_NONE;
|
||||||
|
bool on_border = edge != WLR_EDGE_NONE;
|
||||||
|
bool on_titlebar = cont && !on_border && !surface;
|
||||||
|
bool on_contents = cont && !on_border && surface;
|
||||||
|
bool on_workspace = node && node->type == N_WORKSPACE;
|
||||||
|
|
||||||
|
// Gather information needed for mouse bindings
|
||||||
|
struct wlr_keyboard *keyboard =
|
||||||
|
wlr_seat_get_keyboard(seat->wlr_seat);
|
||||||
|
uint32_t modifiers = keyboard ?
|
||||||
|
wlr_keyboard_get_modifiers(keyboard) : 0;
|
||||||
|
struct wlr_input_device *device =
|
||||||
|
input_device ? input_device->wlr_device : NULL;
|
||||||
|
char *dev_id = device ? input_device_get_identifier(device) :
|
||||||
|
strdup("*");
|
||||||
|
uint32_t button = swipe_to_button(e);
|
||||||
|
|
||||||
|
// Prefer any on-press binding because we did not execute it on gesture
|
||||||
|
// start because we could not know what gesture it would become. Ignore
|
||||||
|
// on-release binding on success.
|
||||||
|
state_add_button(e, button);
|
||||||
|
struct sway_binding *binding = get_active_mouse_binding(e,
|
||||||
|
config->current_mode->mouse_bindings, modifiers, false,
|
||||||
|
on_titlebar, on_border, on_contents, on_workspace,
|
||||||
|
dev_id);
|
||||||
|
if (!binding) {
|
||||||
|
binding = get_active_mouse_binding(e,
|
||||||
|
config->current_mode->mouse_bindings,
|
||||||
|
modifiers, true, on_titlebar, on_border,
|
||||||
|
on_contents, on_workspace, dev_id);
|
||||||
|
}
|
||||||
|
state_erase_button(e, button);
|
||||||
|
if (binding) {
|
||||||
|
seat_execute_command(seat, binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(dev_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------\
|
/*----------------------------------\
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue