Add some hacky PoC XLib/XInput C code to fetch slave device nodes
This commit is contained in:
		
							
								
								
									
										5
									
								
								xdg/get-x-slave-devnodes/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								xdg/get-x-slave-devnodes/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										160
									
								
								xdg/get-x-slave-devnodes/get-x-slave-devnodes.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								xdg/get-x-slave-devnodes/get-x-slave-devnodes.c
									
									
									
									
									
										Normal file
									
								
							@@ -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 <string.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <X11/extensions/XInput2.h>
 | 
				
			||||||
 | 
					#include <X11/Xatom.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user