diff --git a/src/calibrator.cpp b/src/calibrator.cpp index 403ae8e..bb8656d 100644 --- a/src/calibrator.cpp +++ b/src/calibrator.cpp @@ -144,31 +144,42 @@ bool Calibrator::finish(int width, int height) // based on old_axys: inversion/swapping is relative to the old axis XYinfo new_axis(old_axys); - - // calculate average of clicks - float x_min = (clicked.x[UL] + clicked.x[LL])/2.0; - float x_max = (clicked.x[UR] + clicked.x[LR])/2.0; - float y_min = (clicked.y[UL] + clicked.y[UR])/2.0; - float y_max = (clicked.y[LL] + clicked.y[LR])/2.0; - // Should x and y be swapped? + bool swap_axes = false; if (abs(clicked.x[UL] - clicked.x[UR]) < abs(clicked.y[UL] - clicked.y[UR])) { + swap_axes = true; new_axis.swap_xy = !new_axis.swap_xy; - std::swap(x_min, y_min); - std::swap(x_max, y_max); + + // These swaps result in a reflection of the clicks, about the line x=y. + std::swap(clicked.x[LL], clicked.x[UR]); + std::swap(clicked.y[LL], clicked.y[UR]); } + // calculate average of clicks + double x_min = (clicked.x[UL] + clicked.x[LL])/2.0; + double x_max = (clicked.x[UR] + clicked.x[LR])/2.0; + double y_min = (clicked.y[UL] + clicked.y[UR])/2.0; + double y_max = (clicked.y[LL] + clicked.y[LR])/2.0; + + // This has an empty implementation here, but derived classes + // may implement it to modify {x,y}_* and new_axis as needed. + // See Evdev.cpp which uses this routine to compensate for + // calculations done within the evdev device. + compensateForDevice( width, height, x_min, y_min, x_max, y_max, new_axis ); + // the screen was divided in num_blocks blocks, and the touch points were at // one block away from the true edges of the screen. - const float block_x = width/(float)num_blocks; - const float block_y = height/(float)num_blocks; + const double block_x = width/(double)num_blocks; + const double block_y = height/(double)num_blocks; + // rescale these blocks from the range of the drawn touchpoints to the range of the // actually clicked coordinates, and substract/add from the clicked coordinates // to obtain the coordinates corresponding to the edges of the screen. - float scale_x = (x_max - x_min)/(width - 2*block_x); + double scale_x = (x_max - x_min)/(width - 2*block_x); x_min -= block_x * scale_x; x_max += block_x * scale_x; - float scale_y = (y_max - y_min)/(height - 2*block_y); + + double scale_y = (y_max - y_min)/(height - 2*block_y); y_min -= block_y * scale_y; y_max += block_y * scale_y; @@ -181,6 +192,10 @@ bool Calibrator::finish(int width, int height) y_min = scaleAxis(y_min, old_axys.y.max, old_axys.y.min, height, 0); y_max = scaleAxis(y_max, old_axys.y.max, old_axys.y.min, height, 0); + if ( swap_axes ) { + std::swap( x_min, y_min ); + std::swap( x_max, y_max ); + } // round and put in new_axis struct new_axis.x.min = round(x_min); new_axis.x.max = round(x_max); @@ -260,6 +275,19 @@ bool Calibrator::has_xorgconfd_support(Display* dpy) { return has_support; } +int +xf86ScaleAxis(int Cx, int to_max, int to_min, int from_max, int from_min) +{ + double X = scaleAxis(Cx, to_max, to_min, from_max, from_min); + + if (X > to_max) + X = to_max; + if (X < to_min) + X = to_min; + + return (int)X; +} + /* * FROM xf86Xinput.c * @@ -277,53 +305,21 @@ bool Calibrator::has_xorgconfd_support(Display* dpy) { * e.g. to scale from device coordinates into screen coordinates, call * xf86ScaleAxis(x, 0, screen_width, dev_min, dev_max); */ -int -xf86ScaleAxis(int Cx, int to_max, int to_min, int from_max, int from_min) +double +scaleAxis(double Cx, int to_max, int to_min, int from_max, int from_min) { - int X; - int64_t to_width = to_max - to_min; - int64_t from_width = from_max - from_min; - - if (from_width) { - X = (int) (((to_width * (Cx - from_min)) / from_width) + to_min); - } - else { - X = 0; - printf("Divide by Zero in xf86ScaleAxis\n"); - exit(1); - } - - if (X > to_max) - X = to_max; - if (X < to_min) - X = to_min; + double X; + double to_width = to_max - to_min; + double from_width = from_max - from_min; - return X; -} - -// same but without rounding to min/max -float -scaleAxis(float Cx, int to_max, int to_min, int from_max, int from_min) -{ - float X; - int64_t to_width = to_max - to_min; - int64_t from_width = from_max - from_min; - - if (from_width) { + if (from_max - from_min) { X = (((to_width * (Cx - from_min)) / from_width) + to_min); } else { - X = 0; + X = 0.0; printf("Divide by Zero in scaleAxis\n"); exit(1); } - /* no rounding to max/min - if (X > to_max) - X = to_max; - if (X < to_min) - X = to_min; - */ - return X; } diff --git a/src/calibrator.hh b/src/calibrator.hh index 96cff2b..64f35e4 100644 --- a/src/calibrator.hh +++ b/src/calibrator.hh @@ -31,7 +31,7 @@ #include int xf86ScaleAxis(int Cx, int to_max, int to_min, int from_max, int from_min); -float scaleAxis(float Cx, int to_max, int to_min, int from_max, int from_min); +double scaleAxis(double Cx, int to_max, int to_min, int from_max, int from_min); /* * Number of blocks. We partition the screen into 'num_blocks' x 'num_blocks' @@ -147,7 +147,7 @@ public: const char* geometry=0, const bool use_timeout=1); - ~Calibrator() {} + virtual ~Calibrator() {} /// set the doubleclick treshold void set_threshold_doubleclick(int t) @@ -171,8 +171,43 @@ public: /// add a click with the given coordinates bool add_click(int x, int y); + + // Called by base class finish() method. + // Allows for derived class specific "adjustments" to be made + // just prior to the scaling and calibration calculations being + // performed. + // + // @param width + // The screen width, in pixels, as passed to calibrator::finish() + // + // @param height + // The screen height, in pixels, as passed to calibrator::finish() + // + // @param x_min + // The mean minimum x coordinate. Calculated in Calibrator::finish() + // like so: double x_min = (clicked.x[UL] + clicked.x[LL])/2.0; + // + // @param y_min + // The mean minimum y coordinate. Calculated in Calibrator::finish() + // like so: double y_min = (clicked.y[UL] + clicked.y[UR])/2.0; + // + // @param x_max + // The mean maximum x coordinate. Calculated in Calibrator::finish() + // like so: double x_max = (clicked.x[UR] + clicked.x[LR])/2.0; + // + // @param y_max + // The mean maximum x coordinate. Calculated in Calibrator::finish() + // like so: double y_max = (clicked.y[LL] + clicked.y[LR])/2.0; + // + // @param new_axis + // The axes calibration data, of type XYinfo, being set by calibrator:finish(). + // This is ultimately passed as an arg to finish_data(). + virtual void compensateForDevice( int width, int height, double &x_min, double &y_min, + double &x_max, double &y_max, XYinfo &new_axis ) {} + /// calculate and apply the calibration - virtual bool finish(int width, int height); + bool finish(int width, int height); + /// get the sysfs name of the device, /// returns NULL if it can not be found const char* get_sysfs_name(); diff --git a/src/calibrator/Evdev.cpp b/src/calibrator/Evdev.cpp index a370689..29db9b5 100644 --- a/src/calibrator/Evdev.cpp +++ b/src/calibrator/Evdev.cpp @@ -175,26 +175,45 @@ CalibratorEvdev::~CalibratorEvdev () { XCloseDisplay(display); } -// From Calibrator but with evdev specific invertion option -// KEEP IN SYNC with Calibrator::finish() !! -bool CalibratorEvdev::finish(int width, int height) + +// Called by base class finish() method. +// Allows for derived class specific "adjustments" to be made +// just prior to the scaling and calibration calculations being +// performed. +// +// @param width +// The screen width, in pixels, as passed to calibrator::finish() +// +// @param height +// The screen height, in pixels, as passed to calibrator::finish() +// +// @param x_min +// The mean minimum x coordinate. Calculated in Calibrator::finish() +// like so: float x_min = (clicked.x[UL] + clicked.x[LL])/2.0; +// +// @param y_min +// The mean minimum y coordinate. Calculated in Calibrator::finish() +// like so: float y_min = (clicked.y[UL] + clicked.y[UR])/2.0; +// +// @param x_max +// The mean maximum x coordinate. Calculated in Calibrator::finish() +// like so: float x_max = (clicked.x[UR] + clicked.x[LR])/2.0; +// +// @param y_max +// The mean maximum x coordinate. Calculated in Calibrator::finish() +// like so: float y_max = (clicked.y[LL] + clicked.y[LR])/2.0; +// +// @param new_axis +// The axes calibration data, of type XYinfo, being set by calibrator:finish(). +// This is ultimately passed as an arg to finish_data(). +void CalibratorEvdev::compensateForDevice( int width, int height, double &x_min, + double &y_min, double &x_max, + double &y_max, XYinfo &new_axis ) { - if (get_numclicks() != NUM_POINTS) { - return false; + if ( verbose ) { + printf( "DEBUG: compensating for evdev \"crazy\" code." ); } - // new axis origin and scaling - // based on old_axys: inversion/swapping is relative to the old axis - XYinfo new_axis(old_axys); - - - // calculate average of clicks - float x_min = (clicked.x[UL] + clicked.x[LL])/2.0; - float x_max = (clicked.x[UR] + clicked.x[LR])/2.0; - float y_min = (clicked.y[UL] + clicked.y[UR])/2.0; - float y_max = (clicked.y[LL] + clicked.y[LR])/2.0; - - // When evdev detects an invert_X/Y option, // it performs the following *crazy* code just before returning // val = (pEvdev->absinfo[i].maximum - val + pEvdev->absinfo[i].minimum); @@ -202,57 +221,20 @@ bool CalibratorEvdev::finish(int width, int height) if (old_axys.x.invert) { x_min = width - x_min; x_max = width - x_max; + // avoid invert_x property from here on, // the calibration code can handle this dynamically! new_axis.x.invert = false; } + if (old_axys.y.invert) { y_min = height - y_min; y_max = height - y_max; + // avoid invert_y property from here on, // the calibration code can handle this dynamically! new_axis.y.invert = false; } - // end of evdev inversion crazyness - - - // Should x and y be swapped? - if (abs(clicked.x[UL] - clicked.x[UR]) < abs(clicked.y[UL] - clicked.y[UR])) { - new_axis.swap_xy = !new_axis.swap_xy; - std::swap(x_min, y_min); - std::swap(x_max, y_max); - } - - // the screen was divided in num_blocks blocks, and the touch points were at - // one block away from the true edges of the screen. - const float block_x = width/(float)num_blocks; - const float block_y = height/(float)num_blocks; - // rescale these blocks from the range of the drawn touchpoints to the range of the - // actually clicked coordinates, and substract/add from the clicked coordinates - // to obtain the coordinates corresponding to the edges of the screen. - float scale_x = (x_max - x_min)/(width - 2*block_x); - x_min -= block_x * scale_x; - x_max += block_x * scale_x; - float scale_y = (y_max - y_min)/(height - 2*block_y); - y_min -= block_y * scale_y; - y_max += block_y * scale_y; - - // now, undo the transformations done by the X server, to obtain the true 'raw' value in X. - // The raw value was scaled from old_axis to the device min/max, and from the device min/max - // to the screen min/max - // hence, the reverse transformation is from screen to old_axis - x_min = scaleAxis(x_min, old_axys.x.max, old_axys.x.min, width, 0); - x_max = scaleAxis(x_max, old_axys.x.max, old_axys.x.min, width, 0); - y_min = scaleAxis(y_min, old_axys.y.max, old_axys.y.min, height, 0); - y_max = scaleAxis(y_max, old_axys.y.max, old_axys.y.min, height, 0); - - - // round and put in new_axis struct - new_axis.x.min = round(x_min); new_axis.x.max = round(x_max); - new_axis.y.min = round(y_min); new_axis.y.max = round(y_max); - - // finish the data, driver/calibrator specific - return finish_data(new_axis); } // Activate calibrated data and output it diff --git a/src/calibrator/Evdev.hpp b/src/calibrator/Evdev.hpp index c586ba2..d574df5 100644 --- a/src/calibrator/Evdev.hpp +++ b/src/calibrator/Evdev.hpp @@ -60,8 +60,40 @@ class CalibratorEvdev: public Calibrator const bool use_timeout=false); ~CalibratorEvdev(); + // Called by base class finish() method. + // Allows for derived class specific "adjustments" to be made + // just prior to the scaling and calibration calculations being + // performed. + // + // @param width + // The screen width, in pixels, as passed to calibrator::finish() + // + // @param height + // The screen height, in pixels, as passed to calibrator::finish() + // + // @param x_min + // The mean minimum x coordinate. Calculated in Calibrator::finish() + // like so: double x_min = (clicked.x[UL] + clicked.x[LL])/2.0; + // + // @param y_min + // The mean minimum y coordinate. Calculated in Calibrator::finish() + // like so: double y_min = (clicked.y[UL] + clicked.y[UR])/2.0; + // + // @param x_max + // The mean maximum x coordinate. Calculated in Calibrator::finish() + // like so: double x_max = (clicked.x[UR] + clicked.x[LR])/2.0; + // + // @param y_max + // The mean maximum x coordinate. Calculated in Calibrator::finish() + // like so: double y_max = (clicked.y[LL] + clicked.y[LR])/2.0; + // + // @param new_axis + // The axes calibration data, of type XYinfo, being set by calibrator:finish(). + // This is ultimately passed as an arg to finish_data(). + virtual void compensateForDevice( int width, int height, double &x_min, double &y_min, + double &x_max, double &y_max, XYinfo &new_axis ); + /// calculate and apply the calibration - virtual bool finish(int width, int height); virtual bool finish_data(const XYinfo new_axys); bool set_swapxy(const int swap_xy); diff --git a/src/calibrator/Usbtouchscreen.cpp b/src/calibrator/Usbtouchscreen.cpp index c9fc20a..5694fd5 100644 --- a/src/calibrator/Usbtouchscreen.cpp +++ b/src/calibrator/Usbtouchscreen.cpp @@ -149,34 +149,43 @@ bool CalibratorUsbtouchscreen::finish_data(const XYinfo new_axys) 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) { + perror( "CalibratorUsbtouchscreen::read_int_parameter" ); fprintf(stderr, "Could not read parameter '%s'\n", param); return; } - dummy = fscanf(fid, "%d", &value); + if ( 1 != fscanf(fid, "%d", &value) ) { + perror( "CalibratorUsbtouchscreen::read_int_parameter" ); + fprintf(stderr, "Could not read value of parameter '%s'\n", param); + } + 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) { + perror( "CalibratorUsbtouchscreen::read_bool_parameter" ); fprintf(stderr, "Could not read parameter '%s'\n", param); return; } - char val[3]; - dummy = fgets(val, 2, fid); + char val[3] = { '\0' }; // ensure that val contains nul chars (not 'Y') + if ( NULL == fgets(val, 2, fid) ) { + perror( "CalibratorUsbtouchscreen::read_bool_parameter" ); + fprintf(stderr, "Could not read value of boolean parameter '%s'. Using false.\n", param); + // Dropping through here simply means that the value of the boolean + // is set to false. + } fclose(fid); - value = (val[0] == yesno(true)); + value = (val[0] == yesno(true)); } void CalibratorUsbtouchscreen::write_int_parameter(const char *param, const int value) diff --git a/src/gui/gtkmm.cpp b/src/gui/gtkmm.cpp index 32bb889..2f52e25 100644 --- a/src/gui/gtkmm.cpp +++ b/src/gui/gtkmm.cpp @@ -204,21 +204,23 @@ void CalibrationArea::redraw() bool CalibrationArea::on_timer_signal() { - time_elapsed += time_step; - if (time_elapsed > max_time) { - exit(0); - } - - // Update clock - Glib::RefPtr win = get_window(); - if (win) { - const Gdk::Rectangle rect(display_width/2 - clock_radius - clock_line_width, - display_height/2 - clock_radius - clock_line_width, - 2 * clock_radius + 1 + 2 * clock_line_width, - 2 * clock_radius + 1 + 2 * clock_line_width); - win->invalidate_rect(rect, false); + if (calibrator->get_use_timeout()) { + time_elapsed += time_step; + if (time_elapsed > max_time) { + exit(0); + } + + // Update clock + Glib::RefPtr win = get_window(); + if (win) { + const Gdk::Rectangle rect(display_width/2 - clock_radius - clock_line_width, + display_height/2 - clock_radius - clock_line_width, + 2 * clock_radius + 1 + 2 * clock_line_width, + 2 * clock_radius + 1 + 2 * clock_line_width); + win->invalidate_rect(rect, false); + } } - + return true; } diff --git a/src/gui/x11.cpp b/src/gui/x11.cpp index db8a8a5..dfcd9fd 100644 --- a/src/gui/x11.cpp +++ b/src/gui/x11.cpp @@ -293,13 +293,14 @@ bool GuiCalibratorX11::on_expose_event() bool GuiCalibratorX11::on_timer_signal() { - time_elapsed += time_step; - if (time_elapsed > max_time) { - exit(0); - } - // Update clock - if(calibrator->get_use_timeout()){ + if(calibrator->get_use_timeout()) { + + time_elapsed += time_step; + if (time_elapsed > max_time) { + exit(0); + } + XSetForeground(display, gc, pixel[BLACK]); XSetLineAttributes(display, gc, clock_line_width, LineSolid, CapButt, JoinMiter); diff --git a/src/main_common.cpp b/src/main_common.cpp index f840e3d..ed72428 100644 --- a/src/main_common.cpp +++ b/src/main_common.cpp @@ -287,9 +287,9 @@ Calibrator* Calibrator::make_calibrator(int argc, char** argv) } else // Disable timeout - if (strcmp("--no-timeout", argv[i]) == 0) { - use_timeout = false; - } + if (strcmp("--no-timeout", argv[i]) == 0) { + use_timeout = false; + } // unknown option else {