XDevice* device_is_touchpad (XDeviceInfo deviceinfo) { XDevice *device; Atom realtype, prop; int realformat; unsigned long nitems, bytes_after; unsigned char *data; if (deviceinfo.type != XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XI_TOUCHPAD, False)) return NULL; prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Off", False); if (!prop) return NULL; gdk_error_trap_push (); device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), deviceinfo.id); if (gdk_error_trap_pop () || (device == NULL)) return NULL; gdk_error_trap_push (); if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device, prop, 0, 1, False, XA_INTEGER, &realtype, &realformat, &nitems, &bytes_after, &data) == Success) && (realtype != None)) { gdk_error_trap_pop (); XFree (data); return device; } gdk_error_trap_pop (); XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device); return NULL; }
static XDevice * dp_get_device(Display * dpy) { XDevice *dev = NULL; XDeviceInfo *info = NULL; int ndevices = 0; Atom touchpad_type = 0; Atom synaptics_property = 0; Atom *properties = NULL; int nprops = 0; int error = 0; touchpad_type = XInternAtom(dpy, XI_TOUCHPAD, True); synaptics_property = XInternAtom(dpy, SYNAPTICS_PROP_EDGES, True); info = XListInputDevices(dpy, &ndevices); while (ndevices--) { if (info[ndevices].type == touchpad_type) { dev = XOpenDevice(dpy, info[ndevices].id); if (!dev) { fprintf(stderr, "Failed to open device '%s'.\n", info[ndevices].name); error = 1; goto unwind; } properties = XListDeviceProperties(dpy, dev, &nprops); if (!properties || !nprops) { fprintf(stderr, "No properties on device '%s'.\n", info[ndevices].name); error = 1; goto unwind; } while (nprops--) { if (properties[nprops] == synaptics_property) break; } if (!nprops) { fprintf(stderr, "No synaptics properties on device '%s'.\n", info[ndevices].name); error = 1; goto unwind; } break; /* Yay, device is suitable */ } } unwind: XFree(properties); XFreeDeviceList(info); if (!dev) fprintf(stderr, "Unable to find a synaptics device.\n"); else if (error && dev) { XCloseDevice(dpy, dev); dev = NULL; } return dev; }
int check_device(XDeviceInfo *info) { XDevice *device; Atom type; int format; unsigned long nitems, nbytes; unsigned char *retval; if (verbose) printf("Checking device %lu: %s...", info->id, info->name); device = XOpenDevice(display, info->id); XGetDeviceProperty(display, device, prop_calibration, 0, 4, False, XA_INTEGER, &type, &format, &nitems, &nbytes, &retval); XCloseDevice(display, device); if (nitems != 4) { if (verbose) printf("can't be calibrated\n"); return False; } if (verbose) printf("can be calibrated\n"); return True; }
static int delete_prop_xi1(Display *dpy, int argc, char** argv, char* n, char *desc) { XDevice *dev; XDeviceInfo *info; char *name; Atom prop; info = find_device_info(dpy, argv[0], False); if (!info) { fprintf(stderr, "unable to find device %s\n", argv[0]); return EXIT_FAILURE; } dev = XOpenDevice(dpy, info->id); if (!dev) { fprintf(stderr, "unable to open device '%s'\n", info->name); return EXIT_FAILURE; } name = argv[1]; prop = parse_atom(dpy, name); XDeleteDeviceProperty(dpy, dev, prop); XCloseDevice(dpy, dev); return EXIT_SUCCESS; }
static int register_events(Display *dpy, XDeviceInfo *info, char *dev_name, Bool handle_proximity) { int number = 0; /* number of events registered */ XEventClass event_list[7]; int i; XDevice *device; Window root_win; unsigned long screen; XInputClassInfo *ip; screen = DefaultScreen(dpy); root_win = RootWindow(dpy, screen); device = XOpenDevice(dpy, info->id); if (!device) { fprintf(stderr, "unable to open device '%s'\n", dev_name); return 0; } if (device->num_classes > 0) { for (ip = device->classes, i=0; i<info->num_classes; ip++, i++) { switch (ip->input_class) { case KeyClass: DeviceKeyPress(device, key_press_type, event_list[number]); number++; DeviceKeyRelease(device, key_release_type, event_list[number]); number++; break; case ButtonClass: DeviceButtonPress(device, button_press_type, event_list[number]); number++; DeviceButtonRelease(device, button_release_type, event_list[number]); number++; break; case ValuatorClass: DeviceMotionNotify(device, motion_type, event_list[number]); number++; if (handle_proximity) { ProximityIn(device, proximity_in_type, event_list[number]); number++; ProximityOut(device, proximity_out_type, event_list[number]); number++; } break; default: fprintf(stderr, "unknown class\n"); break; } } if (XSelectExtensionEvent(dpy, root_win, event_list, number)) { fprintf(stderr, "error selecting extended events\n"); return 0; } } return number; }
static gboolean find_synaptics (void) { gboolean ret = FALSE; #ifdef HAVE_XINPUT int numdevices, i; XDeviceInfo *devicelist; Atom realtype, prop; int realformat; unsigned long nitems, bytes_after; unsigned char *data; XExtensionVersion *version; /* Input device properties require version 1.5 or higher */ version = XGetExtensionVersion (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "XInputExtension"); if (!version->present || (version->major_version * 1000 + version->minor_version) < 1005) { XFree (version); return False; } prop = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Synaptics Off", True); if (!prop) return False; devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), &numdevices); for (i = 0; i < numdevices; i++) { if (devicelist[i].use != IsXExtensionPointer) continue; gdk_error_trap_push(); XDevice *device = XOpenDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), devicelist[i].id); if (gdk_error_trap_pop ()) continue; gdk_error_trap_push (); if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, prop, 0, 1, False, XA_INTEGER, &realtype, &realformat, &nitems, &bytes_after, &data) == Success) && (realtype != None)) { XFree (data); ret = TRUE; } gdk_error_trap_pop (); XCloseDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device); if (ret) break; } XFree (version); XFreeDeviceList (devicelist); #endif return ret; }
bool KeyMonitor::registerEvents() { unsigned long screen; Window window; XDeviceInfo *devices; int num_devices; int i, j; XDevice *device; XInputClassInfo *info; XEventClass event_class; m_display = XOpenDisplay(NULL); screen = DefaultScreen(m_display); window = RootWindow(m_display, screen); devices = XListInputDevices(m_display, &num_devices); for(i=0; i<num_devices; i++) { device = XOpenDevice(m_display, devices[i].id); if (device == NULL) { /* That's not critical since "Virtual core..." devices don't allow opening. */ UQ_DEBUG << "Could not open device: " << devices[i].name; continue; } if (devices[i].use == IsXExtensionKeyboard) { for (info=device->classes, j=0; j < device->num_classes; j++, info++) { if (info->input_class == KeyClass) { DeviceKeyPress(device, key_press_type, event_class); m_eventList.append(event_class); DeviceMappingNotify(device, notify_type, event_class); m_eventList.append(event_class); } } } } if (m_eventList.size() == 0) { UQ_WARNING << "No input devices found."; return false; } if (XSelectExtensionEvent(m_display, window, m_eventList.data(), m_eventList.size())) { UQ_WARNING << "Error selecting events."; return false; } return true; }
static void synaptics_check_capabilities (GtkBuilder *dialog) { #ifdef HAVE_XINPUT int numdevices, i; XDeviceInfo *devicelist; Atom realtype, prop; int realformat; unsigned long nitems, bytes_after; unsigned char *data; prop = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Synaptics Capabilities", True); if (!prop) return; devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), &numdevices); for (i = 0; i < numdevices; i++) { if (devicelist[i].use != IsXExtensionPointer) continue; gdk_error_trap_push (); XDevice *device = XOpenDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), devicelist[i].id); if (gdk_error_trap_pop ()) continue; gdk_error_trap_push (); if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, prop, 0, 2, False, XA_INTEGER, &realtype, &realformat, &nitems, &bytes_after, &data) == Success) && (realtype != None)) { /* Property data is booleans for has_left, has_middle, * has_right, has_double, has_triple */ if (!data[0]) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (WID ("tap_to_click_toggle")), TRUE); gtk_widget_set_sensitive (WID ("tap_to_click_toggle"), FALSE); } if (!data[3]) gtk_widget_set_sensitive (WID ("scroll_twofinger_radio"), FALSE); XFree (data); } gdk_error_trap_pop (); XCloseDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device); } XFreeDeviceList (devicelist); #endif }
static int list_props_xi1(Display *dpy, int argc, char** argv, char* name, char *desc) { XDeviceInfo *info; XDevice *dev; int i; int nprops; Atom *props; if (argc == 0) { fprintf(stderr, "Usage: xinput %s %s\n", name, desc); return EXIT_FAILURE; } for (i = 0; i < argc; i++) { info = find_device_info(dpy, argv[i], False); if (!info) { fprintf(stderr, "unable to find device %s\n", argv[i]); continue; } dev = XOpenDevice(dpy, info->id); if (!dev) { fprintf(stderr, "unable to open device '%s'\n", info->name); continue; } props = XListDeviceProperties(dpy, dev, &nprops); if (!nprops) { printf("Device '%s' does not report any properties.\n", info->name); continue; } printf("Device '%s':\n", info->name); while(nprops--) { print_property(dpy, dev, props[nprops]); } XFree(props); XCloseDevice(dpy, dev); } return EXIT_SUCCESS; }
static void synaptics_check_capabilities (GtkBuilder *dialog) { int numdevices, i; XDeviceInfo *devicelist; Atom realtype, prop; int realformat; unsigned long nitems, bytes_after; unsigned char *data; prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Capabilities", True); if (!prop) return; devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &numdevices); for (i = 0; i < numdevices; i++) { if (devicelist[i].use != IsXExtensionPointer) continue; gdk_error_trap_push (); XDevice *device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), devicelist[i].id); if (gdk_error_trap_pop ()) continue; gdk_error_trap_push (); if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device, prop, 0, 2, False, XA_INTEGER, &realtype, &realformat, &nitems, &bytes_after, &data) == Success) && (realtype != None)) { /* Property data is booleans for has_left, has_middle, has_right, has_double, has_triple. * Newer drivers (X.org/kerrnel) will also include has_pressure and has_width. */ if (!data[0]) { gtk_widget_set_sensitive (WID ("tap_to_click_toggle"), FALSE); } /* Disable two finger scrolling unless the hardware supports * double touch */ if (!(data[3])) gtk_widget_set_sensitive (WID ("two_finger_scroll_toggle"), FALSE); XFree (data); } gdk_error_trap_pop_ignored (); XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device); } XFreeDeviceList (devicelist); }
static gboolean device_type_is_present (InfoIdentifyFunc info_func, DeviceIdentifyFunc device_func) { XDeviceInfo *device_info; gint n_devices; guint i; gboolean retval; if (supports_xinput_devices () == FALSE) return TRUE; retval = FALSE; device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices); if (device_info == NULL) return FALSE; for (i = 0; i < n_devices; i++) { XDevice *device; /* Check with the device info first */ retval = (info_func) (&device_info[i]); if (retval == FALSE) continue; /* If we only have an info func, we're done checking */ if (device_func == NULL) break; gdk_error_trap_push (); device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device_info[i].id); if (gdk_error_trap_pop () || (device == NULL)) continue; retval = (device_func) (device); if (retval) { XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device); break; } XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device); } XFreeDeviceList (device_info); return retval; }
int watch_props(Display *dpy, int argc, char** argv, char* n, char *desc) { XDevice *dev; XDeviceInfo *info; XEvent ev; XDevicePropertyNotifyEvent *dpev; char *name; int type_prop; XEventClass cls_prop; if (list_props(dpy, argc, argv, n, desc) != EXIT_SUCCESS) return EXIT_FAILURE; info = find_device_info(dpy, argv[0], False); if (!info) { fprintf(stderr, "unable to find device %s\n", argv[0]); return EXIT_FAILURE; } dev = XOpenDevice(dpy, info->id); if (!dev) { fprintf(stderr, "unable to open device '%s'\n", info->name); return EXIT_FAILURE; } DevicePropertyNotify(dev, type_prop, cls_prop); XSelectExtensionEvent(dpy, DefaultRootWindow(dpy), &cls_prop, 1); while(1) { XNextEvent(dpy, &ev); dpev = (XDevicePropertyNotifyEvent*)&ev; if (dpev->type != type_prop) continue; name = XGetAtomName(dpy, dpev->atom); printf("Property '%s' changed.\n", name); print_property(dpy, dev, dpev->atom); } XCloseDevice(dpy, dev); }
int set_pointer(Display *display, int argc, char *argv[], char *name, char *desc) { XDeviceInfo *info; XDevice *device; int xaxis = 0; int yaxis = 1; if ((argc != 1) && (argc != 3)) { fprintf(stderr, "usage: xinput %s %s\n", name, desc); return EXIT_FAILURE; } if (argc == 3) { xaxis = atoi(argv[1]); yaxis = atoi(argv[2]); } info = find_device_info(display, argv[0], True); if (!info) { fprintf(stderr, "unable to find device %s\n", argv[0]); return EXIT_FAILURE; } device = XOpenDevice(display, info->id); if (device) { XChangePointerDevice(display, device, xaxis, yaxis); return EXIT_SUCCESS; } else { fprintf(stderr, "Unable to open device\n"); return EXIT_FAILURE; } }
void executeCommand(Display *dpy, XDeviceInfo *info, const char *command, unsigned char data) { if (!info) { fprintf(stderr, "unable to find the device\n"); return; } XDevice *dev = XOpenDevice(dpy, info->id); if (!dev) { fprintf(stderr, "unable to open the device\n"); return; } Atom prop = XInternAtom(dpy, command, False); XChangeDeviceProperty(dpy, dev, prop, XA_INTEGER, 8, PropModeReplace, &data, 1); XCloseDevice(dpy, dev); }
XDevice* device_is_touchpad (XDeviceInfo *deviceinfo) { GdkDisplay *display; XDevice *device; display = gdk_display_get_default (); if (deviceinfo->type != XInternAtom (GDK_DISPLAY_XDISPLAY (display), XI_TOUCHPAD, True)) return NULL; gdk_x11_display_error_trap_push (display); device = XOpenDevice (GDK_DISPLAY_XDISPLAY (display), deviceinfo->id); if (gdk_x11_display_error_trap_pop (display) || (device == NULL)) return NULL; if (device_has_property (device, "libinput Tapping Enabled") || device_has_property (device, "Synaptics Off")) { return device; } XCloseDevice (GDK_DISPLAY_XDISPLAY (display), device); return NULL; }
gboolean touchpad_is_present (void) { XDeviceInfo *device_info; gint n_devices; guint i; gboolean retval; if (supports_xinput_devices () == FALSE) return TRUE; retval = FALSE; device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices); if (device_info == NULL) return FALSE; for (i = 0; i < n_devices; i++) { XDevice *device; gdk_error_trap_push (); device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device_info[i].id); if (gdk_error_trap_pop () || (device == NULL)) continue; retval = device_is_touchpad (device); if (retval) { XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device); break; } XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device); } XFreeDeviceList (device_info); return retval; }
static int probeDevices(void) { static Bool been_here = False; static int support; #if !defined(WIN32) XExtensionVersion *version; XDeviceInfoPtr device_info, device; XAnyClassPtr any; XButtonInfoPtr b; XValuatorInfoPtr v; XAxisInfoPtr a; int num_dev, btns, dials; int i, j, k; #endif /* !WIN32 */ if (been_here) { return support; } been_here = True; #if !defined(WIN32) version = XGetExtensionVersion(__glutDisplay, "XInputExtension"); if (version == NULL || ((int) version) == NoSuchExtension) { support = 0; return support; } XFree(version); device_info = XListInputDevices(__glutDisplay, &num_dev); if (device_info) { for (i = 0; i < num_dev; i++) { /* XXX These are SGI names for these devices; unfortunately, no good standard exists for standard types of X input extension devices. */ device = &device_info[i]; any = (XAnyClassPtr) device->inputclassinfo; if (!__glutSpaceball && !strcmp(device->name, "spaceball")) { v = NULL; b = NULL; for (j = 0; j < device->num_classes; j++) { switch (any->class) { case ButtonClass: b = (XButtonInfoPtr) any; btns = b->num_buttons; break; case ValuatorClass: v = (XValuatorInfoPtr) any; /* Sanity check: at least 6 valuators? */ if (v->num_axes < NUM_SPACEBALL_AXIS) goto skip_device; a = (XAxisInfoPtr) ((char *) v + sizeof(XValuatorInfo)); for (k = 0; k < NUM_SPACEBALL_AXIS; k++, a++) { __glutSpaceballRange[k].min = a->min_value; __glutSpaceballRange[k].range = a->max_value - a->min_value; } break; } any = (XAnyClassPtr) ((char *) any + any->length); } if (v) { __glutSpaceball = XOpenDevice(__glutDisplay, device->id); if (__glutSpaceball) { __glutNumSpaceballButtons = btns; addDeviceEventParser(); } } } else if (!__glutDials && !strcmp(device->name, "dial+buttons")) { v = NULL; b = NULL; for (j = 0; j < device->num_classes; j++) { switch (any->class) { case ButtonClass: b = (XButtonInfoPtr) any; btns = b->num_buttons; break; case ValuatorClass: v = (XValuatorInfoPtr) any; /* Sanity check: at least 8 valuators? */ if (v->num_axes < NUM_DIALS_AXIS) goto skip_device; dials = v->num_axes; __glutDialsResolution = (int *) malloc(sizeof(int) * dials); a = (XAxisInfoPtr) ((char *) v + sizeof(XValuatorInfo)); for (k = 0; k < dials; k++, a++) { __glutDialsResolution[k] = a->resolution; } break; } any = (XAnyClassPtr) ((char *) any + any->length); } if (v) { __glutDials = XOpenDevice(__glutDisplay, device->id); if (__glutDials) { __glutNumButtonBoxButtons = btns; __glutNumDials = dials; addDeviceEventParser(); } } } else if (!__glutTablet && !strcmp(device->name, "tablet")) {
int main(int argc, char *argv[], char *env[]) { char *display_name = NULL; char *device_name = NULL; char *output_name = NULL; XSetWindowAttributes xswa; int i = 0; double a, a1, a2, b, b1, b2, xerr, yerr; int xi_opcode, event, error; XExtensionVersion *version; XDeviceInfo *info; XDevice *device; long calib_data[4]; unsigned long mask; unsigned char swap; int keep_cursor = 0, ch; /* Crosshair placement */ int cpx[] = { 0, 0, 1, 1, 1 }; int cpy[] = { 0, 1, 0, 0, 1 }; while ((ch = getopt(argc, argv, "cD:d:o:v")) != -1) { switch (ch) { case 'c': keep_cursor++; break; case 'D': display_name = optarg; break; case 'd': device_name = optarg; break; case 'o': output_name = optarg; break; case 'v': verbose = True; break; default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc != 0) usage(); /* connect to X server */ if ((display = XOpenDisplay(display_name)) == NULL) { fprintf(stderr, "%s: cannot connect to X server %s\n", __progname, XDisplayName(display_name)); exit(1); } screen = DefaultScreen(display); root = RootWindow(display, screen); /* get screen size from display structure macro */ xpos = 0; ypos = 0; width = DisplayWidth(display, screen); height = DisplayHeight(display, screen); if (XRRQueryExtension(display, &event, &error)) { int major, minor; if (XRRQueryVersion(display, &major, &minor) != True) { fprintf(stderr, "Error querying XRandR version"); } else { printf("XRandR extension version %d.%d present\n", major, minor); has_xrandr = True; if (major > 1 || (major == 1 && minor >=2)) has_xrandr_1_2 = True; if (major > 1 || (major == 1 && minor >=3)) has_xrandr_1_3 = True; } } if (output_name != NULL) { if (has_xrandr_1_2) { get_xrandr_config(display, root, output_name, &xpos, &ypos, &width, &height); } else { fprintf(stderr, "%s: can not specify an output " "whithout XRandr 1.2 or later", __progname); exit(2); } } if (!XQueryExtension(display, INAME, &xi_opcode, &event, &error)) { fprintf(stderr, "%s: X Input extension not available.\n", __progname); exit(1); } version = XGetExtensionVersion(display, INAME); if (version == NULL || version == (XExtensionVersion *)NoSuchExtension) { fprintf(stderr, "Cannot query X Input version.\n"); exit(1); } XFree(version); prop_calibration = XInternAtom(display, WS_PROP_CALIBRATION, True); if (prop_calibration == None) { fprintf(stderr, "Unable to find the \"%s\" device property.\n" "There are probably no calibrable devices " "on this system.\n", WS_PROP_CALIBRATION); exit(1); } prop_swap = XInternAtom(display, WS_PROP_SWAP_AXES, True); if (prop_swap == None) { fprintf(stderr, "Unable to find the \"%s\" device property\n", WS_PROP_SWAP_AXES); exit(1); } info = find_device_info(device_name); if (info == NULL) { fprintf(stderr, "Unable to find the %s device\n", device_name ? device_name : "default"); exit(1); } /* setup window attributes */ xswa.override_redirect = True; xswa.background_pixel = BlackPixel(display, screen); xswa.event_mask = ExposureMask | KeyPressMask; mask = CWOverrideRedirect | CWBackPixel | CWEventMask; if (!keep_cursor) { xswa.cursor = create_empty_cursor(); mask |= CWCursor; } win = XCreateWindow(display, RootWindow(display, screen), xpos, ypos, width, height, 0, CopyFromParent, InputOutput, CopyFromParent, mask, &xswa); render_init(); XMapWindow(display, win); XGrabKeyboard(display, win, False, GrabModeAsync, GrabModeAsync, CurrentTime); XGrabServer(display); XClearWindow(display, win); if (verbose) printf("Calibrating %s\n", info->name); device = XOpenDevice(display, info->id); if (!device) { fprintf(stderr, "Unable to open the X input device \"%s\"\n", info->name); return 0; } if (!register_events(info, device, 0)) exit(1); uncalibrate(device); calib: XftDrawRect(draw, &bg, 0, 0, width, height); for (i = 0; i < 5; i++) { draw_graphics(cpx[i], cpy[i], i); XFlush(display); if (!get_events(i)) break; XftDrawRect(draw, &bg, 0, 0, width, height); } if (interrupted) cleanup_exit(device); /* Check if X and Y should be swapped */ if (fabs(x[0] - x[1]) > fabs(y[0] - y[1])) { calib.swapxy = 1; for (i = 0; i < 5; i++) { int t = x[i]; x[i] = y[i]; y[i] = t; } } /* get touch pad resolution to screen resolution ratio */ a1 = (double) (x[4] - x[0]) / (double) (cx[4] - cx[0]); a2 = (double) (x[3] - x[1]) / (double) (cx[3] - cx[1]); /* get the minimum pad position on the X-axis */ b1 = x[0] - a1 * cx[0]; b2 = x[1] - a2 * cx[1]; /* use the average ratio and average minimum position */ a = (a1 + a2) / 2.0; b = (b1 + b2) / 2.0; xerr = a * width / 2 + b - x[2]; if (fabs(xerr) > fabs(a * width * .01)) { fprintf(stderr, "Calibration problem: X axis error (%.2f) too high, try again\n", fabs(xerr)); goto err; } calib.minx = (int) (b + 0.5); calib.maxx = (int) (a * width + b + 0.5); /* get touch pad resolution to screen resolution ratio */ a1 = (double) (y[4] - y[0]) / (double) (cy[4] - cy[0]); a2 = (double) (y[3] - y[1]) / (double) (cy[3] - cy[1]); /* get the minimum pad position on the Y-axis */ b1 = y[0] - a1 * cy[0]; b2 = y[1] - a2 * cy[1]; /* use the average ratio and average minimum position */ a = (a1 + a2) / 2.0; b = (b1 + b2) / 2.0; yerr = a * height / 2 + b - y[2]; if (fabs(yerr) > fabs(a * height * 0.01)) { fprintf(stderr, "Calibration problem: Y axis error (%.2f) too high, try again\n", fabs(yerr)); goto err; } calib.miny = (int) (b + 0.5); calib.maxy = (int) (a * height + b + 0.5); XFlush(display); calib.resx = width; calib.resy = height; /* Send new values to the X server */ calib_data[0] = calib.minx; calib_data[1] = calib.maxx; calib_data[2] = calib.miny; calib_data[3] = calib.maxy; XChangeDeviceProperty(display, device, prop_calibration, XA_INTEGER, 32, PropModeReplace, (unsigned char *)calib_data, 4); swap = calib.swapxy; XChangeDeviceProperty(display, device, prop_swap, XA_INTEGER, 8, PropModeReplace, (unsigned char *)&swap, 1); XCloseDevice(display, device); XCloseDisplay(display); /* And print them for storage in wsconsctl.conf */ printf("mouse.scale=%d,%d,%d,%d,%d,%d,%d\n", calib.minx, calib.maxx, calib.miny, calib.maxy, calib.swapxy, calib.resx, calib.resy); return 0; err: draw_text(error_message, &errorColor); XFlush(display); sleep(2); goto calib; }
int main(int argc, char * argv[]) { int loop, num_extensions, num_devices; char **extensions; XDeviceInfo *devices; Display *dpy; Window root_win; unsigned long screen; int list = 0; if (argc != 2) { fprintf(stderr, "usage : %s (-l | <device name>)\n", argv[0]); exit(1); } if (strcmp(argv[1], "-l") == 0) { list = 1; } dpy = XOpenDisplay(NULL); if (!dpy) { printf("unable to connect to X Server try to set the DISPLAY variable\n"); exit(1); } #ifdef DEBUG printf("connected to %s\n", XDisplayString(dpy)); #endif screen = DefaultScreen(dpy); root_win = RootWindow(dpy, screen); extensions = XListExtensions(dpy, &num_extensions); for (loop = 0; loop < num_extensions && (strcmp(extensions[loop], "XInputExtension") != 0); loop++); XFreeExtensionList(extensions); if (loop != num_extensions) { devices = XListInputDevices(dpy, &num_devices); for(loop=0; loop<num_devices; loop++) { if (list) { printf("\"%s\" [", devices[loop].name ? devices[loop].name : "<noname>"); switch(devices[loop].use) { case IsXPointer: printf("XPointer]\n"); break; case IsXKeyboard: printf("XKeyboard]\n"); break; case IsXExtensionDevice: printf("XExtensionDevice]\n"); break; default: printf("invalid value]\n"); break; } } else { if ((argc == 2) && devices[loop].name && (StrCaseCmp(devices[loop].name, argv[1]) == 0)) if (devices[loop].use == IsXExtensionDevice) { XDevice *device; #ifdef DEBUG fprintf(stderr, "opening device %s\n", devices[loop].name ? devices[loop].name : "<noname>"); #endif device = XOpenDevice(dpy, devices[loop].id); if (device) { XChangePointerDevice(dpy, device, 0, 1); exit(0); } else { fprintf(stderr, "error opening device\n"); exit(1); } } } } XFreeDeviceList(devices); } else { fprintf(stderr, "No XInput extension available\n"); exit(1); } if (list) { exit(0); } else { fprintf(stderr, "Extended device %s not found\n", argv[1]); exit(1); } }
JNIEXPORT void JNICALL Java_com_turbovnc_vncviewer_Viewport_setupExtInput (JNIEnv *env, jobject obj) { jclass cls, eidcls; jfieldID fid; jmethodID mid; Display *dpy = NULL; Window win = 0; XDeviceInfo *devInfo = NULL; XDevice *device = NULL; int nDevices = 0, i, ci, ai, nEvents = 0; int buttonPressType = -1, buttonReleaseType = -1, motionType = -1; XEventClass events[100] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; jobject extInputDevice; if ((dpy = XOpenDisplay(NULL)) == NULL) _throw("Could not open X display"); bailif0(cls = (*env)->GetObjectClass(env, obj)); bailif0(fid = (*env)->GetFieldID(env, cls, "x11win", "J")); if ((win = (Window)(*env)->GetLongField(env, obj, fid)) == 0) _throw("X window handle has not been initialized"); if ((devInfo = XListInputDevices(dpy, &nDevices)) == NULL) _throw("Could not list XI devices"); for (i = 0; i < nDevices; i++) { char *type; XAnyClassPtr classInfo = devInfo[i].inputclassinfo; CARD32 canGenerate = 0, productID = 0; if (devInfo[i].use != IsXExtensionPointer) continue; if (devInfo[i].type == None) continue; type = XGetAtomName(dpy, devInfo[i].type); if (!strcmp(type, "MOUSE")) { XFree(type); continue; } /* TurboVNC-specific: we use productID to represent the device type, so we can recreate it on the server */ if (!strcmp(type, "CURSOR")) productID = rfbGIIDevTypeCursor; else if (!strcmp(type, "STYLUS")) productID = rfbGIIDevTypeStylus; else if (!strcmp(type, "ERASER")) productID = rfbGIIDevTypeEraser; else if (!strcmp(type, "TOUCH")) productID = rfbGIIDevTypeTouch; else if (!strcmp(type, "PAD")) productID = rfbGIIDevTypePad; XFree(type); bailif0(eidcls = (*env)->FindClass(env, "com/turbovnc/rfb/ExtInputDevice")); bailif0(extInputDevice = (*env)->AllocObject(env, eidcls)); SET_STRING(eidcls, extInputDevice, name, devInfo[i].name); SET_LONG(eidcls, extInputDevice, vendorID, 4242); SET_LONG(eidcls, extInputDevice, productID, productID); SET_LONG(eidcls, extInputDevice, id, devInfo[i].id); for (ci = 0; ci < devInfo[i].num_classes; ci++) { switch (classInfo->class) { case ButtonClass: { XButtonInfoPtr b = (XButtonInfoPtr)classInfo; SET_INT(eidcls, extInputDevice, numButtons, b->num_buttons); canGenerate |= rfbGIIButtonPressMask | rfbGIIButtonReleaseMask; break; } case ValuatorClass: { XValuatorInfoPtr v = (XValuatorInfoPtr)classInfo; jclass valcls; bailif0(valcls = (*env)->FindClass(env, "com/turbovnc/rfb/ExtInputDevice$Valuator")); if (v->mode == Absolute) canGenerate |= rfbGIIValuatorAbsoluteMask; else if (v->mode == Relative) canGenerate |= rfbGIIValuatorRelativeMask; for (ai = 0; ai < v->num_axes; ai++) { jobject valuator; XAxisInfoPtr a = &v->axes[ai]; char longName[75], shortName[5]; bailif0(valuator = (*env)->AllocObject(env, valcls)); SET_INT(valcls, valuator, index, ai); snprintf(longName, 75, "Valuator %d", ai); SET_STRING(valcls, valuator, longName, longName); snprintf(shortName, 5, "%d", ai); SET_STRING(valcls, valuator, shortName, shortName); SET_INT(valcls, valuator, rangeMin, a->min_value); SET_INT(valcls, valuator, rangeCenter, (a->min_value + a->max_value) / 2); SET_INT(valcls, valuator, rangeMax, a->max_value); SET_INT(valcls, valuator, siUnit, rfbGIIUnitLength); SET_INT(valcls, valuator, siDiv, a->resolution); bailif0(mid = (*env)->GetMethodID(env, eidcls, "addValuator", "(Lcom/turbovnc/rfb/ExtInputDevice$Valuator;)V")); (*env)->CallVoidMethod(env, extInputDevice, mid, valuator); } break; } } classInfo = (XAnyClassPtr)((char *)classInfo + classInfo->length); } SET_LONG(eidcls, extInputDevice, canGenerate, canGenerate); if (canGenerate & rfbGIIValuatorAbsoluteMask) SET_BOOL(eidcls, extInputDevice, absolute, 1); if ((device = XOpenDevice(dpy, devInfo[i].id)) == NULL) _throw("Could not open XI device"); for (ci = 0; ci < device->num_classes; ci++) { if (device->classes[ci].input_class == ButtonClass) { DeviceButtonPress(device, buttonPressType, events[nEvents]); nEvents++; DeviceButtonRelease(device, buttonReleaseType, events[nEvents]); nEvents++; } else if (device->classes[ci].input_class == ValuatorClass) { DeviceMotionNotify(device, motionType, events[nEvents]); nEvents++; } } XCloseDevice(dpy, device); device=NULL; bailif0(mid = (*env)->GetMethodID(env, cls, "addInputDevice", "(Lcom/turbovnc/rfb/ExtInputDevice;)V")); (*env)->CallVoidMethod(env, obj, mid, extInputDevice); } XFreeDeviceList(devInfo); devInfo = NULL; if (nEvents == 0) { printf("No extended input devices.\n"); goto bailout; } if (XSelectExtensionEvent(dpy, win, events, nEvents)) _throw("Could not select XI events"); SET_INT(cls, obj, buttonPressType, buttonPressType); SET_INT(cls, obj, buttonReleaseType, buttonReleaseType); SET_INT(cls, obj, motionType, motionType); SET_LONG(cls, obj, x11dpy, (jlong)dpy); printf("TurboVNC Helper: Listening for XInput events on %s (window 0x%.8x)\n", DisplayString(dpy), (unsigned int)win); bailout: if (dpy && device) XCloseDevice(dpy, device); if (devInfo) XFreeDeviceList(devInfo); }
// Constructor CalibratorEvdev::CalibratorEvdev(const char* const device_name0, const XYinfo& axys0, XID device_id, const int thr_misclick, const int thr_doubleclick, const OutputType output_type, const char* geometry, const bool use_valuator, const bool use_timeout, const char* output_filename) : Calibrator(device_name0, axys0, thr_misclick, thr_doubleclick, output_type, geometry, use_timeout, output_filename) { // init display = XOpenDisplay(NULL); if (display == NULL) { throw WrongCalibratorException("Evdev: Unable to connect to X server"); } // normaly, we already have the device id if (device_id == (XID)-1) { devInfo = xinput_find_device_info(display, device_name, False); if (!devInfo) { XCloseDisplay(display); throw WrongCalibratorException("Evdev: Unable to find device"); } device_id = devInfo->id; } dev = XOpenDevice(display, device_id); if (!dev) { XCloseDisplay(display); throw WrongCalibratorException("Evdev: Unable to open device"); } #ifndef HAVE_XI_PROP throw WrongCalibratorException("Evdev: you need at least libXi 1.2 and inputproto 1.5 for dynamic recalibration of evdev."); #else // XGetDeviceProperty vars Atom property; Atom act_type; int act_format; unsigned long nitems, bytes_after; unsigned char *data, *ptr; // get "Evdev Axis Calibration" property property = xinput_parse_atom(display, "Evdev Axis Calibration"); if (XGetDeviceProperty(display, dev, property, 0, 1000, False, AnyPropertyType, &act_type, &act_format, &nitems, &bytes_after, &data) != Success) { XCloseDevice(display, dev); XCloseDisplay(display); throw WrongCalibratorException("Evdev: \"Evdev Axis Calibration\" property missing, not a (valid) evdev device"); } else { if (act_format != 32 || act_type != XA_INTEGER) { XCloseDevice(display, dev); XCloseDisplay(display); throw WrongCalibratorException("Evdev: invalid \"Evdev Axis Calibration\" property format"); } else if (use_valuator) { int ndevices = 0, i, j; XIDeviceInfo *info = XIQueryDevice(display, device_id, &ndevices); if (ndevices != 1) { XCloseDevice(display, dev); XCloseDisplay(display); throw WrongCalibratorException("Evdev: unknown Xinput device ID???"); } for (i = 0; i < ndevices; i++) { XIDeviceInfo *dev = &info[i]; for (j = 0; j < dev->num_classes; j++) { switch(dev->classes[i]->type) { case XIValuatorClass: { XIValuatorClassInfo *v = (XIValuatorClassInfo*)dev->classes[i]; /* Valuator 0 = X, Valuator 1 = Y, others are ignored */ switch (v->number) { case 0: old_axys.x.min = v->min; old_axys.x.max = v->max; old_axys.x.invert = false; break; case 1: old_axys.y.min = v->min; old_axys.y.max = v->max; old_axys.y.invert = false; break; default: break; } break; } default: break; } } } XIFreeDeviceInfo(info); if (verbose) printf("DEBUG: Evdev Axis Calibration set to axis valuators\n"); (void) set_calibration(old_axys); } else if (nitems == 0) { if (verbose) printf("DEBUG: Evdev Axis Calibration not set, setting to axis valuators to be sure.\n"); // No axis calibration set, set it to the default one // QUIRK: when my machine resumes from a sleep, // the calibration property is no longer exported through xinput, but still active // not setting the values here would result in a wrong first calibration (void) set_calibration(old_axys); } else if (nitems > 0) { ptr = data; old_axys.x.min = *((long*)ptr); ptr += sizeof(long); old_axys.x.max = *((long*)ptr); ptr += sizeof(long); old_axys.y.min = *((long*)ptr); ptr += sizeof(long); old_axys.y.max = *((long*)ptr); ptr += sizeof(long); } XFree(data); } // get "Evdev Axes Swap" property property = xinput_parse_atom(display, "Evdev Axes Swap"); if (XGetDeviceProperty(display, dev, property, 0, 1000, False, AnyPropertyType, &act_type, &act_format, &nitems, &bytes_after, &data) == Success) { if (act_format == 8 && act_type == XA_INTEGER && nitems == 1) { old_axys.swap_xy = *((char*)data); if (verbose) printf("DEBUG: Read axes swap value of %i.\n", old_axys.swap_xy); } } // get "Evdev Axes Inversion" property property = xinput_parse_atom(display, "Evdev Axis Inversion"); if (XGetDeviceProperty(display, dev, property, 0, 1000, False, AnyPropertyType, &act_type, &act_format, &nitems, &bytes_after, &data) == Success) { if (act_format == 8 && act_type == XA_INTEGER && nitems == 2) { old_axys.x.invert = *((char*)data++); old_axys.y.invert = *((char*)data); if (verbose) printf("DEBUG: Read InvertX=%i, InvertY=%i.\n", old_axys.x.invert, old_axys.y.invert); } } printf("Calibrating EVDEV driver for \"%s\" id=%i\n", device_name, (int)device_id); printf("\tcurrent calibration values (from XInput): min_x=%d, max_x=%d and min_y=%d, max_y=%d\n", old_axys.x.min, old_axys.x.max, old_axys.y.min, old_axys.y.max); #endif // HAVE_XI_PROP }
int main (int argc, char **argv) { gboolean supports_xinput; gboolean has_touchpad, has_touchscreen, has_trackball; XDeviceInfo *device_info; gint n_devices, opcode; guint i; gtk_init (&argc, &argv); supports_xinput = supports_xinput_devices (); if (supports_xinput) { g_print ("Supports XInput:\t\t\tyes\n"); } else { g_print ("Supports XInput:\t\t\tno\n"); return 0; } supports_xinput = supports_xinput2_devices (&opcode); if (supports_xinput) { g_print ("Supports XInput2:\t\t\tyes (opcode: %d)\n", opcode); } else { g_print ("Supports XInput2:\t\t\tno\n"); return 0; } has_touchpad = touchpad_is_present (); g_print ("Has touchpad:\t\t\t\t%s\n", has_touchpad ? "yes" : "no"); has_touchscreen = touchscreen_is_present (); g_print ("Has touchscreen:\t\t\t%s\n", has_touchscreen ? "yes" : "no"); has_trackball = trackball_is_present (); g_print ("Has trackball:\t\t\t\t%s\n", has_trackball ? "yes" : "no"); device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices); if (device_info == NULL) { g_warning ("Has no input devices"); return 1; } print_disabled_devices (); for (i = 0; i < n_devices; i++) { XDevice *device; if (device_info_is_touchscreen (&device_info[i])) { g_print ("Device %d is touchscreen:\t\t%s\n", (int) device_info[i].id, "yes"); continue; } if (device_info_is_trackball (&device_info[i])) { g_print ("Device %d is trackball:\t\t\t%s\n", (int) device_info[i].id, "yes"); continue; } if (device_info_is_tablet (&device_info[i])) { g_print ("Device %d is tablet:\t\t\t%s\n", (int) device_info[i].id, "yes"); continue; } gdk_error_trap_push (); device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device_info[i].id); if (gdk_error_trap_pop () || (device == NULL)) continue; if (device_is_touchpad (device)) g_print ("Device %d is touchpad:\t\t%s\n", (int) device_info[i].id, "yes"); else { int tool_id; tool_id = xdevice_get_last_tool_id (device_info[i].id); if (tool_id >= 0x0) g_print ("Device %d is touchpad/touchscreen:\t%s (tool ID: 0x%x)\n", (int) device_info[i].id, "no", tool_id); else g_print ("Device %d is touchpad/touchscreen:\t%s\n", (int) device_info[i].id, "no"); } XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device); } XFreeDeviceList (device_info); return 0; }
int Run(Display* pDisp, UI* pUI, FORMATTYPE fmt, const char* pszDeviceName) { int nRtn; XDevice* pDev; XDeviceInfoPtr pDevInfo; int nEventListCnt = 0; XEventClass eventList[32]; XEventClass cls; /* get the device by name */ pDevInfo = GetDevice(pDisp,pszDeviceName); if (!pDevInfo) { fprintf(stderr,"Unable to find input device '%s'\n",pszDeviceName); return 1; } /* open device */ pDev = XOpenDevice(pDisp,pDevInfo->id); if (!pDev) { fprintf(stderr,"Unable to open input device '%s'\n",pszDeviceName); return 1; } /* key events */ DeviceKeyPress(pDev,gnInputEvent[INPUTEVENT_KEY_PRESS],cls); if (cls) eventList[nEventListCnt++] = cls; DeviceKeyRelease(pDev,gnInputEvent[INPUTEVENT_KEY_RELEASE],cls); if (cls) eventList[nEventListCnt++] = cls; /* focus events */ DeviceFocusIn(pDev,gnInputEvent[INPUTEVENT_FOCUS_IN],cls); if (cls) eventList[nEventListCnt++] = cls; DeviceFocusOut(pDev,gnInputEvent[INPUTEVENT_FOCUS_OUT],cls); if (cls) eventList[nEventListCnt++] = cls; /* button events */ DeviceButtonPress(pDev,gnInputEvent[INPUTEVENT_BTN_PRESS],cls); if (cls) eventList[nEventListCnt++] = cls; DeviceButtonRelease(pDev,gnInputEvent[INPUTEVENT_BTN_RELEASE],cls); if (cls) eventList[nEventListCnt++] = cls; /* proximity events */ ProximityIn(pDev,gnInputEvent[INPUTEVENT_PROXIMITY_IN],cls); if (cls) eventList[nEventListCnt++] = cls; ProximityOut(pDev,gnInputEvent[INPUTEVENT_PROXIMITY_OUT],cls); if (cls) eventList[nEventListCnt++] = cls; /* motion events */ DeviceMotionNotify(pDev,gnInputEvent[INPUTEVENT_MOTION_NOTIFY],cls); if (cls) eventList[nEventListCnt++] = cls; /* device state */ DeviceStateNotify(pDev,gnInputEvent[INPUTEVENT_DEVICE_STATE_NOTIFY],cls); if (cls) eventList[nEventListCnt++] = cls; DeviceMappingNotify(pDev, gnInputEvent[INPUTEVENT_DEVICE_MAPPING_NOTIFY],cls); if (cls) eventList[nEventListCnt++] = cls; ChangeDeviceNotify(pDev,gnInputEvent[INPUTEVENT_CHANGE_DEVICE_NOTIFY],cls); if (cls) eventList[nEventListCnt++] = cls; #if 0 /* this cuts the motion data down - not sure if this is useful */ DevicePointerMotionHint(pDev, gnInputEvent[INPUTEVENT_DEVICE_POINTER_MOTION_HINT],cls); if (cls) eventList[nEventListCnt++] = cls; #endif /* button motion */ DeviceButtonMotion(pDev, gnInputEvent[INPUTEVENT_DEVICE_BUTTON_MOTION],cls); if (cls) eventList[nEventListCnt++] = cls; DeviceButton1Motion(pDev, gnInputEvent[INPUTEVENT_DEVICE_BUTTON1_MOTION],cls); if (cls) eventList[nEventListCnt++] = cls; DeviceButton2Motion(pDev, gnInputEvent[INPUTEVENT_DEVICE_BUTTON2_MOTION],cls); if (cls) eventList[nEventListCnt++] = cls; DeviceButton3Motion(pDev, gnInputEvent[INPUTEVENT_DEVICE_BUTTON3_MOTION],cls); if (cls) eventList[nEventListCnt++] = cls; DeviceButton4Motion(pDev, gnInputEvent[INPUTEVENT_DEVICE_BUTTON4_MOTION],cls); if (cls) eventList[nEventListCnt++] = cls; DeviceButton5Motion(pDev, gnInputEvent[INPUTEVENT_DEVICE_BUTTON5_MOTION],cls); if (cls) eventList[nEventListCnt++] = cls; /* specify which events to report */ /* XSelectInput(pDisp,wnd,0x00FFFFFF ^ PointerMotionHintMask); */ /* XSelectExtensionEvent(pDisp,wnd,eventList,nEventListCnt); */ /* grab device - work whether pointer is in active window or not */ XGrabDevice(pDisp,pDev,DefaultRootWindow(pDisp), 0, /* no owner events */ nEventListCnt, eventList, /* events */ GrabModeAsync, /* don't queue, give me whatever you got */ GrabModeAsync, /* same */ CurrentTime); /* fire up the UI */ if ((nRtn=pUI->Init()) != 0) fprintf(stderr,"failed to initialize UI\n"); else { if ((nRtn=pUI->Run(pDisp,pDevInfo,fmt)) != 0) fprintf(stderr,"failed to run UI\n"); pUI->Term(); } XUngrabDevice(pDisp,pDev,CurrentTime); XFree(pDev); XCloseDisplay(pDisp); return nRtn; }
int main(int argc, char **argv) { Display *display = NULL; int device = -1; int newmouse = -1; int newkbd = -1; int count; int i, j; XDeviceInfo *devInfo; XExtensionVersion *ext; if (argc == 2 || argc == 3 || argc == 4 || argc == 5) { if (!(display = XOpenDisplay(argv[1]))) { printf("Cannot open display %s\n", argv[1]); return -1; } if (argc >= 3) device = strtol(argv[2], NULL, 0); if (argc >= 4) newmouse = strtol(argv[3], NULL, 0); if (argc >= 5) newkbd = strtol(argv[4], NULL, 0); } else { printf("Usage: %s display [device] [newmouse] [newkbd]\n", argv[0]); return -1; } if (!display && !(display = XOpenDisplay(NULL))) { printf("Cannot open default display\n"); return -1; } ext = XGetExtensionVersion(display, INAME); if (!ext || ext == (XExtensionVersion *)NoSuchExtension) { printf("No XInputExtension\n"); return -1; } printf("%s version %d.%d\n", INAME, ext->major_version, ext->minor_version); if (!(devInfo = XListInputDevices(display, &count)) || !count) { printf("Cannot list devices\n"); return -1; } for (i = 0; i < count; i++) { XAnyClassPtr any; const char *kind = "Unknown"; int has_key = 0; switch (devInfo[i].use) { case IsXPointer: kind = "XPointer"; break; case IsXKeyboard: kind = "XKeyboard"; break; case IsXExtensionDevice: kind = "XExtensionDevice"; break; } printf("%2lu %-20.20s %-16.16s", (long unsigned)devInfo[i].id, devInfo[i].name ? devInfo[i].name : "", kind); for (j = 0, any = devInfo[i].inputclassinfo; j < devInfo[i].num_classes; any = (XAnyClassPtr)((char *)any + any->length), j++) { const char *class = "unk"; switch (any->class) { case KeyClass: class = "key"; ++has_key; break; case ButtonClass: class = "btn"; break; case ValuatorClass: class = "val"; break; case FeedbackClass: class = "fdb"; break; case ProximityClass: class = "prx"; break; case FocusClass: class = "foc"; break; case OtherClass: class = "oth"; break; } printf(" %s", class); } printf("\n"); printdmxinfo(display, i); if (has_key) { XkbDescPtr xkb; if ((xkb = XkbGetKeyboard(display, XkbAllComponentsMask, devInfo[i].id))) { printf(" Xkb Information:\n"); printf(" Device id = %d\n", xkb->device_spec); printf(" Min keycode = 0x%02x\n", xkb->min_key_code); printf(" Max keycode = 0x%02x\n", xkb->max_key_code); #define PRINTNAME(x) \ printf(" %s = %s\n", \ #x, xkb->names->x ? XGetAtomName(display, xkb->names->x) : "") PRINTNAME(keycodes); PRINTNAME(geometry); PRINTNAME(symbols); PRINTNAME(types); PRINTNAME(compat); } } } if (newmouse >= 0) { XDevice *dev; printf("Trying to make device %d core mouse\n", newmouse); dev = XOpenDevice(display, devInfo[newmouse].id); printf("Status = %d\n", XChangePointerDevice(display, dev, 0, 1)); return 0; } if (newkbd >= 0) { XDevice *dev; printf("Trying to make device %d core keyboard\n", newkbd); dev = XOpenDevice(display, devInfo[newkbd].id); printf("Status = %d\n", XChangeKeyboardDevice(display, dev)); return 0; } if (device >=0){ #define MAX_EVENTS 100 int cnt = 0; XDevice *dev; XEventClass event_list[MAX_EVENTS]; int event_type[MAX_EVENTS]; const char *names[MAX_EVENTS]; int total = 0; #define ADD(type) \ if (cnt >= MAX_EVENTS) abort(); \ names[cnt] = #type; \ type(dev, event_type[cnt], event_list[cnt]); \ if (event_type[cnt]) ++cnt dev = XOpenDevice(display, devInfo[device].id); ADD(DeviceKeyPress); ADD(DeviceKeyRelease); ADD(DeviceButtonPress); ADD(DeviceButtonRelease); ADD(DeviceMotionNotify); ADD(DeviceFocusIn); ADD(DeviceFocusOut); ADD(ProximityIn); ADD(ProximityOut); ADD(DeviceStateNotify); ADD(DeviceMappingNotify); ADD(ChangeDeviceNotify); for (i = 0; i < cnt; i++) { printf("Waiting for %s events of type %d (%lu) on 0x%08lx\n", names[i], event_type[i], (unsigned long)event_list[i], (long unsigned)DefaultRootWindow(display)); } XSelectExtensionEvent(display, DefaultRootWindow(display), event_list, cnt); for (;;) { XEvent event; XNextEvent(display, &event); for (i = 0; i < cnt; i++) { XDeviceMotionEvent *e = (XDeviceMotionEvent *)&event; XDeviceButtonEvent *b = (XDeviceButtonEvent *)&event; if (event.type == event_type[i]) { printf("%s id=%lu (%d @ %d,%d; s=0x%04x, d=%d, t=%lu)" " axes_count=%d first=%d %d %d %d %d %d %d\n", names[i], (long unsigned)e->deviceid, e->type, e->x, e->y, e->device_state, b->button, (long unsigned)b->time, e->axes_count, e->first_axis, e->axis_data[0], e->axis_data[1], e->axis_data[2], e->axis_data[3], e->axis_data[4], e->axis_data[5]); } } ++total; #if 0 /* Used to check motion history for * extension devices. */ if (!(total % 10)) { XDeviceTimeCoord *tc; int n, m, a; struct timeval tv; unsigned long ms; gettimeofday(&tv, NULL); ms = tv.tv_sec * 1000 + tv.tv_usec / 1000; tc = XGetDeviceMotionEvents(display, dev, ms-1000, ms, &n, &m, &a); printf("Got %d events of mode %s with %d axes\n", n, m == Absolute ? "Absolute" : "Relative", a); for (i = 0; i < n && i < 10; i++) { printf(" %d: %lu %d %d\n", i, tc[i].time, tc[i].data[0], tc[i].data[1]); } XFreeDeviceMotionEvents(tc); } #endif } } XCloseDisplay(display); return 0; }
static int do_set_prop_xi1(Display *dpy, Atom type, int format, int argc, char **argv, char *n, char *desc) { XDeviceInfo *info; XDevice *dev; Atom prop; Atom old_type; char *name; int i; Atom float_atom; int old_format, nelements = 0; unsigned long act_nitems, bytes_after; char *endptr; union { unsigned char *c; short *s; long *l; Atom *a; } data; if (argc < 3) { fprintf(stderr, "Usage: xinput %s %s\n", n, desc); return EXIT_FAILURE; } info = find_device_info(dpy, argv[0], False); if (!info) { fprintf(stderr, "unable to find device %s\n", argv[0]); return EXIT_FAILURE; } dev = XOpenDevice(dpy, info->id); if (!dev) { fprintf(stderr, "unable to open device %s\n", argv[0]); return EXIT_FAILURE; } name = argv[1]; prop = parse_atom(dpy, name); if (prop == None) { fprintf(stderr, "invalid property %s\n", name); return EXIT_FAILURE; } float_atom = XInternAtom(dpy, "FLOAT", False); nelements = argc - 2; if (type == None || format == 0) { if (XGetDeviceProperty(dpy, dev, prop, 0, 0, False, AnyPropertyType, &old_type, &old_format, &act_nitems, &bytes_after, &data.c) != Success) { fprintf(stderr, "failed to get property type and format for %s\n", name); return EXIT_FAILURE; } else { if (type == None) type = old_type; if (format == 0) format = old_format; } XFree(data.c); } if (type == None) { fprintf(stderr, "property %s doesn't exist, you need to specify " "its type and format\n", name); return EXIT_FAILURE; } data.c = calloc(nelements, sizeof(long)); for (i = 0; i < nelements; i++) { if (type == XA_INTEGER) { switch (format) { case 8: data.c[i] = atoi(argv[2 + i]); break; case 16: data.s[i] = atoi(argv[2 + i]); break; case 32: data.l[i] = atoi(argv[2 + i]); break; default: fprintf(stderr, "unexpected size for property %s", name); return EXIT_FAILURE; } } else if (type == float_atom) { if (format != 32) { fprintf(stderr, "unexpected format %d for property %s\n", format, name); return EXIT_FAILURE; } *(float *)(data.l + i) = strtod(argv[2 + i], &endptr); if (endptr == argv[2 + i]) { fprintf(stderr, "argument %s could not be parsed\n", argv[2 + i]); return EXIT_FAILURE; } } else if (type == XA_ATOM) { if (format != 32) { fprintf(stderr, "unexpected format %d for property %s\n", format, name); return EXIT_FAILURE; } data.a[i] = parse_atom(dpy, argv[2 + i]); } else { fprintf(stderr, "unexpected type for property %s\n", name); return EXIT_FAILURE; } } XChangeDeviceProperty(dpy, dev, prop, type, format, PropModeReplace, data.c, nelements); free(data.c); XCloseDevice(dpy, dev); return EXIT_SUCCESS; }
void setCalibration(int id, int minX, int maxX, int minY, int maxY, int axesSwap, int screenWidth, int screenHeight, int outputX, int outputY, int outputWidth, int outputHeight, int rotation) { float matrix[] = { 1., 0., 0., /* [0] [1] [2] */ 0., 1., 0., /* [3] [4] [5] */ 0., 0., 1. }; /* [6] [7] [8] */ int matrixMode = 0; /* Check if transformation matrix is supported */ long l; if((sizeof l) == 4 || (sizeof l) == 8) { /* We only support matrix mode on systems where longs are 32 or 64 bits long */ Atom retType; int retFormat; unsigned long retItems, retBytesAfter; unsigned char * data = NULL; if(XIGetProperty(display, id, XInternAtom(display, "Coordinate Transformation Matrix", 0), 0, 9 * 32, False, floatAtom, &retType, &retFormat, &retItems, &retBytesAfter, &data) != Success) { data = NULL; } if(data != NULL && retItems == 9) { matrixMode = 1; } if(data != NULL) { XFree(data); } } unsigned char flipHoriz = 0, flipVerti = 0; if(matrixMode) { if(debugMode) printf("Use matrix method\n"); /* Output rotation */ if(rotation & RR_Rotate_180) { matrix[0] = -1.; matrix[4] = -1; matrix[2] = 1.; matrix[5] = 1.; } else if(rotation & RR_Rotate_90) { matrix[0] = 0.; matrix[1] = -1.; matrix[3] = 1.; matrix[4] = 0.; matrix[2] = 1.; } else if(rotation & RR_Rotate_270) { matrix[0] = 0.; matrix[1] = 1.; matrix[3] = -1.; matrix[4] = 0.; matrix[5] = 1.; } /* Output Reflection */ if(rotation & RR_Reflect_X) { matrix[0]*= -1.; matrix[1]*= -1.; matrix[2]*= -1.; matrix[2]+= 1.; } if(rotation & RR_Reflect_Y) { matrix[3]*= -1.; matrix[4]*= -1.; matrix[5]*= -1.; matrix[5]+= 1.; } /* Output Size */ float widthRel = outputWidth / (float) screenWidth; float heightRel = outputHeight / (float) screenHeight; matrix[0] *= widthRel; matrix[1] *= widthRel; matrix[2] *= widthRel; matrix[3] *= heightRel; matrix[4] *= heightRel; matrix[5] *= heightRel; /* Output Position */ matrix[2] += outputX / (float) screenWidth; matrix[5] += outputY / (float) screenHeight; } else { if(debugMode) printf("Use legacy method\n"); /* No support for transformations, so use legacy method */ if(rotation & RR_Rotate_180) { flipHoriz = !flipHoriz; flipVerti = !flipVerti; } else if(rotation & RR_Rotate_90) { flipVerti = !flipVerti; axesSwap = !axesSwap; } else if(rotation & RR_Rotate_270) { flipHoriz = !flipHoriz; axesSwap = !axesSwap; } /* Output Reflection */ if(rotation & RR_Reflect_X) { flipHoriz = !flipHoriz; } if(rotation & RR_Reflect_Y) { flipVerti = !flipVerti; } if(axesSwap) { swap(&maxX, &maxY); swap(&minX, &minY); } int leftSpace, rightSpace, topSpace, bottomSpace; leftSpace = outputX; rightSpace = screenWidth - outputX - outputWidth; topSpace = outputY; bottomSpace = screenHeight - outputY - outputHeight; if(flipHoriz) swap(&leftSpace, &rightSpace); if(flipVerti) swap(&topSpace, &bottomSpace); float fctX = ((float) (maxX - minX)) / ((float) outputWidth); float fctY = ((float) (maxY - minY)) / ((float) outputHeight); minX = minX - (int) (leftSpace * fctX); maxX = maxX + (int) (rightSpace * fctX); minY = minY - (int) (topSpace * fctY); maxY = maxY + (int) (bottomSpace * fctY); } XDevice *dev = XOpenDevice(display, id); if(dev) { if(matrixMode) { if((sizeof l) == 4) { XChangeDeviceProperty(display, dev, XInternAtom(display, "Coordinate Transformation Matrix", 0), floatAtom, 32, PropModeReplace, (unsigned char*) matrix, 9); } else if((sizeof l) == 8) { /* Xlib needs the floats long-aligned, so let's align them. */ float matrix2[] = { matrix[0], 0., matrix[1], 0., matrix[2], 0., matrix[3], 0., matrix[4], 0., matrix[5], 0., matrix[6], 0., matrix[7], 0., matrix[8], 0. }; XChangeDeviceProperty(display, dev, XInternAtom(display, "Coordinate Transformation Matrix", 0), floatAtom, 32, PropModeReplace, (unsigned char*) matrix2, 9); } } long calib[] = { minX, maxX, minY, maxY }; //TODO instead of long, use platform 32 bit type XChangeDeviceProperty(display, dev, XInternAtom(display, "Evdev Axis Calibration", 0), XA_INTEGER, 32, PropModeReplace, (unsigned char*) calib, 4); unsigned char flipData[] = {flipHoriz, flipVerti}; XChangeDeviceProperty(display, dev, XInternAtom(display, "Evdev Axis Inversion", 0), XA_INTEGER, 8, PropModeReplace, flipData, 2); unsigned char cAxesSwap = (unsigned char) axesSwap; XChangeDeviceProperty(display, dev, XInternAtom(display, "Evdev Axes Swap", 0), XA_INTEGER, 8, PropModeReplace, &cAxesSwap, 1); XCloseDevice(display, dev); } }
int main(int argc, char * argv[]) { int loop, num_extensions, num_devices; char **extensions; XDeviceInfo *devices; Display *dpy; Window root_win; unsigned long screen; int list = 0; if (argc != 3) { fprintf(stderr, "usage : %s <device name> (ABSOLUTE|RELATIVE)\n", argv[0]); exit(1); } if (strcmp(argv[1], "-l") == 0) { list = 1; } dpy = XOpenDisplay(NULL); if (!dpy) { printf("unable to connect to X Server try to set the DISPLAY variable\n"); exit(1); } #ifdef DEBUG printf("connected to %s\n", XDisplayString(dpy)); #endif screen = DefaultScreen(dpy); root_win = RootWindow(dpy, screen); extensions = XListExtensions(dpy, &num_extensions); for (loop = 0; loop < num_extensions && (strcmp(extensions[loop], "XInputExtension") != 0); loop++); XFreeExtensionList(extensions); if (loop != num_extensions) { devices = XListInputDevices(dpy, &num_devices); for(loop=0; loop<num_devices; loop++) { if (devices[loop].name && (StrCaseCmp(devices[loop].name, argv[1]) == 0)) if (devices[loop].use == IsXExtensionDevice) { XDevice *device; #ifdef DEBUG fprintf(stderr, "opening device %s\n", devices[loop].name ? devices[loop].name : "<noname>"); #endif device = XOpenDevice(dpy, devices[loop].id); if (device) { XSetDeviceMode(dpy, device, (strcmp("ABSOLUTE", argv[2]) == 0) ? Absolute : Relative); exit(0); } else { fprintf(stderr, "error opening device\n"); exit(1); } } } XFreeDeviceList(devices); } else { fprintf(stderr, "No XInput extension available\n"); exit(1); } if (list) { exit(0); } else { fprintf(stderr, "Extended device %s not found\n", argv[1]); exit(1); } }
void X11Extras::x11ResetMouseAccelerationChange() { //QTextStream out(stdout); int xi_opcode, event, error; xi_opcode = event = error = 0; Display *display = this->display(); bool result = XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &error); if (!result) { Logger::LogInfo(tr("xinput extension was not found. No mouse acceleration changes will occur.")); //out << tr("xinput extension was not found. No mouse acceleration changes will occur.") << endl; } else { int ximajor = 2, ximinor = 0; if (XIQueryVersion(display, &ximajor, &ximinor) != Success) { Logger::LogInfo(tr("xinput version must be at least 2.0. No mouse acceleration changes will occur.")); //out << tr("xinput version must be at least 2.0. No mouse acceleration changes will occur.") << endl; } } if (result) { XIDeviceInfo *all_devices = 0; XIDeviceInfo *current_devices = 0; XIDeviceInfo *mouse_device = 0; int num_devices = 0; all_devices = XIQueryDevice(display, XIAllDevices, &num_devices); for (int i=0; i < num_devices; i++) { current_devices = &all_devices[i]; if (current_devices->use == XISlavePointer && QString::fromUtf8(current_devices->name) == mouseDeviceName) { Logger::LogInfo(tr("Virtual pointer found with id=%1.").arg(current_devices->deviceid)); //out << tr("Virtual pointer found with id=%1.").arg(current_devices->deviceid) // << endl; mouse_device = current_devices; } } if (mouse_device) { XDevice *device = XOpenDevice(display, mouse_device->deviceid); int num_feedbacks = 0; int feedback_id = -1; XFeedbackState *feedbacks = XGetFeedbackControl(display, device, &num_feedbacks); XFeedbackState *temp = feedbacks; for (int i=0; (i < num_feedbacks) && (feedback_id == -1); i++) { if (temp->c_class == PtrFeedbackClass) { feedback_id = temp->id; } if (i+1 < num_feedbacks) { temp = (XFeedbackState*) ((char*) temp + temp->length); } } XFree(feedbacks); feedbacks = temp = 0; if (feedback_id <= -1) { Logger::LogInfo(tr("PtrFeedbackClass was not found for virtual pointer." "No change to mouse acceleration will occur for device with id=%1").arg(device->device_id)); //out << tr("PtrFeedbackClass was not found for virtual pointer." // "No change to mouse acceleration will occur for device with id=%1").arg(device->device_id) // << endl; result = false; } else { Logger::LogInfo(tr("Changing mouse acceleration for device with id=%1").arg(device->device_id)); //out << tr("Changing mouse acceleration for device with id=%1").arg(device->device_id) // << endl; XPtrFeedbackControl feedback; feedback.c_class = PtrFeedbackClass; feedback.length = sizeof(XPtrFeedbackControl); feedback.id = feedback_id; feedback.threshold = 0; feedback.accelNum = 1; feedback.accelDenom = 1; XChangeFeedbackControl(display, device, DvAccelNum|DvAccelDenom|DvThreshold, (XFeedbackControl*) &feedback); XSync(display, false); } XCloseDevice(display, device); } if (all_devices) { XIFreeDeviceInfo(all_devices); } } }
static void synaptics_check_capabilities_x11 (CcMousePropertiesPrivate *d) { int numdevices, i; XDeviceInfo *devicelist; Atom realtype, prop_capabilities, prop_scroll_methods, prop_tapping_enabled; int realformat; unsigned long nitems, bytes_after; unsigned char *data; gboolean tap_to_click, two_finger_scroll; prop_capabilities = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Capabilities", False); prop_scroll_methods = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "libinput Scroll Methods Available", False); prop_tapping_enabled = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "libinput Tapping Enabled", False); if (!prop_capabilities || !prop_scroll_methods || !prop_tapping_enabled) return; tap_to_click = FALSE; two_finger_scroll = FALSE; devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &numdevices); for (i = 0; i < numdevices; i++) { if (devicelist[i].use != IsXExtensionPointer) continue; gdk_error_trap_push (); XDevice *device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), devicelist[i].id); if (gdk_error_trap_pop ()) continue; gdk_error_trap_push (); /* xorg-x11-drv-synaptics */ if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device, prop_capabilities, 0, 2, False, XA_INTEGER, &realtype, &realformat, &nitems, &bytes_after, &data) == Success) && (realtype != None)) { /* Property data is booleans for has_left, has_middle, has_right, has_double, has_triple. * Newer drivers (X.org/kerrnel) will also include has_pressure and has_width. */ /* Set tap_to_click_toggle sensitive only if the device has hardware buttons */ if (data[0]) tap_to_click = TRUE; /* Set two_finger_scroll_toggle sensitive if the hardware supports double touch */ if (data[3]) two_finger_scroll = TRUE; XFree (data); } /* xorg-x11-drv-libinput */ if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device, prop_scroll_methods, 0, 2, False, XA_INTEGER, &realtype, &realformat, &nitems, &bytes_after, &data) == Success) && (realtype != None)) { /* Property data is booleans for two-finger, edge, on-button scroll available. */ if (data[0] && data[1]) two_finger_scroll = TRUE; XFree (data); } if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device, prop_tapping_enabled, 0, 1, False, XA_INTEGER, &realtype, &realformat, &nitems, &bytes_after, &data) == Success) && (realtype != None)) { /* Property data is boolean for tapping enabled. */ tap_to_click = TRUE; XFree (data); } gdk_error_trap_pop_ignored (); XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device); } XFreeDeviceList (devicelist); gtk_widget_set_sensitive (WID ("tap_to_click_toggle"), tap_to_click); gtk_widget_set_sensitive (WID ("two_finger_scroll_toggle"), two_finger_scroll); }
static PyObject * xextdev_grab(PyObject *self, PyObject *args) { XEventClass cls; const char *devname; int devid; XAnyClassPtr pClass; int j; XEventClass eventList[32]; int nEventListCnt = 0; if (!display) { ASSERTCOND(display = XOpenDisplay(NULL),"open display"); /* polling this seems to be the only way * * to do a timed wait on X events */ x11_fd = ConnectionNumber(display); xdevList = (XDeviceInfoPtr) XListInputDevices(display, &devcount); if (!xdevList) { fprintf(stderr,"Failed to get input device list\n"); return Py_BuildValue("i", 0); } } if (!PyArg_ParseTuple(args, "i", &devid)) return Py_BuildValue("i", 0); ASSERTCOND(devid<devcount, "Tried to grab non-existing device id %d (max %d)", devid,devcount); xdevInfo = xdevList + devid; devname = xdevInfo->name; val = NULL; pClass = xdevInfo->inputclassinfo; for (j=0; j<xdevInfo->num_classes; ++j) { switch (pClass->class) { case ValuatorClass: val = (XValuatorInfoPtr)pClass; break; } pClass = (XAnyClassPtr)((char*)pClass + pClass->length); } ASSERTCOND(val,"xinputextdev: Unable to get valuator " "information of '%s'\n",devname); /* open device */ ASSERTCOND(xdev = XOpenDevice(display,xdevInfo->id), "xinputextdev: Unable to open " "input device '%s'\n",devname); /* button events */ DeviceButtonPress(xdev,inputEventTypes[INPUTEVENT_BTN_PRESS],cls); if (cls) eventList[nEventListCnt++] = cls; DeviceButtonRelease(xdev,inputEventTypes[INPUTEVENT_BTN_RELEASE],cls); if (cls) eventList[nEventListCnt++] = cls; /* motion events */ DeviceMotionNotify(xdev,inputEventTypes[INPUTEVENT_MOTION_NOTIFY],cls); if (cls) eventList[nEventListCnt++] = cls; /* proximity events */ ProximityOut(xdev,inputEventTypes[INPUTEVENT_PROXIMITY_OUT],cls); if (cls) eventList[nEventListCnt++] = cls; ProximityIn(xdev,inputEventTypes[INPUTEVENT_PROXIMITY_IN],cls); if (cls) eventList[nEventListCnt++] = cls; /* grab device */ int err = XGrabDevice(display,xdev,DefaultRootWindow(display), 0,nEventListCnt,eventList, GrabModeAsync,GrabModeAsync,CurrentTime); if (err == AlreadyGrabbed) fprintf(stderr,"xinputextdev: Grab error: AlreadyGrabbed\n"); else if (err == GrabNotViewable) fprintf(stderr, "xinputextdev: Grab error: GrabNotViewable\n"); else if (err == GrabFrozen) fprintf(stderr, "xinputextdev: Grab error: GrabFrozen\n"); else { printf("xinputextdev: Device '%s' grabbed.\n",devname); return Py_BuildValue("[i,i]", val->axes[0].max_value, val->axes[1].max_value); } return Py_BuildValue("i", 0); }