tools: add a tool to list local devices and the default configurations

xinput or an equivalent isn't available under wayland, but the majority of
use-cases of "why doesn't my device work" or "why does feature X not work"
should be covered by simply listing the local devices and their config
options.

Example output:

Device:         SynPS/2 Synaptics TouchPad
Kernel:         /dev/input/event4
Group:          9
Seat:           seat0, default
Size:           97.33x62.40mm
Capabilities:   pointer
Tap-to-click:   disabled
Left-handed:    disabled
Nat.scrolling:  disabled
Calibration:    n/a
Scroll methods: *two-finger
Click methods:  *button-areas clickfinger

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
Peter Hutterer 2015-04-15 11:44:54 +10:00
parent 120199514b
commit c74d07bee9
4 changed files with 326 additions and 0 deletions

1
tools/.gitignore vendored
View file

@ -1,3 +1,4 @@
event-debug
event-gui
ptraccel-debug
libinput-list-devices

View file

@ -1,4 +1,5 @@
noinst_PROGRAMS = event-debug ptraccel-debug
bin_PROGRAMS = libinput-list-devices
noinst_LTLIBRARIES = libshared.la
AM_CPPFLAGS = -I$(top_srcdir)/include \
@ -18,6 +19,11 @@ ptraccel_debug_SOURCES = ptraccel-debug.c
ptraccel_debug_LDADD = ../src/libfilter.la
ptraccel_debug_LDFLAGS = -no-install
libinput_list_devices_SOURCES = libinput-list-devices.c
libinput_list_devices_LDADD = ../src/libinput.la libshared.la $(LIBUDEV_LIBS)
libinput_list_devices_CFLAGS = $(LIBUDEV_CFLAGS)
man1_MANS = libinput-list-devices.man
if BUILD_EVENTGUI
noinst_PROGRAMS += event-gui

View file

@ -0,0 +1,282 @@
/*
* Copyright © 2015 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of the copyright holders not be used in
* advertising or publicity pertaining to distribution of the software
* without specific, written prior permission. The copyright holders make
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <libudev.h>
#include <libinput.h>
#include "shared.h"
static int
open_restricted(const char *path, int flags, void *user_data)
{
int fd = open(path, flags);
if (fd < 0)
fprintf(stderr, "Failed to open %s (%s)\n",
path, strerror(errno));
return fd < 0 ? -errno : fd;
}
static void
close_restricted(int fd, void *user_data)
{
close(fd);
}
static const struct libinput_interface interface = {
.open_restricted = open_restricted,
.close_restricted = close_restricted,
};
static inline const char*
bool_to_str(bool b)
{
if (b)
return "yes";
else
return "no";
}
static const char *
tap_default(struct libinput_device *device)
{
if (!libinput_device_config_tap_get_finger_count(device))
return "n/a";
if (libinput_device_config_tap_get_default_enabled(device))
return "enabled";
else
return "disabled";
}
static const char*
left_handed_default(struct libinput_device *device)
{
if (!libinput_device_config_left_handed_is_available(device))
return "n/a";
if (libinput_device_config_left_handed_get_default(device))
return "enabled";
else
return "disabled";
}
static const char *
nat_scroll_default(struct libinput_device *device)
{
if (!libinput_device_config_scroll_has_natural_scroll(device))
return "n/a";
if (libinput_device_config_scroll_get_default_natural_scroll_enabled(device))
return "enabled";
else
return "disabled";
}
static char *
calibration_default(struct libinput_device *device)
{
char *str;
float calibration[6];
if (!libinput_device_config_calibration_has_matrix(device)) {
asprintf(&str, "n/a");
return str;
}
if (libinput_device_config_calibration_get_default_matrix(device,
calibration) == 0) {
asprintf(&str, "identity matrix");
return str;
}
asprintf(&str,
"%.2f %.2f %.2f %.2f %.2f %.2f",
calibration[0],
calibration[1],
calibration[2],
calibration[3],
calibration[4],
calibration[5]);
return str;
}
static char *
scroll_defaults(struct libinput_device *device)
{
uint32_t scroll_methods;
char *str;
enum libinput_config_scroll_method method;
scroll_methods = libinput_device_config_scroll_get_methods(device);
if (scroll_methods == LIBINPUT_CONFIG_SCROLL_NO_SCROLL) {
asprintf(&str, "none");
return str;
}
method = libinput_device_config_scroll_get_default_method(device);
asprintf(&str,
"%s%s%s%s%s%s",
(method == LIBINPUT_CONFIG_SCROLL_2FG) ? "*" : "",
(scroll_methods & LIBINPUT_CONFIG_SCROLL_2FG) ? "two-finger " : "",
(method == LIBINPUT_CONFIG_SCROLL_EDGE) ? "*" : "",
(scroll_methods & LIBINPUT_CONFIG_SCROLL_EDGE) ? "edge " : "",
(method == LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) ? "*" : "",
(scroll_methods & LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) ? "button" : "");
return str;
}
static char*
click_defaults(struct libinput_device *device)
{
uint32_t click_methods;
char *str;
enum libinput_config_click_method method;
click_methods = libinput_device_config_click_get_methods(device);
if (click_methods == LIBINPUT_CONFIG_CLICK_METHOD_NONE) {
asprintf(&str, "none");
return str;
}
method = libinput_device_config_click_get_default_method(device);
asprintf(&str,
"%s%s%s%s",
(method == LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS) ? "*" : "",
(click_methods & LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS) ? "button-areas " : "",
(method == LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER) ? "*" : "",
(click_methods & LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER) ? "clickfinger " : "");
return str;
}
static void
print_device_notify(struct libinput_event *ev)
{
struct libinput_device *dev = libinput_event_get_device(ev);
struct libinput_seat *seat = libinput_device_get_seat(dev);
struct libinput_device_group *group;
double w, h;
static int next_group_id = 0;
intptr_t group_id;
const char *devnode;
char *str;
group = libinput_device_get_device_group(dev);
group_id = (intptr_t)libinput_device_group_get_user_data(group);
if (!group_id) {
group_id = ++next_group_id;
libinput_device_group_set_user_data(group, (void*)group_id);
}
devnode = udev_device_get_devnode(
libinput_device_get_udev_device(dev));
printf("Device: %s\n"
"Kernel: %s\n"
"Group: %d\n"
"Seat: %s, %s\n",
libinput_device_get_name(dev),
devnode,
(int)group_id,
libinput_seat_get_physical_name(seat),
libinput_seat_get_logical_name(seat));
if (libinput_device_get_size(dev, &w, &h) == 0)
printf("Size: %.2fx%.2fmm\n", w, h);
printf("Capabilities: ");
if (libinput_device_has_capability(dev,
LIBINPUT_DEVICE_CAP_KEYBOARD))
printf("keyboard ");
if (libinput_device_has_capability(dev,
LIBINPUT_DEVICE_CAP_POINTER))
printf("pointer ");
if (libinput_device_has_capability(dev,
LIBINPUT_DEVICE_CAP_TOUCH))
printf("touch");
printf("\n");
printf("Tap-to-click: %s\n", tap_default(dev));
printf("Left-handed: %s\n", left_handed_default(dev));
printf("Nat.scrolling: %s\n", nat_scroll_default(dev));
str = calibration_default(dev);
printf("Calibration: %s\n", str);
free(str);
str = scroll_defaults(dev);
printf("Scroll methods: %s\n", str);
free(str);
str = click_defaults(dev);
printf("Click methods: %s\n", str);
free(str);
printf("\n");
}
int
main(int argc, char **argv)
{
struct libinput *li;
struct tools_options options;
struct libinput_event *ev;
if (argc > 1) {
printf("Usage: %s [--help]\n"
"\n"
"This tool creates a libinput context on the default seat \"seat0\"\n"
"and lists all devices recognized by libinput and the configuration options.\n"
"Where multiple options are possible, the default is prefixed with \"*\".\n"
"\n"
"This tool requires access to the /dev/input/eventX nodes.\n",
program_invocation_short_name);
return 1;
}
tools_init_options(&options);
li = tools_open_backend(&options, NULL, &interface);
if (!li)
return 1;
libinput_dispatch(li);
while ((ev = libinput_get_event(li))) {
if (libinput_event_get_type(ev) == LIBINPUT_EVENT_DEVICE_ADDED)
print_device_notify(ev);
libinput_event_destroy(ev);
libinput_dispatch(li);
}
libinput_unref(li);
return 0;
}

View file

@ -0,0 +1,37 @@
.TH LIBINPUT-LIST_DEVICES "1"
.SH NAME
libinput-list-devices \- list local devices as recognized by libinput
.SH SYNOPSIS
.B libinput-list-devices [--help]
.SH DESCRIPTION
.PP
The
.I libinput-list-devices
tool creates a libinput context on the default seat "seat0" and lists all
devices regonized by libinput. Each device shows available configurations
the respective default configuration setting.
.PP
For configuration options that allow multiple different settings (e.g.
scrolling), all available settings are listed. The default setting is
prefixed by an asterisk (*).
.PP
This tool usually needs to be run as root to have access to the
/dev/input/eventX nodes.
.SH OPTIONS
.TP 8
.B --help
Print help
.SH NOTES
.PP
Some specific feature may still be available on a device even when
no configuration is exposed, a lack of a configuration option does not
necessarily mean that this feature does not work.
.PP
A device may be recognized by libinput but not handled by the X.Org libinput
driver or the Wayland compositor.
.PP
An xorg.conf(5) configuration entry or Wayland compositor setting may have
changed configurations on a device. The
.I libinput-list-devices
tool only shows the device's default configuration, not the current
configuration.