From: "John Willis" <John.Willis@Distant-earth.com>
To: <openembedded-devel@lists.openembedded.org>
Subject: Re: Angstrom: x11-gpe-image : Calibration of Screen ?
Date: Tue, 19 Jan 2010 14:12:56 -0000 [thread overview]
Message-ID: <023001ca9911$809fa3c0$81deeb40$@Willis@Distant-earth.com> (raw)
In-Reply-To: <4B55B26C.5040706@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1891 bytes --]
> No (really good) news,
> but I'm currently working on this.
> I tried to enable touchscreen calibration without success.
>
> I built Xorg version Xorg-1.7.3 configured with --enable-xcalibrate
> but I didn't get this extension in my Xorg, so when I try to call
> xtscal
> I always get this error:
> # xtscal
> XCALIBRATE extension missing: Success
>
> I debugged a bit the following packages: xtscal_0.6.3,
> libxcalibrate_git, libxext_1.1.1
>
> Temporary conclusion is that xtscal is no longer usable because the
> xcalibrate extension is only implemented for kdrive.
> Possible options are to use kdrive (hopefully not) or find another way
> to calibrate our touchscreen.
> I am working on a new way to calibrate the screen in the xorg (not
> kdrive) way.
>
> Any hints or help would be greatly appreciated.
The tail end of last year I found some un-credited code :-o on the internet (believed to be public domain/GPL depending on the header of the file but that does not thrill me to be honest).
I started to work on a fresh reimplementation of that code to return calibration information that could be fed into either xinput evtouch or xinput evdev (if you use a recent version of either driver that supports calibration for TS devices). I never finished the reimplementation work so a lot of the code is still the original un-credited code.
Not sure if this is of any help/interest but wrapped in a suitable GUI (or even scripts and Zenity) it could provide a sensible way to calibrate a touchscreen in X using X drivers that use the Linux event handling interface (rather than TSLib).
Note: I can't even recall if this code builds (I strongly suspect not) as I just grabbed it off my hard drive where it has been rotting for a while. It's really for reference only and fit for nothing more than the scrap heap at a guess.
Regards,
John
[-- Attachment #2: evdev_calibration.c --]
[-- Type: application/octet-stream, Size: 17251 bytes --]
/*
* Generic X based touchscreen calibration program using the
* Linux 2.6 input event handling interface.
*
* Outputs data in formats that can be used with both EVTOUCH
* and EVDEV drivers.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*
* Modified 2009/2010: John Willis
*/
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <stdio.h>
#include <signal.h>
#include <termios.h>
#include <stdlib.h>
#include <sys/time.h>
/*****************************************************************************/
/* Event interface */
struct input_event {
struct timeval time;
unsigned short type;
unsigned short code;
int value;
};
/* Event types */
#define EV_SYN 0x00
#define EV_KEY 0x01
#define EV_REL 0x02
#define EV_ABS 0x03
/* Codes */
#define ABS_X 0x00
#define ABS_Y 0x01
#define SYN_REPORT 0
#define BTN_LEFT 0x110
#define BTN_RIGHT 0x111
#define BTN_TOUCH 0x14a
/*****************************************************************************/
#define FONT_NAME "9x15"
#define IDLETIMEOUT 15
#define BLINKPERD 0.16
#define ROUND_SYMBOL
#define NumRect 5
#if 0
#define Background cCYAN
#define TouchedCross cYELLOW
#define BlinkCrossBG cRED
#define BlinkCrossFG cWHITE
#define nTouchedCross cBLUE
#define Cross cWHITE
#define DrawGrid cWHITE
#define DrawLine cYELLOW
#define DrawUp cRED
#define DrawDown cBLUE
#define TimerLine cRED
#define PromptText cBLUE
#else
#define Background cBLACK
#define TouchedCross cYELLOW
#define BlinkCrossBG cRED
#define BlinkCrossFG cWHITE
#define nTouchedCross cBLUE
#define Cross cYELLOW
#define DrawGrid cGREEN
#define DrawLine cYELLOW
#define DrawUp cRED
#define DrawDown cGREEN
#define TimerLine cRED
#define PromptText cWHITE
#endif
#define N_Colors 10
static char colors[N_Colors][10] =
{ "BLACK", "WHITE", "RED", "YELLOW", "GREEN", "BLUE", "#40C0C0" };
static unsigned long pixels[N_Colors];
#define cBLACK (pixels[0])
#define cWHITE (pixels[1])
#define cRED (pixels[2])
#define cYELLOW (pixels[3])
#define cGREEN (pixels[4])
#define cBLUE (pixels[5])
#define cCYAN (pixels[6])
/* Stupid wait loops */
#define SYS_1( zzz... ) do { \
while ( (zzz) != 1 ); \
} while (0)
#define SYS_0( zzz... ) do { \
while ( (zzz) != 0 ); \
} while (0)
/* Calibration points */
#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 job_done = 0;
int points_touched = 0;
char *deviceName;
int points_x[4], points_y[4];
Display *display;
int screen;
GC gc;
Window root;
Window win;
XFontStruct *font_info;
unsigned int width, height; /* window size */
char *progname;
int evfd;
/*****************************************************************************/
int get_events(int *px, int *py)
{
int ret;
int x = -1, y = -1;
int touch = 0, sync = 0;
struct input_event ev;
/* read till sync event */
while (!sync) {
ret = read(evfd, &ev, sizeof(ev));
if (ret == -1)
return -1;
switch (ev.type) {
case EV_ABS:
switch (ev.code) {
case ABS_X:
if (x == -1)
x = ev.value;
break;
case ABS_Y:
if (y == -1)
y = ev.value;
break;
default:
break;
}
break;
case EV_KEY:
switch (ev.code) {
case BTN_LEFT:
case BTN_TOUCH:
touch = 1;
default:
break;
}
break;
case EV_SYN:
if (ev.code == SYN_REPORT)
sync = 1;
break;
default:
break;
}
}
if (!touch || x == -1 || y == -1)
return -1;
*px = x;
*py = y;
return 0;
}
/*****************************************************************************/
void cleanup_exit()
{
SYS_1(XUnloadFont(display, font_info->fid));
XUngrabServer(display);
XUngrabKeyboard(display, CurrentTime);
SYS_1(XFreeGC(display, gc));
SYS_0(XCloseDisplay(display));
close(evfd);
exit(0);
}
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 point_blink(unsigned long color)
{
int i, j;
int cx, cy;
static int shift = 0;
if (points_touched != 4) {
int RectDist = width / 200;
i = points_touched / 2;
j = points_touched % 2;
cx = (MARK_POINT[j] * width) / SCREEN_MAX;
cy = (MARK_POINT[i] * height) / SCREEN_MAX;
XSetLineAttributes(display, gc, 1, LineSolid, CapRound, JoinRound);
for (i = 0; i < NumRect; i++) {
if ((i + shift) % NumRect == 0)
XSetForeground(display, gc, BlinkCrossBG);
else
XSetForeground(display, gc, BlinkCrossFG);
#ifdef ROUND_SYMBOL
XDrawArc(display, win, gc,
cx - i * RectDist, cy - i * RectDist,
i * (2 * RectDist), i * (2 * RectDist),
0, 359 * 64);
#else
XDrawRectangle(display, win, gc,
cx - i * RectDist, cy - i * RectDist,
i * (2 * RectDist), i * (2 * RectDist));
#endif
}
shift++;
}
}
void draw_message(char *msg)
{
char buf[300];
char *prompt[] = { buf };
#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;
strncpy(buf, msg, sizeof buf);
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 - line_height;
XSetForeground(display, gc, PromptText);
XSetLineAttributes(display, gc, 3, LineSolid, CapRound, JoinRound);
XClearArea(display, win, x - 8, y - 8 - p_height, p_maxwidth + 8 * 2,
num * line_height + 8 * 2, False);
XDrawRectangle(display, win, gc, x - 8, y - 8 - p_height,
p_maxwidth + 8 * 2, num * line_height + 8 * 2);
for (i = 0; i < num; i++) {
XDrawString(display, win, gc, x, y + i * line_height, prompt[i],
p_len[i]);
}
#undef num
}
void draw_text()
{
static char *prompt[] = {
" 4-Pt Calibration",
"Please touch the blinking symbol until beep or stop blinking",
" (ESC to Abort)",
};
#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);
XDrawRectangle(display, win, gc, x - 11, y - 8 - p_height,
p_maxwidth + 11 * 2, num * line_height + 8 * 2);
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, j;
unsigned cx, cy;
unsigned long color;
draw_text();
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
int num = 2 * i + j;
if (num == points_touched)
continue;
if (num > points_touched)
color = nTouchedCross;
else
color = TouchedCross;
cx = (MARK_POINT[j] * width) / SCREEN_MAX;
cy = (MARK_POINT[i] * height) / SCREEN_MAX;
draw_point(cx, cy, 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 mycursor = XCreatePixmapCursor(display, src, msk,
&nullcolor, &nullcolor, 0, 0);
XFreePixmap(display, src);
XFreePixmap(display, msk);
return mycursor;
}
void process_event()
{
XEvent event;
while (XCheckWindowEvent(display, win, -1, &event) == True) {
switch (event.type) {
case KeyPress:
{
KeySym keysym = XKeycodeToKeysym(display,
event.xkey.keycode, 0);
if (keysym == XK_Escape) {
puts("Aborted");
cleanup_exit();
}
}
break;
case Expose:
draw_graphics(win, gc, width, height);
break;
default:
break;
}
}
}
double idle_time = 0;
double tick = 0;
void set_timer(double interval /* in second */ )
{
struct itimerval timer;
long sec = interval;
long usec = (interval - sec) * 1.0e6;
timer.it_value.tv_sec = sec;
timer.it_value.tv_usec = usec;
timer.it_interval = timer.it_value;
setitimer(ITIMER_REAL, &timer, NULL);
tick = interval;
}
void update_timer(void)
{
int current = width * idle_time / IDLETIMEOUT;
XSetLineAttributes(display, gc, 2, LineSolid, CapRound, JoinRound);
XSetForeground(display, gc, Background);
XDrawLine(display, win, gc, 0, height - 1, current, height - 1);
XSetForeground(display, gc, TimerLine);
XDrawLine(display, win, gc, current, height - 1, width, height - 1);
}
int register_fasync(int fd, void (*handle) (int))
{
signal(SIGIO, handle);
fcntl(fd, F_SETOWN, getpid());
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | FASYNC);
return 0;
}
void sig_handler(int num)
{
char buf[100];
int i, rval, x, y;
static int is_busy = 0;
if (is_busy)
return;
is_busy = 1;
switch (num) {
case SIGALRM:
if (!job_done)
point_blink(BlinkCrossFG);
update_timer();
if (idle_time >= IDLETIMEOUT)
cleanup_exit();
idle_time += tick;
XFlush(display);
process_event();
break;
case SIGIO:
rval = get_events(&x, &y);
if (rval == -1)
break;
idle_time = 0;
points_x[points_touched] = x;
points_y[points_touched] = y;
points_touched++;
draw_graphics();
break;
default:
break;
}
/* do the math */
if (points_touched == 4 && !job_done) {
int x_low, y_low, x_hi, y_hi;
int x_min, y_min, x_max, y_max;
int x_seg, y_seg;
int x_inv = 0, y_inv = 0;
int temp;
#ifdef DEBUG
printf("Touch 0 at %d/%d\n", points_x[0], points_y[0]); /* l,l */
printf("Touch 1 at %d/%d\n", points_x[1], points_y[1]); /* l,h */
printf("Touch 2 at %d/%d\n", points_x[2], points_y[2]); /* h,l */
printf("Touch 3 at %d/%d\n", points_x[3], points_y[3]); /* h,h */
#endif
if((points_x[0] > points_x[1]) && (points_x[2] > points_x[3])) {
#ifdef DEBUG
printf("swap x\n");
#endif
temp = points_x[0]; points_x[0] = points_x[1]; points_x[1] = temp;
temp = points_x[2]; points_x[2] = points_x[3]; points_x[3] = temp;
}
if((points_y[0] > points_y[2]) && (points_y[1] > points_y[3])) {
#ifdef DEBUG
printf("swap y\n");
#endif
temp = points_y[0]; points_y[0] = points_y[2]; points_y[2] = temp;
temp = points_y[1]; points_y[1] = points_y[3]; points_y[3] = temp;
}
if((points_x[1] > points_x[2])&&(points_y[1] < points_y[2])) {
#ifdef DEBUG
printf("swap mid\n");
#endif
temp = points_x[1]; points_x[1] = points_x[2]; points_x[2] = temp;
temp = points_y[1]; points_y[1] = points_y[2]; points_y[2] = temp;
}
#ifdef DEBUG
printf("Touch 0 at %d/%d\n", points_x[0], points_y[0]); /* l,l */
printf("Touch 1 at %d/%d\n", points_x[1], points_y[1]); /* l,h */
printf("Touch 2 at %d/%d\n", points_x[2], points_y[2]); /* h,l */
printf("Touch 3 at %d/%d\n", points_x[3], points_y[3]); /* h,h */
#endif
/* get the averages */
x_low = (points_x[0] + points_x[1]) / 2;
y_low = (points_y[0] + points_y[2]) / 2;
x_hi = (points_x[2] + points_x[3]) / 2;
y_hi = (points_y[1] + points_y[3]) / 2;
/* see if one of the axes is inverted */
if (x_low > x_hi) {
int tmp = x_hi;
x_hi = x_low;
x_low = tmp;
x_inv = 1;
}
if (y_low > y_hi) {
int tmp = y_hi;
y_hi = y_low;
y_low = tmp;
y_inv = 1;
}
#if 0
printf("Touch at %d/%d/%d/%d\n", x_low,y_low, x_hi, y_hi);
#endif
/* calc the min and max values */
x_seg = (x_hi - x_low) / (SCREEN_DIVIDE - 2);
x_min = x_low - x_seg;
x_max = x_hi + x_seg;
y_seg = (y_hi - y_low) / (SCREEN_DIVIDE - 2);
y_min = y_low - y_seg;
y_max = y_hi + y_seg;
printf("Copy-Paste friendly, for EVTOUCH XF86 driver\n");
printf("- Version 0.61 >\n");
printf(" Option \"MinX\" \"%d\"\n", x_min);
printf(" Option \"MinY\" \"%d\"\n", y_min);
printf(" Option \"MaxX\" \"%d\"\n", x_max);
printf(" Option \"MaxY\" \"%d\"\n", y_max);
printf(" Option \"SwapX\" \"%d\"\n", x_inv);
printf(" Option \"SwapY\" \"%d\"\n", y_inv);
printf("\n");
printf("Copy-Paste friendly, for EVDEV XF86 driver\n");
printf("- Version 2.3.2 >\n");
printf(" Option \"Calibration\" \"%d\"%d\"%d\"%d\"\n", x_min, x_max, y_min, y_max);
printf(" Option \"SwapAxes\" \"%d\"\n", x_inv);
printf("\n");
draw_message(" Done... ");
XFlush(display);
job_done = 1;
idle_time = IDLETIMEOUT * 3 / 4;
update_timer();
}
is_busy = 0;
return;
}
int main(int argc, char *argv[], char *env[])
{
char *display_name = NULL;
XSetWindowAttributes xswa;
/* one arg: device name */
if (argc != 2) {
fprintf(stderr, "Usage %s <device>!\n", argv[0]);
return 1;
}
evfd = open(argv[1], O_RDONLY | O_NONBLOCK);
if (evfd == -1) {
fprintf(stderr, "Cannot open device file!\n");
return 1;
}
/* 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);
signal(SIGALRM, sig_handler);
set_timer(BLINKPERD);
register_fasync(evfd, sig_handler);
/* wait for signals */
while (1)
pause();
return 0;
}
next prev parent reply other threads:[~2010-01-19 14:24 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-01-19 0:01 Angstrom: x11-gpe-image : Calibration of Screen ? Ulf Samuelsson
2010-01-19 13:23 ` Marco Cavallini
2010-01-19 13:32 ` Phil Blundell
2010-01-19 13:48 ` Marco Cavallini
2010-01-19 13:52 ` Petr Štetiar
2010-01-19 18:38 ` [PATCH] xinput_calibrator: switch to autotools Petr Štetiar
2010-01-19 20:51 ` Rolf Leggewie
2010-01-19 20:59 ` Petr Štetiar
2010-01-19 21:06 ` Petr Štetiar
2010-01-19 14:12 ` John Willis [this message]
2010-01-19 14:25 ` Angstrom: x11-gpe-image : Calibration of Screen ? John Willis
2010-01-19 14:38 ` Marco Cavallini
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='023001ca9911$809fa3c0$81deeb40$@Willis@Distant-earth.com' \
--to=john.willis@distant-earth.com \
--cc=openembedded-devel@lists.openembedded.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox