2
* Copyright (c) 2009 Tias Guns
3
* Copyright (c) 2009 Soren Hauberg
5
* Permission is hereby granted, free of charge, to any person obtaining a copy
6
* of this software and associated documentation files (the "Software"), to deal
7
* in the Software without restriction, including without limitation the rights
8
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
* copies of the Software, and to permit persons to whom the Software is
10
* furnished to do so, subject to the following conditions:
12
* The above copyright notice and this permission notice shall be included in
13
* all copies or substantial portions of the Software.
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30
#include <glib/gi18n.h>
32
#include <X11/extensions/XInput.h>
35
#include "calibrator.h"
38
* find a calibratable touchscreen device (using XInput)
40
* if pre_device is NULL, the last calibratable device is selected.
41
* retuns number of devices found,
42
* the data of the device is returned in the last 3 function parameters
44
static int find_device(const char* pre_device, gboolean verbose, gboolean list_devices,
45
XID* device_id, const char** device_name, XYinfo* device_axis)
47
gboolean pre_device_is_id = TRUE;
50
Display* display = XOpenDisplay(NULL);
51
if (display == NULL) {
52
fprintf(stderr, "Unable to connect to X server\n");
56
int xi_opcode, event, error;
57
if (!XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &error)) {
58
fprintf(stderr, "X Input extension not available.\n");
62
/* verbose, get Xi version */
64
XExtensionVersion *version = XGetExtensionVersion(display, INAME);
66
if (version && (version != (XExtensionVersion*) NoSuchExtension)) {
67
printf("DEBUG: %s version is %i.%i\n",
68
INAME, version->major_version, version->minor_version);
73
if (pre_device != NULL) {
74
/* check whether the pre_device is an ID (only digits) */
75
int len = strlen(pre_device);
77
for (loop=0; loop<len; loop++) {
78
if (!isdigit(pre_device[loop])) {
79
pre_device_is_id = FALSE;
87
printf("DEBUG: Skipping virtual master devices and devices without axis valuators.\n");
89
XDeviceInfoPtr list, slist;
90
slist=list=(XDeviceInfoPtr) XListInputDevices (display, &ndevices);
92
for (i=0; i<ndevices; i++, list++)
94
if (list->use == IsXKeyboard || list->use == IsXPointer) /* virtual master device */
97
/* if we are looking for a specific device */
98
if (pre_device != NULL) {
99
if ((pre_device_is_id && list->id == (XID) atoi(pre_device)) ||
100
(!pre_device_is_id && strcmp(list->name, pre_device) == 0)) {
101
/* OK, fall through */
103
/* skip, not this device */
108
XAnyClassPtr any = (XAnyClassPtr) (list->inputclassinfo);
110
for (j=0; j<list->num_classes; j++)
113
if (any->class == ValuatorClass)
115
XValuatorInfoPtr V = (XValuatorInfoPtr) any;
116
XAxisInfoPtr ax = (XAxisInfoPtr) V->axes;
118
if (V->mode != Absolute) {
120
printf("DEBUG: Skipping device '%s' id=%i, does not report Absolute events.\n",
121
list->name, (int)list->id);
122
} else if (V->num_axes < 2 ||
123
(ax[0].min_value == -1 && ax[0].max_value == -1) ||
124
(ax[1].min_value == -1 && ax[1].max_value == -1)) {
126
printf("DEBUG: Skipping device '%s' id=%i, does not have two calibratable axes.\n",
127
list->name, (int)list->id);
129
/* a calibratable device (has 2 axis valuators) */
131
*device_id = list->id;
132
*device_name = g_strdup(list->name);
133
device_axis->x_min = ax[0].min_value;
134
device_axis->x_max = ax[0].max_value;
135
device_axis->y_min = ax[1].min_value;
136
device_axis->y_max = ax[1].max_value;
139
printf("Device \"%s\" id=%i\n", *device_name, (int)*device_id);
145
* Increment 'any' to point to the next item in the linked
146
* list. The length is in bytes, so 'any' must be cast to
147
* a character pointer before being incremented.
149
any = (XAnyClassPtr) ((char *) any + any->length);
153
XFreeDeviceList(slist);
154
XCloseDisplay(display);
159
static void usage(char* cmd, unsigned thr_misclick)
161
fprintf(stderr, "Usage: %s [-h|--help] [-v|--verbose] [--list] [--device <device name or id>] [--precalib <minx> <maxx> <miny> <maxy>] [--misclick <nr of pixels>] [--output-type <auto|xorg.conf.d|hal|xinput>] [--fake]\n", cmd);
162
fprintf(stderr, "\t-h, --help: print this help message\n");
163
fprintf(stderr, "\t-v, --verbose: print debug messages during the process\n");
164
fprintf(stderr, "\t--list: list calibratable input devices and quit\n");
165
fprintf(stderr, "\t--device <device name or id>: select a specific device to calibrate\n");
166
fprintf(stderr, "\t--precalib: manually provide the current calibration setting (eg. the values in xorg.conf)\n");
167
fprintf(stderr, "\t--misclick: set the misclick threshold (0=off, default: %i pixels)\n",
169
fprintf(stderr, "\t--fake: emulate a fake device (for testing purposes)\n");
172
static struct Calib* CalibratorXorgPrint(const char* const device_name0, const XYinfo *axis0, const gboolean verbose0, const int thr_misclick, const int thr_doubleclick)
174
struct Calib* c = (struct Calib*)calloc(1, sizeof(struct Calib));
175
c->old_axis = *axis0;
176
c->threshold_misclick = thr_misclick;
177
c->threshold_doubleclick = thr_doubleclick;
179
printf("Calibrating standard Xorg driver \"%s\"\n", device_name0);
180
printf("\tcurrent calibration values: min_x=%d, max_x=%d and min_y=%d, max_y=%d\n",
181
c->old_axis.x_min, c->old_axis.x_max, c->old_axis.y_min, c->old_axis.y_max);
182
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");
187
static struct Calib* main_common(int argc, char** argv)
189
gboolean verbose = FALSE;
190
gboolean list_devices = FALSE;
191
gboolean fake = FALSE;
192
gboolean precalib = FALSE;
193
XYinfo pre_axis = {-1, -1, -1, -1};
194
const char* pre_device = NULL;
195
unsigned thr_misclick = 15;
196
unsigned thr_doubleclick = 7;
201
for (i=1; i!=argc; i++) {
203
if (strcmp("-h", argv[i]) == 0 ||
204
strcmp("--help", argv[i]) == 0) {
205
fprintf(stderr, "xinput_calibratior, v%s\n\n", "0.0.0");
206
usage(argv[0], thr_misclick);
210
/* Verbose output ? */
211
if (strcmp("-v", argv[i]) == 0 ||
212
strcmp("--verbose", argv[i]) == 0) {
216
/* Just list devices ? */
217
if (strcmp("--list", argv[i]) == 0) {
221
/* Select specific device ? */
222
if (strcmp("--device", argv[i]) == 0) {
224
pre_device = argv[++i];
226
fprintf(stderr, "Error: --device needs a device name or id as argument; use --list to list the calibratable input devices.\n\n");
227
usage(argv[0], thr_misclick);
232
/* Get pre-calibration ? */
233
if (strcmp("--precalib", argv[i]) == 0) {
236
pre_axis.x_min = atoi(argv[++i]);
238
pre_axis.x_max = atoi(argv[++i]);
240
pre_axis.y_min = atoi(argv[++i]);
242
pre_axis.y_max = atoi(argv[++i]);
245
/* Get mis-click threshold ? */
246
if (strcmp("--misclick", argv[i]) == 0) {
248
thr_misclick = atoi(argv[++i]);
250
fprintf(stderr, "Error: --misclick needs a number (the pixel threshold) as argument. Set to 0 to disable mis-click detection.\n\n");
251
usage(argv[0], thr_misclick);
256
/* Fake calibratable device ? */
257
if (strcmp("--fake", argv[i]) == 0) {
263
fprintf(stderr, "Unknown option: %s\n\n", argv[i]);
264
usage(argv[0], thr_misclick);
271
/* Choose the device to calibrate */
272
XID device_id = (XID) -1;
273
const char* device_name = NULL;
274
XYinfo device_axis = {-1, -1, -1, -1};
276
/* Fake a calibratable device */
277
device_name = "Fake_device";
279
device_axis.x_max=1000;
281
device_axis.y_max=1000;
284
printf("DEBUG: Faking device: %s\n", device_name);
287
/* Find the right device */
288
int nr_found = find_device(pre_device, verbose, list_devices, &device_id, &device_name, &device_axis);
291
/* printed the list in find_device */
293
printf("No calibratable devices found.\n");
298
if (pre_device == NULL)
299
fprintf (stderr, "Error: No calibratable devices found.\n");
301
fprintf (stderr, "Error: Device \"%s\" not found; use --list to list the calibratable input devices.\n", pre_device);
304
} else if (nr_found > 1) {
305
printf ("Warning: multiple calibratable devices found, calibrating last one (%s)\n\tuse --device to select another one.\n", device_name);
309
printf("DEBUG: Selected device: %s\n", device_name);
313
/* override min/max XY from command line ? */
315
if (pre_axis.x_min != -1)
316
device_axis.x_min = pre_axis.x_min;
317
if (pre_axis.x_max != -1)
318
device_axis.x_max = pre_axis.x_max;
319
if (pre_axis.y_min != -1)
320
device_axis.y_min = pre_axis.y_min;
321
if (pre_axis.y_max != -1)
322
device_axis.y_max = pre_axis.y_max;
325
printf("DEBUG: Setting precalibration: %i, %i, %i, %i\n",
326
device_axis.x_min, device_axis.x_max,
327
device_axis.y_min, device_axis.y_max);
331
/* lastly, presume a standard Xorg driver (evtouch, mutouch, ...) */
332
return CalibratorXorgPrint(device_name, &device_axis,
333
verbose, thr_misclick, thr_doubleclick);
336
static gboolean output_xorgconfd(const XYinfo new_axis, int swap_xy, int new_swap_xy)
338
const char* sysfs_name = "!!Name_Of_TouchScreen!!";
340
/* xorg.conf.d snippet */
341
printf(" copy the snippet below into '/etc/X11/xorg.conf.d/99-calibration.conf'\n");
342
printf("Section \"InputClass\"\n");
343
printf(" Identifier \"calibration\"\n");
344
printf(" MatchProduct \"%s\"\n", sysfs_name);
345
printf(" Option \"MinX\" \"%d\"\n", new_axis.x_min);
346
printf(" Option \"MaxX\" \"%d\"\n", new_axis.x_max);
347
printf(" Option \"MinY\" \"%d\"\n", new_axis.y_min);
348
printf(" Option \"MaxY\" \"%d\"\n", new_axis.y_max);
350
printf(" Option \"SwapXY\" \"%d\" # unless it was already set to 1\n", new_swap_xy);
351
printf("EndSection\n");
356
static gboolean finish_data(const XYinfo new_axis, int swap_xy)
358
gboolean success = TRUE;
360
/* we suppose the previous 'swap_xy' value was 0 */
361
/* (unfortunately there is no way to verify this (yet)) */
362
int new_swap_xy = swap_xy;
364
printf("\n\n--> Making the calibration permanent <--\n");
365
success &= output_xorgconfd(new_axis, swap_xy, new_swap_xy);
371
calibration_finished_cb (CalibArea *area,
378
success = calib_area_finish (area, &axis, &swap_xy);
380
success = finish_data (axis, swap_xy);
382
fprintf(stderr, "Error: unable to apply or save configuration values\n");
387
int main(int argc, char** argv)
390
struct Calib* calibrator = main_common(argc, argv);
391
CalibArea *calib_area;
393
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
394
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
395
textdomain (GETTEXT_PACKAGE);
397
g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
400
gtk_init(&argc, &argv);
402
calib_area = calib_area_new (NULL,
404
-1, /* -1 to ignore device ID */
405
calibration_finished_cb,
407
&calibrator->old_axis,
408
calibrator->threshold_doubleclick,
409
calibrator->threshold_misclick);
413
calib_area_free (calib_area);