diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index 50ac453b3..f7e827215 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h @@ -5,6 +5,11 @@ #define SWAY_CURSOR_PRESSED_BUTTONS_CAP 32 +#define SWAY_SCROLL_UP KEY_MAX + 1 +#define SWAY_SCROLL_DOWN KEY_MAX + 2 +#define SWAY_SCROLL_LEFT KEY_MAX + 3 +#define SWAY_SCROLL_RIGHT KEY_MAX + 4 + struct sway_cursor { struct sway_seat *seat; struct wlr_cursor *cursor; diff --git a/meson.build b/meson.build index 6dc5bd8de..e1e0fc2d4 100644 --- a/meson.build +++ b/meson.build @@ -46,6 +46,7 @@ pango = dependency('pango') pangocairo = dependency('pangocairo') gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: false) pixman = dependency('pixman-1') +libevdev = dependency('libevdev') libinput = dependency('libinput', version: '>=1.6.0') libpam = cc.find_library('pam', required: false) crypt = cc.find_library('crypt', required: false) diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 01a35cf2f..5990166ae 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c @@ -1,4 +1,5 @@ #define _POSIX_C_SOURCE 200809L +#include #ifdef __linux__ #include #elif __FreeBSD__ @@ -10,6 +11,7 @@ #include #include "sway/commands.h" #include "sway/config.h" +#include "sway/input/cursor.h" #include "sway/ipc-server.h" #include "list.h" #include "log.h" @@ -102,9 +104,26 @@ static struct cmd_results *identify_key(const char* name, bool first_key, // Check for mouse binding uint32_t button = 0; - if (strncasecmp(name, "button", strlen("button")) == 0 && - strlen(name) == strlen("button0")) { - button = name[strlen("button")] - '1' + BTN_LEFT; + if (strncasecmp(name, "button", strlen("button")) == 0) { + // Map to x11 mouse buttons + button = name[strlen("button")] - '0'; + if (button < 1 || button > 9 || strlen(name) > strlen("button0")) { + return cmd_results_new(CMD_INVALID, "bindsym", + "Only buttons 1-9 are supported. For other mouse " + "buttons, use the name of the event code."); + } + uint32_t buttons[] = {BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, + SWAY_SCROLL_UP, SWAY_SCROLL_DOWN, SWAY_SCROLL_LEFT, + SWAY_SCROLL_RIGHT, BTN_SIDE, BTN_EXTRA}; + button = buttons[button - 1]; + } else if (strncmp(name, "BTN_", strlen("BTN_")) == 0) { + // Get event code + int code = libevdev_event_code_from_name(EV_KEY, name); + if (code == -1) { + return cmd_results_new(CMD_INVALID, "bindsym", + "Invalid event code name %s", name); + } + button = code; } if (*type == BINDING_KEYSYM) { diff --git a/sway/input/cursor.c b/sway/input/cursor.c index ad9b9835a..444fe81db 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -1,5 +1,6 @@ #define _POSIX_C_SOURCE 200809L #include +#include #ifdef __linux__ #include #elif __FreeBSD__ @@ -982,6 +983,18 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) { transaction_commit_dirty(); } +static uint32_t wl_axis_to_button(struct wlr_event_pointer_axis *event) { + switch (event->orientation) { + case WLR_AXIS_ORIENTATION_VERTICAL: + return event->delta < 0 ? SWAY_SCROLL_UP : SWAY_SCROLL_DOWN; + case WLR_AXIS_ORIENTATION_HORIZONTAL: + return event->delta < 0 ? SWAY_SCROLL_LEFT : SWAY_SCROLL_RIGHT; + default: + wlr_log(WLR_DEBUG, "Unknown axis orientation"); + return 0; + } +} + static void dispatch_cursor_axis(struct sway_cursor *cursor, struct wlr_event_pointer_axis *event) { struct sway_seat *seat = cursor->seat; @@ -998,11 +1011,32 @@ static void dispatch_cursor_axis(struct sway_cursor *cursor, enum wlr_edges edge = cont ? find_edge(cont, 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; float scroll_factor = (ic == NULL || ic->scroll_factor == FLT_MIN) ? 1.0f : ic->scroll_factor; - // Scrolling on a tabbed or stacked title bar - if (on_titlebar) { + 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->wlr_device; + char *dev_id = device ? input_device_get_identifier(device) : strdup("*"); + uint32_t button = wl_axis_to_button(event); + + // Handle mouse bindings - x11 mouse buttons 4-7 - press event + struct sway_binding *binding = NULL; + state_add_button(cursor, button); + binding = get_active_mouse_binding(cursor, + config->current_mode->mouse_bindings, modifiers, false, + on_titlebar, on_border, on_contents, dev_id); + if (binding) { + seat_execute_command(seat, binding); + handled = true; + } + + // Scrolling on a tabbed or stacked title bar (handled as press event) + if (!handled && on_titlebar) { enum sway_container_layout layout = container_parent_layout(cont); if (layout == L_TABBED || layout == L_STACKED) { struct sway_node *tabcontainer = node_get_parent(node); @@ -1029,13 +1063,26 @@ static void dispatch_cursor_axis(struct sway_cursor *cursor, seat_set_raw_focus(seat, new_focus); seat_set_raw_focus(seat, old_focus); } - return; + handled = true; } } - wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec, - event->orientation, scroll_factor * event->delta, - round(scroll_factor * event->delta_discrete), event->source); + // Handle mouse bindings - x11 mouse buttons 4-7 - release event + binding = get_active_mouse_binding(cursor, + config->current_mode->mouse_bindings, modifiers, true, + on_titlebar, on_border, on_contents, dev_id); + state_erase_button(cursor, button); + if (binding) { + seat_execute_command(seat, binding); + handled = true; + } + free(dev_id); + + if (!handled) { + wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec, + event->orientation, scroll_factor * event->delta, + round(scroll_factor * event->delta_discrete), event->source); + } } static void handle_cursor_axis(struct wl_listener *listener, void *data) { diff --git a/sway/meson.build b/sway/meson.build index 51b400209..2f977fd2d 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -174,6 +174,7 @@ sway_deps = [ cairo, gdk_pixbuf, jsonc, + libevdev, libinput, math, pango, diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 2fe4e3720..e6abef56f 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -288,6 +288,13 @@ runtime. overwrite a binding, swaynag will give you a warning. To silence this, use the _--no-warn_ flag. + Mouse buttons can either be specified in the form _button[1-9]_ or by using + the name of the event code (ex _BTN\_LEFT_ or _BTN\_RIGHT_). For the former + option, the buttons will be mapped to their values in X11 (1=left, 2=middle, + 3=right, 4=scroll up, 5=scroll down, 6=scroll left, 7=scroll right, 8=back, + 9=forward). For the latter option, you can find the event names using + _libinput debug-events_. + Example: ``` # Execute firefox when alt, shift, and f are pressed together