summaryrefslogtreecommitdiff
path: root/xinput2_ivy.c
diff options
context:
space:
mode:
Diffstat (limited to 'xinput2_ivy.c')
-rw-r--r--xinput2_ivy.c473
1 files changed, 473 insertions, 0 deletions
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;
+}