Add map_from_region command

This commit is contained in:
emersion 2018-04-24 19:39:29 +01:00
parent d94bb78ff3
commit ff61df17ff
No known key found for this signature in database
GPG key ID: 0FDE7BE0E88F5E48
11 changed files with 160 additions and 25 deletions

View file

@ -193,6 +193,7 @@ sway_cmd input_cmd_drag_lock;
sway_cmd input_cmd_dwt;
sway_cmd input_cmd_events;
sway_cmd input_cmd_left_handed;
sway_cmd input_cmd_map_from_region;
sway_cmd input_cmd_map_to_output;
sway_cmd input_cmd_middle_emulation;
sway_cmd input_cmd_natural_scroll;

View file

@ -51,6 +51,12 @@ struct sway_mode {
list_t *keycode_bindings;
};
struct input_config_mapped_from_region {
double x1, y1;
double x2, y2;
bool mm;
};
/**
* options for input devices
*/
@ -77,7 +83,8 @@ struct input_config {
char *xkb_rules;
char *xkb_variant;
char *mapped_output;
struct input_config_mapped_from_region *mapped_from_region;
char *mapped_to_output;
bool capturable;
struct wlr_box region;

View file

@ -191,6 +191,7 @@ static struct cmd_handler input_handlers[] = {
{ "dwt", input_cmd_dwt },
{ "events", input_cmd_events },
{ "left_handed", input_cmd_left_handed },
{ "map_from_region", input_cmd_map_from_region },
{ "map_to_output", input_cmd_map_to_output },
{ "middle_emulation", input_cmd_middle_emulation },
{ "natural_scroll", input_cmd_natural_scroll },

View file

@ -0,0 +1,79 @@
#define _POSIX_C_SOURCE 200809L
#include <stdbool.h>
#include <string.h>
#include <strings.h>
#include "log.h"
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/input/input-manager.h"
static bool parse_coords(const char *str, double *x, double *y, bool *mm) {
*mm = false;
char *end;
*x = strtod(str, &end);
if (end[0] != 'x') {
return false;
}
++end;
*y = strtod(end, &end);
if (end[0] == 'm') {
// Expect mm
if (end[1] != 'm') {
return false;
}
*mm = true;
end = &end[2];
}
if (end[0] != '\0') {
return false;
}
return true;
}
struct cmd_results *input_cmd_map_from_region(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "map_from_region", EXPECTED_EQUAL_TO, 2))) {
return error;
}
struct input_config *current_input_config =
config->handler_context.input_config;
if (!current_input_config) {
return cmd_results_new(CMD_FAILURE, "map_from_region",
"No input device defined");
}
struct input_config *new_config =
new_input_config(current_input_config->identifier);
new_config->mapped_from_region =
calloc(1, sizeof(struct input_config_mapped_from_region));
bool mm1, mm2;
if (!parse_coords(argv[0], &new_config->mapped_from_region->x1,
&new_config->mapped_from_region->y1, &mm1)) {
return cmd_results_new(CMD_FAILURE, "map_from_region",
"Invalid top-left coordinates");
}
if (!parse_coords(argv[1], &new_config->mapped_from_region->x2,
&new_config->mapped_from_region->y2, &mm2)) {
return cmd_results_new(CMD_FAILURE, "map_from_region",
"Invalid bottom-right coordinates");
}
if (new_config->mapped_from_region->x1 > new_config->mapped_from_region->x2 ||
new_config->mapped_from_region->y1 > new_config->mapped_from_region->y2) {
return cmd_results_new(CMD_FAILURE, "map_from_region",
"Invalid rectangle");
}
if (mm1 != mm2) {
return cmd_results_new(CMD_FAILURE, "map_from_region",
"Both coordinates must be in the same unit");
}
new_config->mapped_from_region->mm = mm1;
apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -20,7 +20,7 @@ struct cmd_results *input_cmd_map_to_output(int argc, char **argv) {
struct input_config *new_config =
new_input_config(current_input_config->identifier);
new_config->mapped_output = strdup(argv[0]);
new_config->mapped_to_output = strdup(argv[0]);
apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);

View file

@ -96,9 +96,16 @@ void merge_input_config(struct input_config *dst, struct input_config *src) {
free(dst->xkb_variant);
dst->xkb_variant = strdup(src->xkb_variant);
}
if (src->mapped_output) {
free(dst->mapped_output);
dst->mapped_output = strdup(src->mapped_output);
if (src->mapped_from_region) {
free(dst->mapped_from_region);
dst->mapped_from_region =
malloc(sizeof(struct input_config_mapped_from_region));
memcpy(dst->mapped_from_region, src->mapped_from_region,
sizeof(struct input_config_mapped_from_region));
}
if (src->mapped_to_output) {
free(dst->mapped_to_output);
dst->mapped_to_output = strdup(src->mapped_to_output);
}
}

View file

@ -261,22 +261,60 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
wlr_log(L_DEBUG, "TODO: handle touch motion event: %p", event);
}
static double apply_mapping_from_coord(double low, double high, double value) {
if (value == -1) {
return value;
}
value = (value - low) / (high - low);
if (value < 0) {
return 0;
} else if (value > 1) {
return 1;
} else {
return value;
}
}
static void apply_mapping_from_region(struct wlr_input_device *device,
struct input_config_mapped_from_region *region, double *x, double *y) {
double x1 = region->x1, x2 = region->x2;
double y1 = region->y1, y2 = region->y2;
if (region->mm) {
if (device->width_mm == 0 || device->height_mm == 0) {
return;
}
x1 /= device->width_mm;
x2 /= device->width_mm;
y1 /= device->height_mm;
y2 /= device->height_mm;
}
*x = apply_mapping_from_coord(x1, x2, *x);
*y = apply_mapping_from_coord(y1, y2, *y);
}
static void handle_tool_axis(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_axis);
struct wlr_event_tablet_tool_axis *event = data;
struct sway_input_device *input_device = event->device->data;
if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X) &&
(event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) {
wlr_cursor_warp_absolute(cursor->cursor, event->device,
event->x, event->y);
cursor_send_pointer_motion(cursor, event->time_msec);
} else if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X)) {
wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, -1);
cursor_send_pointer_motion(cursor, event->time_msec);
} else if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) {
wlr_cursor_warp_absolute(cursor->cursor, event->device, -1, event->y);
cursor_send_pointer_motion(cursor, event->time_msec);
double x = -1, y = -1;
if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X)) {
x = event->x;
}
if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) {
y = event->y;
}
struct input_config *ic = input_device_get_config(input_device);
if (ic != NULL && ic->mapped_from_region != NULL) {
apply_mapping_from_region(event->device, ic->mapped_from_region, &x, &y);
}
wlr_cursor_warp_absolute(cursor->cursor, event->device, x, y);
cursor_send_pointer_motion(cursor, event->time_msec);
}
static void handle_tool_tip(struct wl_listener *listener, void *data) {

View file

@ -211,6 +211,7 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
if (!sway_assert(input_device, "could not allocate input device")) {
return;
}
device->data = input_device;
input_device->wlr_device = device;
input_device->identifier = get_device_identifier(device);

View file

@ -269,11 +269,11 @@ static void seat_apply_input_config(struct sway_seat *seat,
}
wlr_log(L_DEBUG, "Applying input config to %s",
sway_device->input_device->identifier);
if (ic->mapped_output) {
if (ic->mapped_to_output) {
struct sway_container *output = NULL;
for (int i = 0; i < root_container.children->length; ++i) {
struct sway_container *_output = root_container.children->items[i];
if (strcasecmp(_output->name, ic->mapped_output) == 0) {
if (strcasecmp(_output->name, ic->mapped_to_output) == 0) {
output = _output;
break;
}

View file

@ -90,6 +90,7 @@ sway_sources = files(
'commands/input/dwt.c',
'commands/input/events.c',
'commands/input/left_handed.c',
'commands/input/map_from_region.c',
'commands/input/map_to_output.c',
'commands/input/middle_emulation.c',
'commands/input/natural_scroll.c',

View file

@ -52,13 +52,13 @@ Mapping Configuration
layout. Only meaningful if the device is a pointer, touch, or drawing tablet
device.
**input** <identifier> map_region <WxH\@X,Y>::
Ignores inputs from this device that do not occur within the specified region.
Can be in millimeters (e.g. 10mmx20mm\@10mm,20mm) or in terms of 0..1 (e.g.
0.5x0.5\@0,0). Not all devices support millimeters. Only meaningful if the
device is not a keyboard an provides events in absolute terms (such as a
drawing tablet or touch screen - most pointers provide events relative to the
previous frame).
**input** <identifier> map_from_region <X1xY1> <X2xY2>::
Ignores inputs from this device that do not occur within the specified
region. Can be in millimeters (e.g. 10x20mm 20x40mm) or in terms of 0..1
(e.g. 0.5x0.5 0.7x0.7). Not all devices support millimeters. Only meaningful
if the device is not a keyboard an provides events in absolute terms (such
as a drawing tablet or touch screen - most pointers provide events relative
to the previous frame).
Libinput Configuration
~~~~~~~~~~~~~~~~~~~~~~