#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <X11/keysym.h>
#include <X11/XF86keysym.h>
#include <X11/extensions/XIproto.h>
#include <string.h>
#include "evdev.h"
#include <xf86.h>
#include <xf86Module.h>
#include <mipointer.h>
#include <xf86_OSproc.h>
#undef DEBUG
static char *rel_axis_names[] = {
"X",
"Y",
"Z",
"RX",
"RY",
"RZ",
"HWHEEL",
"DIAL",
"WHEEL",
"MISC",
"10",
"11",
"12",
"13",
"14",
"15",
NULL
};
static char *abs_axis_names[] = {
"X",
"Y",
"Z",
"RX",
"RY",
"RZ",
"THROTTLE",
"RUDDER",
"WHEEL",
"GAS",
"BRAKE",
"11",
"12",
"13",
"14",
"15",
"HAT0X",
"HAT0Y",
"HAT1X",
"HAT1Y",
"HAT2X",
"HAT2Y",
"HAT3X",
"HAT3Y",
"PRESSURE",
"TILT_X",
"TILT_Y",
"TOOL_WIDTH",
"VOLUME",
"29",
"30",
"31",
"32",
"33",
"34",
"35",
"36",
"37",
"38",
"39",
"MISC",
"41",
"42",
"43",
"44",
"45",
"46",
"47",
"48",
"49",
"50",
"51",
"52",
"53",
"54",
"55",
"56",
"57",
"58",
"59",
"60",
"61",
"62",
NULL
};
static void EvdevAxesTouchCallback (InputInfoPtr pInfo, int button, int value);
void
EvdevAxesMapAxis (InputInfoPtr pInfo, int value, int mode, void *map_data)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
evdevAxesPtr axes = state->axes;
long map = (long) map_data;
if (map >= AXES_MAX || !axes || !(axes->v_flags[map] & (EV_AXES_V_M_ABS | EV_AXES_V_M_REL)))
return;
axes->v[map] = value;
if (mode == 0) {
axes->v_flags[map] &= ~EV_AXES_V_M_ABS;
axes->v_flags[map] |= EV_AXES_V_M_REL;
} else if (mode == 1) {
axes->v_flags[map] &= ~EV_AXES_V_M_REL;
axes->v_flags[map] |= EV_AXES_V_M_ABS;
}
axes->v_flags[map] |= EV_AXES_V_UPDATED;
axes->flags |= EV_AXES_UPDATED;
}
#if 0
typedef struct {
int button_plus;
int button_minus;
int step;
int count;
} AxisMapButton_t;
void
EvdevAxesMapButton (InputInfoPtr pInfo, int value, void *map_data)
{
AxisMapButton_t *map = map_data;
int i;
// FIXME: Scream loudly, this is bad.
if (!map)
return;
map->count += value;
i = map->count / map->step;
if (i) {
map->count -= i * map->step;
if (i > 0)
EvdevBtnPostFakeClicks (pInfo, map->button_plus, i);
else
EvdevBtnPostFakeClicks (pInfo, map->button_minus, -i);
}
}
#endif
static Bool
EvdevParseRelOptions (InputInfoPtr pInfo, const char *name, evdev_option_token_t *option, int *flags)
{
if (!option)
return 0;
for (; option; option = option->next) {
if (option->is_chain)
continue;
if (!strcasecmp (option->u.str, "invert"))
*flags |= EV_REL_V_INVERT;
else
xf86Msg(X_ERROR, "%s: %s unknown relative option '%s'.\n", pInfo->name, name, option->u.str);
}
*flags |= EV_REL_V_PRESENT;
return 1;
}
static Bool
EvdevParseAbsOptions (InputInfoPtr pInfo, const char *name, evdev_option_token_t *option, int *flags)
{
if (!option)
return 0;
for (; option; option = option->next) {
if (option->is_chain)
continue;
if (!strcasecmp (option->u.str, "invert"))
*flags |= EV_ABS_V_INVERT;
else if (!strcasecmp (option->u.str, "use_touch"))
*flags |= EV_ABS_V_USE_TOUCH;
else if (!strcasecmp (option->u.str, "mode_auto"))
*flags |= EV_ABS_V_M_AUTO;
else if (!strcasecmp (option->u.str, "mode_rel"))
*flags |= EV_ABS_V_M_REL;
else
xf86Msg(X_ERROR, "%s: %s unknown absolute option '%s'.\n", pInfo->name, name, option->u.str);
}
*flags |= EV_ABS_V_PRESENT;
return 1;
}
Bool
EvdevParseMapToRelAxis (InputInfoPtr pInfo,
const char *name,
evdev_option_token_t *option,
void **map_data, evdev_map_func_f *map_func)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
evdevAxesPtr axes = state->axes;
long i;
if (!option || option->is_chain)
return 0;
errno = 0;
i = strtol (option->u.str, NULL, 0);
if (errno) {
for (i = 0; rel_axis_names[i]; i++) {
if (!strcmp (option->u.str, rel_axis_names[i]))
break;
}
if (!rel_axis_names[i])
return 0;
}
if ((i < 0) || (i > AXES_MAX))
return 0;
if (axes->v_flags[i] & EV_AXES_V_PRESENT)
return 0;
axes->v_flags[i] = EV_AXES_V_M_REL | EV_AXES_V_PRESENT;
*map_data = (void *) i;
*map_func = EvdevAxesMapAxis;
return 1;
}
Bool
EvdevParseMapToAbsAxis (InputInfoPtr pInfo,
const char *name,
evdev_option_token_t *option,
void **map_data, evdev_map_func_f *map_func)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
evdevAxesPtr axes = state->axes;
long i;
if (!option || option->is_chain) {
xf86Msg (X_ERROR, "%s: %s: No option/option is chain.\n", pInfo->name, name);
return 0;
}
errno = 0;
i = strtol (option->u.str, NULL, 0);
if (errno) {
for (i = 0; abs_axis_names[i]; i++) {
if (!strcmp (option->u.str, abs_axis_names[i]))
break;
}
if (!abs_axis_names[i]) {
xf86Msg (X_ERROR, "%s: %s: No axis named '%s'.\n", pInfo->name, name, option->u.str);
return 0;
}
}
if ((i < 0) || (i > AXES_MAX)) {
xf86Msg (X_ERROR, "%s: %s: Axis %ld out of range.\n", pInfo->name, name, i);
return 0;
}
if (axes->v_flags[i] & EV_AXES_V_PRESENT) {
xf86Msg (X_ERROR, "%s: %s: Axis %ld already claimed.\n", pInfo->name, name, i);
return 0;
}
option = option->next;
if (!option || option->is_chain) {
xf86Msg (X_ERROR, "%s: %s: No min.\n", pInfo->name, name);
return 0;
}
errno = 0;
axes->v_min[i] = strtol (option->u.str, NULL, 0);
if (errno) {
xf86Msg (X_ERROR, "%s: %s: Unable to parse '%s' as min. (%s)\n", pInfo->name, name, option->u.str, strerror(errno));
return 0;
}
option = option->next;
if (!option || option->is_chain) {
xf86Msg (X_ERROR, "%s: %s: No max.\n", pInfo->name, name);
return 0;
}
errno = 0;
axes->v_max[i] = strtol (option->u.str, NULL, 0);
if (errno) {
xf86Msg (X_ERROR, "%s: %s: Unable to parse '%s' as max. (%s)\n", pInfo->name, name, option->u.str, strerror(errno));
return 0;
}
axes->v_flags[i] = EV_AXES_V_M_ABS | EV_AXES_V_PRESENT;
*map_data = (void *) i;
*map_func = EvdevAxesMapAxis;
return 1;
}
static Bool
EvdevConvert(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2,
int v3, int v4, int v5, int *x, int *y)
{
if (first == 0) {
*x = v0;
*y = v1;
return TRUE;
} else
return FALSE;
}
static void
EvdevAxesDoRotation (InputInfoPtr pInfo)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
evdevAxesPtr axes = state->axes;
DeviceIntPtr dev = pInfo->dev;
AbsoluteClassRec *dabs = dev->absolute;
if (dabs->rotation != axes->rotation || (axes->rot_cos == axes->rot_sin)) {
axes->rotation = dabs->rotation % 360;
axes->rot_cos = cos ( ((float) axes->rotation) * (M_PI/180));
axes->rot_sin = sin ( ((float) axes->rotation) * (M_PI/180));
}
if (axes->rotation) {
float x = axes->v[0], y = axes->v[1];
axes->v[0] = (x * axes->rot_cos) - (y * axes->rot_sin);
axes->v[1] = (y * axes->rot_cos) + (x * axes->rot_sin);
axes->v_flags[0] |= EV_AXES_V_UPDATED;
axes->v_flags[1] |= EV_AXES_V_UPDATED;
#if DEBUG
xf86Msg(X_ERROR, "%s %d (%s): rotation=%d, cos=%f, sin=%f, x=%f, y=%f, v[0]=%d, v[1]=%d\n", __FILE__, __LINE__, __FUNCTION__,
axes->rotation, axes->rot_cos, axes->rot_sin, x, y, axes->v[0], axes->v[1]);
#endif
}
}
_X_EXPORT int
EvdevScaleAxis(int Cx,
int Sxlow,
int Sxhigh,
int Rxlow,
int Rxhigh)
{
int X;
int dSx = Sxhigh - Sxlow;
int dRx = Rxhigh - Rxlow;
if (Cx < 0)
Cx = Rxhigh + Cx;
dSx = Sxhigh - Sxlow;
if (dRx) {
X = ((dSx * (Cx - Rxlow)) / dRx) + Sxlow;
}
else {
X = 0;
ErrorF ("Divide by Zero in evdevScaleAxis");
}
if (X < Sxlow)
X = Sxlow;
if (X > Sxhigh)
X = Sxhigh;
return (X);
}
void
EvdevAxesSynRep (InputInfoPtr pInfo)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
evdevAxesPtr axes = state->axes;
DeviceIntPtr dev = pInfo->dev;
AbsoluteClassRec *dabs = dev->absolute;
int i, start, run, mode;
if (!axes || !(axes->flags & EV_AXES_UPDATED))
return;
start = 0;
mode = 0;
run = 0;
if (axes->axes >= 2 && dabs) {
if ((axes->v_flags[0] & EV_AXES_V_M_ABS) &&
(axes->v_flags[1] & EV_AXES_V_M_ABS) &&
((axes->v_flags[0] & EV_AXES_V_UPDATED) ||
(axes->v_flags[1] & EV_AXES_V_UPDATED))
) {
int width, height, min_x, max_x, min_y, max_y;
if (axes->v_flags[0] & EV_AXES_V_UPDATED) axes->x = axes->v[0];
else axes->v[0] = axes->x;
if (axes->v_flags[1] & EV_AXES_V_UPDATED) axes->y = axes->v[1];
else axes->v[1] = axes->y;
if (dabs->width > 0)
width = dabs->width;
else
width = screenInfo.screens[dabs->screen]->width;
if (dabs->height > 0)
height = dabs->height;
else
height = screenInfo.screens[dabs->screen]->height;
if (dabs->flip_x)
axes->v[0] = dabs->max_x - axes->v[0];
if (dabs->flip_y)
axes->v[1] = dabs->max_y - axes->v[1];
if ( (axes->rotation >= 45 && axes->rotation < 135) ||
(axes->rotation >= 225 && axes->rotation < 315)) {
min_x = dabs->min_y;
max_x = dabs->max_y;
min_y = dabs->min_x;
max_y = dabs->max_x;
} else {
min_x = dabs->min_x;
max_x = dabs->max_x;
min_y = dabs->min_y;
max_y = dabs->max_y;
}
EvdevAxesDoRotation (pInfo);
axes->v[0] = EvdevScaleAxis (axes->v[0], 0, width, min_x, max_x);
axes->v[1] = EvdevScaleAxis (axes->v[1], 0, height, min_y, max_y);
axes->v[0] += dabs->offset_x;
axes->v[1] += dabs->offset_y;
xf86XInputSetScreen (pInfo, dabs->screen, axes->v[0], axes->v[1]);
} else if ((axes->v_flags[0] & EV_AXES_V_M_REL) &&
(axes->v_flags[1] & EV_AXES_V_M_REL) &&
((axes->v_flags[0] & EV_AXES_V_UPDATED) ||
(axes->v_flags[1] & EV_AXES_V_UPDATED))
) {
if (axes->v_flags[0] & EV_AXES_V_UPDATED) axes->x = axes->v[0];
else axes->v[0] = axes->x;
if (axes->v_flags[1] & EV_AXES_V_UPDATED) axes->y = axes->v[1];
else axes->v[1] = axes->y;
if (dabs->flip_x)
axes->v[0] = -axes->v[0];
if (dabs->flip_y)
axes->v[1] = -axes->v[1];
EvdevAxesDoRotation (pInfo);
}
}
#if DEBUG
xf86Msg(X_ERROR, "%s %d (%s): v[0]=%d%s%s, v[1]=%d%s%s, v[2]=%d%s%s\n", __FILE__, __LINE__, __FUNCTION__,
axes->v[0],
axes->v_flags[0] & EV_AXES_V_M_ABS ? "!" : "",
axes->v_flags[0] & EV_AXES_V_UPDATED ? "*" : "",
axes->v[1],
axes->v_flags[1] & EV_AXES_V_M_ABS ? "!" : "",
axes->v_flags[1] & EV_AXES_V_UPDATED ? "*" : "",
axes->v[2],
axes->v_flags[2] & EV_AXES_V_M_ABS ? "!" : "",
axes->v_flags[2] & EV_AXES_V_UPDATED ? "*" : "");
#endif
for (i = 0; i < axes->axes; i++) {
if (axes->v_flags[i] & EV_AXES_V_UPDATED) {
if (run) {
if (mode != (axes->v_flags[i] & EV_AXES_V_M_MASK)) {
mode = (mode == EV_AXES_V_M_ABS);
#if DEBUG
xf86Msg(X_ERROR, "%s %d (%s): mode=%d, start=%d, i - start=%d\n", __FILE__, __LINE__, __FUNCTION__,
mode, start, i - start);
#endif
xf86PostMotionEventP (pInfo->dev, mode, start, i - start, axes->v + start);
start = i;
mode = axes->v_flags[i] & EV_AXES_V_M_MASK;
}
} else {
start = i;
mode = axes->v_flags[i] & EV_AXES_V_M_MASK;
}
run = 1;
axes->v_flags[i] &= ~EV_AXES_V_UPDATED;
} else if (run) {
mode = (mode == EV_AXES_V_M_ABS);
xf86PostMotionEventP (pInfo->dev, mode, start, i - start, axes->v + start);
run = 0;
}
}
if (run) {
mode = (mode == EV_AXES_V_M_ABS);
xf86PostMotionEventP (pInfo->dev, mode, start, i - start, axes->v + start);
}
}
void
EvdevAxesSynCfg (InputInfoPtr pInfo)
{
}
void
EvdevAxesAbsProcess (InputInfoPtr pInfo, struct input_event *ev)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
evdevAbsRec *abs = state->abs;
int value, v_flags, is_rel;
if (ev->code >= ABS_MAX || !abs->v_map[ev->code])
return;
value = ev->value;
v_flags = abs->v_flags[ev->code];
if ((v_flags & EV_ABS_V_USE_TOUCH) && !(state->abs->flags & EV_ABS_TOUCH))
return;
if (v_flags & EV_ABS_V_INVERT)
value = state->abs->v_max[ev->code] - value;
if (v_flags & EV_ABS_V_M_REL)
is_rel = 1;
else if ((v_flags & EV_ABS_V_M_AUTO) && state->mode == Relative)
is_rel = 1;
else
is_rel = 0;
if (is_rel) {
if ((v_flags & EV_ABS_V_RESET) && value != abs->v[ev->code]) {
abs->v_flags[ev->code] &= ~EV_ABS_V_RESET;
} else
abs->v_map[ev->code](pInfo, value - abs->v[ev->code], 0, abs->v_map_data[ev->code]);
abs->v[ev->code] = value;
} else
abs->v_map[ev->code](pInfo, value, 1, abs->v_map_data[ev->code]);
}
void
EvdevAxesRelProcess (InputInfoPtr pInfo, struct input_event *ev)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
evdevRelRec *rel = state->rel;
int value, v_flags;
if (ev->code >= REL_MAX || !rel->v_map[ev->code])
return;
value = ev->value;
v_flags = rel->v_flags[ev->code];
if (v_flags & EV_REL_V_INVERT)
value = -value;
rel->v_map[ev->code](pInfo, value, 0, rel->v_map_data[ev->code]);
}
int
EvdevAxesOn (DeviceIntPtr device)
{
return Success;
}
int
EvdevAxesOff (DeviceIntPtr device)
{
return Success;
}
static int
EvdevAxisAbsNew(InputInfoPtr pInfo)
{
evdevDeviceRec *pEvdev = pInfo->private;
evdevStateRec *state = &pEvdev->state;
evdevAbsRec *abs;
struct input_absinfo absinfo;
char option[128], value[128];
const char *s;
int i, j, k, real_axes;
evdev_option_token_t *tokens;
real_axes = 0;
for (i = 0; i < ABS_MAX; i++)
if (test_bit (i, pEvdev->bits.abs))
real_axes++;
if (!real_axes)
return !Success;
state->abs = abs = Xcalloc (sizeof (evdevAbsRec));
xf86Msg(X_INFO, "%s: Found %d absolute axes.\n", pInfo->name, real_axes);
xf86Msg(X_INFO, "%s: Configuring as pointer.\n", pInfo->name);
pInfo->flags |= XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS |
XI86_CONFIGURED;
pInfo->type_name = XI_MOUSE;
pInfo->conversion_proc = EvdevConvert;
for (i = 0, j = 0; i < ABS_MAX; i++) {
if (!test_bit (i, pEvdev->bits.abs))
continue;
if (ioctl (pInfo->fd, EVIOCGABS(i), &absinfo) < 0) {
xf86Msg(X_ERROR, "ioctl EVIOCGABS failed: %s\n", strerror(errno));
return !Success;
}
snprintf(option, sizeof(option), "Abs%sMapTo", abs_axis_names[i]);
snprintf(value, sizeof(value), "AbsAxis %d %d %d", j, absinfo.minimum, absinfo.maximum);
s = xf86SetStrOption(pInfo->options, option, value);
tokens = EvdevTokenize (s, " =", NULL);
if (!tokens->is_chain && tokens->next) {
for (k = 0; evdev_map_parsers[k].name; k++) {
if (!strcasecmp (tokens->u.str, evdev_map_parsers[k].name)) {
if (!evdev_map_parsers[k].func (pInfo, option, tokens->next, &abs->v_map_data[i], &abs->v_map[i]))
xf86Msg (X_ERROR, "%s: Unable to parse '%s' as a map specifier (%s).\n", pInfo->name, s, evdev_map_parsers[k].name);
break;
}
}
if (!evdev_map_parsers[k].name)
xf86Msg (X_ERROR, "%s: Unable to find parser for '%s' as a map specifier.\n", pInfo->name, s);
}
EvdevFreeTokens (tokens);
snprintf(option, sizeof(option), "Abs%sOptions", abs_axis_names[i]);
if (i == ABS_X || i == ABS_Y)
s = xf86SetStrOption(pInfo->options, option, "use_touch mode_auto");
else
s = xf86SetStrOption(pInfo->options, option, "");
if (s[0]) {
tokens = EvdevTokenize (s, " =", NULL);
if (!EvdevParseAbsOptions (pInfo, option, tokens, &abs->v_flags[i]))
xf86Msg (X_ERROR, "%s: Unable to parse '%s' as absolute options.\n", pInfo->name, s);
EvdevFreeTokens (tokens);
}
abs->v_flags[i] |= EV_ABS_V_PRESENT;
j++;
}
state->abs->axes = real_axes;
return Success;
}
static int
EvdevAxisAbsNew1(InputInfoPtr pInfo)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
char *s;
if (!state->abs)
return !Success;
xf86Msg(X_CONFIG, "%s: Configuring %d absolute axes.\n", pInfo->name,
state->abs->axes);
{
int btn;
s = xf86SetStrOption(pInfo->options, "AbsoluteTouch", "DIGI_Touch");
btn = EvdevBtnFind (pInfo, s);
if (btn != -1) {
if (EvdevBtnExists (pInfo, btn)) {
state->abs->flags |= EV_ABS_USE_TOUCH;
xf86Msg(X_ERROR, "%s: Button: %d.\n", pInfo->name, btn);
xf86Msg(X_ERROR, "%s: state->btn: %p.\n", pInfo->name, state->btn);
state->btn->callback[btn] = &EvdevAxesTouchCallback;
} else {
xf86Msg(X_ERROR, "%s: AbsoluteTouch: '%s' does not exist.\n", pInfo->name, s);
}
} else {
xf86Msg(X_ERROR, "%s: AbsoluteTouch: '%s' is not a valid button name.\n", pInfo->name, s);
}
}
s = xf86SetStrOption(pInfo->options, "Mode", "Absolute");
if (!strcasecmp(s, "Absolute")) {
state->mode = Absolute;
xf86Msg(X_CONFIG, "%s: Configuring in %s mode.\n", pInfo->name, s);
} else if (!strcasecmp(s, "Relative")) {
state->mode = Relative;
xf86Msg(X_CONFIG, "%s: Configuring in %s mode.\n", pInfo->name, s);
} else {
state->mode = Absolute;
xf86Msg(X_CONFIG, "%s: Unknown Mode: %s.\n", pInfo->name, s);
}
return Success;
}
static int
EvdevAxisRelNew(InputInfoPtr pInfo)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
evdevRelPtr rel = state->rel;
char *s, option[128], value[128];
int i, j, k, real_axes;
evdev_option_token_t *tokens;
real_axes = 0;
for (i = 0; i < REL_MAX; i++)
if (test_bit (i, pEvdev->bits.rel))
real_axes++;
if (!real_axes && (!state->abs || state->abs->axes < 2))
return !Success;
state->rel = Xcalloc (sizeof (evdevRelRec));
xf86Msg(X_INFO, "%s: Found %d relative axes.\n", pInfo->name,
real_axes);
xf86Msg(X_INFO, "%s: Configuring as pointer.\n", pInfo->name);
pInfo->flags |= XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS |
XI86_CONFIGURED;
pInfo->type_name = XI_MOUSE;
pInfo->conversion_proc = EvdevConvert;
for (i = 0, j = 0; i < REL_MAX; i++) {
if (!test_bit (i, pEvdev->bits.rel))
continue;
snprintf(option, sizeof(option), "Rel%sMapTo", rel_axis_names[i]);
if (i == REL_WHEEL || i == REL_Z)
snprintf(value, sizeof(value), "Buttons 4 5 1");
else if (i == REL_HWHEEL)
snprintf(value, sizeof(value), "Buttons 6 7 1");
else
snprintf(value, sizeof(value), "RelAxis %d", j);
s = xf86SetStrOption(pInfo->options, option, value);
tokens = EvdevTokenize (s, " =", NULL);
if (!tokens->is_chain && tokens->next) {
for (k = 0; evdev_map_parsers[k].name; k++) {
if (!strcasecmp (tokens->u.str, evdev_map_parsers[k].name)) {
if (!evdev_map_parsers[k].func (pInfo, option, tokens->next, &rel->v_map_data[i], &rel->v_map[i]))
xf86Msg (X_ERROR, "%s: Unable to parse '%s' as a map specifier.\n", pInfo->name, s);
break;
}
}
if (!evdev_map_parsers[k].name)
xf86Msg (X_ERROR, "%s: Unable to find parser for '%s' as a map specifier.\n", pInfo->name, s);
}
EvdevFreeTokens (tokens);
snprintf(option, sizeof(option), "Rel%sOptions", rel_axis_names[i]);
s = xf86SetStrOption(pInfo->options, option, "");
if (s[0]) {
tokens = EvdevTokenize (s, " =", NULL);
if (!EvdevParseRelOptions (pInfo, option, tokens, &rel->v_flags[i]))
xf86Msg (X_ERROR, "%s: Unable to parse '%s' as relative options.\n", pInfo->name, s);
EvdevFreeTokens (tokens);
}
rel->v_flags[i] |= EV_REL_V_PRESENT;
j++;
}
return Success;
}
int
EvdevAxesNew0 (InputInfoPtr pInfo)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
int ret = Success;
state->axes = Xcalloc (sizeof (evdevAxesRec));
if (EvdevAxisAbsNew(pInfo) != Success)
ret = !Success;
if (EvdevAxisRelNew(pInfo) != Success)
ret = !Success;
if (!state->abs && !state->rel) {
Xfree (state->axes);
state->axes = NULL;
}
return ret;
}
int
EvdevAxesNew1 (InputInfoPtr pInfo)
{
evdevDeviceRec *pEvdev = pInfo->private;
evdevStateRec *state = &pEvdev->state;
evdevAxesRec *axes = state->axes;
int i, ret = Success;
if (!state->axes)
return ret;
for (i = 0; i < AXES_MAX; i++)
if (axes->v_flags[i] & EV_AXES_V_PRESENT)
axes->axes = i + 1;
if (EvdevAxisAbsNew1(pInfo) != Success)
ret = !Success;
if (!state->abs && !state->rel) {
Xfree (state->axes);
state->axes = NULL;
}
return ret;
}
static void
EvdevPtrCtrlProc(DeviceIntPtr device, PtrCtrl *ctrl)
{
}
int
EvdevAxesInit (DeviceIntPtr device)
{
InputInfoPtr pInfo = device->public.devicePrivate;
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
evdevAxesRec *axes = state->axes;
AbsoluteClassRec *dev_abs;
int i;
if (!axes || !axes->axes)
return Success;
xf86Msg(X_CONFIG, "%s: %d valuators.\n", pInfo->name,
axes->axes);
if (!InitValuatorClassDeviceStruct(device, axes->axes,
GetMotionHistory,
GetMotionHistorySize(),
0))
return !Success;
if ((axes->v_flags[0] & EV_AXES_V_PRESENT) &&
(axes->v_flags[1] & EV_AXES_V_PRESENT) &&
InitAbsoluteClassDeviceStruct (device)) {
dev_abs = device->absolute;
if (axes->v_min[0] != axes->v_max[1] && axes->v_min[1] != axes->v_max[1]) {
device->absolute->min_x = axes->v_min[0];
device->absolute->max_x = axes->v_max[0];
device->absolute->min_y = axes->v_min[1];
device->absolute->max_y = axes->v_max[1];
}
}
for (i = 0; i < axes->axes; i++) {
xf86InitValuatorAxisStruct(device, i, -1, -1, 1, 1, 1);
xf86InitValuatorDefaults(device, i);
}
if (!InitPtrFeedbackClassDeviceStruct(device, EvdevPtrCtrlProc))
return !Success;
return Success;
}
static void
EvdevAxesTouchCallback (InputInfoPtr pInfo, int button, int value)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
int i;
#if DEBUG
xf86Msg(X_INFO, "%s: Touch callback; %d.\n", pInfo->name, value);
#endif
if (state->abs->flags & EV_ABS_USE_TOUCH) {
if (value) {
state->abs->flags |= EV_ABS_TOUCH;
for (i = 0; i < ABS_MAX; i++)
if (state->abs->v_flags[i] & EV_ABS_V_USE_TOUCH)
state->abs->v_flags[i] |= EV_ABS_V_RESET;
} else
state->abs->flags &= ~EV_ABS_TOUCH;
}
}