#include "touch.h"
#ifndef DIRECT_TOUCH
int touchInit(Touch *touch, App *app, const char *dev) { return 0; }
void touchDeinit(Touch *touch) { }
int touchGet(Touch *touch, int *x, int *y, int *p) { return 0; }
#else // DIRECT_TOUCH
#include <math.h>
#include <mtdev.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
static int touch_field_codes[TOUCH_FIELDS] =
{ ABS_MT_POSITION_X, ABS_MT_POSITION_Y, ABS_MT_PRESSURE };
int touchInit(Touch *touch, App *app, const char *dev) {
if (!app || !dev) return 0;
LOGDBG("touch: init");
touch->fd = open(dev, O_RDONLY | O_NONBLOCK);
if (touch->fd < 0)
return LOGERR("touch: init: cannot open file: %s", dev);
int ret = mtdev_open(&touch->dev, touch->fd);
if (ret) {
close(touch->fd);
touch->fd = 0;
return LOGERR("touch: init: cannot open device: %s", dev);
}
for(int i = 0; i < TOUCH_FIELDS; ++i) {
int *f = touch->fields[i];
f[0] = mtdev_get_abs_minimum(&touch->dev, touch_field_codes[i]);
f[1] = mtdev_get_abs_maximum(&touch->dev, touch_field_codes[i]);
if (f[0] >= f[1]) {
mtdev_close(&touch->dev);
close(touch->fd);
return LOGERR("touch: init: cannot get field bounds for device: %s (field %d:%d)", dev, i, touch_field_codes[i]);
}
f[2] = 0;
if (f[2] > f[1]) f[2] = f[1];
if (f[2] < f[0]) f[2] = f[0];
}
touch->app = app;
touch->slot = 0;
touch->id = -1;
touch->pressed = 0;
return 1;
}
void touchDeinit(Touch *touch) {
if (touch->app) {
mtdev_close(&touch->dev);
close(touch->fd);
}
touch->app = NULL;
}
int touchGet(Touch *touch, int *x, int *y, int *p) {
if (!touch->app) return 0;
struct input_event ev;
while(mtdev_get(&touch->dev, touch->fd, &ev, 1) > 0) {
if (ev.type == EV_SYN) {
// return event
double f[TOUCH_FIELDS];
for(int i = 0; i < TOUCH_FIELDS; ++i) {
int *tf = touch->fields[i];
f[i] = (tf[2] - tf[0])/(double)(tf[1] - tf[0]);
}
double fx = f[0], fy = f[1], fp = f[2];
App *app = touch->app;
if (app->sr & RR_Rotate_90)
{ double v = fx; fx = 1-fy; fy = v; }
if (app->sr & RR_Rotate_180)
{ fx = 1-fx; fy = 1-fy; }
if (app->sr & RR_Rotate_270)
{ double v = fx; fx = fy; fy = 1-v; }
if (app->sr & RR_Reflect_X)
fx = 1-fx;
if (app->sr & RR_Reflect_Y)
fy = 1-fy;
*x = (int)round(fx*app->sw - app->x);
*y = (int)round(fy*app->sh - app->y);
*p = touch->id >= 0 && fp > (touch->pressed ? TOUCH_THRESHOLD0 : TOUCH_THRESHOLD1);
touch->pressed = *p;
return 1;
}
if (ev.type != EV_ABS)
continue; // ignore non ABS events
if (ev.code == ABS_MT_SLOT)
{ touch->slot = ev.value; continue; } // switch slot
if (touch->slot != 0)
continue; // handle only first slot
if (ev.code == ABS_MT_TRACKING_ID)
{ touch->id = ev.value; continue; } // set track id
for(int i = 0; i < TOUCH_FIELDS; ++i)
if (ev.code == touch_field_codes[i])
touch->fields[i][2] = ev.value;
}
return 0;
}
#endif // DIRECT_TOUCH