From d628819b66f6e5b8d63899a0fcdf8a725c24c239 Mon Sep 17 00:00:00 2001 From: Paolo D'Apice Date: Mon, 15 Apr 2013 10:13:38 +0800 Subject: [PATCH] Added "--rotate" option After support for the Coordinate Transformation Matrix has been added to relative devices, in order to set axes rotation (see #27688) one has to manually set the matrix. The "rotate" option just set the proper transformation matrix with only the rotation components set. Signed-off-by: Paolo D'Apice --- configure.ac | 1 + man/xinput.man | 8 +++++ src/Makefile.am | 2 +- src/transform.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/xinput.c | 4 +++ src/xinput.h | 1 + 6 files changed, 114 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f53a81f..49b85e3 100644 --- a/configure.ac +++ b/configure.ac @@ -26,6 +26,7 @@ AC_INIT([xinput], [1.6.0], [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg], [xinput]) AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_HEADERS([config.h]) +AC_CHECK_HEADERS([math.h]) # Initialize Automake AM_INIT_AUTOMAKE([foreign dist-bzip2]) diff --git a/man/xinput.man b/man/xinput.man index 540308b..42516a5 100644 --- a/man/xinput.man +++ b/man/xinput.man @@ -158,6 +158,14 @@ Enable the \fIdevice\fP. This call is equivalent to Disable the \fIdevice\fP. This call is equivalent to .B xinput --set-prop device \fI"Device Enabled"\fP 0 .PP +.TP 8 +.B --rotate \fIdevice\fP \fIangle\fP +Apply a rotation of \fIangle\fP degrees to the pointer motion of +relative \fIdevice\fP. +A positive value means clockwise rotation, a negative value means +counter-clockwise rotation. +This option can be applied on relative devices only. +.PP \fIdevice\fP can be the device name as a string or the XID of the device. .PP diff --git a/src/Makefile.am b/src/Makefile.am index 985207b..c103330 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,7 +23,7 @@ bin_PROGRAMS = xinput AM_CFLAGS = $(XINPUT_CFLAGS) -xinput_LDADD = $(XINPUT_LIBS) +xinput_LDADD = $(XINPUT_LIBS) -lm if HAVE_XI2 diff --git a/src/transform.c b/src/transform.c index f80a592..09a5b93 100644 --- a/src/transform.c +++ b/src/transform.c @@ -24,6 +24,7 @@ #include "xinput.h" +#include #include #include #include @@ -168,6 +169,25 @@ find_output_xrandr(Display *dpy, const char *output_name) return output_info; } +static void +set_rotation_matrix(Matrix *m, float rotation) +{ + float radians = fmodf(rotation, 360.0) * M_PI / 180.0; + float cosine = cos(radians); + float sine = sin(radians); + + matrix_set_unity(m); + + matrix_set(m, 0, 0, cosine); + matrix_set(m, 0, 1, -sine); + matrix_set(m, 1, 0, sine); + matrix_set(m, 1, 1, cosine); + +#if DEBUG + matrix_print(m); +#endif +} + static int map_output_xrandr(Display *dpy, int deviceid, const char *output_name) { @@ -287,3 +307,82 @@ map_to_output(Display *dpy, int argc, char *argv[], char *name, char *desc) return map_output_xrandr(dpy, info->deviceid, output_name); } + +/* In XInput.h there is XSetDeviceMode but not XGetDeviceMode. + * The following code is taken from the query_state function + * in state.c */ +static int +is_absolute_device(Display *dpy, XDevice *device) +{ + XDeviceState *state; + XInputClass *cls; + XValuatorState *val_state; + int loop; + int rc = 0; + + state = XQueryDeviceState(dpy, device); + if (state) { + cls = state->data; + for(loop = 0; loop < state->num_classes; loop++) { + if (cls->class == ValuatorClass) { + val_state = (XValuatorState *) cls; + if (val_state->mode & 1) { + rc = 1; + break; + } + } + cls = (XInputClass *) ((char *) cls + cls->length); + } + XFreeDeviceState(state); + } + + return rc; +} + +int +rotate(Display *dpy, int argc, char *argv[], char *name, char *desc) +{ + XIDeviceInfo *info; + XDevice *device; + char *endptr; + float rotation; + Matrix m; + int rc = EXIT_FAILURE; + + if (argc < 2) + { + fprintf(stderr, "Usage: xinput %s %s\n", name, desc); + return EXIT_FAILURE; + } + + info = xi2_find_device_info(dpy, argv[0]); + if (!info) + { + fprintf(stderr, "unable to find device %s\n", argv[0]); + return EXIT_FAILURE; + } + + /* Do not apply rotate on absolute devices */ + device = XOpenDevice(dpy, info->deviceid); + if (!device) + { + fprintf(stderr, "unable to open device %s\n", argv[0]); + return EXIT_FAILURE; + } + if (is_absolute_device(dpy, device)) + { + fprintf(stderr, "not supported for absolute devices\n"); + return EXIT_FAILURE; + } + + rotation = strtof(argv[1], &endptr); + if (endptr == argv[1]) { + fprintf(stderr, "argument %s could not be parsed\n", argv[1]); + return EXIT_FAILURE; + } + + set_rotation_matrix(&m, rotation); + rc = apply_matrix(dpy, info->deviceid, &m); + + return rc; +} diff --git a/src/xinput.c b/src/xinput.c index 0f86720..cc7829c 100644 --- a/src/xinput.c +++ b/src/xinput.c @@ -108,6 +108,10 @@ static entry drivers[] = " ", map_to_output, }, + { "rotate", + " ", + rotate, + }, #endif { "list-props", " [ ...]", diff --git a/src/xinput.h b/src/xinput.h index c37e6e6..627d556 100644 --- a/src/xinput.h +++ b/src/xinput.h @@ -80,5 +80,6 @@ int float_device( Display* display, int argc, char *argv[], char *prog_name, cha int set_clientpointer( Display* display, int argc, char *argv[], char *prog_name, char *prog_desc); int test_xi2( Display* display, int argc, char *argv[], char *prog_name, char *prog_desc); int map_to_output( Display* display, int argc, char *argv[], char *prog_name, char *prog_desc); +int rotate( Display* display, int argc, char *argv[], char *prog_name, char *prog_desc); /* end of xinput.h */ -- 1.7.9.5