由于需要在GTK程序中实现触摸屏校准功能,所以最开始尝试通过popen和execl等调用ts_calibrate程序实现,校准是没有问题,但校准完成后,GTK界面却没了,看了ts_calibrate的代码,发现其实现是直接写framebuffer,所以造成GTK的界面消失。因此特写了一个使用GTK实现的触摸屏校准工具,代码如下:
- /**
- * @file a.c
- *
License
- * Copyright (c) 2011-2012 niu.tao
- *
- * This source code is released under the terms of GNU
- *
- * @author niu.tao
- * @version v1.0
- * @date Sat Nov 10 18:28:01 CST 2012
- *
- * @brief
- */
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- typedef struct {
- int x[5], xfb[5];
- int y[5], yfb[5];
- int a[7];
- } calibration;
- #define TSLIB_TSDEVICE "/dev/input/ts0"
- #define DISPLAY "0:0"
- #define TSLIB_CALIBFILE "/usr/etc/pointercal"
- static __u32 xres, yres;
- static char *defaultfbdevice = "/dev/fb0";
- static char *fbdevice = NULL;
- static struct tsdev *ts;
- static calibration cal;
- static int cal_fd;
- GtkWidget *da;
- GdkGC *gc_red;
- GdkFont *font;
- struct ts_struct {
- int index;
- int x;
- int y;
- };
- struct ts_struct ts_s;
- static int step = 0;
- static void gtk_ts_calibrate_expose_event(GtkWidget * widget, GdkEventExpose * event, gpointer data);
- static void put_string(int x, int y, char *s)
- {
- gdk_draw_text(da->window, font, gc_red, x, y, s, strlen(s));
- }
- static void put_string_center(int x, int y, char *s)
- {
- int len = strlen(s);
- put_string(x - len / 2 * 6, y - 4, s);
- }
- static void line(int x1, int y1, int x2, int y2)
- {
- gdk_draw_line(da->window, gc_red, x1, y1, x2, y2);
- }
- static void put_cross(int x, int y)
- {
- gtk_ts_calibrate_expose_event(da, NULL, NULL);
- put_string_center(xres / 2, yres / 4, "TSLIB calibration utility");
- put_string_center(xres / 2, yres / 4 + 20, "Touch crosshair to calibrate");
- line(x - 10, y, x - 2, y);
- line(x + 2, y, x + 10, y);
- line(x, y - 10, x, y - 2);
- line(x, y + 2, x, y + 10);
- line(x - 6, y - 9, x - 9, y - 9);
- line(x - 9, y - 8, x - 9, y - 6);
- line(x - 9, y + 6, x - 9, y + 9);
- line(x - 8, y + 9, x - 6, y + 9);
- line(x + 6, y + 9, x + 9, y + 9);
- line(x + 9, y + 8, x + 9, y + 6);
- line(x + 9, y - 6, x + 9, y - 9);
- line(x + 8, y - 9, x + 6, y - 9);
- }
- static int sort_by_x(const void *a, const void *b)
- {
- return (((struct ts_sample *)a)->x - ((struct ts_sample *)b)->x);
- }
- static int sort_by_y(const void *a, const void *b)
- {
- return (((struct ts_sample *)a)->y - ((struct ts_sample *)b)->y);
- }
- int getxy(struct tsdev *ts, int *x, int *y)
- {
- #define MAX_SAMPLES 128
- struct ts_sample samp[MAX_SAMPLES];
- int index, middle;
- do {
- if (ts_read_raw(ts, &samp[0], 1) < 0) {
- perror("ts_read");
- return 1;
- }
- } while (samp[0].pressure == 0);
- /* Now collect up to MAX_SAMPLES touches into the samp array. */
- index = 0;
- do {
- if (index < MAX_SAMPLES - 1)
- index++;
- if (ts_read_raw(ts, &samp[index], 1) < 0) {
- perror("ts_read");
- return 1;
- }
- } while (samp[index].pressure > 0);
- printf("Took %d samples...\n", index);
- /*
- * At this point, we have samples in indices zero to (index-1)
- * which means that we have (index) number of samples. We want
- * to calculate the median of the samples so that wild outliers
- * don't skew the result. First off, let's assume that arrays
- * are one-based instead of zero-based. If this were the case
- * and index was odd, we would need sample number ((index+1)/2)
- * of a sorted array; if index was even, we would need the
- * average of sample number (index/2) and sample number
- * ((index/2)+1). To turn this into something useful for the
- * real world, we just need to subtract one off of the sample
- * numbers. So for when index is odd, we need sample number
- * (((index+1)/2)-1). Due to integer division truncation, we
- * can simplify this to just (index/2). When index is even, we
- * need the average of sample number ((index/2)-1) and sample
- * number (index/2). Calculate (index/2) now and we'll handle
- * the even odd stuff after we sort.
- */
- middle = index / 2;
- if (x) {
- qsort(samp, index, sizeof(struct ts_sample), sort_by_x);
- if (index & 1)
- *x = samp[middle].x;
- else
- *x = (samp[middle - 1].x + samp[middle].x) / 2;
- }
- if (y) {
- qsort(samp, index, sizeof(struct ts_sample), sort_by_y);
- if (index & 1)
- *y = samp[middle].y;
- else
- *y = (samp[middle - 1].y + samp[middle].y) / 2;
- }
- return 0;
- }
- void ts_flush(struct tsdev *ts)
- {
- /* Read all unread touchscreen data,
- * so that we are sure that the next data that we read
- * have been input after this flushing.
- */
- #define TS_BUFFER_MAX 32768
- static char buffer[TS_BUFFER_MAX];
- read(ts_fd(ts), buffer, TS_BUFFER_MAX);
- }
- static int perform_calibration(calibration * cal)
- {
- int j;
- float n, x, y, x2, y2, xy, z, zx, zy;
- float det, a, b, c, e, f, i;
- float scaling = 65536.0;
- // Get sums for matrix
- n = x = y = x2 = y2 = xy = 0;
- for (j = 0; j < 5; j++) {
- n += 1.0;
- x += (float)cal->x[j];
- y += (float)cal->y[j];
- x2 += (float)(cal->x[j] * cal->x[j]);
- y2 += (float)(cal->y[j] * cal->y[j]);
- xy += (float)(cal->x[j] * cal->y[j]);
- }
- // Get determinant of matrix -- check if determinant is too small
- det = n * (x2 * y2 - xy * xy) + x * (xy * y - x * y2) + y * (x * xy - y * x2);
- if (det < 0.1 && det > -0.1) {
- printf("ts_calibrate: determinant is too small -- %f\n", det);
- return 0;
- }
- // Get elements of inverse matrix
- a = (x2 * y2 - xy * xy) / det;
- b = (xy * y - x * y2) / det;
- c = (x * xy - y * x2) / det;
- e = (n * y2 - y * y) / det;
- f = (x * y - n * xy) / det;
- i = (n * x2 - x * x) / det;
- // Get sums for x calibration
- z = zx = zy = 0;
- for (j = 0; j < 5; j++) {
- z += (float)cal->xfb[j];
- zx += (float)(cal->xfb[j] * cal->x[j]);
- zy += (float)(cal->xfb[j] * cal->y[j]);
- }
- // Now multiply out to get the calibration for framebuffer x coord
- cal->a[0] = (int)((a * z + b * zx + c * zy) * (scaling));
- cal->a[1] = (int)((b * z + e * zx + f * zy) * (scaling));
- cal->a[2] = (int)((c * z + f * zx + i * zy) * (scaling));
- printf("%f %f %f\n", (a * z + b * zx + c * zy), (b * z + e * zx + f * zy), (c * z + f * zx + i * zy));
- // Get sums for y calibration
- z = zx = zy = 0;
- for (j = 0; j < 5; j++) {
- z += (float)cal->yfb[j];
- zx += (float)(cal->yfb[j] * cal->x[j]);
- zy += (float)(cal->yfb[j] * cal->y[j]);
- }
- // Now multiply out to get the calibration for framebuffer y coord
- cal->a[3] = (int)((a * z + b * zx + c * zy) * (scaling));
- cal->a[4] = (int)((b * z + e * zx + f * zy) * (scaling));
- cal->a[5] = (int)((c * z + f * zx + i * zy) * (scaling));
- printf("%f %f %f\n", (a * z + b * zx + c * zy), (b * z + e * zx + f * zy), (c * z + f * zx + i * zy));
- // If we got here, we're OK, so assign scaling to a[6] and return
- cal->a[6] = (int)scaling;
- return 1;
- }
- gboolean __getxy(gpointer user_data)
- {
- int index;
- int x;
- int y;
- index = ts_s.index;
- x = ts_s.x;
- y = ts_s.y;
- getxy(ts, &cal.x[index], &cal.y[index]);
- put_cross(x, y);
- cal.xfb[index] = x;
- cal.yfb[index] = y;
- printf("X = %4d Y = %4d\n", cal.x[index], cal.y[index]);
- return FALSE;
- }
- static void get_sample(struct tsdev *ts, calibration * cal, int index, int x, int y, char *name)
- {
- ts_s.index = index;
- ts_s.x = x;
- ts_s.y = y;
- put_cross(x, y);
- g_timeout_add(10, __getxy, NULL);
- }
- gboolean ts_calibrate(gpointer user_data);
- int gkt_ts_calibrate_open(void)
- {
- int fb_fd = 0;
- char *tsdevice = NULL;
- struct fb_fix_screeninfo fix;
- struct fb_var_screeninfo var;
- if ((tsdevice = getenv("TSLIB_TSDEVICE")) != NULL) {
- ts = ts_open(tsdevice, 0);
- } else {
- ts = ts_open("/dev/input/event0", 0);
- }
- if (!ts) {
- perror("ts_open");
- return -11;
- }
- if (ts_config(ts)) {
- perror("ts_config");
- return -1;
- }
- if ((fbdevice = getenv("TSLIB_FBDEVICE")) == NULL)
- fbdevice = defaultfbdevice;
- fb_fd = open(fbdevice, O_RDWR);
- if (fb_fd == -1) {
- perror("open fbdevice");
- return -1;
- }
- if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &fix) < 0) {
- perror("ioctl FBIOGET_FSCREENINFO");
- close(fb_fd);
- return -1;
- }
- if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &var) < 0) {
- perror("ioctl FBIOGET_VSCREENINFO");
- close(fb_fd);
- return -1;
- }
- close(fb_fd);
- xres = var.xres;
- yres = var.yres;
- return 0;
- }
- int gtk_ts_calibrate_save_conf(void)
- {
- char cal_buffer[256];
- unsigned int i;
- char *calfile = NULL;
- if (perform_calibration(&cal)) {
- printf("Calibration constants: ");
- for (i = 0; i < 7; i++)
- printf("%d ", cal.a[i]);
- printf("\n");
- if ((calfile = getenv("TSLIB_CALIBFILE")) != NULL) {
- cal_fd = open(calfile, O_CREAT | O_RDWR);
- } else {
- cal_fd = open("/etc/pointercal", O_CREAT | O_RDWR);
- }
- sprintf(cal_buffer, "%d %d %d %d %d %d %d",
- cal.a[1], cal.a[2], cal.a[0], cal.a[4], cal.a[5], cal.a[3], cal.a[6]);
- write(cal_fd, cal_buffer, strlen(cal_buffer) + 1);
- close(cal_fd);
- i = 0;
- } else {
- printf("Calibration failed.\n");
- i = -1;
- }
- return 0;
- }
- static void gtk_ts_calibrate_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
- {
- gdk_draw_rectangle(da->window, widget->style->black_gc, TRUE,
- 0, 0, widget->allocation.width, widget->allocation.height);
- }
- static gboolean gtk_ts_calibrate_configure_event(GtkWidget *widget, GdkEventConfigure *event, gpointer user_data)
- {
- gc_red = gdk_gc_new(da->window);
- GdkColor color;
- color.red = 0xFFFF;
- color.green = 0;
- color.blue = 0;
- gdk_gc_set_rgb_fg_color(gc_red, &color);
- PangoFontDescription *pfont;
- pfont = pango_font_description_from_string("Liberation Sans");
- font = gdk_font_from_description(pfont);
- return TRUE;
- }
- gboolean ts_calibrate(gpointer user_data)
- {
- switch (step) {
- case 0:
- get_sample(ts, &cal, 0, 50, 50, "Top left");
- break;
- case 1:
- get_sample(ts, &cal, 1, xres - 50, 50, "Top right");
- break;
- case 2:
- get_sample(ts, &cal, 2, xres - 50, yres - 50, "Bot right");
- break;
- case 3:
- get_sample(ts, &cal, 3, 50, yres - 50, "Bot left");
- break;
- case 4:
- get_sample(ts, &cal, 4, xres / 2, yres / 2, "Center");
- break;
- default:
- gtk_ts_calibrate_save_conf();
- gtk_main_quit();
- }
- printf("step = %d\n", step);
- step++;
- g_timeout_add(10, ts_calibrate, NULL);
- return FALSE;
- }
- int main(int argc, char *argv[])
- {
- GtkWidget *window;
- GtkWidget *fixed;
- if (getenv("DISPLAY") == NULL)
- setenv("DISPLAY", DISPLAY, 1);
- if (getenv("TSLIB_TSDEVICE") == NULL)
- setenv("TSLIB_TSDEVICE", TSLIB_TSDEVICE, 1);
- if (getenv("TSLIB_CALIBFILE") == NULL)
- setenv("TSLIB_CALIBFILE", TSLIB_TSDEVICE, 1);
- if (!g_thread_supported())
- g_thread_init(NULL);
- setlocale(LC_ALL, "");
- bindtextdomain("gtk_ts_calibrate", ".");
- textdomain("gtk_ts_calibrate");
- gtk_set_locale();
- g_type_init();
- gtk_init(&argc, &argv);
- gkt_ts_calibrate_open();
- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_widget_set_uposition(GTK_WIDGET(window), 0, 0);
- gtk_widget_set_usize(GTK_WIDGET(window), xres, yres);
- fixed = gtk_fixed_new();
- gtk_container_add(GTK_CONTAINER(window), fixed);
- da = gtk_drawing_area_new();
- gtk_widget_set_usize(GTK_WIDGET(da), xres, yres);
- gtk_fixed_put(GTK_FIXED(fixed), da, 0, 0);
- g_signal_connect((gpointer) da, "configure_event", G_CALLBACK(gtk_ts_calibrate_configure_event), NULL);
- g_signal_connect(G_OBJECT(da), "expose_event", GTK_SIGNAL_FUNC(gtk_ts_calibrate_expose_event), 0);
- gtk_widget_show_all(window);
- step = 0;
- printf("xres = %d, yres = %d\n", xres, yres);
- g_timeout_add(1000, ts_calibrate, NULL);
- gtk_main();
- return 0;
- }
阅读(3112) | 评论(1) | 转发(0) |