From a7bdcffd4655e2a73956beef41a96397f458c46f Mon Sep 17 00:00:00 2001 From: ribet Date: Mon, 3 May 2010 13:04:04 +0000 Subject: Ajout de xinput2-ivy --- Makefile | 17 ++ debian/changelog | 5 + debian/compat | 1 + debian/control | 15 ++ debian/copyright | 9 ++ debian/dirs | 1 + debian/docs | 0 debian/install | 1 + debian/rules | 72 +++++++++ xinput2_ivy.c | 473 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 594 insertions(+) create mode 100644 Makefile create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/dirs create mode 100644 debian/docs create mode 100644 debian/install create mode 100755 debian/rules create mode 100644 xinput2_ivy.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d70296b --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ +APPNAME=xinput2_ivy +SRC=${APPNAME}.c + +all: ${APPNAME} + +${APPNAME}: ${SRC} + gcc -Wall $< -lX11 -lXi -livy -o $@ + +clean: + rm -f *~ + rm -f ${APPNAME} + +distclean: clean + +install: all + install -d ${DESTDIR}${PREFIX}/bin + install -m 0755 ${APPNAME} ${DESTDIR}${PREFIX}/bin diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..beebc0e --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +xinput2-ivy (1.0-1) unstable; urgency=low + + * Initial Debian release + + -- Philippe Ribet Mon, 3 May 2010 11:46:00 +0100 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +5 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..e2342ac --- /dev/null +++ b/debian/control @@ -0,0 +1,15 @@ +Source: xinput2-ivy +Priority: optional +Maintainer: Philippe Ribet +Build-Depends: debhelper (>= 4.0.0), xlibs-dev | libx11-dev, ivy-c-dev (>=3.11), libxi-dev | x11proto-input-dev +Standards-Version: 3.6.1 +Section: tools + +Package: xinput2-ivy +Section: x11 +Architecture: any +Depends: ${misc:Depends}, ivy-c (>=3.11), libxi6 +Description: Ivy proxy for XInput2 + "xinput2_ivy" acts as an Ivy proxy, receiving XInput2 events and + broadcasting corresponding Ivy messages. + Useful with Wacom Cintiq tools, Wacom Intuos tools, multi-input peripherals... diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..b121f28 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,9 @@ +This package was debianized by Philippe Ribet on +Mon, 3 May 2010 12:14:41 +0100. + +Author: Philippe Ribet + +Copyright Holder: CENA + +License: +GPL diff --git a/debian/dirs b/debian/dirs new file mode 100644 index 0000000..e772481 --- /dev/null +++ b/debian/dirs @@ -0,0 +1 @@ +usr/bin diff --git a/debian/docs b/debian/docs new file mode 100644 index 0000000..e69de29 diff --git a/debian/install b/debian/install new file mode 100644 index 0000000..1df36c6 --- /dev/null +++ b/debian/install @@ -0,0 +1 @@ +usr/bin/* diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..48d12c8 --- /dev/null +++ b/debian/rules @@ -0,0 +1,72 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# +# + +package=xinput2-ivy + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +configure: configure-stamp +configure-stamp: + dh_testdir + touch configure-stamp + +build: build-stamp +build-stamp: configure-stamp + dh_testdir + touch build-stamp + $(MAKE) DESTDIR=$(CURDIR)/debian/tmp PREFIX=/usr + +clean: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + $(MAKE) clean + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + $(MAKE) install DESTDIR=$(CURDIR)/debian/tmp PREFIX=/usr + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installchangelogs +# dh_installdocs README + dh_installexamples + dh_install --source=$(CURDIR)/debian/tmp +# dh_installmenu +# dh_installdebconf +# dh_installlogrotate +# dh_installemacsen +# dh_installpam +# dh_installmime +# dh_installinit +# dh_installcron +# dh_installinfo + dh_installman + dh_link + dh_strip +# dh_compress +# dh_fixperms +# dh_perl +# dh_python +# dh_makeshlibs + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure diff --git a/xinput2_ivy.c b/xinput2_ivy.c new file mode 100644 index 0000000..87edba1 --- /dev/null +++ b/xinput2_ivy.c @@ -0,0 +1,473 @@ +// gcc -Wall xinput2_ivy.c -lX11 -lXi -livy + +#include +#include +#include +#include +#include +#include /* for isdigit */ +#include +#include +#include + +#include +#include + +#define REGEXP "^ub" + +static char *ivy_bus = NULL; +static int xi_opcode; +static char *application_name="xinput2_ivy"; +static char *identifier="default"; + +static char *device_name=NULL; +static XIDeviceInfo *device_info=NULL; +static char **valuators_names=NULL; +static double *valuators_min=NULL; +static double *valuators_max=NULL; +static int num_valuators=0; +/*void Callback (IvyClientPtr app, void *user_data, int argc, char *argv[]) { + MsgRcvPtr *ptr = (MsgRcvPtr *) user_data; + printf ("%s sent unbind message, unbinding to %s\n", + IvyGetApplicationName(app),REGEXP); + IvyUnbindMsg(*ptr); +} +*/ + +static const char* type_to_name(int evtype) +{ + const char *name; + + switch(evtype) { + case XI_DeviceChanged: name = "DeviceChanged"; break; + case XI_KeyPress: name = "KeyPress"; break; + case XI_KeyRelease: name = "KeyRelease"; break; + case XI_ButtonPress: name = "ButtonPress"; break; + case XI_ButtonRelease: name = "ButtonRelease"; break; + case XI_Motion: name = "Motion"; break; + case XI_Enter: name = "Enter"; break; + case XI_Leave: name = "Leave"; break; + case XI_FocusIn: name = "FocusIn"; break; + case XI_FocusOut: name = "FocusOut"; break; + case XI_HierarchyChanged: name = "HierarchyChanged"; break; + case XI_PropertyEvent: name = "PropertyEvent"; break; + case XI_RawKeyPress: name = "RawKeyPress"; break; + case XI_RawKeyRelease: name = "RawKeyRelease"; break; + case XI_RawButtonPress: name = "RawButtonPress"; break; + case XI_RawButtonRelease: name = "RawButtonRelease"; break; + case XI_RawMotion: name = "RawMotion"; break; + default: + name = "unknown event type"; break; + } + return name; +} + +static void init_valuators_definitions (Display *display, XIDeviceInfo* device) { + int i; + valuators_names = calloc(device->num_classes, sizeof(char *)); + valuators_min = calloc(device->num_classes, sizeof(double)); + valuators_max = calloc(device->num_classes, sizeof(double)); + for (i = 0; i < device->num_classes; i++) { + switch(device->classes[i]->type) { + case XIButtonClass: + { + XIButtonClassInfo *b = (XIButtonClassInfo*)(device->classes[i]); + char *name; + int j; + for (j = 0; j < b->num_buttons; j++) { + name = (b->labels[j]) ? XGetAtomName(display, b->labels[j]) : NULL; + printf("%s, ", (name) ? name : "None"); + XFree(name); + } + printf("\n"); + break; + } + case XIKeyClass: + break; + case XIValuatorClass: + { + XIValuatorClassInfo *v = (XIValuatorClassInfo*)(device->classes[i]); + char *name = v->label ? XGetAtomName(display, v->label) : "unknown"; + int size = strlen(name); + int j; + for (j=0; j < size; j++) { + if (name[j] == ' ') { + name[j] = '_'; + } + } + valuators_names[v->number] = memcpy(malloc(size + 1), name, size + 1); + if (v->label) { + XFree(name); + } + valuators_min[v->number] = v->min; + valuators_max[v->number] = v->max; + num_valuators++; + break; + } + } + } +} + +static void register_events (Display *display, XIDeviceInfo* device) { + XIEventMask mask[2]; + mask[0].deviceid = XIAllDevices; + mask[0].mask_len = XIMaskLen(XI_LASTEVENT); + mask[0].mask = calloc(mask[0].mask_len, sizeof(char)); + XISetMask(mask[0].mask, XI_HierarchyChanged); + + if (device) { + mask[1].deviceid = device->deviceid; + mask[1].mask_len = XIMaskLen(XI_LASTEVENT); + mask[1].mask = calloc(mask[1].mask_len, sizeof(char)); + XISetMask(mask[1].mask, XI_RawKeyPress); + XISetMask(mask[1].mask, XI_RawKeyRelease); + XISetMask(mask[1].mask, XI_RawButtonPress); + XISetMask(mask[1].mask, XI_RawButtonRelease); + XISetMask(mask[1].mask, XI_RawMotion); + init_valuators_definitions(display, device); + } else { + int i; + for (i=0; i < num_valuators; i++) { + free(valuators_names[i]); + } + free(valuators_names); + free(valuators_min); + free(valuators_max); + } + + XISelectEvents(display, DefaultRootWindow(display), mask, device ? 2 : 1); + free(mask[0].mask); + if (device) { + free(mask[1].mask); + } +} + +static XIDeviceInfo* find_device_info (Display *display, char *name) +{ + XIDeviceInfo *info; + int ndevices; + Bool is_id = True; + int i, id = -1; + + for(i = 0; i < strlen(name); i++) { + if (!isdigit(name[i])) { + is_id = False; + break; + } + } + + if (is_id) { + id = atoi(name); + } + + info = XIQueryDevice(display, XIAllDevices, &ndevices); + if (is_id) { + for(i = 0; i < ndevices; i++) { + if (info[i].deviceid == id) { + return &info[i]; + } + } + } else { + for(i = 0; i < ndevices; i++) { + if (strcmp(info[i].name, name) == 0) { + return &info[i]; + } + } + } + XIFreeDeviceInfo(info); + return NULL; +} + +static void hierarchy_changed_callback (Display *display, XIHierarchyEvent *event) { + if (event->flags & (XIDeviceEnabled | XIDeviceDisabled)) { + if (device_info) { + int i; + for (i = 0; i < event->num_info; i++) { + if (event->info[i].deviceid == device_info->deviceid) { + if (!event->info[i].enabled) { + printf("*** Device %s now disabled\n", device_name); + device_info = NULL; + // register_events(event->display, NULL); + register_events(display, NULL); + } + } + } + } else { + // device_info = find_device_info (event->display, device_name); + device_info = find_device_info (display, device_name); + if (device_info) { + printf("*** Device %s now enabled (name=%s, id=%d)\n", device_name, device_info->name, device_info->deviceid); + // register_events(event->display, device_info); + register_events(display, device_info); + } + } + } +} + +static void raw_event_callback (XIRawEvent *event) { + int i; + double *val; + static char message[2000]; + int length; + + if (event->deviceid != device_info->deviceid) { + printf("??????????\n"); + } + + strcpy(message, "InputMoveEvent "); + strcat(message, identifier); + length = strlen(message); + /* printf("device: %d, ", event->deviceid); + printf("detail: %d, ", event->detail); + printf("type: %d, ", event->evtype); + printf("valuators:\n"); + */ + val = event->valuators.values; + for (i = 0; i < event->valuators.mask_len * 8; i++) { + if (XIMaskIsSet(event->valuators.mask, i)) { + length += sprintf(message + length, " %s=%.2f", valuators_names[i], *val++); + } + } + length += sprintf(message + length, " time=%u", (uint32_t)(event->time)); + IvySendMsg(message); + /*printf("%s\n", message);*/ +} + +static void X_callback (Channel channel, HANDLE fd, void *data) { + static XEvent event; + static XGenericEventCookie *cookie = (XGenericEventCookie*)&event.xcookie; + static char message[2000]; + int length; + + while (XPending((Display *)data)) { + /*while (XEventsQueued ((Display *)data, QueuedAlready) > 0) {*/ + XNextEvent((Display *)data, &event); + if (XGetEventData((Display *)data, cookie)) { + if (cookie->type == GenericEvent && + cookie->extension == xi_opcode) + { + switch (cookie->evtype) + { + case XI_HierarchyChanged: + hierarchy_changed_callback(((XAnyEvent*)&event)->display, cookie->data); + break; + case XI_RawKeyPress: + case XI_RawKeyRelease: + break; + case XI_RawButtonPress: + case XI_RawButtonRelease: + { + int ndevices; + XIDeviceInfo* device = XIQueryDevice((Display *)data, ((XIRawEvent*)(cookie->data))->deviceid, &ndevices); + int i; + strcpy(message, "InputButtonEvent "); + strcat(message, identifier); + length = strlen(message); + length += sprintf(message + length, " num=%d state=%s", ((XIRawEvent*)(cookie->data))->detail, (cookie->evtype == XI_RawButtonPress) ? "pressed" : "released"); + for (i = 0; i < device->num_classes; i++) { + switch(device->classes[i]->type) { + case XIButtonClass: + break; + case XIKeyClass: + break; + case XIValuatorClass: + { + XIValuatorClassInfo *v = (XIValuatorClassInfo*)(device->classes[i]); + length += sprintf(message + length, " %s=%.2f", valuators_names[v->number], v->value); + break; + } + } + } + length += sprintf(message + length, " time=%u", (uint32_t)((XIRawEvent*)(cookie->data))->time); + IvySendMsg(message); + /* printf("%s\n", message);*/ + XIFreeDeviceInfo(device); + break; + } + case XI_RawMotion: + raw_event_callback(cookie->data); + break; + /* case XI_Enter: + case XI_Leave: + case XI_FocusIn: + case XI_FocusOut: + break; + case XI_PropertyEvent: + break; + case XI_DeviceChanged: + break;*/ + default: + printf("EVENT type %d (%s)\n", cookie->evtype, type_to_name(cookie->evtype)); + break; + } + } + XFreeEventData((Display *)data, cookie); + } + } +} + +static void loop(Display *display) { + /* MsgRcvPtr ptr;*/ + char *ready_msg = malloc(strlen(application_name) + strlen(" Ready") + 1); + sprintf(ready_msg, "%s Ready", application_name); + IvyInit(application_name, ready_msg, NULL, NULL, NULL, NULL); + /* ptr=IvyBindMsg(Callback,&ptr,REGEXP);*/ + IvyStart(ivy_bus); + IvyChannelAdd(ConnectionNumber(display), display, NULL, &X_callback, NULL); + + /* This code unlocks the IvyMainLoop (don't know why) */ + while (XPending(display)) { + XEvent Event; + XNextEvent(display, &Event); + } + + IvyMainLoop(); +} + + +static int xinput_version (Display *display) { + XExtensionVersion *version; + int result = -1; + + version = XGetExtensionVersion(display, INAME); + if (version && (version != (XExtensionVersion*) NoSuchExtension)) { + result = version->major_version; + XFree(version); + } + + return result; +} + +static int list_devices (Display *display) { + int ndevices; + int i; + XIDeviceInfo *info, *dev; + + info = XIQueryDevice(display, XIAllDevices, &ndevices); + + for(i = 0; i < ndevices; i++) { + dev = &info[i]; + if (dev->use == XIMasterPointer) { + printf("(master) id=%d\t%s\n", dev->deviceid, dev->name); + } + if (dev->use == XISlavePointer) { + printf("(slave) id=%d\t%s\n", dev->deviceid, dev->name); + } + if (!dev->enabled) { + printf("Device %d (%s) is disabled\n", dev->deviceid, dev->name); + } + } + XIFreeDeviceInfo(info); + return EXIT_SUCCESS; +} + +/* static int print_single_device(char*def) { */ +/* XIDeviceInfo *dev = xi2_find_device_info(display, def); */ + +/* if (!info) { */ +/* fprintf(stderr, "unable to find device %s\n", def); */ +/* return EXIT_FAILURE; */ +/* } else { */ +/* print_classes_xi2(display, dev->classes, dev->num_classes); */ +/* return EXIT_SUCCESS; */ +/* } */ +/* } */ + +void usage () { + printf("\nThis tool get data from xinput2 (X11 extension) and send them to\n" + "applications using ivy bus.\n" + "\n" + "Options:\n" + "\t-help:\t\t\tprint this help.\n\n" + "\t-list:\t\t\tlist all pointer devices\n\n" + "\t-application name:\tspecify the application name on the ivy bus\n" + "\t\t\t\t(default is xinput2_ivy)\n\n" + "\t-device id:\t\tinput device to use (can be string or number)\n\n" + "\t-identifier id:\t\tidentifier used as prefix in ivy mesages\n" + "\t\t\t\t(default is \"default\")\n\n" + "\t-b [address]:port:\tspecify the ivy bus\n\n" + "Sent messages:\n" + "\tInputButtonEvent [identifier] num=[button id] state=[pressed|released] axis1name=value ... axisNname=value time=[time in ms]\n\n" + "\tInputMoveEvent [identifier] axis1name=value ... axisNname=value time=[time in ms]\n\n"); +} + +void parse_args (Display *display, int argc, char * argv[]) { + int i; + char *arg_name; + + for (i=1; i < argc; i++) { + arg_name = argv[i]; + if (strcmp(arg_name, "-list") == 0) { + list_devices(display); + } else if (strcmp(arg_name, "-b") == 0) { + i++; + ivy_bus = argv[i]; + } else if (strcmp(arg_name, "-help") == 0) { + usage(); + } else if (strcmp(arg_name, "-application") == 0) { + i++; + application_name = argv[i]; + } else if (strcmp(arg_name, "-device") == 0) { + i++; + device_name = argv[i]; + } else if (strcmp(arg_name, "-identifier") == 0) { + i++; + identifier = argv[i]; + } else { + printf("\n*** Invalid option \"%s\".\n", arg_name); + usage(); + exit(EXIT_FAILURE); + } + } +} + +int main (int argc, char * argv[]) { + Display *display; + int event, error; + int xinput; + + /* Sanity checks */ + display = XOpenDisplay(NULL); + if (display == NULL) { + fprintf(stderr, "Unable to connect to X server\n"); + return EXIT_FAILURE; + } + + if (!XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &error)) { + printf("X Input extension not available.\n"); + return EXIT_FAILURE; + } + + xinput = xinput_version(display); + if (!xinput) { + fprintf(stderr, "%s extension not available\n", INAME); + return EXIT_FAILURE; + } + + if (xinput != XI_2_Major) { + fprintf(stderr, "%s extension version 2 not available\n", INAME); + return EXIT_FAILURE; + } + + if (argc != 1) { + parse_args(display, argc, argv); + } else { + usage(); + return EXIT_FAILURE; + } + + if (device_name) { + device_info = find_device_info(display, device_name); + if (!device_info) { + printf("\n*** Unable to find device <<%s>> at starting time. Valid devices are:\n", device_name); + list_devices(display); + printf("\n*** Waiting for device <<%s>>.\n", device_name); + } + register_events(display, device_info); + loop(display); + } + + XSync(display, False); + XCloseDisplay(display); + return EXIT_SUCCESS; +} -- cgit v1.1