]> diplodocus.org Git - xorg-xinput/blobdiff - src/xinput.c
xinput 1.6.3
[xorg-xinput] / src / xinput.c
index 6f416191bd68f0f3eb0896d681a2a6b3542bc04a..7b27ffeb42d466d7b33411060215bf6b18af1d0b 100644 (file)
 #include <ctype.h>
 #include <string.h>
 
-typedef int (*prog)(
-#if NeedFunctionPrototypes
-                   Display* display, int argc, char *argv[],
-                   char *prog_name, char *prog_desc
-#endif
-);
+int xi_opcode;
+
+typedef int (*prog)(Display* display, int argc, char *argv[],
+                   char *prog_name, char *prog_desc);
 
 typedef struct
 {
@@ -70,7 +68,7 @@ static entry drivers[] =
      set_mode
     },
     {"list",
-     "[--loop || --short || <device name>...]",
+     "[--short || --long || --name-only || --id-only] [<device name>...]",
      list
     },
     {"query-state",
@@ -81,17 +79,13 @@ static entry drivers[] =
      "[-proximity] <device name>",
      test
     },
-    {"version",
-     "",
-     version
-    },
 #if HAVE_XI2
     { "create-master",
-      "<id> [sendCore (dflt:1)] [enable (dflt:1)]",
+      "<id> [<sendCore (dflt:1)>] [<enable (dflt:1)>]",
       create_master
     },
     { "remove-master",
-      "<id> [returnMode (dflt:Floating)] [returnPointer] [returnKeyboard]",
+      "<id> [Floating|AttachToMaster (dflt:Floating)] [<returnPointer>] [<returnKeyboard>]",
       remove_master
     },
     { "reattach",
@@ -106,6 +100,14 @@ static entry drivers[] =
       "<window> <device>",
       set_clientpointer
     },
+    { "test-xi2",
+      "[--root] <device>",
+      test_xi2,
+    },
+    { "map-to-output",
+      "<device> <output name>",
+      map_to_output,
+    },
 #endif
     { "list-props",
       "<device> [<device> ...]",
@@ -119,6 +121,10 @@ static entry drivers[] =
       "<device> <property> <val> [<val> ...]",
       set_float_prop
     },
+    { "set-atom-prop",
+      "<device> <property> <val> [<val> ...]",
+      set_atom_prop
+    },
     { "watch-props",
       "<device>",
       watch_props
@@ -127,29 +133,100 @@ static entry drivers[] =
       "<device> <property>",
       delete_prop
     },
-    {0, 0, 0
+    { "set-prop",
+      "<device> [--type=atom|float|int] [--format=8|16|32] <property> <val> [<val> ...]",
+      set_prop
+    },
+    {
+      "disable",
+      "<device>",
+      disable,
+    },
+    {
+      "enable",
+      "<device>",
+      enable,
+    },
+    {NULL, NULL, NULL
     }
 };
 
-static Bool
-is_xinput_present(Display      *display)
+static const char version_id[] = VERSION;
+
+static int
+print_version(void)
 {
     XExtensionVersion  *version;
-    Bool               present;
+    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;
 
-#if HAVE_XI2
-    version = XQueryInputVersion(display, XI_2_Major, XI_2_Minor);
-#else
     version = XGetExtensionVersion(display, INAME);
-#endif
 
     if (version && (version != (XExtensionVersion*) NoSuchExtension)) {
-       present = version->present;
+       vers = version->major_version;
        XFree(version);
-       return present;
-    } else {
-       return False;
     }
+
+#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*
@@ -163,7 +240,7 @@ find_device_info(Display    *display,
     int                num_devices;
     int                len = strlen(name);
     Bool       is_id = True;
-    XID                id;
+    XID                id = (XID)-1;
 
     for(loop=0; loop<len; loop++) {
        if (!isdigit(name[loop])) {
@@ -184,9 +261,10 @@ find_device_info(Display   *display,
             (is_id && devices[loop].id == id))) {
            if (found) {
                fprintf(stderr,
-                       "Warning: There are multiple devices named \"%s\".\n"
+                       "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];
            }
@@ -195,6 +273,80 @@ find_device_info(Display   *display,
     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)
 {
@@ -209,38 +361,76 @@ usage(void)
     }
 }
 
+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 (argc < 2) {
-       usage();
-       return EXIT_FAILURE;
+    if (strcmp("help", func) == 0) {
+        usage();
+        return 0;
     }
 
     display = XOpenDisplay(NULL);
 
     if (display == NULL) {
        fprintf(stderr, "Unable to connect to X server\n");
-       return EXIT_FAILURE;
+       goto out;
     }
 
-    func = argv[1];
-    while((*func) == '-') func++;
+    if (!XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &error)) {
+        printf("X Input extension not available.\n");
+        goto out;
+    }
 
-    if (!is_xinput_present(display)) {
+    if (!xinput_version(display)) {
        fprintf(stderr, "%s extension not available\n", INAME);
-       return EXIT_FAILURE;
+       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++;
@@ -248,6 +438,9 @@ main(int argc, char * argv[])
 
     usage();
 
+out:
+    if (display)
+        XCloseDisplay(display);
     return EXIT_FAILURE;
 }