• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

A generic touchscreen calibration program for X.Org


Commit MetaInfo

Revision416e33f611f6a9e459dddd18f544bb6c8d79bac0 (tree)
Time2009-11-29 23:08:19
AuthorTias <tias@kata...>
CommiterTias

Log Message

Add support for dynamic evdev re-calibration

Change Summary

Incremental Difference

--- a/xinput_calibrator.cc
+++ b/xinput_calibrator.cc
@@ -66,6 +66,18 @@
6666 #include <X11/Xlib.h>
6767 #include <X11/extensions/XInput.h>
6868
69+// begin EvDev includes
70+#include <X11/Xatom.h>
71+//#include <X11/Xutil.h>
72+
73+#ifndef EXIT_SUCCESS
74+#define EXIT_SUCCESS 1
75+#endif
76+#ifndef EXIT_FAILURE
77+#define EXIT_FAILURE 0
78+#endif
79+// end EvDev includes
80+
6981 /* Number of points the user should click */
7082 const int num_points = 4;
7183
@@ -219,7 +231,6 @@ void Calibrator::finish ()
219231 std::swap (clicked_y [LL], clicked_y [UR]);
220232 }
221233
222-
223234 /* Compute min/max coordinates.
224235 * These are scaled to [oldcalib_min, oldcalib_max]] */
225236 const float scale_x = (oldcalib_max_x - oldcalib_min_x)/(float)width;
@@ -271,7 +282,7 @@ public:
271282 CalibratorXorgPrint::CalibratorXorgPrint (const char* drivername0, int min_x, int max_x, int min_y, int max_y)
272283 : Calibrator (drivername0, min_x, max_x, min_y, max_y)
273284 {
274- printf ("Calibrating driver %s with min_x=%d, max_x=%d and min_y=%d, max_y=%d\n",
285+ printf ("Calibrating unknown driver \"%s\" (having min_x=%d, max_x=%d and min_y=%d, max_y=%d)\n",
275286 drivername, oldcalib_min_x, oldcalib_max_x, oldcalib_min_y, oldcalib_max_y);
276287 }
277288
@@ -294,6 +305,375 @@ void CalibratorXorgPrint::finish_data (
294305 }
295306
296307
308+
309+/***************************
310+ * Class for dynamic evdev calibration
311+ * uses xinput "Evdev Axis Calibration"
312+ ***************************/
313+class CalibratorEvdev: public Calibrator
314+{
315+private:
316+ Display *display;
317+ XDeviceInfo *info;
318+ XDevice *dev;
319+public:
320+ CalibratorEvdev (const char*, int, int, int, int);
321+ ~CalibratorEvdev ();
322+
323+ virtual void finish_data (int, int, int, int, int, int, int);
324+
325+ static Bool check_driver(const char *name);
326+
327+ // xinput functions
328+ static Atom parse_atom(Display *display, const char *name);
329+ static XDeviceInfo* find_device_info(Display *display, const char *name, Bool only_extended);
330+ int do_set_prop(Display *display, Atom type, int format, int argc, char *argv[]);
331+};
332+
333+CalibratorEvdev::CalibratorEvdev (const char* drivername0, int min_x, int max_x, int min_y, int max_y)
334+ : Calibrator (drivername0, min_x, max_x, min_y, max_y)
335+{
336+ Atom property;
337+ Atom act_type;
338+ int act_format;
339+ unsigned long nitems, bytes_after;
340+ unsigned char *data, *ptr;
341+
342+ printf ("Calibrating EVDEV driver for \"%s\"\n", drivername);
343+
344+ // init
345+ display = XOpenDisplay(NULL);
346+ if (display == NULL) {
347+ fprintf(stderr, "Unable to connect to X server\n");
348+ return;
349+ }
350+
351+
352+ info = find_device_info(display, drivername, False);
353+ if (!info)
354+ {
355+ fprintf(stderr, "unable to find device %s\n", drivername);
356+ return;
357+ }
358+
359+ dev = XOpenDevice(display, info->id);
360+ if (!dev)
361+ {
362+ fprintf(stderr, "unable to open device '%s'\n", info->name);
363+ return;
364+ }
365+
366+ // get "Evdev Axis Calibration" property
367+ property = parse_atom(display, "Evdev Axis Calibration");
368+ if (XGetDeviceProperty(display, dev, property, 0, 1000, False,
369+ AnyPropertyType, &act_type, &act_format,
370+ &nitems, &bytes_after, &data) == Success)
371+ {
372+ if (act_format != 32 || act_type != XA_INTEGER) {
373+ fprintf(stderr, "Error: unexpected format or type from \"Evdev Axis Calibration\" property.\n");
374+ }
375+
376+ if (nitems != 0) {
377+ ptr = data;
378+
379+ oldcalib_min_x = *((long*)ptr);
380+ ptr += sizeof(long);
381+ oldcalib_max_x = *((long*)ptr);
382+ ptr += sizeof(long);
383+ oldcalib_min_y = *((long*)ptr);
384+ ptr += sizeof(long);
385+ oldcalib_max_y = *((long*)ptr);
386+ ptr += sizeof(long);
387+
388+ printf("Read current calibration data from XInput: min_x=%d, max_x=%d and min_y=%d, max_y=%d\n",
389+ oldcalib_min_x, oldcalib_max_x, oldcalib_min_y, oldcalib_max_y);
390+ }
391+
392+ XFree(data);
393+ } else
394+ printf("\tFetch failure\n");
395+
396+}
397+
398+CalibratorEvdev::~CalibratorEvdev () {
399+ XCloseDevice(display, dev);
400+ XCloseDisplay(display);
401+}
402+
403+void CalibratorEvdev::finish_data (
404+ int min_x, int max_x, int min_y, int max_y, int swap_xy, int flip_x, int flip_y)
405+{
406+ // Evdev Axes Swap
407+ if (swap_xy) {
408+ printf("Swapping X and Y axis...\n");
409+ // xinput set-int-prop 4 224 8 0
410+ char str_prop[50];
411+ sprintf(str_prop, "Evdev Axes Swap");
412+ char str_swap_xy[20];
413+ sprintf(str_swap_xy, "%d", swap_xy);
414+
415+ int argc = 3;
416+ char* argv[argc];
417+ //argv[0] = "";
418+ argv[1] = str_prop;
419+ argv[2] = str_swap_xy;
420+ do_set_prop(display, XA_INTEGER, 8, argc, argv);
421+ }
422+
423+ // Evdev Axis Inversion
424+ /* Ignored, X server can handle it by flipping min/max values. */
425+
426+ // Evdev Axis Calibration
427+ // xinput set-int-prop 4 223 5 500 8 300
428+ printf("Setting new calibration data: %d, %d, %d, %d\n", min_x, max_x, min_y, max_y);
429+ char str_prop[50];
430+ sprintf(str_prop, "Evdev Axis Calibration");
431+ char str_min_x[20];
432+ sprintf(str_min_x, "%d", min_x);
433+ char str_max_x[20];
434+ sprintf(str_max_x, "%d", max_x);
435+ char str_min_y[20];
436+ sprintf(str_min_y, "%d", min_y);
437+ char str_max_y[20];
438+ sprintf(str_max_y, "%d", max_y);
439+
440+ int argc = 6;
441+ char* argv[argc];
442+ //argv[0] = "";
443+ argv[1] = str_prop;
444+ argv[2] = str_min_x;
445+ argv[3] = str_max_x;
446+ argv[4] = str_min_y;
447+ argv[5] = str_max_y;
448+ do_set_prop(display, XA_INTEGER, 32, argc, argv);
449+
450+ // close
451+ XSync(display, False);
452+}
453+
454+Bool CalibratorEvdev::check_driver(const char *name) {
455+ Display *display;
456+ XDeviceInfo *info;
457+ XDevice *dev;
458+ int nprops;
459+ Atom *props;
460+ Bool found = False;
461+
462+ display = XOpenDisplay(NULL);
463+ if (display == NULL) {
464+ fprintf(stderr, "Unable to connect to X server\n");
465+ quit(1);
466+ }
467+
468+ info = find_device_info(display, name, False);
469+ if (!info)
470+ {
471+ fprintf(stderr, "unable to find device %s\n", name);
472+ return NULL;
473+ }
474+
475+ dev = XOpenDevice(display, info->id);
476+ if (!dev)
477+ {
478+ fprintf(stderr, "unable to open device '%s'\n", info->name);
479+ return NULL;
480+ }
481+
482+ props = XListDeviceProperties(display, dev, &nprops);
483+ if (!nprops)
484+ {
485+ printf("Device '%s' does not report any properties.\n", info->name);
486+ return NULL;
487+ }
488+
489+ // check if "Evdev Axis Calibration" exists, then its an evdev driver
490+ while(nprops--)
491+ {
492+ if (strcmp(XGetAtomName(display, props[nprops]),
493+ "Evdev Axis Calibration") == 0) {
494+ found = True;
495+ break;
496+ }
497+ }
498+
499+ XFree(props);
500+ XCloseDevice(display, dev);
501+ XCloseDisplay(display);
502+
503+ return found;
504+}
505+
506+Atom CalibratorEvdev::parse_atom(Display *display, const char *name) {
507+ Bool is_atom = True;
508+ int i;
509+
510+ for (i = 0; name[i] != '\0'; i++) {
511+ if (!isdigit(name[i])) {
512+ is_atom = False;
513+ break;
514+ }
515+ }
516+
517+ if (is_atom)
518+ return atoi(name);
519+ else
520+ return XInternAtom(display, name, False);
521+}
522+
523+XDeviceInfo* CalibratorEvdev::find_device_info(
524+Display *display, const char *name, Bool only_extended)
525+{
526+ XDeviceInfo *devices;
527+ XDeviceInfo *found = NULL;
528+ int loop;
529+ int num_devices;
530+ int len = strlen(name);
531+ Bool is_id = True;
532+ XID id = (XID)-1;
533+
534+ for (loop=0; loop<len; loop++) {
535+ if (!isdigit(name[loop])) {
536+ is_id = False;
537+ break;
538+ }
539+ }
540+
541+ if (is_id) {
542+ id = atoi(name);
543+ }
544+
545+ devices = XListInputDevices(display, &num_devices);
546+
547+ for (loop=0; loop<num_devices; loop++) {
548+ if ((!only_extended || (devices[loop].use >= IsXExtensionDevice)) &&
549+ ((!is_id && strcmp(devices[loop].name, name) == 0) ||
550+ (is_id && devices[loop].id == id))) {
551+ if (found) {
552+ fprintf(stderr,
553+ "Warning: There are multiple devices named \"%s\".\n"
554+ "To ensure the correct one is selected, please use "
555+ "the device ID instead.\n\n", name);
556+ return NULL;
557+ } else {
558+ found = &devices[loop];
559+ }
560+ }
561+ }
562+
563+ return found;
564+}
565+
566+int CalibratorEvdev::do_set_prop(
567+Display *display, Atom type, int format, int argc, char **argv)
568+{
569+ Atom prop;
570+ Atom old_type;
571+ char *name;
572+ int i;
573+ Atom float_atom;
574+ int old_format, nelements = 0;
575+ unsigned long act_nitems, bytes_after;
576+ char *endptr;
577+ union {
578+ unsigned char *c;
579+ short *s;
580+ long *l;
581+ Atom *a;
582+ } data;
583+
584+ if (argc < 3)
585+ {
586+ fprintf(stderr, "Wrong usage of do_set_prop, need at least 3 arguments\n");
587+ return EXIT_FAILURE;
588+ }
589+
590+ name = argv[1];
591+
592+ prop = parse_atom(display, name);
593+
594+ if (prop == None) {
595+ fprintf(stderr, "invalid property %s\n", name);
596+ return EXIT_FAILURE;
597+ }
598+
599+ float_atom = XInternAtom(display, "FLOAT", False);
600+
601+ nelements = argc - 2;
602+ if (type == None || format == 0) {
603+ if (XGetDeviceProperty(display, dev, prop, 0, 0, False, AnyPropertyType,
604+ &old_type, &old_format, &act_nitems,
605+ &bytes_after, &data.c) != Success) {
606+ fprintf(stderr, "failed to get property type and format for %s\n",
607+ name);
608+ return EXIT_FAILURE;
609+ } else {
610+ if (type == None)
611+ type = old_type;
612+ if (format == 0)
613+ format = old_format;
614+ }
615+
616+ XFree(data.c);
617+ }
618+
619+ if (type == None) {
620+ fprintf(stderr, "property %s doesn't exist, you need to specify "
621+ "its type and format\n", name);
622+ return EXIT_FAILURE;
623+ }
624+
625+ data.c = (unsigned char*)calloc(nelements, sizeof(long));
626+
627+ for (i = 0; i < nelements; i++)
628+ {
629+ if (type == XA_INTEGER) {
630+ switch (format)
631+ {
632+ case 8:
633+ data.c[i] = atoi(argv[2 + i]);
634+ break;
635+ case 16:
636+ data.s[i] = atoi(argv[2 + i]);
637+ break;
638+ case 32:
639+ data.l[i] = atoi(argv[2 + i]);
640+ break;
641+ default:
642+ fprintf(stderr, "unexpected size for property %s", name);
643+ return EXIT_FAILURE;
644+ }
645+ } else if (type == float_atom) {
646+ if (format != 32) {
647+ fprintf(stderr, "unexpected format %d for property %s\n",
648+ format, name);
649+ return EXIT_FAILURE;
650+ }
651+ *(float *)(data.l + i) = strtod(argv[2 + i], &endptr);
652+ if (endptr == argv[2 + i]) {
653+ fprintf(stderr, "argument %s could not be parsed\n", argv[2 + i]);
654+ return EXIT_FAILURE;
655+ }
656+ } else if (type == XA_ATOM) {
657+ if (format != 32) {
658+ fprintf(stderr, "unexpected format %d for property %s\n",
659+ format, name);
660+ return EXIT_FAILURE;
661+ }
662+ data.a[i] = parse_atom(display, argv[2 + i]);
663+ } else {
664+ fprintf(stderr, "unexpected type for property %s\n", name);
665+ return EXIT_FAILURE;
666+ }
667+ }
668+
669+ XChangeDeviceProperty(display, dev, prop, type, format, PropModeReplace,
670+ data.c, nelements);
671+ free(data.c);
672+ XCloseDevice(display, dev);
673+ return EXIT_SUCCESS;
674+}
675+
676+
297677 /**********************************
298678 * Class for usbtouchscreen driver,
299679 * writes output parameters to running kernel and to modprobe.conf
@@ -499,19 +879,26 @@ CalibrationArea::CalibrationArea ()
499879 /* Not sure this is the right place for this, but here we go
500880 * Get driver name and axis information from XInput */
501881 {
882+ int ndevices;
883+ Display *display;
884+ XDeviceInfoPtr list, slist;
885+ XAnyClassPtr any;
886+ int xi_opcode, event, error;
887+
502888 int found = 0;
503889 const char* drivername = "";
504890 int min_x = 0, max_x = 0;
505891 int min_y = 0, max_y = 0;
506892
507- int ndevices;
508- Display *display;
509- XDeviceInfoPtr list, slist;
510- XAnyClassPtr any;
893+ display = XOpenDisplay(NULL);
511894
512- if ((display = XOpenDisplay (0)) == NULL)
513- {
514- fprintf (stderr, "Error: No connection to Xserver - Terminating.\n");
895+ if (display == NULL) {
896+ fprintf(stderr, "Unable to connect to X server\n");
897+ quit(1);
898+ }
899+
900+ if (!XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &error)) {
901+ printf("X Input extension not available.\n");
515902 quit(1);
516903 }
517904
@@ -553,7 +940,8 @@ CalibrationArea::CalibrationArea ()
553940 }
554941
555942 }
556- XFreeDeviceList (slist);
943+ XFreeDeviceList(slist);
944+ XCloseDisplay(display);
557945
558946 if (found == 0) {
559947 fprintf (stderr, "Error: No calibratable devices found.\n");
@@ -565,9 +953,16 @@ CalibrationArea::CalibrationArea ()
565953 /* Different driver, different backend behaviour (case sensitive ?) */
566954 if (strcmp(drivername, "Usbtouchscreen") == 0)
567955 W = new CalibratorUsbts();
568- else
569- W = new CalibratorXorgPrint(drivername,
570- min_x, max_x, min_y, max_y);
956+ else {
957+ // unable to know device driver from its name alone
958+ // either its EVDEV or an unknown driver
959+ if (CalibratorEvdev::check_driver(drivername))
960+ W = new CalibratorEvdev(drivername,
961+ min_x, max_x, min_y, max_y);
962+ else
963+ W = new CalibratorXorgPrint(drivername,
964+ min_x, max_x, min_y, max_y);
965+ }
571966 }
572967
573968 /* Listen for mouse events */