diff --git a/.gitignore b/.gitignore index 6dbd811..8a90aa6 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,6 @@ Makefile Makefile.in missing mkinstalldirs - +*~ *.o *.pc diff --git a/autogen.sh b/autogen.sh index 904cd67..6364448 100755 --- a/autogen.sh +++ b/autogen.sh @@ -9,4 +9,4 @@ cd $srcdir autoreconf -v --install || exit 1 cd $ORIGDIR || exit $? -$srcdir/configure --enable-maintainer-mode "$@" +$srcdir/configure --enable-maintainer-mode $@ diff --git a/configure.ac b/configure.ac index 9997354..c11c3de 100644 --- a/configure.ac +++ b/configure.ac @@ -46,6 +46,7 @@ AC_SUBST(XINPUT_LIBS) PKG_CHECK_MODULES(XI_PROP, [xi >= 1.2] [inputproto >= 1.5], AC_DEFINE(HAVE_XI_PROP, 1, [Xinput properties available]), foo="bar") +AC_CONFIG_MACRO_DIR([m4]) AC_ARG_WITH([gui], AS_HELP_STRING([--with-gui=default], [Use gtkmm GUI if available, x11 GUI otherwise (default)]),,[with_gui=default]) AC_ARG_WITH([gui], AS_HELP_STRING([--with-gui=gtkmm], [Use gtkmm GUI])) diff --git a/src/.gitignore b/src/.gitignore index 15af283..d186860 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,2 +1,3 @@ xinput_calibrator_x11 xinput_calibrator_gtkmm +xinput_calibrator diff --git a/src/Makefile.am b/src/Makefile.am index ea3621b..8521062 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -28,19 +28,21 @@ SUBDIRS = \ calibrator \ gui -AM_CXXFLAGS = -Wall -ansi -pedantic -Wmissing-declarations +AM_CXXFLAGS = -Wall -ansi -pedantic bin_PROGRAMS = xinput_calibrator +COMMON_SRCS=calibrator.cpp calibrator/XorgPrint.cpp calibrator/Evdev.cpp calibrator/Usbtouchscreen.cpp main_common.cpp + # only one of the BUILD_ flags should be set if BUILD_X11 -xinput_calibrator_SOURCES = main_x11.cpp +xinput_calibrator_SOURCES = gui/x11.cpp main_x11.cpp $(COMMON_SRCS) xinput_calibrator_LDADD = $(XINPUT_LIBS) $(XRANDR_LIBS) $(X11_LIBS) xinput_calibrator_CXXFLAGS = $(XINPUT_CFLAGS) $(X11_CFLAGS) $(XRANDR_CFLAGS) $(AM_CXXFLAGS) endif if BUILD_GTKMM -xinput_calibrator_SOURCES = main_gtkmm.cpp +xinput_calibrator_SOURCES = gui/gtkmm.cpp main_gtkmm.cpp $(COMMON_SRCS) xinput_calibrator_LDADD = $(XINPUT_LIBS) $(GTKMM_LIBS) xinput_calibrator_CXXFLAGS = $(XINPUT_CFLAGS) $(GTKMM_CFLAGS) $(AM_CXXFLAGS) @@ -52,4 +54,5 @@ endif EXTRA_DIST = \ calibrator.cpp \ calibrator.hh \ - main_common.hpp + main_common.cpp + diff --git a/src/calibrator.cpp b/src/calibrator.cpp index ce789e4..2b50db1 100644 --- a/src/calibrator.cpp +++ b/src/calibrator.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2009 Tias Guns * Copyright (c) 2009 Soren Hauberg + * Copyright (c) 2011 Antoine Hue * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,42 +26,38 @@ #include #include #include -#include +#include +#include #include "calibrator.hh" -Calibrator::Calibrator(const char* const device_name0, const XYinfo& axys0, - const bool verbose0, const int thr_misclick, const int thr_doubleclick, const OutputType output_type0) - : device_name(device_name0), old_axys(axys0), verbose(verbose0), num_clicks(0), threshold_doubleclick(thr_doubleclick), threshold_misclick(thr_misclick), output_type(output_type0) -{ -} - -void Calibrator::set_threshold_doubleclick(int t) -{ - threshold_doubleclick = t; -} +// static instance +bool Calibrator::verbose = false; -void Calibrator::set_threshold_misclick(int t) -{ - threshold_misclick = t; -} - -int Calibrator::get_numclicks() +Calibrator::Calibrator(const char* const device_name0, const XYinfo& axys0, + const int thr_misclick, const int thr_doubleclick, const OutputType output_type0, const char* geometry0) + : device_name(device_name0), + threshold_doubleclick(thr_doubleclick), threshold_misclick(thr_misclick), + output_type(output_type0), geometry(geometry0) { - return num_clicks; + old_axys = axys0; + + clicked.num = 0; + //clicked.x(NUM_POINTS); + //clicked.y(NUM_POINTS); } bool Calibrator::add_click(int x, int y) { // Double-click detection - if (threshold_doubleclick > 0 && num_clicks > 0) { - int i = num_clicks-1; + if (threshold_doubleclick > 0 && clicked.num > 0) { + int i = clicked.num - 1; while (i >= 0) { - if (abs(x - clicked_x[i]) <= threshold_doubleclick - && abs(y - clicked_y[i]) <= threshold_doubleclick) { + if (abs(x - clicked.x[i]) <= threshold_doubleclick + && abs(y - clicked.y[i]) <= threshold_doubleclick) { if (verbose) { - printf("DEBUG: Not adding click %i (X=%i, Y=%i): within %i pixels of previous click\n", - num_clicks, x, y, threshold_doubleclick); + trace ( "Not adding click %i (X=%i, Y=%i): within %i pixels of previous click\n", + clicked.num, x, y, threshold_doubleclick); } return false; } @@ -69,52 +66,69 @@ bool Calibrator::add_click(int x, int y) } // Mis-click detection - if (threshold_misclick > 0 && num_clicks > 0) { - bool misclick = true; - - if (num_clicks == 1) { - // check that along one axis of first point - if (along_axis(x,clicked_x[0],clicked_y[0]) || - along_axis(y,clicked_x[0],clicked_y[0])) - misclick = false; - } else if (num_clicks == 2) { - // check that along other axis of first point than second point - if ((along_axis(y,clicked_x[0],clicked_y[0]) && - along_axis(clicked_x[1],clicked_x[0],clicked_y[0])) || - (along_axis(x,clicked_x[0],clicked_y[0]) && - along_axis(clicked_y[1],clicked_x[0],clicked_y[0]))) - misclick = false; - } else if (num_clicks == 3) { - // check that along both axis of second and third point - if ((along_axis(x,clicked_x[1],clicked_y[1]) && - along_axis(y,clicked_x[2],clicked_y[2])) || - (along_axis(y,clicked_x[1],clicked_y[1]) && - along_axis(x,clicked_x[2],clicked_y[2]))) - misclick = false; - } - - if (misclick) { - if (verbose) { - if (num_clicks == 1) - printf("DEBUG: Mis-click detected, click %i (X=%i, Y=%i) not aligned with click 0 (X=%i, Y=%i) (threshold=%i)\n", num_clicks, x, y, clicked_x[0], clicked_y[0], threshold_misclick); - else if (num_clicks == 2) - printf("DEBUG: Mis-click detected, click %i (X=%i, Y=%i) not aligned with click 0 (X=%i, Y=%i) or click 1 (X=%i, Y=%i) (threshold=%i)\n", num_clicks, x, y, clicked_x[0], clicked_y[0], clicked_x[1], clicked_y[1], threshold_misclick); - else if (num_clicks == 3) - printf("DEBUG: Mis-click detected, click %i (X=%i, Y=%i) not aligned with click 1 (X=%i, Y=%i) or click 2 (X=%i, Y=%i) (threshold=%i)\n", num_clicks, x, y, clicked_x[1], clicked_y[1], clicked_x[2], clicked_y[2], threshold_misclick); - } - - reset(); - return false; - } - } - - clicked_x[num_clicks] = x; - clicked_y[num_clicks] = y; - num_clicks++; - - if (verbose) - printf("DEBUG: Adding click %i (X=%i, Y=%i)\n", num_clicks-1, x, y); - + if (threshold_misclick > 0 && clicked.num > 0) + { + bool misclick = true; + + switch (clicked.num) + { + case 1: + // check that along one axis of first point + if (along_axis(x,clicked.x[UL],clicked.y[UL]) + || along_axis(y,clicked.x[UL],clicked.y[UL])) + { + misclick = false; + } + else + { + trace ( "Mis-click detected, click %i (X=%i, Y=%i) not aligned with click 0 (X=%i, Y=%i) (threshold=%i)\n", + clicked.num, x, y, clicked.x[UL], clicked.y[UL], threshold_misclick); + } + break; + + case 2: + // check that along other axis of first point than second point + if ((along_axis( y, clicked.x[UL], clicked.y[UL]) + && along_axis( clicked.x[UR], clicked.x[UL], clicked.y[UL])) + || (along_axis( x, clicked.x[UL], clicked.y[UL]) + && along_axis( clicked.y[UR], clicked.x[UL], clicked.y[UL]))) + { + misclick = false; + } + else + { + trace ( "Mis-click detected, click %i (X=%i, Y=%i) not aligned with click 0 (X=%i, Y=%i) or click 1 (X=%i, Y=%i) (threshold=%i)\n", + clicked.num, x, y, clicked.x[UL], clicked.y[UL], clicked.x[UR], clicked.y[UR], threshold_misclick); + } + break; + + case 3: + // check that along both axis of second and third point + if ( ( along_axis( x, clicked.x[UR], clicked.y[UR]) + && along_axis( y, clicked.x[LL], clicked.y[LL]) ) + ||( along_axis( y, clicked.x[UR], clicked.y[UR]) + && along_axis( x, clicked.x[LL], clicked.y[LL]) ) ) + { + misclick = false; + } + else + { + trace ( "Mis-click detected, click %i (X=%i, Y=%i) not aligned with click 1 (X=%i, Y=%i) or click 2 (X=%i, Y=%i) (threshold=%i)\n", + clicked.num, x, y, clicked.x[UR], clicked.y[UR], clicked.x[LL], clicked.y[LL], threshold_misclick); + } + } + + if (misclick) { + reset(); + return false; + } + } + + clicked.x.push_back(x); + clicked.y.push_back(y); + clicked.num++; + + trace("Adding click %i (X=%i, Y=%i)\n", clicked.num-1, x, y); return true; } @@ -124,47 +138,95 @@ inline bool Calibrator::along_axis(int xy, int x0, int y0) (abs(xy - y0) <= threshold_misclick)); } -bool Calibrator::finish(int width, int height) +/// Compute calibration on 1 axis +/// (all +0.5 for float to int rounding) +void Calibrator::process_axys( int screen_dim, const AxisInfo &previous, std::vector &clicked, AxisInfo &updated ) { - if (get_numclicks() != 4) { - return false; - } - - // Should x and y be swapped? - const bool swap_xy = (abs (clicked_x [UL] - clicked_x [UR]) < abs (clicked_y [UL] - clicked_y [UR])); - if (swap_xy) { - std::swap(clicked_x[LL], clicked_x[UR]); - std::swap(clicked_y[LL], clicked_y[UR]); - } - - // Compute min/max coordinates. - XYinfo axys; - // These are scaled using the values of old_axys - const float scale_x = (old_axys.x_max - old_axys.x_min)/(float)width; - axys.x_min = ((clicked_x[UL] + clicked_x[LL]) * scale_x/2) + old_axys.x_min; - axys.x_max = ((clicked_x[UR] + clicked_x[LR]) * scale_x/2) + old_axys.x_min; - const float scale_y = (old_axys.y_max - old_axys.y_min)/(float)height; - axys.y_min = ((clicked_y[UL] + clicked_y[UR]) * scale_y/2) + old_axys.y_min; - axys.y_max = ((clicked_y[LL] + clicked_y[LR]) * scale_y/2) + old_axys.y_min; - - // Add/subtract the offset that comes from not having the points in the - // corners (using the same coordinate system they are currently in) - const int delta_x = (axys.x_max - axys.x_min) / (float)(num_blocks - 2); - axys.x_min -= delta_x; - axys.x_max += delta_x; - const int delta_y = (axys.y_max - axys.y_min) / (float)(num_blocks - 2); - axys.y_min -= delta_y; - axys.y_max += delta_y; - - - // If x and y has to be swapped we also have to swap the parameters - if (swap_xy) { - std::swap(axys.x_min, axys.y_max); - std::swap(axys.y_min, axys.x_max); - } + // These are scaled using the values of old_axys + const float old_scale = (previous.max - previous.min)/(float)screen_dim; + + // Sort to get lowest two and highest two whatever is the orientation + std::sort( clicked.begin(), clicked.end()); + // If inverted, must undo inversion since calibration is before in evdev driver. + if ( previous.invert ) + { + updated.min = ( (2*screen_dim - clicked[2] - clicked[3]) * old_scale/2 ) + previous.min + 0.5; + updated.max = ( (2*screen_dim - clicked[0] - clicked[1]) * old_scale/2 ) + previous.min + 0.5; + } + else + { + updated.min = ( (clicked[0] + clicked[1]) * old_scale/2 ) + previous.min + 0.5; + updated.max = ( (clicked[2] + clicked[3]) * old_scale/2 ) + previous.min + 0.5; + } + + // Add/subtract the offset that comes from not having the points in the + // corners (using the new scale, assumed better than previous) + const int new_delta = (updated.max - updated.min) / (float)(num_blocks - 2) + 0.5; + updated.min -= new_delta; + updated.max += new_delta; +} - // finish the data, driver/calibrator specific - return finish_data(axys, swap_xy); +// Compute calibration and correct orientation from captured coordinates +bool Calibrator::finish(int width, int height) +{ + if (get_numclicks() != NUM_POINTS) + { + return false; + } + + trace ( "Screen size=%dx%d\n", width, height ); + trace ( "Expected screen coordinates, x.min=%d, x.max=%d, y.min=%d, y.max=%d\n", + width/num_blocks, width-width/num_blocks, + height/num_blocks, height - height/num_blocks); + + // Evdev v2.3.2 order to compute coordinates from peripheral to screen: + // - swap xy axis + // - calibration (offset and scale) + // - invert x, invert y axis + + trace ( "Previous orientation: swap_xy=%d, invert_x=%d, invert_y=%d\n", old_axys.swap_xy, old_axys.x.invert, old_axys.y.invert ); + + // Compute orientation modifications from existing (if orientation is already corrected, no change) + // Start reverse order vs. evdev: from screen to peripheral + + // Check if axes are inverted ? + bool invert_x = false, invert_y = false; + if ( clicked.x[UL] > clicked.x[LR] ) + { + invert_x = true; + } + + if ( clicked.y[UL] > clicked.y[LR] ) + { + invert_y = true; + } + + XYinfo new_axys; // new axys origin and scaling + + // Should x and y be swapped + const bool swap_xy = (abs (clicked.x [UL] - clicked.x [UR]) < abs (clicked.y [UL] - clicked.y [UR])); + trace ( "Orientation modifications: swap_xy=%d, invert_x=%d, invert_y=%d\n", swap_xy, invert_x, invert_y); + + /// Compute calibration + if (swap_xy) + { + process_axys( height, old_axys.x, clicked.y, new_axys.x ); + process_axys( width, old_axys.y, clicked.x, new_axys.y ); + } + else + { + process_axys( width, old_axys.x, clicked.x, new_axys.x ); + process_axys( height, old_axys.y, clicked.y, new_axys.y ); + } + + new_axys.swap_xy = old_axys.swap_xy ^ swap_xy; + new_axys.x.invert = old_axys.x.invert ^ invert_x; + new_axys.y.invert = old_axys.y.invert ^ invert_y; + + trace ( "New orientation: swap_xy=%d, invert_x=%d, invert_y=%d\n", new_axys.swap_xy, new_axys.x.invert, new_axys.y.invert ); + + // finish the data, driver/calibrator specific + return finish_data(new_axys); } const char* Calibrator::get_sysfs_name() @@ -197,10 +259,9 @@ bool Calibrator::is_sysfs_name(const char* name) { std::string devname; std::getline(ifile, devname); if (devname == name) { - if (verbose) - printf("DEBUG: Found that '%s' is a sysfs name.\n", name); - return true; - } + trace("Found that '%s' is a sysfs name.\n", name); + return true; + } } ifile.close(); } @@ -208,8 +269,7 @@ bool Calibrator::is_sysfs_name(const char* name) { } (void) closedir(dp); - if (verbose) - printf("DEBUG: Name '%s' does not match any in '%s/event*/%s'\n", + trace ("Name '%s' does not match any in '%s/event*/%s'\n", name, SYSFS_INPUT, SYSFS_DEVNAME); return false; } @@ -222,7 +282,7 @@ bool Calibrator::has_xorgconfd_support(Display* dpy) { display = XOpenDisplay(NULL); if (display == NULL) { - fprintf(stderr, "Unable to connect to X server\n"); + error ( "Unable to connect to X server\n"); exit(1); } @@ -236,3 +296,48 @@ bool Calibrator::has_xorgconfd_support(Display* dpy) { return has_support; } + +/// Write calibration output (to stdout) +void Calibrator::output ( const char *format, ... ) +{ + va_list vl; + va_start ( vl, format ); + vprintf ( format, vl ); + va_end ( vl ); +} + +/// Dump debug information if verbose activated +void Calibrator::trace ( const char *format, ...) +{ + if ( verbose == true ) + { + printf ( "DEBUG: "); + va_list vl; + va_start ( vl, format ); + vprintf ( format, vl ); + va_end ( vl ); + } +} + +/// Information to user, if verbose mode activated +void Calibrator::info ( const char *format, ... ) +{ + if ( verbose == true ) + { + printf ( "INFO: "); + va_list vl; + va_start ( vl, format ); + vprintf ( format, vl ); + va_end ( vl ); + } +} + +/// Error (non fatal) +void Calibrator::error ( const char *format, ...) +{ + fprintf ( stderr, "ERROR: "); + va_list vl; + va_start ( vl, format ); + vprintf ( format, vl ); + va_end ( vl ); +} diff --git a/src/calibrator.hh b/src/calibrator.hh index 01b3fb9..d66de29 100644 --- a/src/calibrator.hh +++ b/src/calibrator.hh @@ -1,6 +1,7 @@ /* * Copyright (c) 2009 Tias Guns * Copyright (c) 2009 Soren Hauberg + * Copyright (c) 2011 Antoine Hue * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,54 +25,178 @@ #ifndef _calibrator_hh #define _calibrator_hh -// Abstract base class for calculating new calibration parameters +#include +#include +#include + +/* + * Number of blocks. We partition the screen into 'num_blocks' x 'num_blocks' + * rectangles of equal size. We then ask the user to press points that are + * located at the corner closes to the center of the four blocks in the corners + * of the screen. The following ascii art illustrates the situation. We partition + * the screen into 8 blocks in each direction. We then let the user press the + * points marked with 'O'. + * + * +--+--+--+--+--+--+--+--+ + * | | | | | | | | | + * +--O--+--+--+--+--+--O--+ + * | | | | | | | | | + * +--+--+--+--+--+--+--+--+ + * | | | | | | | | | + * +--+--+--+--+--+--+--+--+ + * | | | | | | | | | + * +--+--+--+--+--+--+--+--+ + * | | | | | | | | | + * +--+--+--+--+--+--+--+--+ + * | | | | | | | | | + * +--+--+--+--+--+--+--+--+ + * | | | | | | | | | + * +--O--+--+--+--+--+--O--+ + * | | | | | | | | | + * +--+--+--+--+--+--+--+--+ + */ +const int num_blocks = 8; + +struct AxisInfo { + int min, max; + bool invert; + AxisInfo() : min(-1), max(-1), invert(false) { } +}; + +/// struct to hold min/max info of the X and Y axis +struct XYinfo { + /// Axis swapped + bool swap_xy; + /// X, Y axis + AxisInfo x, y; + + XYinfo() : swap_xy(false) {} + + XYinfo(int xmi, int xma, int ymi, int yma, bool swap_xy_ = false): + swap_xy(swap_xy_) { x.min = xmi; x.max = xma; y.min = ymi; y.max = yma;} +}; + +/// Names of the points +enum { + UL = 0, // Upper-left + UR = 1, // Upper-right + LL = 2, // Lower-left + LR = 3, // Lower-right + NUM_POINTS +}; + +/// Output types +enum OutputType { + OUTYPE_AUTO, + OUTYPE_XORGCONFD, + OUTYPE_HAL, + OUTYPE_XINPUT +}; + +class WrongCalibratorException : public std::invalid_argument { + public: + WrongCalibratorException(const std::string& msg = "") : + std::invalid_argument(msg) {} +}; + +/// Base class for calculating new calibration parameters class Calibrator { -public: - /* Constructor for a specific calibrator - * - * The constructor will throw an exception, - * if the touchscreen is not of the type it supports - */ - Calibrator(const char* const device_name, const XYinfo& axys, - const bool verbose, const int thr_misclick=0, const int thr_doubleclick=0, const OutputType output_type=OUTYPE_AUTO); - ~Calibrator() {} - - // set the doubleclick treshold - void set_threshold_doubleclick(int t); - // set the misclick treshold - void set_threshold_misclick(int t); - // get the number of clicks already registered - int get_numclicks(); - // reset clicks - void reset() { - num_clicks = 0; - } - // add a click with the given coordinates + public: + /// Parse arguments and create calibrator + static Calibrator* make_calibrator(int argc, char** argv); + + /// Constructor + /// + /// The constructor will throw an exception, + /// if the touchscreen is not of the type it supports + Calibrator(const char* const device_name, + const XYinfo& axys, + const int thr_misclick=0, + const int thr_doubleclick=0, + const OutputType output_type=OUTYPE_AUTO, + const char* geometry=0); + + ~Calibrator() + {} + + /// set the doubleclick treshold + void set_threshold_doubleclick(int t) + { threshold_doubleclick = t; } + + /// set the misclick treshold + void set_threshold_misclick(int t) + { threshold_misclick = t; } + + /// get the number of clicks already registered + int get_numclicks() const + { return clicked.num; } + + /// return geometry string or NULL + const char* get_geometry() const + { return geometry; } + + /// reset clicks + void reset() + { clicked.num = 0; clicked.x.clear(); clicked.y.clear();} + + /// add a click with the given coordinates bool add_click(int x, int y); - // calculate and apply the calibration + /// calculate and apply the calibration bool finish(int width, int height); - // get the sysfs name of the device, - // returns NULL if it can not be found + /// get the sysfs name of the device, + /// returns NULL if it can not be found const char* get_sysfs_name(); protected: - // check whether the coordinates are along the respective axis + /// check whether the coordinates are along the respective axis bool along_axis(int xy, int x0, int y0); - // overloaded function that applies the new calibration - virtual bool finish_data(const XYinfo new_axys, int swap_xy) =0; - + /// Apply new calibration, implementation dependent + ///\param[in] swap_xy if true, X and Y axes are swapped + ///\param[in] invert_x if true, X axis is inverted + ///\param[in] invert_y if true, Y axis is inverted + virtual bool finish_data(const XYinfo new_axys ) =0; + + /// Compute calibration on 1 axis + void process_axys( int screen_dim, const AxisInfo &previous, std::vector &clicked, AxisInfo &updated ); + + /// Check whether the given name is a sysfs device name + bool is_sysfs_name(const char* name); + + /// Check whether the X server has xorg.conf.d support + bool has_xorgconfd_support(Display* display=NULL); + + /// Write output calibration (to stdout) + void output ( const char *format, ... ); + + /// Write information to user, if verbose mode activated + static void info ( const char *format, ... ); + + /// Trace debug information if verbose activated + static void trace ( const char *format, ...); + + /// Write error (non fatal) + static void error ( const char *format, ...); + + static int find_device(const char* pre_device, bool list_devices, + XID& device_id, const char*& device_name, XYinfo& device_axys); + protected: + // be verbose or not + static bool verbose; + // name of the device (driver) const char* const device_name; - // original axys values - XYinfo old_axys; - // be verbose or not - bool verbose; - // nr of clicks registered - int num_clicks; - // click coordinates - int clicked_x[4], clicked_y[4]; + /// Original values + XYinfo old_axys; + + /// Clicked values (screen coordinates) + struct { + /// actual number of clicks registered + int num; + /// click coordinates + std::vector x, y; + } clicked; // Threshold to keep the same point from being clicked twice. // Set to zero if you don't want this check @@ -82,14 +207,11 @@ protected: // Set to zero if you don't want this check int threshold_misclick; - // Type of output + /// Format or type of output calibration OutputType output_type; - // Check whether the given name is a sysfs device name - bool is_sysfs_name(const char* name); - - // Check whether the X server has xorg.conf.d support - bool has_xorgconfd_support(Display* display=NULL); + /// manually specified geometry string for the calibration pattern + const char* geometry; }; #endif diff --git a/src/calibrator/Evdev.cpp b/src/calibrator/Evdev.cpp new file mode 100644 index 0000000..6182e70 --- /dev/null +++ b/src/calibrator/Evdev.cpp @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2009 Tias Guns + * Copyright 2007 Peter Hutterer (xinput_ methods from xinput) + * Copyright (c) 2011 Antoine Hue (invertX/Y) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "calibrator/Evdev.hpp" + +#include +#include +#include +#include +#include +#include + +#ifndef EXIT_SUCCESS +#define EXIT_SUCCESS 1 +#endif +#ifndef EXIT_FAILURE +#define EXIT_FAILURE 0 +#endif + +// 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) + : Calibrator(device_name0, axys0, thr_misclick, thr_doubleclick, output_type, geometry) +{ + // 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 (nitems == 0) { + if (verbose) + trace ( "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 + 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); + + trace("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); + + trace("Read InvertX=%i, InvertY=%i.\n", old_axys.x.invert, old_axys.y.invert); + } + } + + // TODO? evdev < 2.3.2 with swap_xy had a bug which calibrated before swapping (eg X calib on Y axis) + // see http://cgit.freedesktop.org/xorg/driver/xf86-input-evdev/commit/?h=evdev-2.3-branch&id=3772676fd65065b43a94234127537ab5030b09f8 + + trace("Calibrating EVDEV driver for \"%s\" id=%i\n", device_name, (int)device_id); + trace("\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 + +} + +// Destructor +CalibratorEvdev::~CalibratorEvdev () { + XCloseDevice(display, dev); + XCloseDisplay(display); +} + +// Activate calibrated data or write it +bool CalibratorEvdev::finish_data(const XYinfo new_axys) +{ + bool success = true; + + // swap x and y axis, indicated by swap_xy + // new value is old value (could have been 0 or 1) swapped: + int new_swap_xy = (new_axys.swap_xy)?1:0; + int new_invert_x = (new_axys.x.invert)?1:0; + int new_invert_y = (new_axys.y.invert)?1:0; + + trace("--- Doing dynamic recalibration:\n"); + + // Evdev Axes Swap + success &= set_swapxy(new_swap_xy); + success &= set_invert_xy(true, new_invert_x, new_invert_y); + + // Evdev Axis Calibration + trace("\tSetting new calibration data: %d, %d, %d, %d\n", new_axys.x.min, new_axys.x.max, new_axys.y.min, new_axys.y.max); + success &= set_calibration(new_axys); + + // close + XSync(display, False); + + trace("\t--> Making the calibration permanent <--\n"); + switch (output_type) { + case OUTYPE_AUTO: + // xorg.conf.d or alternatively xinput commands + if (has_xorgconfd_support()) { + success &= output_xorgconfd(new_axys, new_swap_xy, new_invert_x, new_invert_y); + } else { + success &= output_xinput(new_axys, new_swap_xy, new_invert_x, new_invert_y); + } + break; + case OUTYPE_XORGCONFD: + success &= output_xorgconfd(new_axys, new_swap_xy, new_invert_x, new_invert_y); + break; + case OUTYPE_HAL: + success &= output_hal(new_axys, new_swap_xy, new_invert_x, new_invert_y); + break; + case OUTYPE_XINPUT: + success &= output_xinput(new_axys, new_swap_xy, new_invert_x, new_invert_y); + break; + default: + error ( "ERROR: Evdev Calibrator does not support the supplied --output-type\n"); + success = false; + } + + return success; +} + +bool CalibratorEvdev::set_swapxy(const int swap_xy) +{ + int arr_cmd[1]; + arr_cmd[0] = swap_xy; + + bool ret = xinput_do_set_int_prop("Evdev Axes Swap", display, 8, 1, arr_cmd); + + if (ret == true) + trace("Successfully set swapped X and Y axes = %d.\n", swap_xy); + else + trace("Failed to set swap X and Y axes.\n"); + + return ret; +} + +bool CalibratorEvdev::set_invert_xy(bool axisX, const int invert_x, const int invert_y) +{ + int arr_cmd[2]; + arr_cmd[0] = invert_x; + arr_cmd[1] = invert_y; + + int ret = xinput_do_set_int_prop("Evdev Axis Inversion", display, 8, 2, arr_cmd); + + if (ret == true) + trace("Successfully set invert axis X=%d, Y=%d.\n", invert_x, invert_y); + else + trace("Failed to set axis inversion.\n"); + + return ret; +} + + +bool CalibratorEvdev::set_calibration(const XYinfo new_axys) +{ + // xinput set-int-prop 4 223 32 5 500 8 300 + int arr_cmd[4]; + arr_cmd[0] = new_axys.x.min; + arr_cmd[1] = new_axys.x.max; + arr_cmd[2] = new_axys.y.min; + arr_cmd[3] = new_axys.y.max; + + int ret = xinput_do_set_int_prop("Evdev Axis Calibration", display, 32, 4, arr_cmd); + + if (ret == true) + trace("Successfully applied axis calibration.\n"); + else + trace("Failed to apply axis calibration.\n"); + + return ret; +} + +Atom CalibratorEvdev::xinput_parse_atom(Display *display, const char *name) +{ + Bool is_atom = True; + + for (int i = 0; name[i] != '\0'; i++) { + if (!isdigit(name[i])) { + is_atom = False; + break; + } + } + + if (is_atom) + return atoi(name); + else + return XInternAtom(display, name, False); +} + +XDeviceInfo* CalibratorEvdev::xinput_find_device_info( +Display *display, const char *name, Bool only_extended) +{ + XDeviceInfo *devices; + XDeviceInfo *found = NULL; + int num_devices; + int len = strlen(name); + Bool is_id = True; + XID id = (XID)-1; + + for (int loop = 0; loop < len; loop++) + { + if (!isdigit(name[loop])) { + is_id = False; + break; + } + } + + if (is_id) { + id = atoi(name); + } + + devices = XListInputDevices(display, &num_devices); + + for ( int loop = 0; loop < num_devices; loop++) + { + if ((!only_extended || (devices[loop].use >= IsXExtensionDevice)) && + ((!is_id && strcmp(devices[loop].name, name) == 0) || + (is_id && devices[loop].id == id))) { + if (found) { + error ( "Warning: There are multiple devices named \"%s\".\n" + "To ensure the correct one is selected, please use " + "the device ID instead.\n\n", name); + return NULL; + } else { + found = &devices[loop]; + } + } + } + + return found; +} + +// Set Integer property on X +bool CalibratorEvdev::xinput_do_set_int_prop( const char * name, + Display *display, + int format, + int argc, + const int *argv ) +{ +#ifndef HAVE_XI_PROP + return false; +#else + + Atom prop; + Atom old_type; + int i; + int old_format; + unsigned long act_nitems, bytes_after; + + union { + unsigned char *c; + short *s; + long *l; + Atom *a; + } data; + + if (argc < 1) + { + error ( "Wrong usage of xinput_do_set_prop, need at least 1 argument\n"); + return false; + } + + prop = xinput_parse_atom(display, name); + + if (prop == None) { + error ( "invalid property %s\n", name); + return false; + } + + if ( format == 0) { + if (XGetDeviceProperty(display, dev, prop, 0, 0, False, AnyPropertyType, + &old_type, &old_format, &act_nitems, + &bytes_after, &data.c) != Success) { + error ( "failed to get property type and format for %s\n", + name); + return false; + } else { + format = old_format; + } + + XFree(data.c); + } + + data.c = (unsigned char*)calloc(argc, sizeof(long)); + + for (i = 0; i < argc; i++) + { + switch (format) + { + case 8: + data.c[i] = argv[i]; + case 16: + data.s[i] = argv[i]; + break; + case 32: + data.l[i] = argv[i]; + break; + + default: + error ( "unexpected size for property %s", name); + return false; + } + } + + XChangeDeviceProperty(display, dev, prop, XA_INTEGER, format, PropModeReplace, + data.c, argc); + free(data.c); + return true; +#endif // HAVE_XI_PROP + +} + +bool CalibratorEvdev::output_xorgconfd(const XYinfo new_axys, int new_swap_xy, int new_invert_x, int new_invert_y) +{ + const char* sysfs_name = get_sysfs_name(); + bool not_sysfs_name = (sysfs_name == NULL); + if (not_sysfs_name) + sysfs_name = "!!Name_Of_TouchScreen!!"; + + // xorg.conf.d snippet + info (" copy the snippet below into '/etc/X11/xorg.conf.d/99-calibration.conf'\n"); + output("Section \"InputClass\"\n"); + output(" Identifier \"calibration\"\n"); + output(" MatchProduct \"%s\"\n", sysfs_name); + output(" Option \"Calibration\" \"%d %d %d %d\"\n", + new_axys.x.min, new_axys.x.max, new_axys.y.min, new_axys.y.max); + output (" Option \"SwapAxes\" \"%d\"\n", new_swap_xy); + output ( "\tOption \"InvertX\" \"%d\"\n", new_invert_x); + output ( "\tOption \"InvertY\" \"%d\"\n", new_invert_y); + output("EndSection\n"); + + if (not_sysfs_name) + info ("\nChange '%s' to your device's name in the snippet above.\n", sysfs_name); + + return true; +} + +bool CalibratorEvdev::output_hal(const XYinfo new_axys, int new_swap_xy, int new_invert_x, int new_invert_y) +{ + const char* sysfs_name = get_sysfs_name(); + bool not_sysfs_name = (sysfs_name == NULL); + if (not_sysfs_name) + sysfs_name = "!!Name_Of_TouchScreen!!"; + + // HAL policy output + info (" copy the policy below into '/etc/hal/fdi/policy/touchscreen.fdi'\n"); + output ( "\n\ + %d %d %d %d\n", + sysfs_name, new_axys.x.min, new_axys.x.max, new_axys.y.min, new_axys.y.max); + output(" %d\n", new_swap_xy); + output(" %d\n", new_invert_x); + output(" %d\n", new_invert_y); + output("\n"); + + if (not_sysfs_name) + info ("\nChange '%s' to your device's name in the config above.\n", sysfs_name); + + return true; +} + +bool CalibratorEvdev::output_xinput(const XYinfo new_axys, int new_swap_xy, int new_invert_x, int new_invert_y) +{ + // create startup script + info (" Install the 'xinput' tool and copy the command(s) below in a script that starts with your X session\n"); + output (" xinput set-prop \"%s\" \"Evdev Axis Calibration\" %d %d %d %d\n", device_name, new_axys.x.min, new_axys.x.max, new_axys.y.min, new_axys.y.max); + + output (" xinput set-prop \"%s\" \"Evdev Axes Swap\" %d\n", device_name, new_swap_xy); + output (" xinput set-prop \"%s\" \"Evdev Axis Inversion\" %d %d\n", device_name, new_invert_x, new_invert_y); + return true; +} diff --git a/src/calibrator/Evdev.hpp b/src/calibrator/Evdev.hpp new file mode 100644 index 0000000..2a389cf --- /dev/null +++ b/src/calibrator/Evdev.hpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2009 Tias Guns + * Copyright 2007 Peter Hutterer (xinput_ methods from xinput) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef CALIBRATOR_EVDEV_HPP +#define CALIBRATOR_EVDEV_HPP + +#include "calibrator.hh" +#include + +/*************************************** + * Class for dynamic evdev calibration + * uses xinput "Evdev Axis Calibration" + ***************************************/ +class CalibratorEvdev: public Calibrator +{ +private: + Display *display; + XDeviceInfo *devInfo; + XDevice *dev; + +public: + CalibratorEvdev(const char* const device_name, const XYinfo& axys, + XID device_id=(XID)-1, const int thr_misclick=0, const int thr_doubleclick=0, + const OutputType output_type=OUTYPE_AUTO, const char* geometry=0); + ~CalibratorEvdev(); + + virtual bool finish_data(const XYinfo new_axys ); + + bool set_swapxy(const int swap_xy); + bool set_invert_xy(bool axisX, const int invert_x, const int invert_y ); + bool set_calibration(const XYinfo new_axys); + + // xinput_ functions (from the xinput project) + Atom xinput_parse_atom(Display *display, const char* name); + XDeviceInfo* xinput_find_device_info(Display *display, const char* name, Bool only_extended); + bool xinput_do_set_int_prop( const char * name, + Display *display, + int format, + int argc, + const int* argv); +protected: + bool output_xorgconfd(const XYinfo new_axys, int new_swap_xy, int new_invert_x, int new_invert_y); + bool output_hal(const XYinfo new_axys, int new_swap_xy, int new_invert_x, int new_invert_y); + bool output_xinput(const XYinfo new_axys, int new_swap_xy, int new_invert_x, int new_invert_y); +}; + +#endif diff --git a/src/calibrator/Makefile.am b/src/calibrator/Makefile.am index 63f2924..ec773a6 100644 --- a/src/calibrator/Makefile.am +++ b/src/calibrator/Makefile.am @@ -1,4 +1,4 @@ EXTRA_DIST = \ - calibratorEvdev.cpp \ - calibratorUsbtouchscreen.cpp \ - calibratorXorgPrint.cpp + Evdev.cpp \ + Usbtouchscreen.cpp \ + XorgPrint.cpp diff --git a/src/calibrator/calibratorUsbtouchscreen.cpp b/src/calibrator/Usbtouchscreen.cpp similarity index 55% rename from src/calibrator/calibratorUsbtouchscreen.cpp rename to src/calibrator/Usbtouchscreen.cpp index d15c719..299e549 100644 --- a/src/calibrator/calibratorUsbtouchscreen.cpp +++ b/src/calibrator/Usbtouchscreen.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2009 Soren Hauberg + * Copyright (c) 2011 Antoine Hue * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -19,182 +20,96 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include + +#include "calibrator/Usbtouchscreen.hpp" + +#include +#include +#include /************************* * Variables for usbtouchscreen specifically *************************/ // The file to which the calibration parameters are saved. // (XXX: is this distribution dependend?) -const char *modprobe_conf_local = "/etc/modprobe.conf.local"; +static const char *modprobe_conf_local = "/etc/modprobe.conf.local"; // Prefix to the kernel path where we can set the parameters -const char *module_prefix = "/sys/module/usbtouchscreen/parameters"; +static const char *module_prefix = "/sys/module/usbtouchscreen/parameters"; // Names of kernel parameters -const char *p_range_x = "range_x"; -const char *p_range_y = "range_y"; -const char *p_min_x = "min_x"; -const char *p_min_y = "min_y"; -const char *p_max_x = "max_x"; -const char *p_max_y = "max_y"; -const char *p_transform_xy = "transform_xy"; -const char *p_flip_x = "flip_x"; -const char *p_flip_y = "flip_y"; -const char *p_swap_xy = "swap_xy"; - - -/********************************** - * Class for usbtouchscreen driver, - * writes output parameters to running kernel and to modprobe.conf - **********************************/ -class CalibratorUsbtouchscreen: public Calibrator -{ -public: - CalibratorUsbtouchscreen(const char* const device_name, const XYinfo& axys, - const bool verbose, const int thr_misclick=0, const int thr_doubleclick=0, - const OutputType output_type=OUTYPE_AUTO); - ~CalibratorUsbtouchscreen(); - - virtual bool finish_data(const XYinfo new_axys, int swap_xy); - -protected: - // Globals for kernel parameters from startup. - // We revert to these if the program aborts - bool val_transform_xy, val_flip_x, val_flip_y, val_swap_xy; - - // Helper functions - char yesno(const bool value) - { - if (value) - return 'Y'; - else - return 'N'; - } - - void read_int_parameter(const char *param, int &value) - { - int dummy; - char filename[100]; - sprintf(filename, "%s/%s", module_prefix, param); - FILE *fid = fopen(filename, "r"); - if (fid == NULL) { - fprintf(stderr, "Could not read parameter '%s'\n", param); - return; - } - - dummy = fscanf(fid, "%d", &value); - fclose(fid); - } - - void read_bool_parameter(const char *param, bool &value) - { - char *dummy; - char filename[100]; - sprintf(filename, "%s/%s", module_prefix, param); - FILE *fid = fopen(filename, "r"); - if (fid == NULL) { - fprintf(stderr, "Could not read parameter '%s'\n", param); - return; - } - - char val[3]; - dummy = fgets(val, 2, fid); - fclose(fid); - - value = (val[0] == yesno(true)); - } - - void write_int_parameter(const char *param, const int value) - { - char filename[100]; - sprintf(filename, "%s/%s", module_prefix, param); - FILE *fid = fopen(filename, "w"); - if (fid == NULL) { - fprintf(stderr, "Could not save parameter '%s'\n", param); - return; - } - - fprintf(fid, "%d", value); - fclose(fid); - } - - void write_bool_parameter(const char *param, const bool value) - { - char filename[100]; - sprintf(filename, "%s/%s", module_prefix, param); - FILE *fid = fopen(filename, "w"); - if (fid == NULL) { - fprintf(stderr, "Could not save parameter '%s'\n", param); - return; - } - - fprintf(fid, "%c", yesno (value)); - fclose(fid); - } -}; - -CalibratorUsbtouchscreen::CalibratorUsbtouchscreen(const char* const device_name0, const XYinfo& axys0, const bool verbose0, const int thr_misclick, const int thr_doubleclick, const OutputType output_type) - : Calibrator(device_name0, axys0, verbose0, thr_misclick, thr_doubleclick, output_type) +static const char *p_range_x = "range_x"; +static const char *p_range_y = "range_y"; +static const char *p_min_x = "min_x"; +static const char *p_min_y = "min_y"; +static const char *p_max_x = "max_x"; +static const char *p_max_y = "max_y"; +static const char *p_transform_xy = "transform_xy"; +static const char *p_flip_x = "flip_x"; +static const char *p_flip_y = "flip_y"; +static const char *p_swap_xy = "swap_xy"; + +CalibratorUsbtouchscreen::CalibratorUsbtouchscreen(const char* const device_name0, const XYinfo& axys0, const int thr_misclick, const int thr_doubleclick, const OutputType output_type, const char* geometry) + : Calibrator(device_name0, axys0, thr_misclick, thr_doubleclick, output_type, geometry) { if (strcmp(device_name, "Usbtouchscreen") != 0) throw WrongCalibratorException("Not a usbtouchscreen device"); // Reset the currently running kernel read_bool_parameter(p_transform_xy, val_transform_xy); - read_bool_parameter(p_flip_x, val_flip_x); - read_bool_parameter(p_flip_y, val_flip_y); - read_bool_parameter(p_swap_xy, val_swap_xy); + read_bool_parameter(p_flip_x, old_axys.x.invert); + read_bool_parameter(p_flip_y, old_axys.y.invert); + read_bool_parameter(p_swap_xy, old_axys.swap_xy); +#if 0 // do not modify current write_bool_parameter(p_transform_xy, false); write_bool_parameter(p_flip_x, false); write_bool_parameter(p_flip_y, false); write_bool_parameter(p_swap_xy, false); - - printf("Calibrating Usbtouchscreen, through the kernel module\n"); +#endif + info ("Calibrating Usbtouchscreen, through the kernel module\n"); } CalibratorUsbtouchscreen::~CalibratorUsbtouchscreen() { +#if 0 // do not modify current // Dirty exit, so we restore the parameters of the running kernel write_bool_parameter (p_transform_xy, val_transform_xy); write_bool_parameter (p_flip_x, val_flip_x); write_bool_parameter (p_flip_y, val_flip_y); write_bool_parameter (p_swap_xy, val_swap_xy); +#endif } -bool CalibratorUsbtouchscreen::finish_data(const XYinfo new_axys, int swap_xy) +bool CalibratorUsbtouchscreen::finish_data(const XYinfo new_axys) { if (output_type != OUTYPE_AUTO) { - fprintf(stderr, "ERROR: Usbtouchscreen Calibrator does not support the supplied --output-type\n"); + error ("Usbtouchscreen Calibrator does not support the supplied --output-type\n"); return false; } // New ranges - const int range_x = (new_axys.x_max - new_axys.x_min); - const int range_y = (new_axys.y_max - new_axys.y_min); - // Should x and y be flipped ? - const bool flip_x = (new_axys.x_min > new_axys.x_max); - const bool flip_y = (new_axys.y_min > new_axys.y_max); - + const int range_x = (new_axys.x.max - new_axys.x.min); + const int range_y = (new_axys.y.max - new_axys.y.min); + // Send the estimated parameters to the currently running kernel write_int_parameter(p_range_x, range_x); write_int_parameter(p_range_y, range_y); - write_int_parameter(p_min_x, new_axys.x_min); - write_int_parameter(p_max_x, new_axys.x_max); - write_int_parameter(p_min_y, new_axys.y_min); - write_int_parameter(p_max_y, new_axys.y_max); + write_int_parameter(p_min_x, new_axys.x.min); + write_int_parameter(p_max_x, new_axys.x.max); + write_int_parameter(p_min_y, new_axys.y.min); + write_int_parameter(p_max_y, new_axys.y.max); write_bool_parameter(p_transform_xy, true); - write_bool_parameter(p_flip_x, flip_x); - write_bool_parameter(p_flip_y, flip_y); - write_bool_parameter(p_swap_xy, swap_xy); + write_bool_parameter(p_flip_x, new_axys.x.invert); + write_bool_parameter(p_flip_y, new_axys.y.invert); + write_bool_parameter(p_swap_xy, new_axys.swap_xy); // Read, then write calibration parameters to modprobe_conf_local, // to keep the for the next boot FILE *fid = fopen(modprobe_conf_local, "r"); if (fid == NULL) { - fprintf(stderr, "Error: Can't open '%s' for reading. Make sure you have the necessary rights\n", modprobe_conf_local); - fprintf(stderr, "New calibration data NOT saved\n"); + error ( "Can't open '%s' for reading. Make sure you have the necessary rights\n", modprobe_conf_local); + error ( "\tNew calibration data NOT saved\n"); return false; } @@ -215,16 +130,16 @@ bool CalibratorUsbtouchscreen::finish_data(const XYinfo new_axys, int swap_xy) char *new_opt = new char[opt_len]; sprintf(new_opt, "%s %s=%d %s=%d %s=%d %s=%d %s=%d %s=%d %s=%c %s=%c %s=%c %s=%c\n", opt, p_range_x, range_x, p_range_y, range_y, - p_min_x, new_axys.x_min, p_min_y, new_axys.y_min, - p_max_x, new_axys.x_max, p_max_y, new_axys.y_max, - p_transform_xy, yesno(true), p_flip_x, yesno(flip_x), - p_flip_y, yesno(flip_y), p_swap_xy, yesno(swap_xy)); + p_min_x, new_axys.x.min, p_min_y, new_axys.y.min, + p_max_x, new_axys.x.max, p_max_y, new_axys.y.max, + p_transform_xy, yesno(true), p_flip_x, yesno(new_axys.x.invert), + p_flip_y, yesno(new_axys.y.invert), p_swap_xy, yesno(new_axys.swap_xy)); new_contents += new_opt; fid = fopen(modprobe_conf_local, "w"); if (fid == NULL) { - fprintf(stderr, "Error: Can't open '%s' for writing. Make sure you have the necessary rights\n", modprobe_conf_local); - fprintf(stderr, "New calibration data NOT saved\n"); + error ( "Can't open '%s' for writing. Make sure you have the necessary rights\n", modprobe_conf_local); + error ( "\tNew calibration data NOT saved\n"); return false; } fprintf(fid, "%s", new_contents.c_str ()); @@ -232,3 +147,65 @@ bool CalibratorUsbtouchscreen::finish_data(const XYinfo new_axys, int swap_xy) return true; } + +void CalibratorUsbtouchscreen::read_int_parameter(const char *param, int &value) + { + int dummy; + char filename[100]; + sprintf(filename, "%s/%s", module_prefix, param); + FILE *fid = fopen(filename, "r"); + if (fid == NULL) { + error ( "Could not read parameter '%s'\n", param); + return; + } + + dummy = fscanf(fid, "%d", &value); + fclose(fid); + } + + void CalibratorUsbtouchscreen::read_bool_parameter(const char *param, bool &value) + { + char *dummy; + char filename[100]; + sprintf(filename, "%s/%s", module_prefix, param); + FILE *fid = fopen(filename, "r"); + if (fid == NULL) { + error ( "Could not read parameter '%s'\n", param); + return; + } + + char val[3]; + dummy = fgets(val, 2, fid); + fclose(fid); + + value = (val[0] == yesno(true)); + } + + void CalibratorUsbtouchscreen::write_int_parameter(const char *param, const int value) + { + char filename[100]; + sprintf(filename, "%s/%s", module_prefix, param); + FILE *fid = fopen(filename, "w"); + if (fid == NULL) { + error ( "Could not save parameter '%s'\n", param); + return; + } + + fprintf(fid, "%d", value); + fclose(fid); + } + +void CalibratorUsbtouchscreen::write_bool_parameter(const char *param, const bool value) +{ + char filename[100]; + sprintf(filename, "%s/%s", module_prefix, param); + FILE *fid = fopen(filename, "w"); + if (fid == NULL) { + error ("Could not save parameter '%s'\n", param); + return; + } + + fprintf(fid, "%c", yesno (value)); + fclose(fid); + } + diff --git a/src/calibrator/Usbtouchscreen.hpp b/src/calibrator/Usbtouchscreen.hpp new file mode 100644 index 0000000..f24a6f5 --- /dev/null +++ b/src/calibrator/Usbtouchscreen.hpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2009 Soren Hauberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef CALIBRATOR_USBTOUCHSCREEN_HPP +#define CALIBRATOR_USBTOUCHSCREEN_HPP + +#include "calibrator.hh" + +/********************************** + * Class for usbtouchscreen driver, + * writes output parameters to running kernel and to modprobe.conf + **********************************/ +class CalibratorUsbtouchscreen: public Calibrator +{ +public: + CalibratorUsbtouchscreen(const char* const device_name, const XYinfo& axys, + const int thr_misclick=0, const int thr_doubleclick=0, + const OutputType output_type=OUTYPE_AUTO, const char* geometry=0); + + ~CalibratorUsbtouchscreen(); + + virtual bool finish_data(const XYinfo new_axys ); + +protected: + // Globals for kernel parameters from startup. + // We revert to these if the program aborts + bool val_transform_xy; + + // Helper functions + inline char yesno(const bool value) + { + if (value) + return 'Y'; + else + return 'N'; + } + + void read_int_parameter(const char *param, int &value); + + void read_bool_parameter(const char *param, bool &value); + + void write_int_parameter(const char *param, const int value); + + void write_bool_parameter(const char *param, const bool value); +}; + +#endif diff --git a/src/calibrator/XorgPrint.cpp b/src/calibrator/XorgPrint.cpp new file mode 100644 index 0000000..c5e7d64 --- /dev/null +++ b/src/calibrator/XorgPrint.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2009 Tias Guns + * Copyright (c) 2011 Antoine Hue + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "calibrator/XorgPrint.hpp" + +#include + +CalibratorXorgPrint::CalibratorXorgPrint(const char* const device_name0, const XYinfo& axys0, const int thr_misclick, const int thr_doubleclick, const OutputType output_type, const char* geometry) + : Calibrator(device_name0, axys0, thr_misclick, thr_doubleclick, output_type, geometry) +{ + trace("Calibrating standard Xorg driver \"%s\"\n", device_name); + trace("\tcurrent calibration values: 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); + trace("\tIf these values are estimated wrong, either supply it manually with the --precalib option, or run the 'get_precalib.sh' script to automatically get it (through HAL).\n"); +} + +bool CalibratorXorgPrint::finish_data(const XYinfo new_axys) +{ + bool success = true; + + // we suppose the previous 'swap_xy', 'invert_x', 'invert_y' value was 0 + // (unfortunately there is no way to verify this (yet)) + int new_swap_xy = (new_axys.swap_xy)? 1: 0; + int new_invert_x = (new_axys.x.invert)? 1: 0; + int new_invert_y = (new_axys.y.invert)? 1: 0; + + info ("\t--> Making the calibration permanent <--\n"); + switch (output_type) { + case OUTYPE_AUTO: + // xorg.conf.d or alternatively hal config + if (has_xorgconfd_support()) { + success &= output_xorgconfd(new_axys, new_swap_xy, new_invert_x, new_invert_y); + } else { + success &= output_hal(new_axys, new_swap_xy, new_invert_x, new_invert_y); + } + break; + case OUTYPE_XORGCONFD: + success &= output_xorgconfd(new_axys, new_swap_xy, new_invert_x, new_invert_y); + break; + case OUTYPE_HAL: + success &= output_hal(new_axys, new_swap_xy, new_invert_x, new_invert_y); + break; + default: + error ( "XorgPrint Calibrator does not support the supplied --output-type\n"); + success = false; + } + + return success; +} + +bool CalibratorXorgPrint::output_xorgconfd(const XYinfo new_axys, int new_swap_xy, int new_invert_x, int new_invert_y) +{ + const char* sysfs_name = get_sysfs_name(); + bool not_sysfs_name = (sysfs_name == NULL); + if (not_sysfs_name) + sysfs_name = "!!Name_Of_TouchScreen!!"; + + // xorg.conf.d snippet + info (" copy the snippet below into '/etc/X11/xorg.conf.d/99-calibration.conf'\n"); + output("Section \"InputClass\"\n"); + output(" Identifier \"calibration\"\n"); + output(" MatchProduct \"%s\"\n", sysfs_name); + output(" Option \"MinX\" \"%d\"\n", new_axys.x.min); + output(" Option \"MaxX\" \"%d\"\n", new_axys.x.max); + output(" Option \"MinY\" \"%d\"\n", new_axys.y.min); + output(" Option \"MaxY\" \"%d\"\n", new_axys.y.max); + output(" Option \"SwapXY\" \"%d\" # unless it was already set\n", new_swap_xy); + output ( "\tOption \"InvertX\" \"%d\" # unless it was already set\n", new_invert_x); + output ( "\tOption \"InvertY\" \"%d\" # unless it was already set\n", new_invert_y); + output ("EndSection\n"); + + if (not_sysfs_name) + trace("Change '%s' to your device's name in the config above.\n", sysfs_name); + + return true; +} + +bool CalibratorXorgPrint::output_hal(const XYinfo new_axys, int new_swap_xy, int new_invert_x, int new_invert_y) +{ + const char* sysfs_name = get_sysfs_name(); + bool not_sysfs_name = (sysfs_name == NULL); + if (not_sysfs_name) + sysfs_name = "!!Name_Of_TouchScreen!!"; + + // HAL policy output + info (" copy the policy below into '/etc/hal/fdi/policy/touchscreen.fdi'\n"); + output ( "\n\ + %d\n\ + %d\n\ + %d\n\ + %d\n" + , sysfs_name, new_axys.x.min, new_axys.x.max, new_axys.y.min, new_axys.y.max); + + output(" %d\n", new_swap_xy); + output(" %d\n", new_invert_x); + output(" %d\n", new_invert_y); + output("\n"); + + if (not_sysfs_name) + info("\nChange '%s' to your device's name in the config above.\n", sysfs_name); + + return true; +} diff --git a/src/calibrator/XorgPrint.hpp b/src/calibrator/XorgPrint.hpp new file mode 100644 index 0000000..aaadbef --- /dev/null +++ b/src/calibrator/XorgPrint.hpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2009 Tias Guns + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef CALIBRATOR_XORGPRINT_HPP +#define CALIBRATOR_XORGPRINT_HPP + +#include "calibrator.hh" + +/*************************************** + * Class for generic Xorg driver, + * outputs new Xorg.conf and FDI policy, on stdout + ***************************************/ +class CalibratorXorgPrint: public Calibrator +{ +public: + CalibratorXorgPrint(const char* const device_name, const XYinfo& axys, + const int thr_misclick=0, const int thr_doubleclick=0, + const OutputType output_type=OUTYPE_AUTO, const char* geometry=0); + + virtual bool finish_data(const XYinfo new_axys); + +protected: + bool output_xorgconfd(const XYinfo new_axys, int new_swap_xy, int new_invert_x, int new_invert_y); + bool output_hal(const XYinfo new_axys, int new_swap_xy, int new_invert_x, int new_invert_y); +}; + +#endif diff --git a/src/calibrator/calibratorEvdev.cpp b/src/calibrator/calibratorEvdev.cpp deleted file mode 100644 index b19a899..0000000 --- a/src/calibrator/calibratorEvdev.cpp +++ /dev/null @@ -1,520 +0,0 @@ -/* - * Copyright (c) 2009 Tias Guns - * Copyright 2007 Peter Hutterer (xinput_ methods from xinput) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include - -#include -#include -#include -//#include - -#ifndef EXIT_SUCCESS -#define EXIT_SUCCESS 1 -#endif -#ifndef EXIT_FAILURE -#define EXIT_FAILURE 0 -#endif - -/*************************************** - * Class for dynamic evdev calibration - * uses xinput "Evdev Axis Calibration" - ***************************************/ -class CalibratorEvdev: public Calibrator -{ -private: - Display *display; - XDeviceInfo *info; - XDevice *dev; - - int old_swap_xy; -public: - CalibratorEvdev(const char* const device_name, const XYinfo& axys, const bool verbose, - XID device_id=(XID)-1, const int thr_misclick=0, const int thr_doubleclick=0, - const OutputType output_type=OUTYPE_AUTO); - ~CalibratorEvdev(); - - virtual bool finish_data(const XYinfo new_axys, int swap_xy); - - bool set_swapxy(const int swap_xy); - bool set_calibration(const XYinfo new_axys); - - // xinput_ functions (from the xinput project) - Atom xinput_parse_atom(Display *display, const char* name); - XDeviceInfo* xinput_find_device_info(Display *display, const char* name, Bool only_extended); - int xinput_do_set_prop(Display *display, Atom type, int format, int argc, char* argv[]); -protected: - bool output_xorgconfd(const XYinfo new_axys, int swap_xy, int new_swap_xy); - bool output_hal(const XYinfo new_axys, int swap_xy, int new_swap_xy); - bool output_xinput(const XYinfo new_axys, int swap_xy, int new_swap_xy); -}; - -CalibratorEvdev::CalibratorEvdev(const char* const device_name0, const XYinfo& axys0, const bool verbose0, XID device_id, const int thr_misclick, const int thr_doubleclick, const OutputType output_type) - : Calibrator(device_name0, axys0, verbose0, thr_misclick, thr_doubleclick, output_type), old_swap_xy(0) -{ - // 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) { - info = xinput_find_device_info(display, device_name, False); - if (!info) { - XCloseDisplay(display); - throw WrongCalibratorException("Evdev: Unable to find device"); - } - device_id = info->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 (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 thourgh xinput, but still active - // not setting the values here would result in a wrong first calibration - bool ok = set_calibration(old_axys); - - if (verbose) { - if (ok) - printf("DEBUG: Successfully applied axis calibration.\n"); - else - printf("DEBUG: Failed to apply axis calibration.\n"); - } - - } 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_swap_xy = *((char*)data); - - if (verbose) - printf("DEBUG: Read axes swap value of %i.\n", old_swap_xy); - } - } - // TODO? evdev < 2.3.2 with swap_xy had a bug which calibrated before swapping (eg X calib on Y axis) - // see http://cgit.freedesktop.org/xorg/driver/xf86-input-evdev/commit/?h=evdev-2.3-branch&id=3772676fd65065b43a94234127537ab5030b09f8 - - 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 - -} - -CalibratorEvdev::~CalibratorEvdev () { - XCloseDevice(display, dev); - XCloseDisplay(display); -} - -bool CalibratorEvdev::finish_data(const XYinfo new_axys, int swap_xy) -{ - bool success = true; - - // swap x and y axis, indicated by swap_xy - // new value is old value (could have been 0 or 1) swapped: - int new_swap_xy = 1 - old_swap_xy; - - printf("\nDoing dynamic recalibration:\n"); - // Evdev Axes Swap - if (swap_xy) { - printf("\tSwapping X and Y axis...\n"); - bool ok = set_swapxy(new_swap_xy); - success &= ok; - - if (verbose) { - if (ok) - printf("DEBUG: Successfully swapped X and Y axis.\n"); - else - printf("DEBUG: Failed to swap X and Y axis.\n"); - } - } - - // Evdev Axis Calibration - printf("\tSetting new calibration data: %d, %d, %d, %d\n", new_axys.x_min, new_axys.x_max, new_axys.y_min, new_axys.y_max); - bool ok = set_calibration(new_axys); - success &= ok; - - if (verbose) { - if (ok) - printf("DEBUG: Successfully applied axis calibration.\n"); - else - printf("DEBUG: Failed to apply axis calibration.\n"); - } - // close - XSync(display, False); - - - - printf("\n\n--> Making the calibration permanent <--\n"); - switch (output_type) { - case OUTYPE_AUTO: - // xorg.conf.d or alternatively xinput commands - if (has_xorgconfd_support()) { - success &= output_xorgconfd(new_axys, swap_xy, new_swap_xy); - } else { - success &= output_xinput(new_axys, swap_xy, new_swap_xy); - } - break; - case OUTYPE_XORGCONFD: - success &= output_xorgconfd(new_axys, swap_xy, new_swap_xy); - break; - case OUTYPE_HAL: - success &= output_hal(new_axys, swap_xy, new_swap_xy); - break; - case OUTYPE_XINPUT: - success &= output_xinput(new_axys, swap_xy, new_swap_xy); - break; - default: - fprintf(stderr, "ERROR: Evdev Calibrator does not support the supplied --output-type\n"); - success = false; - } - - return success; -} - -bool CalibratorEvdev::set_swapxy(const int swap_xy) -{ - // xinput set-int-prop "divername" "Evdev Axes Swap" 8 0 - char* arr_cmd[3]; - //arr_cmd[0] = ""; - char str_prop[50]; - sprintf(str_prop, "Evdev Axes Swap"); - arr_cmd[1] = str_prop; - char str_swap_xy[20]; - sprintf(str_swap_xy, "%d", swap_xy); - arr_cmd[2] = str_swap_xy; - - int ret = xinput_do_set_prop(display, XA_INTEGER, 8, 3, arr_cmd); - return (ret == EXIT_SUCCESS); -} - -bool CalibratorEvdev::set_calibration(const XYinfo new_axys) -{ - // xinput set-int-prop 4 223 32 5 500 8 300 - char* arr_cmd[6]; - //arr_cmd[0] = ""; - char str_prop[50]; - sprintf(str_prop, "Evdev Axis Calibration"); - arr_cmd[1] = str_prop; - char str_min_x[20]; - sprintf(str_min_x, "%d", new_axys.x_min); - arr_cmd[2] = str_min_x; - char str_max_x[20]; - sprintf(str_max_x, "%d", new_axys.x_max); - arr_cmd[3] = str_max_x; - char str_min_y[20]; - sprintf(str_min_y, "%d", new_axys.y_min); - arr_cmd[4] = str_min_y; - char str_max_y[20]; - sprintf(str_max_y, "%d", new_axys.y_max); - arr_cmd[5] = str_max_y; - - int ret = xinput_do_set_prop(display, XA_INTEGER, 32, 6, arr_cmd); - return (ret == EXIT_SUCCESS); -} - -Atom CalibratorEvdev::xinput_parse_atom(Display *display, const char *name) { - Bool is_atom = True; - int i; - - for (i = 0; name[i] != '\0'; i++) { - if (!isdigit(name[i])) { - is_atom = False; - break; - } - } - - if (is_atom) - return atoi(name); - else - return XInternAtom(display, name, False); -} - -XDeviceInfo* CalibratorEvdev::xinput_find_device_info( -Display *display, const char *name, Bool only_extended) -{ - XDeviceInfo *devices; - XDeviceInfo *found = NULL; - int loop; - int num_devices; - int len = strlen(name); - Bool is_id = True; - XID id = (XID)-1; - - for (loop=0; loop= IsXExtensionDevice)) && - ((!is_id && strcmp(devices[loop].name, name) == 0) || - (is_id && devices[loop].id == id))) { - if (found) { - fprintf(stderr, - "Warning: There are multiple devices named \"%s\".\n" - "To ensure the correct one is selected, please use " - "the device ID instead.\n\n", name); - return NULL; - } else { - found = &devices[loop]; - } - } - } - - return found; -} - -int CalibratorEvdev::xinput_do_set_prop( -Display *display, Atom type, int format, int argc, char **argv) -{ -#ifndef HAVE_XI_PROP - return EXIT_FAILURE; -#else - - 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, "Wrong usage of xinput_do_set_prop, need at least 3 arguments\n"); - return EXIT_FAILURE; - } - - name = argv[1]; - - prop = xinput_parse_atom(display, name); - - if (prop == None) { - fprintf(stderr, "invalid property %s\n", name); - return EXIT_FAILURE; - } - - float_atom = XInternAtom(display, "FLOAT", False); - - nelements = argc - 2; - if (type == None || format == 0) { - if (XGetDeviceProperty(display, 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 = (unsigned char*)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] = xinput_parse_atom(display, argv[2 + i]); - } else { - fprintf(stderr, "unexpected type for property %s\n", name); - return EXIT_FAILURE; - } - } - - XChangeDeviceProperty(display, dev, prop, type, format, PropModeReplace, - data.c, nelements); - free(data.c); - return EXIT_SUCCESS; -#endif // HAVE_XI_PROP - -} - -bool CalibratorEvdev::output_xorgconfd(const XYinfo new_axys, int swap_xy, int new_swap_xy) -{ - const char* sysfs_name = get_sysfs_name(); - bool not_sysfs_name = (sysfs_name == NULL); - if (not_sysfs_name) - sysfs_name = "!!Name_Of_TouchScreen!!"; - - // xorg.conf.d snippet - printf(" copy the snippet below into '/etc/X11/xorg.conf.d/99-calibration.conf'\n"); - printf("Section \"InputClass\"\n"); - printf(" Identifier \"calibration\"\n"); - printf(" MatchProduct \"%s\"\n", sysfs_name); - printf(" Option \"Calibration\" \"%d %d %d %d\"\n", - new_axys.x_min, new_axys.x_max, new_axys.y_min, new_axys.y_max); - if (swap_xy != 0) - printf(" Option \"SwapAxes\" \"%d\"\n", new_swap_xy); - printf("EndSection\n"); - - if (not_sysfs_name) - printf("\nChange '%s' to your device's name in the snippet above.\n", sysfs_name); - - return true; -} - -bool CalibratorEvdev::output_hal(const XYinfo new_axys, int swap_xy, int new_swap_xy) -{ - const char* sysfs_name = get_sysfs_name(); - bool not_sysfs_name = (sysfs_name == NULL); - if (not_sysfs_name) - sysfs_name = "!!Name_Of_TouchScreen!!"; - - // HAL policy output - printf(" copy the policy below into '/etc/hal/fdi/policy/touchscreen.fdi'\n\ -\n\ - %d %d %d %d\n" - , sysfs_name, new_axys.x_min, new_axys.x_max, new_axys.y_min, new_axys.y_max); - if (swap_xy != 0) - printf(" %d\n", new_swap_xy); - printf("\n"); - - if (not_sysfs_name) - printf("\nChange '%s' to your device's name in the config above.\n", sysfs_name); - - return true; -} - -bool CalibratorEvdev::output_xinput(const XYinfo new_axys, int swap_xy, int new_swap_xy) -{ - // create startup script - printf(" Install the 'xinput' tool and copy the command(s) below in a script that starts with your X session\n"); - printf(" xinput set-int-prop \"%s\" \"Evdev Axis Calibration\" 32 %d %d %d %d\n", device_name, new_axys.x_min, new_axys.x_max, new_axys.y_min, new_axys.y_max); - if (swap_xy) - printf(" xinput set-int-prop \"%s\" \"Evdev Axes Swap\" 8 %d\n", device_name, new_swap_xy); - - return true; -} diff --git a/src/calibrator/calibratorXorgPrint.cpp b/src/calibrator/calibratorXorgPrint.cpp deleted file mode 100644 index 4e6910f..0000000 --- a/src/calibrator/calibratorXorgPrint.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2009 Tias Guns - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/*************************************** - * Class for generic Xorg driver, - * outputs new Xorg.conf and FDI policy, on stdout - ***************************************/ -class CalibratorXorgPrint: public Calibrator -{ -public: - CalibratorXorgPrint(const char* const device_name, const XYinfo& axys, - const bool verbose, const int thr_misclick=0, const int thr_doubleclick=0, - const OutputType output_type=OUTYPE_AUTO); - - virtual bool finish_data(const XYinfo new_axys, int swap_xy); -protected: - bool output_xorgconfd(const XYinfo new_axys, int swap_xy, int new_swap_xy); - bool output_hal(const XYinfo new_axys, int swap_xy, int new_swap_xy); -}; - -CalibratorXorgPrint::CalibratorXorgPrint(const char* const device_name0, const XYinfo& axys0, const bool verbose0, const int thr_misclick, const int thr_doubleclick, const OutputType output_type) - : Calibrator(device_name0, axys0, verbose0, thr_misclick, thr_doubleclick, output_type) -{ - printf("Calibrating standard Xorg driver \"%s\"\n", device_name); - printf("\tcurrent calibration values: 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); - printf("\tIf these values are estimated wrong, either supply it manually with the --precalib option, or run the 'get_precalib.sh' script to automatically get it (through HAL).\n"); -} - -bool CalibratorXorgPrint::finish_data(const XYinfo new_axys, int swap_xy) -{ - bool success = true; - - // we suppose the previous 'swap_xy' value was 0 - // (unfortunately there is no way to verify this (yet)) - int new_swap_xy = swap_xy; - - printf("\n\n--> Making the calibration permanent <--\n"); - switch (output_type) { - case OUTYPE_AUTO: - // xorg.conf.d or alternatively hal config - if (has_xorgconfd_support()) { - success &= output_xorgconfd(new_axys, swap_xy, new_swap_xy); - } else { - success &= output_hal(new_axys, swap_xy, new_swap_xy); - } - break; - case OUTYPE_XORGCONFD: - success &= output_xorgconfd(new_axys, swap_xy, new_swap_xy); - break; - case OUTYPE_HAL: - success &= output_hal(new_axys, swap_xy, new_swap_xy); - break; - default: - fprintf(stderr, "ERROR: XorgPrint Calibrator does not support the supplied --output-type\n"); - success = false; - } - - return success; -} - -bool CalibratorXorgPrint::output_xorgconfd(const XYinfo new_axys, int swap_xy, int new_swap_xy) -{ - const char* sysfs_name = get_sysfs_name(); - bool not_sysfs_name = (sysfs_name == NULL); - if (not_sysfs_name) - sysfs_name = "!!Name_Of_TouchScreen!!"; - - // xorg.conf.d snippet - printf(" copy the snippet below into '/etc/X11/xorg.conf.d/99-calibration.conf'\n"); - printf("Section \"InputClass\"\n"); - printf(" Identifier \"calibration\"\n"); - printf(" MatchProduct \"%s\"\n", sysfs_name); - printf(" Option \"MinX\" \"%d\"\n", new_axys.x_min); - printf(" Option \"MaxX\" \"%d\"\n", new_axys.x_max); - printf(" Option \"MinY\" \"%d\"\n", new_axys.y_min); - printf(" Option \"MaxY\" \"%d\"\n", new_axys.y_max); - if (swap_xy != 0) - printf(" Option \"SwapXY\" \"%d\" # unless it was already set to 1\n", new_swap_xy); - printf("EndSection\n"); - - if (not_sysfs_name) - printf("\nChange '%s' to your device's name in the config above.\n", sysfs_name); - - return true; -} - -bool CalibratorXorgPrint::output_hal(const XYinfo new_axys, int swap_xy, int new_swap_xy) -{ - const char* sysfs_name = get_sysfs_name(); - bool not_sysfs_name = (sysfs_name == NULL); - if (not_sysfs_name) - sysfs_name = "!!Name_Of_TouchScreen!!"; - - // HAL policy output - printf(" copy the policy below into '/etc/hal/fdi/policy/touchscreen.fdi'\n\ -\n\ - %d\n\ - %d\n\ - %d\n\ - %d\n" - , sysfs_name, new_axys.x_min, new_axys.x_max, new_axys.y_min, new_axys.y_max); - if (swap_xy != 0) - printf(" %d\n", new_swap_xy); - printf("\n"); - - if (not_sysfs_name) - printf("\nChange '%s' to your device's name in the config above.\n", sysfs_name); - - return true; -} diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 0e0870f..ddc3812 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -1,3 +1,3 @@ EXTRA_DIST = \ - gui_gtkmm.cpp \ - gui_x11.cpp + gtkmm.cpp \ + x11.cpp diff --git a/src/gui/gui_gtkmm.cpp b/src/gui/gtkmm.cpp similarity index 90% rename from src/gui/gui_gtkmm.cpp rename to src/gui/gtkmm.cpp index e4acf46..9806bc9 100644 --- a/src/gui/gui_gtkmm.cpp +++ b/src/gui/gtkmm.cpp @@ -20,13 +20,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include - -#include "calibrator.hh" +#include "gui/gtkmm.hpp" // Timeout parameters const int time_step = 100; // in milliseconds @@ -48,36 +43,6 @@ const std::string help_text[help_lines] = { "(To abort, press any key or wait)" }; - -/******************************************* - * GTK-mm class for the the calibration GUI - *******************************************/ -class CalibrationArea : public Gtk::DrawingArea -{ -public: - CalibrationArea(Calibrator* w); - -protected: - // Data - Calibrator* calibrator; - double X[4], Y[4]; - int display_width, display_height; - int time_elapsed; - - const char* message; - - // Signal handlers - bool on_timer_signal(); - bool on_expose_event(GdkEventExpose *event); - bool on_button_press_event(GdkEventButton *event); - bool on_key_press_event(GdkEventKey *event); - - // Helper functions - void set_display_size(int width, int height); - void redraw(); - void draw_message(const char* msg); -}; - CalibrationArea::CalibrationArea(Calibrator* calibrator0) : calibrator(calibrator0), time_elapsed(0), message(NULL) { diff --git a/src/gui/gtkmm.hpp b/src/gui/gtkmm.hpp new file mode 100644 index 0000000..1548a35 --- /dev/null +++ b/src/gui/gtkmm.hpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2009 Tias Guns + * Copyright (c) 2009 Soren Hauberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef GUI_GTKMM_HPP +#define GUI_GTKMM_HPP + +#include +#include "calibrator.hh" + +/******************************************* + * GTK-mm class for the the calibration GUI + *******************************************/ +class CalibrationArea : public Gtk::DrawingArea +{ +public: + CalibrationArea(Calibrator* w); + +protected: + // Data + Calibrator* calibrator; + double X[4], Y[4]; + int display_width, display_height; + int time_elapsed; + + const char* message; + + // Signal handlers + bool on_timer_signal(); + bool on_expose_event(GdkEventExpose *event); + bool on_button_press_event(GdkEventButton *event); + bool on_key_press_event(GdkEventKey *event); + + // Helper functions + void set_display_size(int width, int height); + void redraw(); + void draw_message(const char* msg); +}; + +#endif diff --git a/src/gui/gui_x11.cpp b/src/gui/x11.cpp similarity index 88% rename from src/gui/gui_x11.cpp rename to src/gui/x11.cpp index a7d1246..2d4f7b2 100644 --- a/src/gui/gui_x11.cpp +++ b/src/gui/x11.cpp @@ -19,6 +19,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + +#include "gui/x11.hpp" + #include #include #include @@ -34,12 +37,10 @@ #include #include -#include "calibrator.hh" - // Timeout parameters const int time_step = 100; // in milliseconds -const int max_time = 15000; // 5000 = 5 sec +const int max_time = 60000; // in milliseconds, 60000 = 60 sec // Clock appereance const int cross_lines = 25; @@ -57,58 +58,18 @@ const std::string help_text[help_lines] = { "(To abort, press any key or wait)" }; -// color management -enum { BLACK=0, WHITE=1, GRAY=2, DIMGRAY=3, RED=4 }; -const int nr_colors = 5; -const char* colors[nr_colors] = {"BLACK", "WHITE", "GRAY", "DIMGRAY", "RED"}; - +const char* GuiCalibratorX11::colors[GuiCalibratorX11::NUM_COLORS] = {"BLACK", "WHITE", "GRAY", "DIMGRAY", "RED"}; void sigalarm_handler(int num); - -/******************************************* - * X11 class for the the calibration GUI - *******************************************/ -class GuiCalibratorX11 +/// Create singleton instance associated to calibrator w +void GuiCalibratorX11::make_instance(Calibrator* w) { -public: - GuiCalibratorX11(Calibrator* w); - ~GuiCalibratorX11(); - static bool set_instance(GuiCalibratorX11* W); - static void give_timer_signal(); - -protected: - // Data - Calibrator* calibrator; - double X[4], Y[4]; - int display_width, display_height; - int time_elapsed; - - // X11 vars - Display* display; - int screen_num; - Window win; - GC gc; - XFontStruct* font_info; - // color mngmt - unsigned long pixel[nr_colors]; - - - // Signal handlers - bool on_timer_signal(); - bool on_expose_event(); - bool on_button_press_event(XEvent event); - - // Helper functions - void set_display_size(int width, int height); - void redraw(); - void draw_message(const char* msg); - -private: - static GuiCalibratorX11* instance; -}; -GuiCalibratorX11* GuiCalibratorX11::instance = NULL; + instance = new GuiCalibratorX11(w); +} +// Singleton instance +GuiCalibratorX11* GuiCalibratorX11::instance = NULL; GuiCalibratorX11::GuiCalibratorX11(Calibrator* calibrator0) : calibrator(calibrator0), time_elapsed(0) @@ -144,13 +105,30 @@ GuiCalibratorX11::GuiCalibratorX11(Calibrator* calibrator0) DisplayHeight(display, screen_num)); #endif + // window offsets + int gx = 0; + int gy = 0; + + // parse geometry string + const char* geo = calibrator->get_geometry(); + if (geo != NULL) { + int gw,gh; + int res = sscanf(geo,"%dx%d+%d+%d",&gw,&gh,&gx,&gy); + if (res != 4) { + fprintf(stderr,"Warning: error parsing geometry string - using defaults.\n"); + gx = gy = 0; + } else { + set_display_size( gw, gh ); + } + } + // Register events on the window XSetWindowAttributes attributes; attributes.override_redirect = True; attributes.event_mask = ExposureMask | KeyPressMask | ButtonPressMask; win = XCreateWindow(display, RootWindow(display, screen_num), - 0, 0, display_width, display_height, 0, + gx, gy, display_width, display_height, 0, CopyFromParent, InputOutput, CopyFromParent, CWOverrideRedirect | CWEventMask, &attributes); @@ -164,7 +142,7 @@ GuiCalibratorX11::GuiCalibratorX11(Calibrator* calibrator0) Colormap colormap = DefaultColormap(display, screen_num); XColor color; - for (int i = 0; i != nr_colors; i++) { + for (int i = 0; i != NUM_COLORS; i++) { XParseColor(display, colormap, colors[i], &color); XAllocColor(display, colormap, &color); pixel[i] = color.pixel; @@ -216,6 +194,7 @@ void GuiCalibratorX11::redraw() XRRScreenSize* randrsize = XRRSizes(display, screen_num, &nsizes); if (nsizes != 0 && (display_width != randrsize->width || display_height != randrsize->height)) { + if (calibrator->get_geometry() == NULL) set_display_size(randrsize->width, randrsize->height); } #endif @@ -279,7 +258,7 @@ bool GuiCalibratorX11::on_timer_signal() { time_elapsed += time_step; if (time_elapsed > max_time) { - exit(0); + exit(1); } // Update clock @@ -373,14 +352,6 @@ void GuiCalibratorX11::give_timer_signal() } } -bool GuiCalibratorX11::set_instance(GuiCalibratorX11* W) -{ - bool wasSet = (instance != NULL); - instance = W; - - return wasSet; -} - // handle SIGALRM signal, pass to singleton void sigalarm_handler(int num) diff --git a/src/gui/x11.hpp b/src/gui/x11.hpp new file mode 100644 index 0000000..cf5a39a --- /dev/null +++ b/src/gui/x11.hpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2009 Tias Guns + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef GUI_CALIBRATOR_X11 +#define GUI_CALIBRATOR_X11 + +#include "calibrator.hh" + +/******************************************* + * X11 class for the the calibration GUI + *******************************************/ +class GuiCalibratorX11 +{ +public: + static void make_instance(Calibrator* w); + static void give_timer_signal(); + +protected: + GuiCalibratorX11(Calibrator* w); + ~GuiCalibratorX11(); + + // Data + Calibrator* calibrator; + double X[NUM_POINTS], Y[NUM_POINTS]; + int display_width, display_height; + int time_elapsed; + + // X11 vars + Display* display; + int screen_num; + Window win; + GC gc; + XFontStruct* font_info; + + // color management + enum { BLACK=0, WHITE=1, GRAY=2, DIMGRAY=3, RED=4, NUM_COLORS }; + static const char* colors[NUM_COLORS]; + unsigned long pixel[NUM_COLORS]; + + // Signal handlers + bool on_timer_signal(); + bool on_expose_event(); + bool on_button_press_event(XEvent event); + + // Helper functions + void set_display_size(int width, int height); + void redraw(); + void draw_message(const char* msg); + +private: + static GuiCalibratorX11* instance; +}; + +#endif diff --git a/src/main_common.cpp b/src/main_common.cpp new file mode 100644 index 0000000..85d2d80 --- /dev/null +++ b/src/main_common.cpp @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2009 Tias Guns + * Copyright (c) 2009 Soren Hauberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "calibrator.hh" + +// Calibrator implementations +#include "calibrator/Usbtouchscreen.hpp" +#include "calibrator/Evdev.hpp" +#include "calibrator/XorgPrint.hpp" + +#include +#include +#include +#include + +#include +#include + +// strdup: non-ansi +static char* my_strdup(const char* s) { + size_t len = strlen(s) + 1; + void* p = malloc(len); + + if (p == NULL) + return NULL; + + return (char*) memcpy(p, s, len); +} + +/** + * find a calibratable touchscreen device (using XInput) + * + * if pre_device is NULL, the last calibratable device is selected. + * retuns number of devices found, + * the data of the device is returned in the last 3 function parameters + */ +int Calibrator::find_device(const char* pre_device, bool list_devices, + XID& device_id, const char*& device_name, XYinfo& device_axys) +{ + bool pre_device_is_id = true; + int found = 0; + + Display* display = XOpenDisplay(NULL); + if (display == NULL) { + error ( "Unable to connect to X server\n"); + exit(1); + } + + int xi_opcode, event, err; + if (!XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &err)) { + error ( "X Input extension not available.\n"); + exit(1); + } + + // verbose, get Xi version + if (verbose) { + XExtensionVersion *version = XGetExtensionVersion(display, INAME); + + if (version && (version != (XExtensionVersion*) NoSuchExtension)) { + trace ("%s version is %i.%i\n", + INAME, version->major_version, version->minor_version); + XFree(version); + } + } + + if (pre_device != NULL) { + // check whether the pre_device is an ID (only digits) + int len = strlen(pre_device); + for (int loop=0; loopuse == IsXKeyboard || list->use == IsXPointer) // virtual master device + continue; + + // if we are looking for a specific device + if (pre_device != NULL) { + if ((pre_device_is_id && list->id == (XID) atoi(pre_device)) || + (!pre_device_is_id && strcmp(list->name, pre_device) == 0)) { + // OK, fall through + } else { + // skip, not this device + continue; + } + } + + XAnyClassPtr any = (XAnyClassPtr) (list->inputclassinfo); + for (int j=0; jnum_classes; j++) + { + + if (any->c_class == ValuatorClass) + { + XValuatorInfoPtr V = (XValuatorInfoPtr) any; + XAxisInfoPtr ax = (XAxisInfoPtr) V->axes; + + if (V->mode != Absolute) { + trace ( "Skipping device '%s' id=%i, does not report Absolute events.\n", + list->name, (int)list->id); + } else if (V->num_axes < 2 || + (ax[0].min_value == -1 && ax[0].max_value == -1) || + (ax[1].min_value == -1 && ax[1].max_value == -1)) { + trace ( "Skipping device '%s' id=%i, does not have two calibratable axes.\n", + list->name, (int)list->id); + } else { + /* a calibratable device (has 2 axis valuators) */ + found++; + device_id = list->id; + device_name = my_strdup(list->name); + device_axys.x.min = ax[0].min_value; + device_axys.x.max = ax[0].max_value; + device_axys.y.min = ax[1].min_value; + device_axys.y.max = ax[1].max_value; + + if (list_devices) + info ("Device \"%s\" id=%i\n", device_name, (int)device_id); + } + + } + + /* + * Increment 'any' to point to the next item in the linked + * list. The length is in bytes, so 'any' must be cast to + * a character pointer before being incremented. + */ + any = (XAnyClassPtr) ((char *) any + any->length); + } + + } + XFreeDeviceList(slist); + XCloseDisplay(display); + + return found; +} + +static void usage(char* cmd, unsigned thr_misclick) +{ + fprintf(stderr, "Usage: %s [-h|--help] [-v|--verbose] [--list] [--device ] [--precalib ] [--misclick ] [--output-type ] [--fake] [--geometry x++]\n", cmd); + fprintf(stderr, "\t-h, --help: print this help message\n"); + fprintf(stderr, "\t-v, --verbose: print debug messages during the process\n"); + fprintf(stderr, "\t--list: list calibratable input devices and quit\n"); + fprintf(stderr, "\t--device : select a specific device to calibrate\n"); + fprintf(stderr, "\t--precalib: manually provide the current calibration setting (eg. the values in xorg.conf)\n"); + fprintf(stderr, "\t--misclick: set the misclick threshold (0=off, default: %i pixels)\n", + thr_misclick); + fprintf(stderr, "\t--output-type : type of config to ouput (auto=automatically detect, default: auto)\n"); + fprintf(stderr, "\t--fake: emulate a fake device (for testing purposes)\n"); + fprintf(stderr, "\t--geometry: manually provide the geometry for the calibration window\n"); +} + +Calibrator* Calibrator::make_calibrator(int argc, char** argv) +{ + bool list_devices = false; + bool fake = false; + bool precalib = false; + XYinfo pre_axys; + const char* pre_device = NULL; + const char* geometry = NULL; + unsigned thr_misclick = 15; + unsigned thr_doubleclick = 7; + OutputType output_type = OUTYPE_AUTO; + + // parse input + for (int i=1; i!=argc; i++) + { + // Display help ? + if (strcmp("-h", argv[i]) == 0 || + strcmp("--help", argv[i]) == 0) + { + error ( "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; + } + + // Just list devices ? + else if (strcmp("--list", argv[i]) == 0) + { + list_devices = true; + } + + // Select specific device ? + else if (strcmp("--device", argv[i]) == 0) + { + if (argc > i+1) + pre_device = argv[++i]; + else { + 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); + } + } + + // Get pre-calibration ? + else 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 + + // Get mis-click threshold ? + if (strcmp("--misclick", argv[i]) == 0) + { + if (argc > i+1) + thr_misclick = atoi(argv[++i]); + else { + 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); + } + } + + // Get output type ? + else 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 + { + error ( "--output-type needs one of auto|xorg.conf.d|hal|xinput.\n\n"); + usage(argv[0], thr_misclick); + exit(1); + } + } else { + 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; + } + + // unknown option + else { + error ( "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); + + trace ("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) + error ("No calibratable devices found.\n"); + exit(0); + } + + if (nr_found == 0) { + if (pre_device == NULL) + error ( "Error: No calibratable devices found.\n"); + else + error ( "Error: Device \"%s\" not found; use --list to list the calibratable input devices.\n", pre_device); + exit(1); + + } else if (nr_found > 1) { + info ("Warning: multiple calibratable devices found, calibrating last one (%s)\n\tuse --device to select another one.\n", device_name); + } + + trace ("Selected device: %s\n", device_name); + } + + // override min/max XY from command line ? + if (precalib) { + 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; + + trace ( "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); + + } catch(WrongCalibratorException& x) { + trace("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); + + } catch(WrongCalibratorException& x) { + trace ("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); +} diff --git a/src/main_common.hpp b/src/main_common.hpp deleted file mode 100644 index 47b7595..0000000 --- a/src/main_common.hpp +++ /dev/null @@ -1,436 +0,0 @@ -/* - * Copyright (c) 2009 Tias Guns - * Copyright (c) 2009 Soren Hauberg - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include -#include -#include - -#include -#include - -/* - * Number of blocks. We partition the screen into 'num_blocks' x 'num_blocks' - * rectangles of equal size. We then ask the user to press points that are - * located at the corner closes to the center of the four blocks in the corners - * of the screen. The following ascii art illustrates the situation. We partition - * the screen into 8 blocks in each direction. We then let the user press the - * points marked with 'O'. - * - * +--+--+--+--+--+--+--+--+ - * | | | | | | | | | - * +--O--+--+--+--+--+--O--+ - * | | | | | | | | | - * +--+--+--+--+--+--+--+--+ - * | | | | | | | | | - * +--+--+--+--+--+--+--+--+ - * | | | | | | | | | - * +--+--+--+--+--+--+--+--+ - * | | | | | | | | | - * +--+--+--+--+--+--+--+--+ - * | | | | | | | | | - * +--+--+--+--+--+--+--+--+ - * | | | | | | | | | - * +--O--+--+--+--+--+--O--+ - * | | | | | | | | | - * +--+--+--+--+--+--+--+--+ - */ -const int num_blocks = 8; - -// Names of the points -enum { - UL = 0, // Upper-left - UR = 1, // Upper-right - LL = 2, // Lower-left - LR = 3 // Lower-right -}; - -// Output types -enum OutputType { - OUTYPE_AUTO, - OUTYPE_XORGCONFD, - OUTYPE_HAL, - OUTYPE_XINPUT -}; - -// struct to hold min/max info of the X and Y axis -struct XYinfo { - int x_min; - int x_max; - int y_min; - int y_max; - XYinfo() : x_min(-1), x_max(-1), y_min(-1), y_max(-1) {} - XYinfo(int xmi, int xma, int ymi, int yma) : - x_min(xmi), x_max(xma), y_min(ymi), y_max(yma) {} -}; - -class WrongCalibratorException : public std::invalid_argument { - public: - WrongCalibratorException(const std::string& msg = "") : - std::invalid_argument(msg) {} -}; - -// strdup: non-ansi -char* my_strdup(const char* s); -char* my_strdup(const char* s) { - size_t len = strlen(s) + 1; - void* p = malloc(len); - - if (p == NULL) - return NULL; - - return (char*) memcpy(p, s, len); -} - -// all need struct XYinfo, and some the consts too -#include "calibrator.cpp" -#include "calibrator/calibratorXorgPrint.cpp" -#include "calibrator/calibratorEvdev.cpp" -#include "calibrator/calibratorUsbtouchscreen.cpp" - - -/** - * find a calibratable touchscreen device (using XInput) - * - * if pre_device is NULL, the last calibratable device is selected. - * retuns number of devices found, - * the data of the device is returned in the last 3 function parameters - */ -int find_device(const char*, bool, bool, XID&, const char*&, XYinfo&); -int find_device(const char* pre_device, bool verbose, bool list_devices, - XID& device_id, const char*& device_name, XYinfo& device_axys) -{ - bool pre_device_is_id = true; - int found = 0; - - Display* display = XOpenDisplay(NULL); - if (display == NULL) { - fprintf(stderr, "Unable to connect to X server\n"); - exit(1); - } - - int xi_opcode, event, error; - if (!XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &error)) { - fprintf(stderr, "X Input extension not available.\n"); - exit(1); - } - - // verbose, get Xi version - if (verbose) { - XExtensionVersion *version = XGetExtensionVersion(display, INAME); - - if (version && (version != (XExtensionVersion*) NoSuchExtension)) { - printf("DEBUG: %s version is %i.%i\n", - INAME, version->major_version, version->minor_version); - XFree(version); - } - } - - if (pre_device != NULL) { - // check whether the pre_device is an ID (only digits) - int len = strlen(pre_device); - for (int loop=0; loopuse == IsXKeyboard || list->use == IsXPointer) // virtual master device - continue; - - // if we are looking for a specific device - if (pre_device != NULL) { - if ((pre_device_is_id && list->id == (XID) atoi(pre_device)) || - (!pre_device_is_id && strcmp(list->name, pre_device) == 0)) { - // OK, fall through - } else { - // skip, not this device - continue; - } - } - - XAnyClassPtr any = (XAnyClassPtr) (list->inputclassinfo); - for (int j=0; jnum_classes; j++) - { - - if (any->c_class == ValuatorClass) - { - XValuatorInfoPtr V = (XValuatorInfoPtr) any; - XAxisInfoPtr ax = (XAxisInfoPtr) V->axes; - - if (V->mode != Absolute) { - if (verbose) - printf("DEBUG: Skipping device '%s' id=%i, does not report Absolute events.\n", - list->name, (int)list->id); - } else if (V->num_axes < 2 || - (ax[0].min_value == -1 && ax[0].max_value == -1) || - (ax[1].min_value == -1 && ax[1].max_value == -1)) { - if (verbose) - printf("DEBUG: Skipping device '%s' id=%i, does not have two calibratable axes.\n", - list->name, (int)list->id); - } else { - /* a calibratable device (has 2 axis valuators) */ - found++; - device_id = list->id; - device_name = my_strdup(list->name); - device_axys.x_min = ax[0].min_value; - device_axys.x_max = ax[0].max_value; - device_axys.y_min = ax[1].min_value; - device_axys.y_max = ax[1].max_value; - - if (list_devices) - printf("Device \"%s\" id=%i\n", device_name, (int)device_id); - } - - } - - /* - * Increment 'any' to point to the next item in the linked - * list. The length is in bytes, so 'any' must be cast to - * a character pointer before being incremented. - */ - any = (XAnyClassPtr) ((char *) any + any->length); - } - - } - XFreeDeviceList(slist); - XCloseDisplay(display); - - return found; -} - -static void usage(char* cmd, unsigned thr_misclick) -{ - fprintf(stderr, "Usage: %s [-h|--help] [-v|--verbose] [--list] [--device ] [--precalib ] [--misclick ] [--output-type ] [--fake]\n", cmd); - fprintf(stderr, "\t-h, --help: print this help message\n"); - fprintf(stderr, "\t-v, --verbose: print debug messages during the process\n"); - fprintf(stderr, "\t--list: list calibratable input devices and quit\n"); - fprintf(stderr, "\t--device : select a specific device to calibrate\n"); - fprintf(stderr, "\t--precalib: manually provide the current calibration setting (eg. the values in xorg.conf)\n"); - fprintf(stderr, "\t--misclick: set the misclick threshold (0=off, default: %i pixels)\n", - thr_misclick); - fprintf(stderr, "\t--output-type : type of config to ouput (auto=automatically detect, default: auto)\n"); - fprintf(stderr, "\t--fake: emulate a fake device (for testing purposes)\n"); -} - -Calibrator* main_common(int argc, char** argv); -Calibrator* main_common(int argc, char** argv) -{ - bool verbose = false; - bool list_devices = false; - bool fake = false; - bool precalib = false; - XYinfo pre_axys; - const char* pre_device = 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_calibratior, 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 - - // 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 - - // Fake calibratable device ? - if (strcmp("--fake", argv[i]) == 0) { - fake = true; - } - - // 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, verbose, 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(0); - } - - 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) { - 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, - verbose, thr_misclick, thr_doubleclick, output_type); - - } 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, verbose, device_id, - thr_misclick, thr_doubleclick, output_type); - - } 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, - verbose, thr_misclick, thr_doubleclick, output_type); -} diff --git a/src/main_gtkmm.cpp b/src/main_gtkmm.cpp index 327c36e..b3e9cb1 100644 --- a/src/main_gtkmm.cpp +++ b/src/main_gtkmm.cpp @@ -24,15 +24,14 @@ // Must be before Xlib stuff #include #include -#include #include -#include "main_common.hpp" -#include "gui/gui_gtkmm.cpp" +#include "calibrator.hh" +#include "gui/gtkmm.hpp" int main(int argc, char** argv) { - Calibrator* calibrator = main_common(argc, argv); + Calibrator* calibrator = Calibrator::make_calibrator(argc, argv); // GTK-mm setup Gtk::Main kit(argc, argv); diff --git a/src/main_x11.cpp b/src/main_x11.cpp index 26c871d..5f27116 100644 --- a/src/main_x11.cpp +++ b/src/main_x11.cpp @@ -20,15 +20,14 @@ * THE SOFTWARE. */ -#include "main_common.hpp" -#include "gui/gui_x11.cpp" +#include "calibrator.hh" +#include "gui/x11.hpp" int main(int argc, char** argv) { - Calibrator* calibrator = main_common(argc, argv); + Calibrator* calibrator = Calibrator::make_calibrator(argc, argv); - GuiCalibratorX11 gui(calibrator); - GuiCalibratorX11::set_instance(&gui); + GuiCalibratorX11::make_instance( calibrator ); // wait for timer signal, processes events while(1)