diff options
Diffstat (limited to 'app/xtsscale')
-rw-r--r-- | app/xtsscale/Makefile | 15 | ||||
-rw-r--r-- | app/xtsscale/xtsscale.1 | 59 | ||||
-rw-r--r-- | app/xtsscale/xtsscale.c | 399 |
3 files changed, 473 insertions, 0 deletions
diff --git a/app/xtsscale/Makefile b/app/xtsscale/Makefile new file mode 100644 index 000000000..a98d82a21 --- /dev/null +++ b/app/xtsscale/Makefile @@ -0,0 +1,15 @@ +# $OpenBSD: Makefile,v 1.1 2007/05/20 14:43:12 robert Exp $ + +PROG= xtsscale +MAN= xtsscale.1 + +CPPFLAGS+= -I${X11BASE}/include +LDADD+= -L${X11BASE}/lib -lX11 + +X11BASE?= /usr/X11R6 +MANDIR= ${X11BASE}/man/cat + +obj: _xenocara_obj + +.include <bsd.prog.mk> +.include <bsd.xorg.mk> diff --git a/app/xtsscale/xtsscale.1 b/app/xtsscale/xtsscale.1 new file mode 100644 index 000000000..80efe54d3 --- /dev/null +++ b/app/xtsscale/xtsscale.1 @@ -0,0 +1,59 @@ +.\" $OpenBSD: xtsscale.1,v 1.1 2007/05/20 14:43:12 robert Exp $ +.\" +.\" Copyright (c) 2007 Robert Nagy <robert@openbsd.org> +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD +.\" PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd May 17, 2007 +.Dt XTSSCALE 1 +.Os +.Sh NAME +.Nm xtsscale +.Nd X touch screen calibration tool +.Sh SYNOPSIS +.Nm xtsscale +.Bk -words +.Op Ar device +.Ek +.Sh DESCRIPTION +.Nm +is used interactively to calculate both the scaling and offset values which +will make the pointer act at the indicated location on the screen. +.Pp +When good deviations are calculated from the selections made at these +points, +.Nm +will exit and provide on standard output a result like the following: +.Pp +.Dl mouse.scale=200,3400,312,3672,1,1024,768 +.Pp +.Sh SEE ALSO +.Xr ioctl 2 , +.Xr uts 4 , +.Xr wscons 4 , +.Xr wsconsctl 8 , +.Xr X 7 +.Sh HISTORY +The +.Nm +command appeared in +.Ox 4.2 . diff --git a/app/xtsscale/xtsscale.c b/app/xtsscale/xtsscale.c new file mode 100644 index 000000000..ede8e3fa2 --- /dev/null +++ b/app/xtsscale/xtsscale.c @@ -0,0 +1,399 @@ +/* $OpenBSD: xtsscale.c,v 1.1 2007/05/20 14:43:12 robert Exp $ */ +/* + * Copyright (c) 2007 Robert Nagy <robert@openbsd.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD + * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xos.h> +#include <X11/Xatom.h> +#include <X11/keysym.h> + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <dev/wscons/wsconsio.h> + +#include <err.h> +#include <stdio.h> +#include <termios.h> +#include <stdlib.h> +#include <math.h> + +#define FONT_NAME "9x15" + +#define Background cWHITE +#define TouchCross cBLACK +#define PromptText cBLACK + +#define N_Colors 3 + +static char colors[N_Colors][10] = +{"BLACK", "WHITE"}; + +static unsigned long pixels[N_Colors]; + +#define cBLACK (pixels[0]) +#define cWHITE (pixels[1]) + +/* where the calibration points are placed */ +#define SCREEN_DIVIDE 16 +#define SCREEN_MAX 0x800 +#define M_POINT (SCREEN_MAX/SCREEN_DIVIDE) +int MARK_POINT[] = {M_POINT, SCREEN_MAX - 1 - M_POINT}; + +int touched = 0; +char *deviceName; + +Display *display; +int screen; +GC gc; +Window root; +Window win; +XFontStruct *font_info; +unsigned int width, height; /* window size */ +char *progname; +int evfd; + +unsigned int cx[5], cy[5]; +unsigned int x[5], y[5]; + +void +get_events(int i) +{ + ssize_t len; + int down; + struct wscons_event ev; + + down = 0; + x[i] = y[i] = -1; + while (down || x[i] == -1 || y[i] == -1) { + len = read(evfd, &ev, sizeof(ev)); + if (len != 16) + break; + switch (ev.type) { + case WSCONS_EVENT_MOUSE_DOWN: + down = 1; + break; + case WSCONS_EVENT_MOUSE_UP: + down = 0; + break; + case WSCONS_EVENT_MOUSE_ABSOLUTE_X: + if (down) + x[i] = ev.value; + break; + case WSCONS_EVENT_MOUSE_ABSOLUTE_Y: + if (down) + y[i] = ev.value; + break; + default: + break; + } + } +} + + +void +cleanup_exit() +{ + XUnloadFont(display, font_info->fid); + XUngrabServer(display); + XUngrabKeyboard(display, CurrentTime); + XFreeGC(display, gc); + XCloseDisplay(display); + close(evfd); +} + + +void +load_font(XFontStruct ** font_info) +{ + char *fontname = FONT_NAME; + + if ((*font_info = XLoadQueryFont(display, fontname)) == NULL) { + printf("Cannot open %s font\n", FONT_NAME); + exit(1); + } +} + + +void +draw_point(int x, int y, int width, int size, unsigned long color) +{ + XSetForeground(display, gc, color); + XSetLineAttributes(display, gc, width, LineSolid, + CapRound, JoinRound); + XDrawLine(display, win, gc, x - size, y, x + size, y); + XDrawLine(display, win, gc, x, y - size, x, y + size); +} + +void +draw_text() +{ + static char *prompt[] = { + " TOUCH SCREEN CALIBRATION", + "Press on the cross hairs please..." + }; + +#define num (sizeof(prompt) / sizeof(prompt[0])) + static int init = 0; + static int p_len[num]; + static int p_width[num]; + static int p_height; + static int p_maxwidth = 0; + int i, x, y; + int line_height; + + if (!init) { + for (i = 0; i < num; i++) { + p_len[i] = strlen(prompt[i]); + p_width[i] = XTextWidth(font_info, prompt[i], p_len[i]); + if (p_width[i] > p_maxwidth) + p_maxwidth = p_width[i]; + } + p_height = font_info->ascent + font_info->descent; + init = 1; + } + line_height = p_height + 5; + x = (width - p_maxwidth) / 2; + y = height / 2 - 6 * line_height; + + XSetForeground(display, gc, PromptText); + XClearArea(display, win, x - 11, y - 8 - p_height, + p_maxwidth + 11 * 2, num * line_height + 8 * 2, False); + XSetLineAttributes(display, gc, 3, FillSolid, + CapRound, JoinRound); + + for (i = 0; i < num; i++) { + XDrawString(display, win, gc, x, y + i * line_height, prompt[i], + p_len[i]); + } +#undef num +} + + +void +draw_graphics(int i, int j, int n) +{ + unsigned long color; + + draw_text(); + color = TouchCross; + + if (n == 2) { + cx[n] = width / 2; + cy[n] = height / 2; + } else { + cx[n] = (MARK_POINT[i] * width) / SCREEN_MAX; + cy[n] = (MARK_POINT[j] * height) / SCREEN_MAX; + } + draw_point(cx[n], cy[n], width / 200, width / 64, color); +} + +void +get_gc(Window win, GC * gc, XFontStruct * font_info) +{ + unsigned long valuemask = 0; /* ignore XGCvalues and use defaults */ + XGCValues values; + unsigned int line_width = 5; + int line_style = LineSolid; + int cap_style = CapRound; + int join_style = JoinRound; + + *gc = XCreateGC(display, win, valuemask, &values); + + XSetFont(display, *gc, font_info->fid); + + XSetLineAttributes(display, *gc, line_width, line_style, + cap_style, join_style); +} + + +int +get_color() +{ + int default_depth; + Colormap default_cmap; + XColor my_color; + int i; + + default_depth = DefaultDepth(display, screen); + default_cmap = DefaultColormap(display, screen); + + for (i = 0; i < N_Colors; i++) { + XParseColor(display, default_cmap, colors[i], &my_color); + XAllocColor(display, default_cmap, &my_color); + pixels[i] = my_color.pixel; + } + + return 0; +} + + +Cursor +create_empty_cursor() +{ + char nothing[] = {0}; + XColor nullcolor; + Pixmap src = XCreateBitmapFromData(display, root, nothing, 1, 1); + Pixmap msk = XCreateBitmapFromData(display, root, nothing, 1, 1); + Cursor mcyursor = XCreatePixmapCursor(display, src, msk, + &nullcolor, &nullcolor, 0, 0); + XFreePixmap(display, src); + XFreePixmap(display, msk); + + return mcyursor; +} + +int +main(int argc, char *argv[], char *env[]) +{ + char *display_name = NULL; + XSetWindowAttributes xswa; + int i = 0, orawmode; + double a, a1, a2, b, b1, b2, xerr, yerr; + struct wsmouse_calibcoords wmcoords; + extern char *__progname; + + /* Crosshair placement */ + int cpx[] = { 0, 0, 1, 1, 1 }; + int cpy[] = { 0, 1, 0, 0, 1 }; + + struct tsscale { + int ts_minx; + int ts_maxx; + int ts_miny; + int ts_maxy; + int ts_swapxy; + } ts; + + if (argc != 2) { + fprintf(stderr, "usage: %s <device>\n", __progname); + return 1; + } + + if ((evfd = open(argv[1], O_RDONLY)) == -1) + err(1, "open()"); + + /* connect to X server */ + if ((display = XOpenDisplay(display_name)) == NULL) { + fprintf(stderr, "%s: cannot connect to X server %s\n", + progname, XDisplayName(display_name)); + close(evfd); + exit(1); + } + screen = DefaultScreen(display); + root = RootWindow(display, screen); + + /* setup window attributes */ + xswa.override_redirect = True; + xswa.background_pixel = BlackPixel(display, screen); + xswa.event_mask = ExposureMask | KeyPressMask; + xswa.cursor = create_empty_cursor(); + + /* get screen size from display structure macro */ + width = DisplayWidth(display, screen); + height = DisplayHeight(display, screen); + + win = XCreateWindow(display, RootWindow(display, screen), + 0, 0, width, height, 0, + CopyFromParent, InputOutput, CopyFromParent, + CWOverrideRedirect | CWBackPixel | CWEventMask | + CWCursor, &xswa); + XMapWindow(display, win); + XGrabKeyboard(display, win, False, GrabModeAsync, GrabModeAsync, + CurrentTime); + XGrabServer(display); + load_font(&font_info); + get_gc(win, &gc, font_info); + get_color(); + + XSetWindowBackground(display, win, Background); + XClearWindow(display, win); + + if (ioctl(evfd, WSMOUSEIO_GCALIBCOORDS, &wmcoords) < 0) + err(1, "WSMOUSEIO_GCALIBCOORDS"); + + orawmode = wmcoords.samplelen; + wmcoords.samplelen = 1; + + if (ioctl(evfd, WSMOUSEIO_SCALIBCOORDS, &wmcoords) < 0) + err(1, "WSMOUSEIO_SCALIBCOORDS"); + +calib: + for (i = 0; i < 5; i++) { + draw_graphics(cpx[i], cpy[i], i); + XFlush(display); + get_events(i); + XClearWindow(display, win); + } + + /* get touch pad resolution to screen resolution ratio */ + a1 = (double) (x[4] - x[0]) / (double) (cx[4] - cx[0]); + a2 = (double) (x[3] - x[1]) / (double) (cx[3] - cx[1]); + /* get the minimum pad position on the X-axis */ + b1 = x[0] - a1 * cx[0]; + b2 = x[1] - a2 * cx[1]; + /* use the average ratio and average minimum position */ + a = (a1 + a2) / 2.0; + b = (b1 + b2) / 2.0; + xerr = a * width / 2 + b - x[2]; + if (fabs(xerr) > (a * width + b) * .01) { + fprintf(stderr, "X error (%.2f) too high, try again\n", + fabs(xerr)); + goto calib; + } + ts.ts_minx = (int) (b + 0.5); + ts.ts_maxx = (int) (a * width + b + 0.5); + + /* get touch pad resolution to screen resolution ratio */ + a1 = (double) (y[4] - y[0]) / (double) (cy[4] - cy[0]); + a2 = (double) (y[3] - y[1]) / (double) (cy[3] - cy[1]); + /* get the minimum pad position on the Y-axis */ + b1 = y[0] - a1 * cy[0]; + b2 = y[1] - a2 * cy[1]; + /* use the average ratio and average minimum position */ + a = (a1 + a2) / 2.0; + b = (b1 + b2) / 2.0; + yerr = a * height / 2 + b - y[2]; + if (fabs(yerr) > (a * height + b)) { + fprintf(stderr, "Y error (%.2f) too high, try again\n", + fabs(yerr)); + goto calib; + } + ts.ts_miny = (int) (b + 0.5) / 4; + ts.ts_maxy = (int) (a * height + b + 0.5); + + XFlush(display); + + wmcoords.samplelen = orawmode; + + if (ioctl(evfd, WSMOUSEIO_SCALIBCOORDS, &wmcoords) < 0) + err(1, "WSMOUSEIO_SCALIBCOORDS"); + + printf("mouse.scale=%d,%d,%d,%d,%d,%d,%d\n", + ts.ts_minx, ts.ts_maxx, ts.ts_miny, + ts.ts_maxy, wmcoords.swapxy, width, height); + + return 0; +} |