/*****************************************************************************
*
* utouch-frame - Touch Frame Library
*
* Copyright (C) 2010 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
****************************************************************************/
#include
#include "frame-impl.h"
#include
#include
#include
int utouch_frame_is_supported_mtdev(const struct evemu_device *dev)
{
/* only support pure absolute devices at this time */
if (evemu_has_event(dev, EV_REL, REL_X) ||
evemu_has_event(dev, EV_REL, REL_Y))
return 0;
if (evemu_has_event(dev, EV_ABS, ABS_MT_POSITION_X) &&
evemu_has_event(dev, EV_ABS, ABS_MT_POSITION_Y))
return 1;
return evemu_has_event(dev, EV_ABS, ABS_X) &&
evemu_has_event(dev, EV_ABS, ABS_Y) &&
evemu_has_event(dev, EV_KEY, BTN_TOUCH) &&
evemu_has_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP);
}
int utouch_frame_init_mtdev(utouch_frame_handle fh,
const struct evemu_device *dev)
{
struct utouch_surface *s = fh->surface;
float tmp;
if (!utouch_frame_is_supported_mtdev(dev))
return -ENODEV;
#ifdef INPUT_PROP_POINTER
s->needs_pointer = evemu_has_prop(dev, INPUT_PROP_POINTER);
s->is_direct = evemu_has_prop(dev, INPUT_PROP_DIRECT);
s->is_buttonpad = evemu_has_prop(dev, INPUT_PROP_BUTTONPAD);
s->is_semi_mt = evemu_has_prop(dev, INPUT_PROP_SEMI_MT);
#endif
s->use_touch_major = evemu_has_event(dev, EV_ABS, ABS_MT_TOUCH_MAJOR);
s->use_touch_minor = evemu_has_event(dev, EV_ABS, ABS_MT_TOUCH_MINOR);
s->use_width_major = evemu_has_event(dev, EV_ABS, ABS_MT_WIDTH_MAJOR);
s->use_width_minor = evemu_has_event(dev, EV_ABS, ABS_MT_WIDTH_MINOR);
s->use_orientation = evemu_has_event(dev, EV_ABS, ABS_MT_ORIENTATION);
s->use_pressure = evemu_has_event(dev, EV_ABS, ABS_MT_PRESSURE);
#ifdef ABS_MT_DISTANCE
s->use_distance = evemu_has_event(dev, EV_ABS, ABS_MT_DISTANCE);
#endif
s->min_x = evemu_get_abs_minimum(dev, ABS_MT_POSITION_X);
s->min_y = evemu_get_abs_minimum(dev, ABS_MT_POSITION_Y);
s->max_x = evemu_get_abs_maximum(dev, ABS_MT_POSITION_X);
s->max_y = evemu_get_abs_maximum(dev, ABS_MT_POSITION_Y);
if (s->min_x == s->max_x) {
s->min_x = 0;
s->max_x = 1024;
}
if (s->min_y == s->max_y) {
s->min_y = 0;
s->max_y = 768;
}
s->max_pressure = evemu_get_abs_maximum(dev, ABS_MT_PRESSURE);
if (s->use_pressure && s->max_pressure == 0)
s->max_pressure = 256;
fh->max_orient = evemu_get_abs_maximum(dev, ABS_MT_ORIENTATION);
if (s->use_orientation && fh->max_orient == 0)
fh->max_orient = 1;
tmp = evemu_get_abs_resolution(dev, ABS_MT_POSITION_X);
if (tmp > 0)
s->phys_width = (s->max_x - s->min_x) / tmp;
else if (s->needs_pointer)
s->phys_width = 100;
else
s->phys_width = 250;
tmp = evemu_get_abs_resolution(dev, ABS_MT_POSITION_Y);
if (tmp > 0)
s->phys_height = (s->max_y - s->min_y) / tmp;
else if (s->needs_pointer)
s->phys_height = 65;
else
s->phys_height = 160;
tmp = evemu_get_abs_resolution(dev, ABS_MT_PRESSURE);
if (tmp > 0)
s->phys_pressure = s->max_pressure / tmp;
else
s->phys_pressure = 10;
return 0;
}
static float touch_angle(utouch_frame_handle fh, int orient)
{
return orient / fh->max_orient * M_PI_2;
}
static int handle_abs_event(utouch_frame_handle fh,
const struct input_event *ev)
{
struct utouch_contact *t = utouch_frame_get_current_slot(fh);
switch (ev->code) {
case ABS_MT_SLOT:
utouch_frame_set_current_slot(fh, ev->value);
return 1;
case ABS_MT_POSITION_X:
t->x = ev->value;
return 1;
case ABS_MT_POSITION_Y:
t->y = ev->value;
return 1;
case ABS_MT_TOUCH_MAJOR:
t->touch_major = ev->value;
return 1;
case ABS_MT_TOUCH_MINOR:
t->touch_minor = ev->value;
return 1;
case ABS_MT_WIDTH_MAJOR:
t->width_major = ev->value;
return 1;
case ABS_MT_WIDTH_MINOR:
t->width_minor = ev->value;
return 1;
case ABS_MT_ORIENTATION:
t->orientation = touch_angle(fh, ev->value);
return 1;
case ABS_MT_PRESSURE:
t->pressure = ev->value;
return 1;
#ifdef ABS_MT_DISTANCE
case ABS_MT_DISTANCE:
t->distance = ev->value;
return 1;
#endif
case ABS_MT_TOOL_TYPE:
t->tool_type = ev->value;
return 1;
case ABS_MT_TRACKING_ID:
t->id = ev->value;
return 1;
default:
return 0;
}
}
static utouch_frame_time_t get_evtime_ms(const struct input_event *syn)
{
static const utouch_frame_time_t ms = 1000;
return syn->time.tv_usec / ms + syn->time.tv_sec * ms;
}
const struct utouch_frame *
utouch_frame_pump_mtdev(utouch_frame_handle fh, const struct input_event *ev)
{
const struct utouch_frame *f = 0;
if (ev->type == EV_SYN && ev->code == SYN_REPORT)
f = utouch_frame_sync(fh, get_evtime_ms(ev));
else if (ev->type == EV_ABS)
handle_abs_event(fh, ev);
return f;
}