Blob Blame Raw

#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