You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I've tested xinput_calibrator-0.7.5 with touchscreen driven by evdev, but it did not work because of several (design) problems of xinput_calibrator.
the touch produces events with different axis range than is the screen resolution
xinput_calibrator uses click events from xlib or gtk that are in screen coordinates range
evdev calibration final setup changes xinput evdev calibration attributes that expect evdev range, not the screen resolution range
evdev calibration uses wrong defaults if started for second time (unless explicit full range --precalib option is used)
Since I wanted to get xinput_calibrator running in order to use the feature to calibrate without restart of xserver, I had to make following changes/hacks (done only in x11 gui version):
register listening for xinput evdev events directly to obtain native evdev click coordinates
skip overwriting of old_axys in CalibratorEvdev constructor, use old_axys to setup default calibration parameters using full range of input coordinates
apply old_axys (i.e. full range) parameters as evdev calibration unconditionally always in the CalibratorEvdev constructor in order to avoid miss calibration when run for second time on already calibrated touchscreen
extend xlib event loop to listen also for xinput events
use xinput old_axys (i.e. full range) as target resolution for final calculation of calibration and let the conversion of coordinate ranges to screen to be handled by xserver
Please note, I am not experienced with xlib programming and I did not want to redesign the architecture of xinput_calibrator, so my changes are quite dirty, but they work for me. So I am posting the patch here for you so you may think about it and possibly fix or redesign the xinput_calibrator which I find as great application that was missing for a long time.
First few more information on what sw components were used:
linux kernel v2.6.35
x11-drivers/xf86-input-evdev-2.4.0
x11-base/xorg-server-1.8.2
x11-proto/inputproto-2.0
x11-apps/xinput-1.5.2
x11-proto/randrproto-1.3.1
x11-proto/xcalibrateproto-0.1_pre20081210 (this is not used, is it?)
-bash-4.1# evtest /dev/input/event4
Input driver version is 1.0.0
Input device ID: bus 0x13 vendor 0x80 product 0x0 version 0x1
Input device name: "eGalax EETI Serial TouchScreen"
Supported events:
Event type 0 (Sync)
Event type 1 (Key)
Event code 330 (Touch)
Event type 3 (Absolute)
Event code 0 (X)
Value 0
Min 0
Max 2047
Event code 1 (Y)
Value 0
Min 0
Max 2047
Event code 24 (Pressure)
Value 0
Min 0
Max 127
Testing ... (interrupt to exit)
-bash-4.1# xinput list --long EETI
EETI id=8 [slave pointer (2)]
Reporting 4 classes:
Class originated from: 8
Buttons supported: 5
Button labels: Button Unknown Button Unknown Button Unknown Button Wheel Up Button Wheel Down
Button state:
Class originated from: 8
Detail for Valuator 0:
Label: Abs X
Range: 0.000000 - 2047.000000
Resolution: 10000 units/m
Mode: absolute
Current value: 400.000000
Class originated from: 8
Detail for Valuator 1:
Label: Abs Y
Range: 0.000000 - 2047.000000
Resolution: 10000 units/m
Mode: absolute
Current value: 240.000000
Class originated from: 8
Detail for Valuator 2:
Label: Abs Pressure
Range: 0.000000 - 127.000000
Resolution: 10000 units/m
Mode: absolute
Current value: 0.000000
diff -urNp xinput_calibrator-0.7.5-orig/src/calibrator/calibratorEvdev.cpp xinput_calibrator-0.7.5/src/calibrator/calibratorEvdev.cpp
--- xinput_calibrator-0.7.5-orig/src/calibrator/calibratorEvdev.cpp 2010-09-12 21:46:10.000000000 +0200
+++ xinput_calibrator-0.7.5/src/calibrator/calibratorEvdev.cpp 2010-12-21 09:33:06.000000000 +0100
@@ -34,6 +34,8 @@
#define EXIT_FAILURE 0
#endif
+#define INVALID_EVENT_TYPE -1
+
/***************************************
* Class for dynamic evdev calibration
* uses xinput "Evdev Axis Calibration"
@@ -46,12 +48,18 @@ private:
XDevice *dev;
int old_swap_xy;
+ int button_press_type;
+ int button_release_type;
+ int motion_type;
+ int motion_a, motion_b;
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 int register_events();
+ virtual int check_press_event(int *x, int *y);
virtual bool finish_data(const XYinfo new_axys, int swap_xy);
bool set_swapxy(const int swap_xy);
@@ -67,9 +75,16 @@ protected:
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)
{
+ XYinfo curr_calib;
+ button_press_type = INVALID_EVENT_TYPE;
+ button_release_type = INVALID_EVENT_TYPE;
+ motion_type = INVALID_EVENT_TYPE;
+ motion_a = motion_b = 0;
+
// init
display = XOpenDisplay(NULL);
if (display == NULL) {
@@ -139,19 +154,37 @@ CalibratorEvdev::CalibratorEvdev(const c
} else if (nitems > 0) {
ptr = data;
- old_axys.x_min = *((long*)ptr);
+ curr_calib.x_min = *((long*)ptr);
ptr += sizeof(long);
- old_axys.x_max = *((long*)ptr);
+ curr_calib.x_max = *((long*)ptr);
ptr += sizeof(long);
- old_axys.y_min = *((long*)ptr);
+ curr_calib.y_min = *((long*)ptr);
ptr += sizeof(long);
- old_axys.y_max = *((long*)ptr);
+ curr_calib.y_max = *((long*)ptr);
ptr += sizeof(long);
}
XFree(data);
}
+ {
+ if (verbose)
+ printf("DEBUG: setting Evdev Axis Calibration to axis valuators.\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");
+ }
+ }
+
// get "Evdev Axes Swap" property
property = xinput_parse_atom(display, "Evdev Axes Swap");
if (XGetDeviceProperty(display, dev, property, 0, 1000, False,
@@ -169,8 +202,8 @@ CalibratorEvdev::CalibratorEvdev(const c
// 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);
+ printf("\tprevious calibration values (from XInput): min_x=%d, max_x=%d and min_y=%d, max_y=%d\n",
+ curr_calib.x_min, curr_calib.x_max, curr_calib.y_min, curr_calib.y_max);
#endif // HAVE_XI_PROP
}
@@ -180,6 +213,72 @@ CalibratorEvdev::~CalibratorEvdev () {
XCloseDisplay(display);
}
+
+
+int CalibratorEvdev::register_events()
+{
+ int number = 0;
+ XEventClass event_list[7];
+ int i;
+ Window root_win;
+ unsigned long screen;
+ XInputClassInfo *ip;
+
+ screen = DefaultScreen(display);
+ root_win = RootWindow(display, screen);
+
+ if (dev->num_classes > 0) {
+ printf("register_events: num_classes=%d\n", dev->num_classes);
+ for (ip = dev->classes, i=0; i<dev->num_classes; ip++, i++) {
+ printf("register_events: input_class=%d\n", ip->input_class);
+ switch (ip->input_class) {
+ case ButtonClass:
+ DeviceButtonPress(dev, button_press_type, event_list[number]); number++;
+ DeviceButtonRelease(dev, button_release_type, event_list[number]); number++;
+ break;
+ case ValuatorClass:
+ DeviceMotionNotify(dev, motion_type, event_list[number]); number++;
+ break;
+ default:
+ fprintf(stderr, "unknown class\n");
+ break;
+ }
+ }
+
+ if (XSelectExtensionEvent(display, root_win, event_list, number)) {
+ fprintf(stderr, "error selecting extended events\n");
+ return 0;
+ }
+ printf("register_events: registered %d events with xinput\n", number);
+ }
+ return 1;
+}
+
+int CalibratorEvdev::check_press_event(int *x, int *y)
+{
+ XEvent event;
+
+ if (XCheckTypedEvent(display, motion_type, &event)) {
+ XDeviceMotionEvent *motion = (XDeviceMotionEvent *)&event;
+
+// printf("motion a=%d b=%d\n",
+// motion->axis_data[0], motion->axis_data[1]);
+ motion_a = motion->axis_data[0];
+ motion_b = motion->axis_data[1];
+ }
+ if (XCheckTypedEvent(display, button_release_type, &event)) {
+ XDeviceButtonEvent *button = (XDeviceButtonEvent *)&event;
+
+ printf("button release %d [%d,%d]\n", button->button, motion_a, motion_b);
+ *x = motion_a;
+ *y = motion_b;
+ return 1;
+ }
+ *x = -1;
+ *y = -1;
+ return 0;
+}
+
bool CalibratorEvdev::finish_data(const XYinfo new_axys, int swap_xy)
{
bool success = true;
diff -urNp xinput_calibrator-0.7.5-orig/src/calibrator.cpp xinput_calibrator-0.7.5/src/calibrator.cpp
--- xinput_calibrator-0.7.5-orig/src/calibrator.cpp 2010-09-12 21:46:10.000000000 +0200
+++ xinput_calibrator-0.7.5/src/calibrator.cpp 2010-12-20 12:42:26.000000000 +0100
@@ -124,12 +124,18 @@ inline bool Calibrator::along_axis(int x
(abs(xy - y0) <= threshold_misclick));
}
-bool Calibrator::finish(int width, int height)
+bool Calibrator::finish()
{
+ int width;
+ int height;
+
if (get_numclicks() != 4) {
return false;
}
+ width = abs(old_axys.x_max - old_axys.x_min) + 1;
+ height = abs(old_axys.y_max - old_axys.y_min) + 1;
+
// 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) {
diff -urNp xinput_calibrator-0.7.5-orig/src/calibrator.hh xinput_calibrator-0.7.5/src/calibrator.hh
--- xinput_calibrator-0.7.5-orig/src/calibrator.hh 2010-09-12 21:46:10.000000000 +0200
+++ xinput_calibrator-0.7.5/src/calibrator.hh 2010-12-20 12:42:26.000000000 +0100
@@ -50,11 +50,16 @@ public:
// add a click with the given coordinates
bool add_click(int x, int y);
// calculate and apply the calibration
- bool finish(int width, int height);
+ bool finish();
// get the sysfs name of the device,
// returns NULL if it can not be found
const char* get_sysfs_name();
+ // optionally overload this to listen for events ourselves
+ virtual int register_events() { return 0; }
+ // optionally overload this to process events directly
+ virtual int check_press_event(int *x, int *y) { return 0; }
+
protected:
// check whether the coordinates are along the respective axis
bool along_axis(int xy, int x0, int y0);
diff -urNp xinput_calibrator-0.7.5-orig/src/gui/gui_x11.cpp xinput_calibrator-0.7.5/src/gui/gui_x11.cpp
--- xinput_calibrator-0.7.5-orig/src/gui/gui_x11.cpp 2010-09-12 21:46:10.000000000 +0200
+++ xinput_calibrator-0.7.5/src/gui/gui_x11.cpp 2010-12-21 09:33:48.000000000 +0100
@@ -92,12 +92,13 @@ protected:
XFontStruct* font_info;
// color mngmt
unsigned long pixel[nr_colors];
+ bool calib_input;
// Signal handlers
bool on_timer_signal();
bool on_expose_event();
- bool on_button_press_event(XEvent event);
+ bool on_button_press_event(int x, int y);
// Helper functions
void set_display_size(int width, int height);
@@ -159,8 +160,11 @@ GuiCalibratorX11::GuiCalibratorX11(Calib
// Listen to events
XGrabKeyboard(display, win, False, GrabModeAsync, GrabModeAsync,
CurrentTime);
- XGrabPointer(display, win, False, ButtonPressMask, GrabModeAsync,
+ calib_input = calibrator->register_events();
+ if (!calib_input) {
+ XGrabPointer(display, win, False, ButtonPressMask, GrabModeAsync,
GrabModeAsync, None, None, CurrentTime);
+ }
Colormap colormap = DefaultColormap(display, screen_num);
XColor color;
@@ -294,7 +298,7 @@ bool GuiCalibratorX11::on_timer_signal()
return true;
}
-bool GuiCalibratorX11::on_button_press_event(XEvent event)
+bool GuiCalibratorX11::on_button_press_event(int x, int y)
{
// Clear window, maybe a bit overdone, but easiest for me atm.
// (goal is to clear possible message and other clicks)
@@ -302,7 +306,7 @@ bool GuiCalibratorX11::on_button_press_e
// Handle click
time_elapsed = 0;
- bool success = calibrator->add_click(event.xbutton.x, event.xbutton.y);
+ bool success = calibrator->add_click(x, y);
if (!success && calibrator->get_numclicks() == 0) {
draw_message("Mis-click detected, restarting...");
@@ -311,7 +315,7 @@ bool GuiCalibratorX11::on_button_press_e
// Are we done yet?
if (calibrator->get_numclicks() >= 4) {
// Recalibrate
- success = calibrator->finish(display_width, display_height);
+ success = calibrator->finish();
if (success) {
exit(0);
@@ -352,6 +356,10 @@ void GuiCalibratorX11::give_timer_signal
// process events
XEvent event;
+ int x, y;
+ if (instance->calib_input)
+ if (instance->calibrator->check_press_event(&x, &y))
+ instance->on_button_press_event(x, y);
while (XCheckWindowEvent(instance->display, instance->win, -1, &event) == True) {
switch (event.type) {
case Expose:
@@ -360,11 +368,10 @@ void GuiCalibratorX11::give_timer_signal
break;
instance->on_expose_event();
break;
-
case ButtonPress:
- instance->on_button_press_event(event);
+ if (!instance->calib_input)
+ instance->on_button_press_event(event.xbutton.x, event.xbutton.y);
break;
-
case KeyPress:
exit(0);
break;
Finally a debug output of successful calibration:
-bash-4.1# ./xinput_calibrator --output-type xinput -v
DEBUG: XInputExtension version is 2.0
DEBUG: Skipping virtual master devices and devices without axis valuators.
DEBUG: Skipping device 'Virtual core XTEST pointer' id=4, does not report Absolute events.
DEBUG: Skipping device 'Mouse0' id=6, does not report Absolute events.
DEBUG: Selected device: EETI
DEBUG: Not usbtouchscreen calibrator: Not a usbtouchscreen device
DEBUG: setting Evdev Axis Calibration to axis valuators.
DEBUG: Successfully applied axis calibration.
DEBUG: Read axes swap value of 0.
Calibrating EVDEV driver for "EETI" id=8
previous calibration values (from XInput): min_x=0, max_x=2047 and min_y=0, max_y=2047
register_events: num_classes=4
register_events: input_class=1
register_events: input_class=2
register_events: input_class=3
unknown class
register_events: input_class=6
unknown class
register_events: registered 3 events with xinput
button release 1 [381,1691]
DEBUG: Adding click 0 (X=381, Y=1691)
button release 1 [1699,1676]
DEBUG: Adding click 1 (X=1699, Y=1676)
button release 1 [380,363]
DEBUG: Adding click 2 (X=380, Y=363)
button release 1 [1711,369]
DEBUG: Adding click 3 (X=1711, Y=369)
Doing dynamic recalibration:
Setting new calibration data: 160, 1924, 1901, 146
DEBUG: Successfully applied axis calibration.
--> Making the calibration permanent
Install the 'xinput' tool and copy the command(s) below in a script that starts with your X session
xinput set-int-prop "EETI" "Evdev Axis Calibration" 32 160 1924 1901 146
Hope that helps...
And maybe a final note - I am not completely sure about the Calibrator::finish() formulas - there are used 'width' and 'height' parameters on one side but on the other side inside the scaling computation, difference between 'max' and 'min' coordinates is used. If the source and target resolutions were the same, there would be off by one difference between (max - min) and width/height. Probably would not influence much and I do not see too deep into the calculation so it may be ok, but I was just wondering...
The text was updated successfully, but these errors were encountered:
This sounds pretty reasonable. I wonder why the code is not merged...
BTW, I've got the following problems with xinput_calibrator:
It does not recognise that the axis should be swapped for my touch screen. As it is pretty hard for xinput_calibrator alone to find out, I guess that there should be an command option the force the swap, i.e. something like '--swapaxes 1'.
In my case the calibration leads to a state where it is difficult to point to the very screen borders. I could imagine the outcome would be better if the calibration points where more near to the screen corners.
It would be a nice enhancement if the calibration would also allow mouse button (emulation) to gesture mapping.
I've tested xinput_calibrator-0.7.5 with touchscreen driven by evdev, but it did not work because of several (design) problems of xinput_calibrator.
Since I wanted to get xinput_calibrator running in order to use the feature to calibrate without restart of xserver, I had to make following changes/hacks (done only in x11 gui version):
Please note, I am not experienced with xlib programming and I did not want to redesign the architecture of xinput_calibrator, so my changes are quite dirty, but they work for me. So I am posting the patch here for you so you may think about it and possibly fix or redesign the xinput_calibrator which I find as great application that was missing for a long time.
First few more information on what sw components were used:
And the dirty patch itself:
Finally a debug output of successful calibration:
Hope that helps...
And maybe a final note - I am not completely sure about the Calibrator::finish() formulas - there are used 'width' and 'height' parameters on one side but on the other side inside the scaling computation, difference between 'max' and 'min' coordinates is used. If the source and target resolutions were the same, there would be off by one difference between (max - min) and width/height. Probably would not influence much and I do not see too deep into the calculation so it may be ok, but I was just wondering...
The text was updated successfully, but these errors were encountered: