diff options
author | Zephaniah E. Hull <warp@aehallh.com> | 2006-02-14 14:57:37 +0000 |
---|---|---|
committer | Zephaniah E. Hull <warp@aehallh.com> | 2006-02-14 14:57:37 +0000 |
commit | e7d4e6b11eb4cc026e91fd561fda24d9cf19adc4 (patch) | |
tree | e39330364b81f0e36cb3baaaeaaf3668b7b03ed4 /src/evdev_abs.c | |
parent | Add evdev manpage (diff) | |
download | xf86-input-evdev-e7d4e6b11eb4cc026e91fd561fda24d9cf19adc4.tar.gz xf86-input-evdev-e7d4e6b11eb4cc026e91fd561fda24d9cf19adc4.tar.bz2 xf86-input-evdev-e7d4e6b11eb4cc026e91fd561fda24d9cf19adc4.zip |
Bugzilla #5696 <https://bugs.freedesktop.org/show_bug.cgi?id=5696> Slightly
updated version of the patch listed. Basicly a rewrite of the driver,
with a few pieces of the old. XKB support, proper device matching,
basic absolute pointer support. Lots more, will require some user
config changes.
Diffstat (limited to 'src/evdev_abs.c')
-rw-r--r-- | src/evdev_abs.c | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/src/evdev_abs.c b/src/evdev_abs.c new file mode 100644 index 0000000..2b6113a --- /dev/null +++ b/src/evdev_abs.c @@ -0,0 +1,348 @@ +/* + * Copyright © 2006 Zephaniah E. Hull + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Soft- + * ware"), to deal in the Software without restriction, including without + * limitation the rights to use, copy, modify, merge, publish, distribute, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, provided that the above copyright + * notice(s) and this permission notice appear in all copies of the Soft- + * ware and that both the above copyright notice(s) and this permission + * notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- + * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY + * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN + * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- + * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- + * MANCE OF THIS SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization of + * the copyright holder. + * + * Author: Zephaniah E. Hull (warp@aehallh.com) + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <X11/keysym.h> +#include <X11/XF86keysym.h> +#include <X11/extensions/XIproto.h> + +/* The libc wrapper just blows... linux/input.h must be included + * before xf86_ansic.h and xf86_libc.h so we avoid defining ioctl + * twice. */ + +#include <linux/input.h> + +#include <misc.h> +#include <xf86.h> +#include <xf86str.h> +#include <xf86_OSproc.h> +#include <xf86_ansic.h> +#include <xf86_libc.h> +#include <xf86Xinput.h> +#include <exevents.h> +#include <mipointer.h> + +#include <xf86Module.h> + +#include "evdev.h" + +#define ArrayLength(a) (sizeof(a) / (sizeof((a)[0]))) + +#define BITS_PER_LONG (sizeof(long) * 8) +#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) +#define OFF(x) ((x)%BITS_PER_LONG) +#define LONG(x) ((x)/BITS_PER_LONG) +#define TestBit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1) + +static char *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 +EvdevPtrCtrlProc(DeviceIntPtr device, PtrCtrl *ctrl) +{ + /* Nothing to do, dix handles all settings */ +} + +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; +} + +/* + * FIXME: Verify that the C standard lets us pass more variable arguments + * then we specify. + */ +void +EvdevAbsSyn (InputInfoPtr pInfo) +{ + evdevDevicePtr pEvdev = pInfo->private; + evdevStatePtr state = &pEvdev->state; + int i; + int n = state->abs_n & 1; + + if (!state->abs_axes) + return; + + if (state->mode == Absolute) { + if ((state->abs_screen >= 0) && state->abs_axes >= 2) { + int conv_x, conv_y; + + for (i = 0; i < 2; i++) + state->abs_v[n][i] = xf86ScaleAxis (state->abs_v[n][i], 0, + state->abs_scale_x, + state->abs_min[i], state->abs_max[i]); + + + EvdevConvert (pInfo, 0, 2, state->abs_v[n][0], state->abs_v[n][1], + 0, 0, 0, 0, &conv_x, &conv_y); + xf86XInputSetScreen (pInfo, state->abs_screen, conv_x, conv_y); + } + + + xf86PostMotionEvent(pInfo->dev, 1, 0, state->abs_axes, + state->abs_v[n][0], + state->abs_v[n][1], state->abs_v[n][2], state->abs_v[n][3], + state->abs_v[n][4], state->abs_v[n][5], state->abs_v[n][6], + state->abs_v[n][7], state->abs_v[n][8], state->abs_v[n][9], + state->abs_v[n][10], state->abs_v[n][11], state->abs_v[n][12], + state->abs_v[n][13], state->abs_v[n][14], state->abs_v[n][15]); + } else { + for (i = 0; i < 2; i++) + state->rel_v[i] = state->abs_v[n][i] - state->abs_v[!n][i]; + } + + state->abs_n++; +} + +void +EvdevAbsProcess (InputInfoPtr pInfo, struct input_event *ev) +{ + evdevDevicePtr pEvdev = pInfo->private; + evdevStatePtr state = &pEvdev->state; + int n = state->abs_n & 1; + int map; + + if (ev->code >= ABS_MAX) + return; + + map = pEvdev->state.absMap[ev->code]; + if (map >= 0) + pEvdev->state.abs_v[n][map] += ev->value; + else + pEvdev->state.abs_v[n][-map] -= ev->value; + + if (!pEvdev->state.sync) + EvdevAbsSyn (pInfo); +} + +int +EvdevAbsInit (DeviceIntPtr device) +{ + InputInfoPtr pInfo = device->public.devicePrivate; + evdevDevicePtr pEvdev = pInfo->private; + int i; + + if (!InitValuatorClassDeviceStruct(device, pEvdev->state.abs_axes, + miPointerGetMotionEvents, + miPointerGetMotionBufferSize(), 0)) + return !Success; + + for (i = 0; i < pEvdev->state.abs_axes; i++) { + xf86InitValuatorAxisStruct(device, i, 0, 0, 0, 0, 1); + xf86InitValuatorDefaults(device, i); + } + + if (!InitPtrFeedbackClassDeviceStruct(device, EvdevPtrCtrlProc)) + return !Success; + + return Success; +} + +int +EvdevAbsOn (DeviceIntPtr device) +{ + return Success; +} + +int +EvdevAbsOff (DeviceIntPtr device) +{ + return Success; +} + +int +EvdevAbsNew(InputInfoPtr pInfo) +{ + evdevDevicePtr pEvdev = pInfo->private; + evdevStatePtr state = &pEvdev->state; + long abs_bitmask[NBITS(KEY_MAX)]; + struct input_absinfo absinfo; + char *s, option[64]; + int i, j, k = 0, real_axes; + + if (ioctl(pInfo->fd, + EVIOCGBIT(EV_ABS, ABS_MAX), abs_bitmask) < 0) { + xf86Msg(X_ERROR, "ioctl EVIOCGBIT failed: %s\n", strerror(errno)); + return !Success; + } + + real_axes = 0; + for (i = 0; i < ABS_MAX; i++) + if (TestBit (i, abs_bitmask)) + real_axes++; + + if (!real_axes) + return !Success; + + 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 (!TestBit (i, abs_bitmask)) + continue; + + snprintf(option, sizeof(option), "%sAbsoluteAxisMap", axis_names[i]); + k = xf86SetIntOption(pInfo->options, option, -1); + if (k != -1) + state->absMap[i] = k; + else + state->absMap[i] = j; + + if (k != -1) + xf86Msg(X_CONFIG, "%s: %s: %d.\n", pInfo->name, option, k); + + if (ioctl (pInfo->fd, EVIOCGABS(i), &absinfo) < 0) { + xf86Msg(X_ERROR, "ioctl EVIOCGABS failed: %s\n", strerror(errno)); + return !Success; + } + state->abs_min[state->absMap[i]] = absinfo.minimum; + state->abs_max[state->absMap[i]] = absinfo.maximum; + + j++; + } + + state->abs_axes = real_axes; + for (i = 0; i < ABS_MAX; i++) { + if (state->absMap[i] > state->abs_axes) + state->abs_axes = state->absMap[i]; + } + + if (state->abs_axes != real_axes) + xf86Msg(X_CONFIG, "%s: Configuring %d absolute axes.\n", pInfo->name, + state->abs_axes); + + 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); + } + + if (TestBit (ABS_X, abs_bitmask) && TestBit (ABS_Y, abs_bitmask)) + k = xf86SetIntOption(pInfo->options, "AbsoluteScreen", 0); + else + k = xf86SetIntOption(pInfo->options, "AbsoluteScreen", -1); + if (k < screenInfo.numScreens) { + state->abs_screen = k; + xf86Msg(X_CONFIG, "%s: AbsoluteScreen: %d.\n", pInfo->name, k); + } else { + state->abs_screen = 0; + xf86Msg(X_CONFIG, "%s: AbsoluteScreen: %d is not a valid screen.\n", pInfo->name, k); + } + + state->abs_scale_x = screenInfo.screens[state->abs_screen]->width; + state->abs_scale_y = screenInfo.screens[state->abs_screen]->height; + + return Success; +} |