Calibrator* Calibrator::make_calibrator(int argc, char** argv)
{
    bool list_devices = false;
    bool fake = false;
    bool precalib = false;
    bool use_valuator = false;
    bool use_timeout = true;
    XYinfo pre_axys;
    const char* pre_device = NULL;
    const char* geometry = NULL;
    const char* output_filename = NULL;
    unsigned thr_misclick = 15;
    unsigned thr_doubleclick = 7;
    OutputType output_type = OUTYPE_AUTO;

    // parse input
    if (argc > 1) {
        for (int i=1; i!=argc; i++) {
            // Display help ?
            if (strcmp("-h", argv[i]) == 0 ||
                strcmp("--help", argv[i]) == 0) {
                fprintf(stderr, "xinput_calibrator, v%s\n\n", VERSION);
                usage(argv[0], thr_misclick);
                exit(0);
            } else

            // Verbose output ?
            if (strcmp("-v", argv[i]) == 0 ||
                strcmp("--verbose", argv[i]) == 0) {
                verbose = true;
            } else

            // Just list devices ?
            if (strcmp("--list", argv[i]) == 0) {
                list_devices = true;
            } else

            // Select specific device ?
            if (strcmp("--device", argv[i]) == 0) {
                if (argc > i+1)
                    pre_device = argv[++i];
                else {
                    fprintf(stderr, "Error: --device needs a device name or id as argument; use --list to list the calibratable input devices.\n\n");
                    usage(argv[0], thr_misclick);
                    exit(1);
                }
            } else

            // Get pre-calibration ?
            if (strcmp("--precalib", argv[i]) == 0) {
                precalib = true;
                if (argc > i+1)
                    pre_axys.x.min = atoi(argv[++i]);
                if (argc > i+1)
                    pre_axys.x.max = atoi(argv[++i]);
                if (argc > i+1)
                    pre_axys.y.min = atoi(argv[++i]);
                if (argc > i+1)
                    pre_axys.y.max = atoi(argv[++i]);
            } else

            if (strcmp("--valuator", argv[i]) == 0) {
                use_valuator = true;
            } else

            // Get mis-click threshold ?
            if (strcmp("--misclick", argv[i]) == 0) {
                if (argc > i+1)
                    thr_misclick = atoi(argv[++i]);
                else {
                    fprintf(stderr, "Error: --misclick needs a number (the pixel threshold) as argument. Set to 0 to disable mis-click detection.\n\n");
                    usage(argv[0], thr_misclick);
                    exit(1);
                }
            } else

            // Get output type ?
            if (strcmp("--output-type", argv[i]) == 0) {
                if (argc > i+1) {
                    i++; // eat it or exit
                    if (strcmp("auto", argv[i]) == 0)
                        output_type = OUTYPE_AUTO;
                    else if (strcmp("xorg.conf.d", argv[i]) == 0)
                        output_type = OUTYPE_XORGCONFD;
                    else if (strcmp("hal", argv[i]) == 0)
                        output_type = OUTYPE_HAL;
                    else if (strcmp("xinput", argv[i]) == 0)
                        output_type = OUTYPE_XINPUT;
                    else {
                        fprintf(stderr, "Error: --output-type needs one of auto|xorg.conf.d|hal|xinput.\n\n");
                        usage(argv[0], thr_misclick);
                        exit(1);
                    }
                } else {
                    fprintf(stderr, "Error: --output-type needs one argument.\n\n");
                    usage(argv[0], thr_misclick);
                    exit(1);
                }
            } else

            // specify window geometry?
            if (strcmp("--geometry", argv[i]) == 0) {
                geometry = argv[++i];
            } else

            // Fake calibratable device ?
            if (strcmp("--fake", argv[i]) == 0) {
                fake = true;
            } else

            // Disable timeout
			if (strcmp("--no-timeout", argv[i]) == 0) {
				use_timeout = false;
			} else

			// Output file
			if (strcmp("--output-filename", argv[i]) == 0) {
				output_filename = argv[++i];
			}

            // unknown option
            else {
                fprintf(stderr, "Unknown option: %s\n\n", argv[i]);
                usage(argv[0], thr_misclick);
                exit(0);
            }
        }
    }


    /// Choose the device to calibrate
    XID         device_id   = (XID) -1;
    const char* device_name = NULL;
    XYinfo      device_axys;
    if (fake) {
        // Fake a calibratable device
        device_name = "Fake_device";
        device_axys = XYinfo(0,1000,0,1000);

        if (verbose) {
            printf("DEBUG: Faking device: %s\n", device_name);
        }
    } else {
        // Find the right device
        int nr_found = find_device(pre_device, list_devices, device_id, device_name, device_axys);

        if (list_devices) {
            // printed the list in find_device
            if (nr_found == 0)
                printf("No calibratable devices found.\n");
            exit(2);
        }

        if (nr_found == 0) {
            if (pre_device == NULL)
                fprintf (stderr, "Error: No calibratable devices found.\n");
            else
                fprintf (stderr, "Error: Device \"%s\" not found; use --list to list the calibratable input devices.\n", pre_device);
            exit(1);

        } else if (nr_found > 1) {
            printf ("Warning: multiple calibratable devices found, calibrating last one (%s)\n\tuse --device to select another one.\n", device_name);
        }

        if (verbose) {
            printf("DEBUG: Selected device: %s\n", device_name);
        }
    }

    // override min/max XY from command line ?
    if (precalib && !use_valuator) {
        if (pre_axys.x.min != -1)
            device_axys.x.min = pre_axys.x.min;
        if (pre_axys.x.max != -1)
            device_axys.x.max = pre_axys.x.max;
        if (pre_axys.y.min != -1)
            device_axys.y.min = pre_axys.y.min;
        if (pre_axys.y.max != -1)
            device_axys.y.max = pre_axys.y.max;

        if (verbose) {
            printf("DEBUG: Setting precalibration: %i, %i, %i, %i\n",
                device_axys.x.min, device_axys.x.max,
                device_axys.y.min, device_axys.y.max);
        }
    }


    // Different device/driver, different ways to apply the calibration values
    try {
        // try Usbtouchscreen driver
        return new CalibratorUsbtouchscreen(device_name, device_axys,
            thr_misclick, thr_doubleclick, output_type, geometry,
            use_timeout, output_filename);

    } catch(WrongCalibratorException& x) {
        if (verbose)
            printf("DEBUG: Not usbtouchscreen calibrator: %s\n", x.what());
    }

    try {
        // next, try Evdev driver (with XID)
        return new CalibratorEvdev(device_name, device_axys, device_id,
            thr_misclick, thr_doubleclick, output_type, geometry,
            use_valuator, use_timeout, output_filename);

    } catch(WrongCalibratorException& x) {
        if (verbose)
            printf("DEBUG: Not evdev calibrator: %s\n", x.what());
    }

    // lastly, presume a standard Xorg driver (evtouch, mutouch, ...)
    return new CalibratorXorgPrint(device_name, device_axys,
            thr_misclick, thr_doubleclick, output_type, geometry,
            use_timeout, output_filename);
}
Example #2
0
int main() {
    // screen dimensions
    int width = 800;
    int height = 600;
    XYinfo screen_res(0, width, 0, height);

    int delta_x = width/(float)num_blocks;
    int delta_y = height/(float)num_blocks;
    XYinfo target(delta_x, width-delta_x, delta_y, height-delta_y);

    int slack = 2; // amount of pixels result can be off target

    XYinfo dev_res(0, 1000, 0, 1000);

    std::vector<XYinfo> old_axes;
    old_axes.push_back( XYinfo(0, 1000, 0, 1000) );
    old_axes.push_back( XYinfo(1000, 0, 0, 1000) );
    old_axes.push_back( XYinfo(0, 1000, 1000, 0) );
    old_axes.push_back( XYinfo(1000, 0, 0, 1000) );
    old_axes.push_back( XYinfo(0, 1000, 0, 1000, 1, 0, 0) );
    old_axes.push_back( XYinfo(0, 1000, 0, 1000, 1, 0, 1) );
    old_axes.push_back( XYinfo(0, 1000, 0, 1000, 1, 1, 0) );
    old_axes.push_back( XYinfo(0, 1000, 0, 1000, 1, 1, 1) );
    old_axes.push_back( XYinfo(1000, 0, 0, 1000, 1, 0, 0) );
    old_axes.push_back( XYinfo(1000, 0, 0, 1000, 1, 0, 1) );
    old_axes.push_back( XYinfo(1000, 0, 0, 1000, 1, 1, 0) );
    old_axes.push_back( XYinfo(1000, 0, 0, 1000, 1, 1, 1) );
    // non device-resolution calibs
    old_axes.push_back( XYinfo(42, 929, 20, 888) );
    // xf86ScaleAxis rounds to min/max, this can lead to inaccurate
    // results! Can we fix that?
    old_axes.push_back( XYinfo(42, 929, 20, 888) );
    //old_axes.push_back( XYinfo(-9, 895, 124, 990) ); // this is the true axis
                                                       // rounding error when raw_coords are swapped???
    //old_axes.push_back( XYinfo(75, 750, 20, 888) ); // rounding error on X axis
    //old_axes.push_back( XYinfo(42, 929, 120, 888) ); // rounding error on Y axis

    // raw device coordinates to emulate
    std::vector<XYinfo> raw_coords;
    // normal
    raw_coords.push_back( XYinfo(105, 783, 233, 883) );
    // invert x, y, x+y
    raw_coords.push_back( XYinfo(783, 105, 233, 883) );
    raw_coords.push_back( XYinfo(105, 783, 883, 233) );
    raw_coords.push_back( XYinfo(783, 105, 883, 233) );
    // swap
    raw_coords.push_back( XYinfo(233, 883, 105, 783) );
    // swap and inverts
    raw_coords.push_back( XYinfo(233, 883, 783, 105) );
    raw_coords.push_back( XYinfo(883, 233, 105, 783) );
    raw_coords.push_back( XYinfo(883, 233, 783, 105) );

    CalibratorTesterInterface* calib;
    for (unsigned t=0; t<=1; t++) {
        if (t == 0)
            printf("CalibratorTester\n");
        else if (t == 1)
            printf("CalibratorEvdevTester\n");

    for (unsigned a=0; a != old_axes.size(); a++) {
        XYinfo old_axis(old_axes[a]);
        printf("Old axis: "); old_axis.print();

    for (unsigned c=0; c != raw_coords.size(); c++) {
        XYinfo raw(raw_coords[c]);
        //printf("Raw: "); raw.print();

        // reset calibrator object
        if (t == 0)
            calib = new CalibratorTester("Tester", old_axis);
        else if (t == 1)
            calib = new CalibratorEvdevTester("Tester", old_axis);

        // clicked from raw
        XYinfo clicked = calib->emulate_driver(raw, false, screen_res, dev_res);// false=old_axis
        //printf("\tClicked: "); clicked.print();

        // emulate screen clicks
        calib->add_click(clicked.x.min, clicked.y.min);
        calib->add_click(clicked.x.max, clicked.y.min);
        calib->add_click(clicked.x.min, clicked.y.max);
        calib->add_click(clicked.x.max, clicked.y.max);
        calib->finish(width, height);

        // test result
        XYinfo result = calib->emulate_driver(raw, true, screen_res, dev_res); // true=new_axis

        int maxdiff = std::max(abs(target.x.min - result.x.min),
                      std::max(abs(target.x.max - result.x.max),
                      std::max(abs(target.y.min - result.y.min),
                               abs(target.y.max - result.y.max)))); // no n-ary max in c++??
        if (maxdiff > slack) {
            printf("-\n");
            printf("Old axis: "); old_axis.print();
            printf("Raw: "); raw.print();
            printf("Clicked: "); clicked.print();
            printf("New axis: "); calib->new_axis_print();
            printf("Error: difference between target and result: %i > %i:\n", maxdiff, slack);
            printf("\tTarget: "); target.print();
            printf("\tResult: "); result.print();
            exit(1);
        }

        printf("%i", maxdiff);
    } // loop over raw_coords

        printf(". OK\n");
    } // loop over old_axes

        printf("\n");
    } // loop over calibrators

    delete calib;
}