Implement libinput device configuration

This commit is contained in:
project-repo 2021-09-15 08:37:50 +02:00
commit f9efd40c9d
9 changed files with 429 additions and 117 deletions

View file

@ -1,4 +1,4 @@
*
/*
* Cagebreak: A Wayland tiling compositor.
*
* Copyright (C) 2018-2020 Jente Hidskes
@ -362,8 +362,6 @@ main(int argc, char *argv[]) {
}
server.input = input_manager_create(&server);
fprintf(stderr, "input_manager_create:%d\n",wl_list_length(&server.input->devices));
data_control_manager =
wlr_data_control_manager_v1_create(server.wl_display);
@ -599,6 +597,7 @@ end:
wl_display_destroy(server.wl_display);
wlr_output_layout_destroy(server.output_layout);
free(server.input);
pango_cairo_font_map_set_default(NULL);
cairo_debug_reset_static_data();
FcFini();

View file

@ -1,12 +1,16 @@
#ifndef _LIBINPUT_H
#define _LIBINPUT_H
#ifndef _CG_INPUT_H
#define _CG_INPUT_H
#include <stdbool.h>
struct cg_input_device;
struct cg_input_config;
struct cg_server;
void cg_input_configure_libinput_device(struct cg_input_device *device);
void cg_input_apply_config(struct cg_input_config *config, struct cg_server *server);
void cg_input_reset_libinput_device(struct cg_input_device *device);
bool cg_libinput_device_is_builtin(struct cg_input_device *device);

View file

@ -23,6 +23,7 @@
#include <wlr/types/wlr_virtual_pointer_v1.h>
#include <wlr/types/wlr_input_inhibitor.h>
#include <wayland-server-core.h>
#include <libevdev/libevdev.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
@ -210,58 +211,50 @@ struct cg_input_manager *input_manager_create(struct cg_server *server) {
return input;
}
static bool device_is_touchpad(struct cg_input_device *device) {
if (device->wlr_device->type != WLR_INPUT_DEVICE_POINTER ||
!wlr_input_device_is_libinput(device->wlr_device)) {
return false;
uint32_t get_mouse_bindsym(const char *name, char **error) {
// Get event code from name
int code = libevdev_event_code_from_name(EV_KEY, name);
if (code == -1) {
size_t len = snprintf(NULL, 0, "Unknown event %s", name) + 1;
*error = malloc(len);
if (*error) {
snprintf(*error, len, "Unknown event %s", name);
}
return 0;
}
struct libinput_device *libinput_device =
wlr_libinput_get_device_handle(device->wlr_device);
return libinput_device_config_tap_get_finger_count(libinput_device) > 0;
return code;
}
const char *input_device_get_type(struct cg_input_device *device) {
switch (device->wlr_device->type) {
case WLR_INPUT_DEVICE_POINTER:
if (device_is_touchpad(device)) {
return "touchpad";
} else {
return "pointer";
}
case WLR_INPUT_DEVICE_KEYBOARD:
return "keyboard";
case WLR_INPUT_DEVICE_TOUCH:
return "touch";
case WLR_INPUT_DEVICE_TABLET_TOOL:
return "tablet_tool";
case WLR_INPUT_DEVICE_TABLET_PAD:
return "tablet_pad";
case WLR_INPUT_DEVICE_SWITCH:
return "switch";
uint32_t get_mouse_bindcode(const char *name, char **error) {
// Validate event code
errno = 0;
char *endptr;
int code = strtol(name, &endptr, 10);
if (endptr == name && code <= 0) {
*error = strdup("Button event code must be a positive integer.");
return 0;
} else if (errno == ERANGE) {
*error = strdup("Button event code out of range.");
return 0;
}
return "unknown";
const char *event = libevdev_event_code_get_name(EV_KEY, code);
if (!event || strncmp(event, "BTN_", strlen("BTN_")) != 0) {
size_t len = snprintf(NULL, 0, "Event code %d (%s) is not a button",
code, event ? event : "(null)") + 1;
*error = malloc(len);
if (*error) {
snprintf(*error, len, "Event code %d (%s) is not a button",
code, event ? event : "(null)");
}
return 0;
}
return code;
}
struct cg_input_config *input_device_get_config(struct cg_input_device *device) {
struct cg_server *server=device->server;
struct cg_input_config *wildcard_config = NULL;
struct cg_input_config *config = NULL;
wl_list_for_each(config, &server->input_config, link) {
if (strcmp(config->identifier, device->identifier) == 0) {
return config;
} else if (strcmp(config->identifier, "*") == 0) {
wildcard_config = config;
}
uint32_t input_manager_get_mouse_button(const char *name, char **error) {
uint32_t button = get_mouse_bindsym(name, error);
if (!button && !*error) {
button = get_mouse_bindcode(name, error);
}
const char *device_type = input_device_get_type(device);
wl_list_for_each(config, &server->input_config, link) {
if (strncmp(config->identifier,"type:",5)&&strcmp(config->identifier + 5, device_type) == 0) {
return config;
}
}
return wildcard_config;
return button;
}

View file

@ -10,6 +10,7 @@
struct cg_input_manager *input_manager_create(struct cg_server *server);
struct cg_input_config *input_device_get_config(struct cg_input_device *device);
void input_manager_handle_device_destroy(struct wl_listener *listener, void *data);
uint32_t input_manager_get_mouse_button(const char *name, char **error);
struct cg_input_manager {
struct wl_list devices;
@ -46,7 +47,6 @@ enum cg_input_config_mapped_to {
*/
struct cg_input_config {
char *identifier;
const char *input_type;
int accel_profile;
struct calibration_matrix calibration_matrix;
@ -67,7 +67,7 @@ struct cg_input_config {
int tap;
int tap_button_map;
char *xkb_layout;
/* char *xkb_layout;
char *xkb_model;
char *xkb_options;
char *xkb_rules;
@ -77,16 +77,16 @@ struct cg_input_config {
bool xkb_file_is_set;
int xkb_numlock;
int xkb_capslock;
int xkb_capslock;*/
struct wl_list link;
struct cg_input_config_mapped_from_region *mapped_from_region;
enum cg_input_config_mapped_to mapped_to;
char *mapped_to_output;
struct wlr_box *mapped_to_region;
/*struct wlr_box *mapped_to_region;*/
struct wl_list tools;
/*struct wl_list tools;*/
bool capturable;
struct wlr_box region;

View file

@ -12,6 +12,7 @@
#include "keybinding.h"
#include "message.h"
#include "output.h"
#include "input.h"
#include "input_manager.h"
#include "seat.h"
#include "server.h"
@ -64,6 +65,16 @@ keybinding_free(struct keybinding *keybinding, bool recursive) {
case KEYBINDING_CONFIGURE_OUTPUT:
free(keybinding->data.o_cfg->output_name);
free(keybinding->data.o_cfg);
break;
case KEYBINDING_CONFIGURE_INPUT:
free(keybinding->data.i_cfg->identifier);
if(keybinding->data.i_cfg->mapped_from_region) {
free(keybinding->data.i_cfg->mapped_from_region);
}
if(keybinding->data.i_cfg->mapped_to_output) {
free(keybinding->data.i_cfg->mapped_to_output);
}
free(keybinding->data.o_cfg);
default:
break;
}
@ -871,6 +882,12 @@ keybinding_configure_output(struct cg_server *server,
}
}
void
keybinding_configure_input(struct cg_server *server,
struct cg_input_config *cfg) {
cg_input_apply_config(cfg,server);
}
void
keybinding_configure_input_dev(struct cg_server *server, struct cg_input_config *cfg) {
@ -1001,6 +1018,9 @@ run_action(enum keybinding_action action, struct cg_server *server,
case KEYBINDING_CONFIGURE_OUTPUT:
keybinding_configure_output(server, data.o_cfg);
break;
case KEYBINDING_CONFIGURE_INPUT:
keybinding_configure_input(server, data.i_cfg);
break;
case KEYBINDING_CLOSE_VIEW:
keybinding_close_view(
server->curr_output->workspaces[server->curr_output->curr_workspace]

View file

@ -5,6 +5,7 @@
#include "config.h"
#include <stdint.h>
#include <stdbool.h>
#include <xkbcommon/xkbcommon.h>
struct cg_server;
@ -24,6 +25,8 @@ enum keybinding_action {
KEYBINDING_CYCLE_OUTPUT, // data.b is 0 if forward, 1 if reverse
KEYBINDING_CONFIGURE_OUTPUT, // data.o_cfg is the desired output
// configuration
KEYBINDING_CONFIGURE_INPUT, // data.i_cfg is the desired input
// configuration
KEYBINDING_QUIT,
KEYBINDING_NOOP,
KEYBINDING_SWITCH_WORKSPACE, // data.u is the desired workspace
@ -61,6 +64,7 @@ union keybinding_params {
float color[3];
struct keybinding *kb;
struct cg_output_config *o_cfg;
struct cg_input_config *i_cfg;
};
struct keybinding {

View file

@ -207,76 +207,137 @@ struct cg_output *output_by_name_or_id(const char *name_or_id, struct cg_server
return NULL;
}
void cg_input_configure_libinput_device(struct cg_input_device *input_device) {
struct cg_input_config *ic = input_device_get_config(input_device);
if (!ic || !wlr_input_device_is_libinput(input_device->wlr_device)) {
static bool device_is_touchpad(struct cg_input_device *device) {
if (device->wlr_device->type != WLR_INPUT_DEVICE_POINTER ||
!wlr_input_device_is_libinput(device->wlr_device)) {
return false;
}
struct libinput_device *libinput_device =
wlr_libinput_get_device_handle(device->wlr_device);
return libinput_device_config_tap_get_finger_count(libinput_device) > 0;
}
const char *input_device_get_type(struct cg_input_device *device) {
switch (device->wlr_device->type) {
case WLR_INPUT_DEVICE_POINTER:
if (device_is_touchpad(device)) {
return "touchpad";
} else {
return "pointer";
}
case WLR_INPUT_DEVICE_KEYBOARD:
return "keyboard";
case WLR_INPUT_DEVICE_TOUCH:
return "touch";
case WLR_INPUT_DEVICE_TABLET_TOOL:
return "tablet_tool";
case WLR_INPUT_DEVICE_TABLET_PAD:
return "tablet_pad";
case WLR_INPUT_DEVICE_SWITCH:
return "switch";
}
return "unknown";
}
void apply_config_to_device(struct cg_input_config *config, struct cg_input_device *input_device) {
if (!wlr_input_device_is_libinput(input_device->wlr_device)) {
return;
}
struct libinput_device *device =
wlr_libinput_get_device_handle(input_device->wlr_device);
wlr_log(WLR_DEBUG, "cg_input_configure_libinput_device('%s' on '%s')",
ic->identifier, input_device->identifier);
bool changed = false;
if (ic->mapped_to_output &&
!output_by_name_or_id(ic->mapped_to_output,input_device->server)) {
if (config->mapped_to_output &&
!output_by_name_or_id(config->mapped_to_output,input_device->server)) {
wlr_log(WLR_DEBUG,
"%s '%s' is mapped to offline output '%s'; disabling input",
ic->input_type, ic->identifier, ic->mapped_to_output);
changed |= set_send_events(device,
"'%s' is mapped to offline output '%s'; disabling input",
config->identifier, config->mapped_to_output);
set_send_events(device,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
} else if (ic->send_events != INT_MIN) {
changed |= set_send_events(device, ic->send_events);
} else if (config->send_events != INT_MIN) {
set_send_events(device, config->send_events);
} else {
// Have to reset to the default mode here, otherwise if ic->send_events
// is unset and a mapped output just came online after being disabled,
// we'd remain stuck sending no events.
changed |= set_send_events(device,
set_send_events(device,
libinput_device_config_send_events_get_default_mode(device));
}
if (ic->tap != INT_MIN) {
changed |= set_tap(device, ic->tap);
if (config->tap != INT_MIN) {
set_tap(device, config->tap);
}
if (ic->tap_button_map != INT_MIN) {
changed |= set_tap_button_map(device, ic->tap_button_map);
if (config->tap_button_map != INT_MIN) {
set_tap_button_map(device, config->tap_button_map);
}
if (ic->drag != INT_MIN) {
changed |= set_tap_drag(device, ic->drag);
if (config->drag != INT_MIN) {
set_tap_drag(device, config->drag);
}
if (ic->drag_lock != INT_MIN) {
changed |= set_tap_drag_lock(device, ic->drag_lock);
if (config->drag_lock != INT_MIN) {
set_tap_drag_lock(device, config->drag_lock);
}
if (ic->pointer_accel != FLT_MIN) {
changed |= set_accel_speed(device, ic->pointer_accel);
if (config->pointer_accel != FLT_MIN) {
set_accel_speed(device, config->pointer_accel);
}
if (ic->accel_profile != INT_MIN) {
changed |= set_accel_profile(device, ic->accel_profile);
if (config->accel_profile != INT_MIN) {
set_accel_profile(device, config->accel_profile);
}
if (ic->natural_scroll != INT_MIN) {
changed |= set_natural_scroll(device, ic->natural_scroll);
if (config->natural_scroll != INT_MIN) {
set_natural_scroll(device, config->natural_scroll);
}
if (ic->left_handed != INT_MIN) {
changed |= set_left_handed(device, ic->left_handed);
if (config->left_handed != INT_MIN) {
set_left_handed(device, config->left_handed);
}
if (ic->click_method != INT_MIN) {
changed |= set_click_method(device, ic->click_method);
if (config->click_method != INT_MIN) {
set_click_method(device, config->click_method);
}
if (ic->middle_emulation != INT_MIN) {
changed |= set_middle_emulation(device, ic->middle_emulation);
if (config->middle_emulation != INT_MIN) {
set_middle_emulation(device, config->middle_emulation);
}
if (ic->scroll_method != INT_MIN) {
changed |= set_scroll_method(device, ic->scroll_method);
if (config->scroll_method != INT_MIN) {
set_scroll_method(device, config->scroll_method);
}
if (ic->scroll_button != INT_MIN) {
changed |= set_scroll_button(device, ic->scroll_button);
if (config->scroll_button != INT_MIN) {
set_scroll_button(device, config->scroll_button);
}
if (ic->dwt != INT_MIN) {
changed |= set_dwt(device, ic->dwt);
if (config->dwt != INT_MIN) {
set_dwt(device, config->dwt);
}
if (ic->calibration_matrix.configured) {
changed |= set_calibration_matrix(device, ic->calibration_matrix.matrix);
if (config->calibration_matrix.configured) {
set_calibration_matrix(device, config->calibration_matrix.matrix);
}
}
void cg_input_apply_config(struct cg_input_config *config, struct cg_server *server) {
struct cg_input_device *device=NULL;
wl_list_for_each(device,&server->input->devices,link) {
if (strcmp(config->identifier, device->identifier) != 0&&strcmp(config->identifier, "*") != 0) {
continue;
}
const char *device_type = input_device_get_type(device);
if (strncmp(config->identifier,"type:",5)==0&&strcmp(config->identifier + 5, device_type) != 0) {
continue;
}
apply_config_to_device(config,device);
}
}
void cg_input_configure_libinput_device(struct cg_input_device *input_device) {
struct cg_server *server=input_device->server;
struct cg_input_config *config = NULL;
wl_list_for_each(config, &server->input_config, link) {
if (strcmp(config->identifier, input_device->identifier) != 0&&strcmp(config->identifier, "*") != 0) {
continue;
}
const char *device_type = input_device_get_type(input_device);
if (!(strncmp(config->identifier,"type:",5)&&strcmp(config->identifier + 5, device_type) == 0)) {
continue;
}
apply_config_to_device(config,input_device);
}
}

View file

@ -65,6 +65,7 @@ pango = dependency('pango')
pangocairo = dependency('pangocairo')
fontconfig = dependency('fontconfig')
libinput = dependency('libinput')
libevdev = dependency('libevdev')
libudev = dependency('libudev')
math = cc.find_library('m')
@ -191,6 +192,7 @@ cagebreak_dependencies_dict = {
'xkbcommon': [xkbcommon,true],
'fontconfig': [fontconfig,true],
'libinput': [libinput,true],
'libevdev': [libevdev,true],
'libudev': [libudev,true],
'pixman': [pixman,true],
'pango': [pango,true],
@ -208,6 +210,7 @@ reproducible_build_versions = {
'xkbcommon': '1.3.0',
'fontconfig': '2.13.94',
'libinput': '2.13.94',
'libevdev': '2.13.94',
'libudev': '2.13.94',
'pixman': '0.40.0',
'pango': '1.48.7',

264
parse.c
View file

@ -1,11 +1,14 @@
#define _POSIX_C_SOURCE 200812L
#include <limits.h>
#include <float.h>
#include <string.h>
#include <wlr/util/log.h>
#include <libinput.h>
#include "keybinding.h"
#include "output.h"
#include "input_manager.h"
#include "parse.h"
#include "server.h"
@ -106,6 +109,242 @@ parse_keybinding(struct cg_server *server, char **saveptr, char **errstr) {
return keybinding;
}
float
parse_float(char **saveptr, const char *delim) {
char *uint_str = strtok_r(NULL, delim, saveptr);
if(uint_str == NULL) {
wlr_log(WLR_ERROR, "Expected a float, got nothing");
return -1;
}
float ufloat = strtof(uint_str, NULL);
if(ufloat != NAN && ufloat != INFINITY && errno!=ERANGE) {
return ufloat;
} else {
wlr_log(WLR_ERROR, "Error parsing float");
return FLT_MIN;
}
}
struct cg_input_config *
parse_input_config(char **saveptr, char **errstr) {
struct cg_input_config *cfg = calloc(1,sizeof(struct cg_input_config));
char *value=NULL;
char *ident = NULL;
if(cfg == NULL) {
*errstr =
log_error("Failed to allocate memory for output configuration");
goto error;
}
cfg->tap = INT_MIN;
cfg->tap_button_map = INT_MIN;
cfg->drag = INT_MIN;
cfg->drag_lock = INT_MIN;
cfg->dwt = INT_MIN;
cfg->send_events = INT_MIN;
cfg->click_method = INT_MIN;
cfg->middle_emulation = INT_MIN;
cfg->natural_scroll = INT_MIN;
cfg->accel_profile = INT_MIN;
cfg->pointer_accel = FLT_MIN;
cfg->scroll_factor = FLT_MIN;
cfg->scroll_button = INT_MIN;
cfg->scroll_method = INT_MIN;
cfg->left_handed = INT_MIN;
cfg->repeat_delay = INT_MIN;
cfg->repeat_rate = INT_MIN;
/*cfg->xkb_numlock = INT_MIN;
cfg->xkb_capslock = INT_MIN;
cfg->xkb_file_is_set = false;
wl_list_init(&cfg->tools);*/
ident = strtok_r(NULL, " ", saveptr);
if(ident == NULL) {
*errstr = log_error("Expected identifier of input device to configure, got none");
goto error;
}
cfg->identifier=strdup(ident);
char *setting = strtok_r(NULL, " ", saveptr);
if(setting == NULL) {
*errstr =
log_error("Expected setting to be set on input device, got none");
goto error;
}
value = strdup(*saveptr);
if(value == NULL) {
*errstr =
log_error("Failed to obtain value for input device configuration of device \"%s\"",ident);
goto error;
}
if(strcmp(setting,"accel_profile") == 0) {
if(strcmp(value,"adaptive") == 0) {
cfg->accel_profile=LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
} else if(strcmp(value,"flat") == 0) {
cfg->accel_profile=LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT;
} else {
*errstr = log_error("Invalid profile \"%s\" for accel_profile configuration", value);
goto error;
}
} else if(strcmp(setting,"calibration_matrix") == 0) {
cfg->calibration_matrix.configured=true;
for(int i=0;i<6;++i) {
cfg->calibration_matrix.matrix[i]=parse_float(saveptr," ");
if(cfg->calibration_matrix.matrix[i]==FLT_MIN) {
*errstr = log_error("Failed to read calibration matrix, expected 6 floating point values separated by spaces");
goto error;
}
}
} else if(strcmp(setting,"click_method") == 0) {
if(strcmp(value,"none")) {
cfg->click_method=LIBINPUT_CONFIG_CLICK_METHOD_NONE;
} else if(strcmp(value,"button_areas")) {
cfg->click_method=LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
} else if(strcmp(value,"clickfinger")) {
cfg->click_method=LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
} else {
*errstr = log_error("Invalid method \"%s\" for click_method configuration", value);
goto error;
}
} else if(strcmp(setting,"drag") == 0) {
if(strcmp(value,"enabled") == 0) {
cfg->drag=LIBINPUT_CONFIG_DRAG_ENABLED;
} else if(strcmp(value,"disabled") == 0) {
cfg->drag=LIBINPUT_CONFIG_DRAG_DISABLED;
} else {
*errstr = log_error("Invalid option \"%s\" to setting \"drag\"", value);
goto error;
}
} else if(strcmp(setting,"drag_lock") == 0) {
if(strcmp(value,"enabled") == 0) {
cfg->drag_lock=LIBINPUT_CONFIG_DRAG_LOCK_ENABLED;
} else if(strcmp(value,"disabled") == 0) {
cfg->drag_lock=LIBINPUT_CONFIG_DRAG_LOCK_DISABLED;
} else {
*errstr = log_error("Invalid option \"%s\" to setting \"drag_lock\"", value);
goto error;
}
} else if(strcmp(setting,"dwt") == 0) {
if(strcmp(value,"enabled") == 0) {
cfg->dwt=LIBINPUT_CONFIG_DWT_ENABLED;
} else if(strcmp(value,"disabled") == 0) {
cfg->dwt=LIBINPUT_CONFIG_DWT_DISABLED;
} else {
*errstr = log_error("Invalid option \"%s\" to setting \"dwt\"", value);
goto error;
}
} else if(strcmp(setting,"events") == 0) {
if(strcmp(value,"enabled") == 0) {
cfg->send_events=LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
} else if(strcmp(value,"disabled") == 0) {
cfg->send_events=LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
} else if(strcmp(value,"disabled_on_external_mouse") == 0) {
cfg->send_events=LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
} else {
*errstr = log_error("Invalid option \"%s\" to setting \"events\"", value);
goto error;
}
} else if(strcmp(setting,"left_handed") == 0) {
if(strcmp(value,"enabled") == 0) {
cfg->left_handed=true;
} else if(strcmp(value,"disabled") == 0) {
cfg->left_handed=false;
} else {
*errstr = log_error("Invalid option \"%s\" to setting \"left_handed\"", value);
goto error;
}
} else if(strcmp(setting,"middle_emulation") == 0) {
if(strcmp(value,"enabled") == 0) {
cfg->middle_emulation=LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED;
} else if(strcmp(value,"disabled") == 0) {
cfg->middle_emulation=LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED;
} else {
*errstr = log_error("Invalid option \"%s\" to setting \"middle_emulation\"", value);
goto error;
}
} else if(strcmp(setting,"natural_scroll") == 0) {
if(strcmp(value,"enabled") == 0) {
cfg->natural_scroll=true;
} else if(strcmp(value,"disabled") == 0) {
cfg->natural_scroll=false;
} else {
*errstr = log_error("Invalid option \"%s\" to setting \"natural_scroll\"", value);
goto error;
}
} else if(strcmp(setting,"pointer_accel") == 0) {
cfg->pointer_accel=parse_float(saveptr, " ");
if(cfg->pointer_accel==FLT_MIN) {
*errstr = log_error("Invalid option \"%s\" to setting \"pointer_accel\", expected float value", value);
goto error;
}
} else if(strcmp(setting,"scroll_button") == 0) {
char *err=NULL;
cfg->scroll_button=input_manager_get_mouse_button(value,&err);
if(err) {
*errstr = log_error("Error parsing button for \"scroll_button\" setting. Returned error \"%s\"", err);
goto error;
}
} else if(strcmp(setting,"scroll_factor") == 0) {
cfg->scroll_factor=parse_float(saveptr, " ");
if(cfg->scroll_factor==FLT_MIN) {
*errstr = log_error("Invalid option \"%s\" to setting \"scroll_factor\", expected float value", value);
goto error;
}
} else if(strcmp(setting,"scroll_method") == 0) {
if(strcmp(value,"none") == 0) {
cfg->scroll_method=LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
} else if(strcmp(value,"two_finger") == 0) {
cfg->scroll_method=LIBINPUT_CONFIG_SCROLL_2FG;
} else if(strcmp(value,"edge") == 0) {
cfg->scroll_method=LIBINPUT_CONFIG_SCROLL_EDGE;
} else if(strcmp(value,"on_button_down") == 0) {
cfg->scroll_method=LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN;
} else {
*errstr = log_error("Invalid option \"%s\" to setting \"scroll_method\"", value);
goto error;
}
} else if(strcmp(setting,"tap") == 0) {
if(strcmp(value,"enabled") == 0) {
cfg->tap=LIBINPUT_CONFIG_TAP_ENABLED;
} else if(strcmp(value,"disabled") == 0) {
cfg->tap=LIBINPUT_CONFIG_TAP_DISABLED;
} else {
*errstr = log_error("Invalid option \"%s\" to setting \"tap\"", value);
goto error;
}
} else if(strcmp(setting,"tap_button_map") == 0) {
if(strcmp(value,"lrm") == 0) {
cfg->tap=LIBINPUT_CONFIG_TAP_MAP_LRM;
} else if(strcmp(value,"lmr") == 0) {
cfg->tap=LIBINPUT_CONFIG_TAP_MAP_LMR;
} else {
*errstr = log_error("Invalid option \"%s\" to setting \"tap_button_map\"", value);
goto error;
}
}
free(value);
return cfg;
error:
if(cfg) {
if(cfg->identifier) {
free(cfg->identifier);
}
free(cfg);
}
if(value) {
free(value);
}
wlr_log(WLR_ERROR,
"Input configuration must be of the form 'input \"<ident>\" <setting> <value>'");
return NULL;
}
struct keybinding *
parse_bind(struct cg_server *server, char **saveptr, char **errstr) {
struct keybinding *keybinding = parse_keybinding(server, saveptr, errstr);
@ -242,23 +481,6 @@ parse_uint(char **saveptr, const char *delim) {
}
}
float
parse_float(char **saveptr, const char *delim) {
char *uint_str = strtok_r(NULL, delim, saveptr);
if(uint_str == NULL) {
wlr_log(WLR_ERROR, "Expected a non-negative float, got nothing");
return -1;
}
float ufloat = strtof(uint_str, NULL);
if(ufloat >= 0) {
return ufloat;
} else {
wlr_log(WLR_ERROR, "Error parsing non-negative float. Must be a number "
"larger or equal to 0");
return -1;
}
}
int
parse_output_config_keyword(char *key_str, enum output_status *status) {
if(key_str == NULL) {
@ -353,7 +575,7 @@ parse_output_config(char **saveptr, char **errstr) {
cfg->refresh_rate = parse_float(saveptr, " ");
if(cfg->refresh_rate <= 0.0) {
*errstr = log_error(
"Error parsing refresh rate of output configuration for output %s",
"Error parsing refresh rate of output configuration for output %s, expected positive float",
name);
goto error;
}
@ -562,6 +784,12 @@ parse_command(struct cg_server *server, struct keybinding *keybinding,
if(keybinding->data.o_cfg == NULL) {
return -1;
}
} else if(strcmp(action, "input") == 0) {
keybinding->action = KEYBINDING_CONFIGURE_INPUT;
keybinding->data.i_cfg = parse_input_config(&saveptr, errstr);
if(keybinding->data.i_cfg == NULL) {
return -1;
}
} else {
*errstr = log_error("Error, unsupported action \"%s\".", action);
return -1;