diff --git a/include/sway/commands.h b/include/sway/commands.h index f549626b..964b3661 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -264,6 +264,7 @@ sway_cmd input_cmd_scroll_button; sway_cmd input_cmd_scroll_method; sway_cmd input_cmd_tap; sway_cmd input_cmd_tap_button_map; +sway_cmd input_cmd_tool_mode; sway_cmd input_cmd_xkb_capslock; sway_cmd input_cmd_xkb_file; sway_cmd input_cmd_xkb_layout; diff --git a/include/sway/config.h b/include/sway/config.h index ee1852d4..473f723b 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -6,11 +6,13 @@ #include #include #include +#include #include #include "../include/config.h" #include "list.h" #include "swaynag.h" #include "tree/container.h" +#include "sway/input/tablet.h" #include "sway/tree/root.h" #include "wlr-layer-shell-unstable-v1-protocol.h" @@ -116,6 +118,11 @@ enum input_config_mapped_to { MAPPED_TO_REGION, }; +struct input_config_tool { + enum wlr_tablet_tool_type type; + enum sway_tablet_tool_mode mode; +}; + /** * options for input devices */ @@ -160,6 +167,8 @@ struct input_config { char *mapped_to_output; struct wlr_box *mapped_to_region; + list_t *tools; + bool capturable; struct wlr_box region; }; diff --git a/include/sway/input/tablet.h b/include/sway/input/tablet.h index f30e232a..d7e4c242 100644 --- a/include/sway/input/tablet.h +++ b/include/sway/input/tablet.h @@ -11,11 +11,17 @@ struct sway_tablet { struct wlr_tablet_v2_tablet *tablet_v2; }; +enum sway_tablet_tool_mode { + SWAY_TABLET_TOOL_MODE_ABSOLUTE, + SWAY_TABLET_TOOL_MODE_RELATIVE, +}; + struct sway_tablet_tool { struct sway_seat *seat; struct sway_tablet *tablet; struct wlr_tablet_v2_tablet_tool *tablet_v2_tool; + enum sway_tablet_tool_mode mode; double tilt_x, tilt_y; struct wl_listener set_cursor; diff --git a/sway/commands/input.c b/sway/commands/input.c index 53db9a16..c9bb8e06 100644 --- a/sway/commands/input.c +++ b/sway/commands/input.c @@ -29,6 +29,7 @@ static struct cmd_handler input_handlers[] = { { "scroll_method", input_cmd_scroll_method }, { "tap", input_cmd_tap }, { "tap_button_map", input_cmd_tap_button_map }, + { "tool_mode", input_cmd_tool_mode }, { "xkb_file", input_cmd_xkb_file }, { "xkb_layout", input_cmd_xkb_layout }, { "xkb_model", input_cmd_xkb_model }, diff --git a/sway/commands/input/tool_mode.c b/sway/commands/input/tool_mode.c new file mode 100644 index 00000000..04316857 --- /dev/null +++ b/sway/commands/input/tool_mode.c @@ -0,0 +1,73 @@ +#include +#include "sway/commands.h" +#include "sway/config.h" + +static void set_tool_mode(struct input_config *ic, + enum wlr_tablet_tool_type type, enum sway_tablet_tool_mode mode) { + for (int i = 0; i < ic->tools->length; i++) { + struct input_config_tool *tool = ic->tools->items[i]; + if (tool->type == type) { + tool->mode = mode; + return; + } + } + + struct input_config_tool *tool = calloc(1, sizeof(*tool)); + if (tool) { + tool->type = type; + tool->mode = mode; + list_add(ic->tools, tool); + } +} + +struct cmd_results *input_cmd_tool_mode(int argc, char **argv) { + struct cmd_results *error; + if ((error = checkarg(argc, "tool_mode", EXPECTED_AT_LEAST, 2))) { + return error; + } + + struct input_config *ic = config->handler_context.input_config; + if (!ic) { + return cmd_results_new(CMD_FAILURE, "No input device defined."); + } + + enum sway_tablet_tool_mode tool_mode; + if (!strcasecmp(argv[1], "absolute")) { + tool_mode = SWAY_TABLET_TOOL_MODE_ABSOLUTE; + } else if (!strcasecmp(argv[1], "relative")) { + tool_mode = SWAY_TABLET_TOOL_MODE_RELATIVE; + } else { + goto invalid_command; + } + + if (!strcasecmp(argv[0], "*")) { + set_tool_mode(ic, WLR_TABLET_TOOL_TYPE_PEN, tool_mode); + set_tool_mode(ic, WLR_TABLET_TOOL_TYPE_ERASER, tool_mode); + set_tool_mode(ic, WLR_TABLET_TOOL_TYPE_BRUSH, tool_mode); + set_tool_mode(ic, WLR_TABLET_TOOL_TYPE_PENCIL, tool_mode); + set_tool_mode(ic, WLR_TABLET_TOOL_TYPE_AIRBRUSH, tool_mode); + } else { + enum wlr_tablet_tool_type tool_type; + if (!strcasecmp(argv[0], "pen")) { + tool_type = WLR_TABLET_TOOL_TYPE_PEN; + } else if (!strcasecmp(argv[0], "eraser")) { + tool_type = WLR_TABLET_TOOL_TYPE_ERASER; + } else if (!strcasecmp(argv[0], "brush")) { + tool_type = WLR_TABLET_TOOL_TYPE_BRUSH; + } else if (!strcasecmp(argv[0], "pencil")) { + tool_type = WLR_TABLET_TOOL_TYPE_PENCIL; + } else if (!strcasecmp(argv[0], "airbrush")) { + tool_type = WLR_TABLET_TOOL_TYPE_AIRBRUSH; + } else { + goto invalid_command; + } + + set_tool_mode(ic, tool_type, tool_mode); + } + + return cmd_results_new(CMD_SUCCESS, NULL); + +invalid_command: + return cmd_results_new(CMD_INVALID, + "Expected 'tool_mode '"); +} diff --git a/sway/config/input.c b/sway/config/input.c index 2ed9c016..a998e170 100644 --- a/sway/config/input.c +++ b/sway/config/input.c @@ -40,6 +40,7 @@ struct input_config *new_input_config(const char* identifier) { input->xkb_numlock = INT_MIN; input->xkb_capslock = INT_MIN; input->xkb_file_is_set = false; + input->tools = create_list(); return input; } @@ -153,6 +154,22 @@ void merge_input_config(struct input_config *dst, struct input_config *src) { memcpy(dst->calibration_matrix.matrix, src->calibration_matrix.matrix, sizeof(src->calibration_matrix.matrix)); } + for (int i = 0; i < src->tools->length; i++) { + struct input_config_tool *src_tool = src->tools->items[i]; + for (int j = 0; j < dst->tools->length; j++) { + struct input_config_tool *dst_tool = dst->tools->items[j]; + if (src_tool->type == dst_tool->type) { + dst_tool->mode = src_tool->mode; + goto tool_merge_outer; + } + } + + struct input_config_tool *dst_tool = malloc(sizeof(*dst_tool)); + memcpy(dst_tool, src_tool, sizeof(*dst_tool)); + list_add(dst->tools, dst_tool); + + tool_merge_outer:; + } } static bool validate_xkb_merge(struct input_config *dest, @@ -358,6 +375,7 @@ void free_input_config(struct input_config *ic) { free(ic->mapped_from_region); free(ic->mapped_to_output); free(ic->mapped_to_region); + list_free_items_and_destroy(ic->tools); free(ic); } diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 61d75b8a..e47410a5 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -567,14 +567,14 @@ static void handle_tablet_tool_position(struct sway_cursor *cursor, ic->mapped_from_region, &x, &y); } - switch (tool->tablet_v2_tool->wlr_tool->type) { - case WLR_TABLET_TOOL_TYPE_LENS: - case WLR_TABLET_TOOL_TYPE_MOUSE: - wlr_cursor_move(cursor->cursor, input_device->wlr_device, dx, dy); - break; - default: + switch (tool->mode) { + case SWAY_TABLET_TOOL_MODE_ABSOLUTE: wlr_cursor_warp_absolute(cursor->cursor, input_device->wlr_device, change_x ? x : NAN, change_y ? y : NAN); + break; + case SWAY_TABLET_TOOL_MODE_RELATIVE: + wlr_cursor_move(cursor->cursor, input_device->wlr_device, dx, dy); + break; } double sx, sy; diff --git a/sway/input/tablet.c b/sway/input/tablet.c index b74347aa..5f81f772 100644 --- a/sway/input/tablet.c +++ b/sway/input/tablet.c @@ -140,6 +140,29 @@ void sway_tablet_tool_configure(struct sway_tablet *tablet, return; } + switch (wlr_tool->type) { + case WLR_TABLET_TOOL_TYPE_LENS: + case WLR_TABLET_TOOL_TYPE_MOUSE: + tool->mode = SWAY_TABLET_TOOL_MODE_RELATIVE; + break; + default: + tool->mode = SWAY_TABLET_TOOL_MODE_ABSOLUTE; + + struct input_config *ic = input_device_get_config( + tablet->seat_device->input_device); + if (!ic) { + break; + } + + for (int i = 0; i < ic->tools->length; i++) { + struct input_config_tool *tool_config = ic->tools->items[i]; + if (tool_config->type == wlr_tool->type) { + tool->mode = tool_config->mode; + break; + } + } + } + tool->seat = tablet->seat_device->sway_seat; tool->tablet = tablet; tool->tablet_v2_tool = diff --git a/sway/meson.build b/sway/meson.build index b65a5211..6e138101 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -168,6 +168,7 @@ sway_sources = files( 'commands/input/scroll_method.c', 'commands/input/tap.c', 'commands/input/tap_button_map.c', + 'commands/input/tool_mode.c', 'commands/input/xkb_capslock.c', 'commands/input/xkb_file.c', 'commands/input/xkb_layout.c', diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd index 9ec5eeae..d8180c1c 100644 --- a/sway/sway-input.5.scd +++ b/sway/sway-input.5.scd @@ -94,6 +94,17 @@ The following commands may only be used in the configuration file. *input* xkb_numlock enabled|disabled Initially enables or disables NumLock on startup, the default is disabled. +## TABLET CONFIGURATION + +*input* tool_mode + Sets whether movement of a tablet tool should be treated as absolute or + relative; the default is absolute. + + Valid values for _\_ are currently "pen", "eraser", "brush", + "pencil", "airbrush", and the wildcard _\*_, which matches all tools. + + Mouse and lens tools ignore this setting and are always treated as relative. + ## MAPPING CONFIGURATION *input* map_to_output