/* * Copyright 1996 by Frederic Lepied, France. * * 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 authors not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. The authors make no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL THE AUTHORS 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. * */ #include "xinput.h" #include #include int xi_opcode; typedef int (*prog)(Display* display, int argc, char *argv[], char *prog_name, char *prog_desc); typedef struct { char *func_name; char *arg_desc; prog func; } entry; static entry drivers[] = { {"get-feedbacks", "", get_feedbacks }, {"set-ptr-feedback", " ", set_ptr_feedback }, {"set-integer-feedback", " ", set_integer_feedback }, {"get-button-map", "", get_button_map }, {"set-button-map", " [ [...]]", set_button_map }, {"set-pointer", " [ ]", set_pointer }, {"set-mode", " ABSOLUTE|RELATIVE", set_mode }, {"list", "[--short || --long || --name-only || --id-only] [...]", list }, {"query-state", "", query_state }, {"test", "[-proximity] ", test }, #if HAVE_XI2 { "create-master", " [] []", create_master }, { "remove-master", " [Floating|AttachToMaster (dflt:Floating)] [] []", remove_master }, { "reattach", " ", change_attachment }, { "float", "", float_device }, { "set-cp", " ", set_clientpointer }, { "test-xi2", "[--root] ", test_xi2, }, { "map-to-output", " ", map_to_output, }, #endif { "list-props", " [ ...]", list_props }, { "set-int-prop", " [ ...]", set_int_prop }, { "set-float-prop", " [ ...]", set_float_prop }, { "set-atom-prop", " [ ...]", set_atom_prop }, { "watch-props", "", watch_props }, { "delete-prop", " ", delete_prop }, { "set-prop", " [--type=atom|float|int] [--format=8|16|32] [ ...]", set_prop }, { "disable", "", disable, }, { "enable", "", enable, }, {NULL, NULL, NULL } }; static const char version_id[] = VERSION; static int print_version(void) { XExtensionVersion *version; Display *display; printf("xinput version %s\n", version_id); display = XOpenDisplay(NULL); printf("XI version on server: "); if (display == NULL) printf("Failed to open display.\n"); else { version = XGetExtensionVersion(display, INAME); if (!version || (version == (XExtensionVersion*) NoSuchExtension)) printf(" Extension not supported.\n"); else { printf("%d.%d\n", version->major_version, version->minor_version); XFree(version); return 0; } } return 1; } int xinput_version(Display *display) { XExtensionVersion *version; static int vers = -1; if (vers != -1) return vers; version = XGetExtensionVersion(display, INAME); if (version && (version != (XExtensionVersion*) NoSuchExtension)) { vers = version->major_version; XFree(version); } #if HAVE_XI2 /* Announce our supported version so the server treats us correctly. */ if (vers >= XI_2_Major) { const char *forced_version; int maj = 2, min = 0; #if HAVE_XI22 min = 2; #elif HAVE_XI21 min = 1; #endif forced_version = getenv("XINPUT_XI2_VERSION"); if (forced_version) { if (sscanf(forced_version, "%d.%d", &maj, &min) != 2) { fprintf(stderr, "Invalid format of XINPUT_XI2_VERSION " "environment variable. Need major.minor\n"); exit(1); } printf("Overriding XI2 version to: %d.%d\n", maj, min); } XIQueryVersion(display, &maj, &min); } #endif return vers; } XDeviceInfo* find_device_info(Display *display, char *name, Bool only_extended) { XDeviceInfo *devices; XDeviceInfo *found = NULL; int loop; int num_devices; int len = strlen(name); Bool is_id = True; XID id = (XID)-1; for(loop=0; loop= IsXExtensionDevice)) && ((!is_id && strcmp(devices[loop].name, name) == 0) || (is_id && devices[loop].id == id))) { if (found) { fprintf(stderr, "Warning: There are multiple devices named '%s'.\n" "To ensure the correct one is selected, please use " "the device ID instead.\n\n", name); return NULL; } else { found = &devices[loop]; } } } return found; } #if HAVE_XI2 Bool is_pointer(int use) { return use == XIMasterPointer || use == XISlavePointer; } Bool is_keyboard(int use) { return use == XIMasterKeyboard || use == XISlaveKeyboard; } Bool device_matches(XIDeviceInfo *info, char *name) { if (strcmp(info->name, name) == 0) { return True; } if (strncmp(name, "pointer:", strlen("pointer:")) == 0 && strcmp(info->name, name + strlen("pointer:")) == 0 && is_pointer(info->use)) { return True; } if (strncmp(name, "keyboard:", strlen("keyboard:")) == 0 && strcmp(info->name, name + strlen("keyboard:")) == 0 && is_keyboard(info->use)) { return True; } return False; } XIDeviceInfo* xi2_find_device_info(Display *display, char *name) { XIDeviceInfo *info; XIDeviceInfo *found = NULL; int ndevices; Bool is_id = True; int i, id = -1; for(i = 0; i < strlen(name); i++) { if (!isdigit(name[i])) { is_id = False; break; } } if (is_id) { id = atoi(name); } info = XIQueryDevice(display, XIAllDevices, &ndevices); for(i = 0; i < ndevices; i++) { if (is_id ? info[i].deviceid == id : device_matches (&info[i], name)) { if (found) { fprintf(stderr, "Warning: There are multiple devices matching '%s'.\n" "To ensure the correct one is selected, please use " "the device ID, or prefix the\ndevice name with " "'pointer:' or 'keyboard:' as appropriate.\n\n", name); XIFreeDeviceInfo(info); return NULL; } else { found = &info[i]; } } } return found; } #endif static void usage(void) { entry *pdriver = drivers; fprintf(stderr, "usage :\n"); while(pdriver->func_name) { fprintf(stderr, "\txinput %s %s\n", pdriver->func_name, pdriver->arg_desc); pdriver++; } } static Bool is_xwayland(Display *dpy) { XDeviceInfo *devices; int n; Bool is_xwayland = False; devices = XListInputDevices(dpy, &n); while (n-- > 0) { if (strncmp(devices[n].name, "xwayland-", 9) == 0) { is_xwayland = True; break; } } XFreeDeviceList(devices); return is_xwayland; } int main(int argc, char * argv[]) { Display *display; entry *driver = drivers; char *func; int event, error; if (argc > 1) { func = argv[1]; while(func[0] == '-') func++; } else { func = "list"; } if (strcmp("version", func) == 0) { return print_version(); } if (strcmp("help", func) == 0) { usage(); return 0; } display = XOpenDisplay(NULL); if (display == NULL) { fprintf(stderr, "Unable to connect to X server\n"); goto out; } if (!XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &error)) { printf("X Input extension not available.\n"); goto out; } if (!xinput_version(display)) { fprintf(stderr, "%s extension not available\n", INAME); goto out; } if (is_xwayland(display)) fprintf(stderr, "WARNING: running xinput against an Xwayland server. See the xinput man page for details.\n"); while(driver->func_name) { if (strcmp(driver->func_name, func) == 0) { int r = (*driver->func)(display, argc-2, argv+2, driver->func_name, driver->arg_desc); XSync(display, False); XCloseDisplay(display); return r; } driver++; } usage(); out: if (display) XCloseDisplay(display); return EXIT_FAILURE; } /* end of xinput.c */