From 8ae7f2cf5b2bf07ca8bf55fbd8b9ac931c61399e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20T=C3=B3th?= Date: Fri, 15 Oct 2021 21:04:03 +0200 Subject: [PATCH] Add some hacky PoC XLib/XInput C code to fetch slave device nodes --- xdg/get-x-slave-devnodes/Makefile | 5 + .../get-x-slave-devnodes.c | 160 ++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 xdg/get-x-slave-devnodes/Makefile create mode 100644 xdg/get-x-slave-devnodes/get-x-slave-devnodes.c diff --git a/xdg/get-x-slave-devnodes/Makefile b/xdg/get-x-slave-devnodes/Makefile new file mode 100644 index 0000000..78b1927 --- /dev/null +++ b/xdg/get-x-slave-devnodes/Makefile @@ -0,0 +1,5 @@ +get-x-slave-devnodes: get-x-slave-devnodes.c + $(CC) -O2 --std=c99 -pedantic -Wall get-x-slave-devnodes.c -o get-x-slave-devnodes -lX11 -lXi +clean: + rm -f get-x-slave-devnodes + diff --git a/xdg/get-x-slave-devnodes/get-x-slave-devnodes.c b/xdg/get-x-slave-devnodes/get-x-slave-devnodes.c new file mode 100644 index 0000000..fabb304 --- /dev/null +++ b/xdg/get-x-slave-devnodes/get-x-slave-devnodes.c @@ -0,0 +1,160 @@ +/* + * Loosely based on a mix of: + * - xorg-xinput + * https://github.com/freedesktop/xorg-xinput/blob/master/src/property.c::print_property_xi2 + * - xkbcat + * https://github.com/anko/xkbcat +*/ + +#include +#include +#include +#include +#include + +#include +#include + + +char* get_property_xi2(Display* dpy, int deviceid, Atom property, const char* property_name) +{ + Atom act_type; + char* name; + int act_format; + unsigned long nitems, bytes_after; + unsigned char* data; + unsigned char* ptr; + int j, done = False; + char* ret = NULL; + + name = XGetAtomName(dpy, property); + int interested_in_property = (strcmp(name, property_name) == 0); + XFree(name); + if (!interested_in_property) + return ret; + + if (XIGetProperty(dpy, deviceid, property, 0, 1000, False, + AnyPropertyType, &act_type, &act_format, + &nitems, &bytes_after, &data) == Success) + { + ptr = data; + for (j = 0; j < nitems; j++) + { + switch(act_type) + { + case XA_STRING: + if (act_format != 8) + { + //Unknown string format + done = True; + break; + } + + int len = strlen((char*)ptr); + ret = (char*)malloc(len+1); + strcpy(ret, (const char*)ptr); + + j += len; /* The loop's j++ jumps over the + terminating 0 */ + ptr += len; /* ptr += size below jumps over + the terminating 0 */ + break; + default: + // Unknown type + done = True; + break; + } + + ptr += act_format/8; + + if (done == True) + break; + } + XFree(data); + } + return ret; +} + + +void assert_xinput2(Display* disp) +{ + int xiOpcode; + { // Test for XInput 2 extension + int queryEvent, queryError; + if (! XQueryExtension(disp, "XInputExtension", &xiOpcode, &queryEvent, &queryError)) + { + fprintf(stderr, "X Input extension not available\n"); + exit(2); + } + } + { // Request XInput 2.0, to guard against changes in future versions + int major = 2, minor = 0; + int queryResult = XIQueryVersion(disp, &major, &minor); + if (queryResult == BadRequest) + { + fprintf(stderr, "Need XI 2.0 support (got %d.%d)\n", major, minor); + exit(3); + } + else if (queryResult != Success) + { + fprintf(stderr, "XIQueryVersion failed!\n"); + exit(4); + } + } +} + + +void print_device_nodes(Display* disp) +{ + XIDeviceInfo* all_slaves; + XIDeviceInfo* current_slave; + int num_slaves; + + all_slaves = XIQueryDevice(disp, XIAllDevices, &num_slaves); + for (int i = 0; i < num_slaves; i++) + { + current_slave = &all_slaves[i]; + + int nprops; + Atom* props; + props = XIListProperties(disp, current_slave->deviceid, &nprops); + if (!nprops) + printf("Device '%s' does not report any properties.\n", current_slave->name); + + while(nprops--) + { + char* property = get_property_xi2(disp, current_slave->deviceid, props[nprops], "Device Node"); + if (property != NULL) + { + printf("%s=%s\n", current_slave->name, property); + free(property); + } + } + XFree(props); + } + + XIFreeDeviceInfo(all_slaves); +} + + +int main(int argc, char * argv[]) +{ + char* xDisplayName = getenv("DISPLAY"); + if (xDisplayName == NULL) + { + printf("DISPLAY environment variable not found\n"); + exit(1); + } + + // Connect to X display + Display* disp = XOpenDisplay(xDisplayName); + if (NULL == disp) + { + fprintf(stderr, "Cannot open X display '%s'\n", xDisplayName); + exit(1); + } + assert_xinput2(disp); + + print_device_nodes(disp); + exit(0); +}