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); }
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; }