summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorribet2010-05-03 13:04:04 +0000
committerribet2010-05-03 13:04:04 +0000
commita7bdcffd4655e2a73956beef41a96397f458c46f (patch)
treefab0d997d4b37ed30134ee4460c3c4484113e36c
downloadxinput2-ivy-a7bdcffd4655e2a73956beef41a96397f458c46f.zip
xinput2-ivy-a7bdcffd4655e2a73956beef41a96397f458c46f.tar.gz
xinput2-ivy-a7bdcffd4655e2a73956beef41a96397f458c46f.tar.bz2
xinput2-ivy-a7bdcffd4655e2a73956beef41a96397f458c46f.tar.xz
Ajout de xinput2-ivy
-rw-r--r--Makefile17
-rw-r--r--debian/changelog5
-rw-r--r--debian/compat1
-rw-r--r--debian/control15
-rw-r--r--debian/copyright9
-rw-r--r--debian/dirs1
-rw-r--r--debian/docs0
-rw-r--r--debian/install1
-rwxr-xr-xdebian/rules72
-rw-r--r--xinput2_ivy.c473
10 files changed, 594 insertions, 0 deletions
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 <ribet@cena.fr> 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 <ribet@cena.fr>
+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 <ribet@cena.fr> on
+Mon, 3 May 2010 12:14:41 +0100.
+
+Author: Philippe Ribet <ribet@cena.fr>
+
+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
--- /dev/null
+++ b/debian/docs
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 <X11/Xlib.h>
+#include <X11/extensions/XInput.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/Xutil.h>
+#include <string.h>
+#include <ctype.h> /* for isdigit */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <Ivy/ivyloop.h>
+#include <Ivy/ivy.h>
+
+#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;
+}