static void * get_property (ClutterInputDevice *device, const gchar *property, Atom type, int format, gulong nitems) { MetaBackend *backend = meta_get_backend (); Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); gulong nitems_ret, bytes_after_ret; int rc, device_id, format_ret; Atom property_atom, type_ret; guchar *data_ret = NULL; property_atom = XInternAtom (xdisplay, property, False); device_id = clutter_input_device_get_device_id (device); rc = XIGetProperty (xdisplay, device_id, property_atom, 0, 10, False, type, &type_ret, &format_ret, &nitems_ret, &bytes_after_ret, &data_ret); if (rc == Success && type_ret == type && format_ret == format && nitems_ret >= nitems) { if (nitems_ret > nitems) g_warning ("Property '%s' for device '%s' returned %lu items, expected %lu", property, clutter_input_device_get_device_name (device), nitems_ret, nitems); return data_ret; } meta_XFree (data_ret); return NULL; }
int xdevice_get_last_tool_id (int deviceid) { Atom prop; Atom act_type; int act_format; unsigned long nitems, bytes_after; unsigned char *data, *ptr; int id; id = 0x0; gdk_display_sync (gdk_display_get_default ()); prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), WACOM_SERIAL_IDS_PROP, False); if (!prop) return id; gdk_error_trap_push (); if (!XIGetProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), deviceid, prop, 0, 1000, False, AnyPropertyType, &act_type, &act_format, &nitems, &bytes_after, &data) == Success) { gdk_error_trap_pop_ignored (); return 0x0; } if (gdk_error_trap_pop ()) goto out; if (nitems != 4) goto out; if (act_type != XA_INTEGER) goto out; if (act_format != 32) goto out; /* item 0 = tablet ID * item 1 = old device serial number (== last tool in proximity) * item 2 = old hardware serial number (including tool ID) * item 3 = current serial number (0 if no tool in proximity) */ ptr = data; ptr += act_format/8 * 2; id = *((int32_t*)ptr); id = id & 0xfffff; /* That means that no tool was set down yet */ if (id == STYLUS_DEVICE_ID || id == ERASER_DEVICE_ID) return 0x0; out: XFree (data); return id; }
static int apply_matrix(Display *dpy, int deviceid, Matrix *m) { Atom prop_float, prop_matrix; union { unsigned char *c; float *f; } data; int format_return; Atom type_return; unsigned long nitems; unsigned long bytes_after; int rc; prop_float = XInternAtom(dpy, "FLOAT", False); prop_matrix = XInternAtom(dpy, "Coordinate Transformation Matrix", False); if (!prop_float) { fprintf(stderr, "Float atom not found. This server is too old.\n"); return EXIT_FAILURE; } if (!prop_matrix) { fprintf(stderr, "Coordinate transformation matrix not found. This " "server is too old\n"); return EXIT_FAILURE; } rc = XIGetProperty(dpy, deviceid, prop_matrix, 0, 9, False, prop_float, &type_return, &format_return, &nitems, &bytes_after, &data.c); if (rc != Success || prop_float != type_return || format_return != 32 || nitems != 9 || bytes_after != 0) { fprintf(stderr, "Failed to retrieve current property values\n"); return EXIT_FAILURE; } memcpy(data.f, m->m, sizeof(m->m)); XIChangeProperty(dpy, deviceid, prop_matrix, prop_float, format_return, PropModeReplace, data.c, nitems); XFree(data.c); return EXIT_SUCCESS; }
char * xdevice_get_device_node (int deviceid) { Atom prop; Atom act_type; int act_format; unsigned long nitems, bytes_after; unsigned char *data; char *ret; gdk_display_sync (gdk_display_get_default ()); prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Device Node", False); if (!prop) return NULL; gdk_error_trap_push (); if (!XIGetProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), deviceid, prop, 0, 1000, False, AnyPropertyType, &act_type, &act_format, &nitems, &bytes_after, &data) == Success) { gdk_error_trap_pop_ignored (); return NULL; } if (gdk_error_trap_pop ()) goto out; if (nitems == 0) goto out; if (act_type != XA_STRING) goto out; /* Unknown string format */ if (act_format != 8) goto out; ret = g_strdup ((char *) data); XFree (data); return ret; out: XFree (data); return NULL; }
/** * The return data type if 'char' must be convert to 'int8_t*' * if 'int' must be convert to 'int32_t*' * if 'float' must be convert to 'float*' **/ unsigned char* get_prop(int id, const char* prop, int* nitems) { if (!prop) { fprintf(stderr, "[get_prop] Empty property for %d\n", id); return NULL; } if (nitems == NULL) { fprintf(stderr, "[get_prop] Invalid item number for %d\n", id); return NULL; } Display* disp = XOpenDisplay(0); if (!disp) { fprintf(stderr, "[get_prop] Open display failed for %d\n", id); return NULL; } Atom prop_id = XInternAtom(disp, prop, True); if (prop_id == None) { XCloseDisplay(disp); fprintf(stderr, "[get_prop] Intern atom %s failed\n", prop); return NULL; } Atom act_type; int act_format; unsigned long num_items, bytes_after; unsigned char* data = NULL; int ret = XIGetProperty(disp, id, prop_id, 0, MAX_BUF_LEN, False, AnyPropertyType, &act_type, &act_format, &num_items, &bytes_after, &data); if (ret != Success) { XCloseDisplay(disp); fprintf(stderr, "[get_prop] Get %s data failed for %d\n", prop, id); return NULL; } *nitems = (int)num_items; XCloseDisplay(disp); return data; }
static int set_prop_float (Display *disp, int deviceid, const char *prop_name, double value) { if (!disp || !prop_name) { fprintf(stderr, "Args error in set_prop_float\n"); return -1; } Atom prop = XInternAtom( disp, prop_name, True); if (prop == None) { fprintf(stderr, "Get '%s' Atom Failed\n", prop_name); return -1; } Atom act_type; int act_format; unsigned long nitems, bytes_after; unsigned char *data; int rc = XIGetProperty(disp, deviceid, prop, 0, 1, False, AnyPropertyType, &act_type, &act_format, &nitems, &bytes_after, &data); if (rc != Success) { fprintf(stderr, "Get '%ld' property failed\n", prop); return -1; } Atom float_atom = XInternAtom(disp, "FLOAT", True); if (float_atom != None && act_type == float_atom && nitems == 1) { *(float*)data = (float)value; XIChangeProperty(disp, deviceid, prop, act_type, act_format, XIPropModeReplace, data, nitems); } XFree(data); return 0; }
/* Reads the calibration data from evdev, should be self-explanatory. */ void readCalibrationData(int exitOnFail) { if(debugMode) { printf("Start calibration\n"); } Atom retType; int retFormat; unsigned long retItems, retBytesAfter; unsigned int* data; if(XIGetProperty(display, deviceID, XInternAtom(display, "Evdev Axis Calibration", 0), 0, 4 * 32, False, XA_INTEGER, &retType, &retFormat, &retItems, &retBytesAfter, (unsigned char**) &data) != Success) { data = NULL; } if (data == NULL || retItems != 4 || data[0] == data[1] || data[2] == data[3]) { /* evdev might not be ready yet after resume. Let's wait a second and try again. */ sleep(1); if(XIGetProperty(display, deviceID, XInternAtom(display, "Evdev Axis Calibration", 0), 0, 4 * 32, False, XA_INTEGER, &retType, &retFormat, &retItems, &retBytesAfter, (unsigned char**) &data) != Success) { return; } if (retItems != 4 || data[0] == data[1] || data[2] == data[3]) { if(debugMode) { printf("No calibration data found, use default values.\n"); } /* Get minimum/maximum of axes */ int nDev; XIDeviceInfo * deviceInfo = XIQueryDevice(display, deviceID, &nDev); int c; for(c = 0; c < deviceInfo->num_classes; c++) { if(deviceInfo->classes[c]->type == XIValuatorClass) { XIValuatorClassInfo* valuatorInfo = (XIValuatorClassInfo *) deviceInfo->classes[c]; if(valuatorInfo->mode == XIModeAbsolute) { if(valuatorInfo->label == XInternAtom(display, "Abs X", 0) || valuatorInfo->label == XInternAtom(display, "Abs MT Position X", 0)) { calibMinX = valuatorInfo->min; calibMaxX = valuatorInfo->max; } else if(valuatorInfo->label == XInternAtom(display, "Abs Y", 0) || valuatorInfo->label == XInternAtom(display, "Abs MT Position Y", 0)) { calibMinY = valuatorInfo->min; calibMaxY = valuatorInfo->max; } } } } XIFreeDeviceInfo(deviceInfo); } else { calibMinX = data[0]; calibMaxX = data[1]; calibMinY = data[2]; calibMaxY = data[3]; } } else { calibMinX = data[0]; calibMaxX = data[1]; calibMinY = data[2]; calibMaxY = data[3]; } if(data != NULL) { XFree(data); } float * data4 = NULL; if(XIGetProperty(display, deviceID, XInternAtom(display, "Coordinate Transformation Matrix", 0), 0, 9 * 32, False, XInternAtom(display, "FLOAT", 0), &retType, &retFormat, &retItems, &retBytesAfter, (unsigned char **) &data4) != Success) { data4 = NULL; } calibMatrixUse = 0; if(data4 != NULL && retItems == 9) { int i; for(i = 0; i < 6; i++) { /* We only take the first two rows of the matrix, the rest is unimportant anyway */ calibMatrix[i] = data4[i]; } calibMatrixUse = 1; } if(data4 != NULL) { XFree(data4); } unsigned char* data2; if(XIGetProperty(display, deviceID, XInternAtom(display, "Evdev Axis Inversion", 0), 0, 2 * 8, False, XA_INTEGER, &retType, &retFormat, &retItems, &retBytesAfter, (unsigned char**) &data2) != Success) { return; } if (retItems != 2) { if (exitOnFail) { printf("No valid axis inversion data found.\n"); exit(1); } else { return; } } calibSwapX = data2[0]; calibSwapY = data2[1]; XFree(data2); if(XIGetProperty(display, deviceID, XInternAtom(display, "Evdev Axes Swap", 0), 0, 8, False, XA_INTEGER, &retType, &retFormat, &retItems, &retBytesAfter, (unsigned char**) &data2) != Success) { return; } if (retItems != 1) { if (exitOnFail) { printf("No valid axes swap data found.\n"); exit(1); } else { return; } } calibSwapAxes = data2[0]; XFree(data2); if(debugMode) { printf("Calibration: MinX: %i; MaxX: %i; MinY: %i; MaxY: %i\n", calibMinX, calibMaxX, calibMinY, calibMaxY); } }
int xdevice_get_last_tool_id (int deviceid) { Atom prop; Atom act_type; int act_format; unsigned long nitems, bytes_after; unsigned char *data; int id; id = -1; gdk_display_sync (gdk_display_get_default ()); prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), WACOM_SERIAL_IDS_PROP, False); if (!prop) return -1; data = NULL; gdk_error_trap_push (); if (XIGetProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), deviceid, prop, 0, 1000, False, AnyPropertyType, &act_type, &act_format, &nitems, &bytes_after, &data) != Success) { gdk_error_trap_pop_ignored (); goto out; } if (gdk_error_trap_pop ()) goto out; if (nitems != 4 && nitems != 5) goto out; if (act_type != XA_INTEGER) goto out; if (act_format != TOOL_ID_FORMAT_SIZE) goto out; /* item 0 = tablet ID * item 1 = old device serial number (== last tool in proximity) * item 2 = old hardware serial number (including tool ID) * item 3 = current serial number (0 if no tool in proximity) * item 4 = current tool ID (since Feb 2012) * * Get the current tool ID first, if available, then the old one */ id = 0x0; if (nitems == 5) id = get_id_for_index (data, 4); if (id == 0x0) id = get_id_for_index (data, 2); /* That means that no tool was set down yet */ if (id == STYLUS_DEVICE_ID || id == ERASER_DEVICE_ID) id = 0x0; out: if (data != NULL) XFree (data); return id; }
bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData) { bool handled = true; Display *xDisplay = static_cast<Display *>(m_xlib_display); xXIGenericDeviceEvent *xiEvent = static_cast<xXIGenericDeviceEvent *>(event); switch (xiEvent->evtype) { case XI_ButtonPress: // stylus down if (reinterpret_cast<xXIDeviceEvent *>(event)->detail == 1) { // ignore the physical buttons on the stylus tabletData->down = true; xi2ReportTabletEvent(*tabletData, xiEvent); } break; case XI_ButtonRelease: // stylus up if (reinterpret_cast<xXIDeviceEvent *>(event)->detail == 1) { tabletData->down = false; xi2ReportTabletEvent(*tabletData, xiEvent); } break; case XI_Motion: // Report TabletMove only when the stylus is touching the tablet. // No possibility to report proximity motion (no suitable Qt event exists yet). if (tabletData->down) xi2ReportTabletEvent(*tabletData, xiEvent); break; case XI_PropertyEvent: { xXIPropertyEvent *ev = reinterpret_cast<xXIPropertyEvent *>(event); if (ev->what == XIPropertyModified) { if (ev->property == atom(QXcbAtom::WacomSerialIDs)) { Atom propType; int propFormat; unsigned long numItems, bytesAfter; unsigned char *data; if (XIGetProperty(xDisplay, tabletData->deviceId, ev->property, 0, 100, 0, AnyPropertyType, &propType, &propFormat, &numItems, &bytesAfter, &data) == Success) { if (propType == atom(QXcbAtom::INTEGER) && propFormat == 32) { int *ptr = reinterpret_cast<int *>(data); for (unsigned long i = 0; i < numItems; ++i) tabletData->serialId |= qint64(ptr[i]) << (i * 32); } XFree(data); } // With recent-enough X drivers this property change event seems to come always // when entering and leaving proximity. Due to the lack of other options hook up // the enter/leave events to it. if (tabletData->inProximity) { tabletData->inProximity = false; QWindowSystemInterface::handleTabletLeaveProximityEvent(QTabletEvent::Stylus, tabletData->pointerType, tabletData->serialId); } else { tabletData->inProximity = true; QWindowSystemInterface::handleTabletEnterProximityEvent(QTabletEvent::Stylus, tabletData->pointerType, tabletData->serialId); } } } break; } default: handled = false; break; } return handled; }
static int do_set_prop_xi2(Display *dpy, Atom type, int format, int argc, char **argv, char *n, char *desc) { XIDeviceInfo *info; Atom prop; Atom old_type; char *name; int i; Atom float_atom; int old_format, nelements = 0; unsigned long act_nitems, bytes_after; char *endptr; union { unsigned char *c; int16_t *s; int32_t *l; } data; if (argc < 3) { fprintf(stderr, "Usage: xinput %s %s\n", n, desc); return EXIT_FAILURE; } info = xi2_find_device_info(dpy, argv[0]); if (!info) { fprintf(stderr, "unable to find device %s\n", argv[0]); return EXIT_FAILURE; } name = argv[1]; prop = parse_atom(dpy, name); if (prop == None) { fprintf(stderr, "invalid property %s\n", name); return EXIT_FAILURE; } float_atom = XInternAtom(dpy, "FLOAT", False); nelements = argc - 2; if (type == None || format == 0) { if (XIGetProperty(dpy, info->deviceid, prop, 0, 0, False, AnyPropertyType, &old_type, &old_format, &act_nitems, &bytes_after, &data.c) != Success) { fprintf(stderr, "failed to get property type and format for %s\n", name); return EXIT_FAILURE; } else { if (type == None) type = old_type; if (format == 0) format = old_format; } XFree(data.c); } if (type == None) { fprintf(stderr, "property %s doesn't exist, you need to specify " "its type and format\n", name); return EXIT_FAILURE; } data.c = calloc(nelements, sizeof(int32_t)); for (i = 0; i < nelements; i++) { if (type == XA_INTEGER) { switch (format) { case 8: data.c[i] = atoi(argv[2 + i]); break; case 16: data.s[i] = atoi(argv[2 + i]); break; case 32: data.l[i] = atoi(argv[2 + i]); break; default: fprintf(stderr, "unexpected size for property %s", name); return EXIT_FAILURE; } } else if (type == float_atom) { if (format != 32) { fprintf(stderr, "unexpected format %d for property %s\n", format, name); return EXIT_FAILURE; } *(float *)(data.l + i) = strtod(argv[2 + i], &endptr); if (endptr == argv[2 + i]) { fprintf(stderr, "argument %s could not be parsed\n", argv[2 + i]); return EXIT_FAILURE; } } else if (type == XA_ATOM) { if (format != 32) { fprintf(stderr, "unexpected format %d for property %s\n", format, name); return EXIT_FAILURE; } data.l[i] = parse_atom(dpy, argv[2 + i]); } else { fprintf(stderr, "unexpected type for property %s\n", name); return EXIT_FAILURE; } } XIChangeProperty(dpy, info->deviceid, prop, type, format, PropModeReplace, data.c, nelements); free(data.c); return EXIT_SUCCESS; }
static void print_property_xi2(Display *dpy, int deviceid, Atom property) { Atom act_type; char *name; int act_format; unsigned long nitems, bytes_after; unsigned char *data, *ptr; int j, done = False; name = XGetAtomName(dpy, property); printf("\t%s (%ld):\t", name, property); if (XIGetProperty(dpy, deviceid, property, 0, 1000, False, AnyPropertyType, &act_type, &act_format, &nitems, &bytes_after, &data) == Success) { Atom float_atom = XInternAtom(dpy, "FLOAT", True); ptr = data; if (nitems == 0) printf("<no items>"); for (j = 0; j < nitems; j++) { switch(act_type) { case XA_INTEGER: switch(act_format) { case 8: printf("%d", *((int8_t*)ptr)); break; case 16: printf("%d", *((int16_t*)ptr)); break; case 32: printf("%d", *((int32_t*)ptr)); break; } break; case XA_STRING: if (act_format != 8) { printf("Unknown string format.\n"); done = True; break; } printf("\"%s\"", ptr); j += strlen((char*)ptr); /* The loop's j++ jumps over the terminating 0 */ ptr += strlen((char*)ptr); /* ptr += size below jumps over the terminating 0 */ break; case XA_ATOM: { Atom a = *(uint32_t*)ptr; printf("\"%s\" (%ld)", (a) ? XGetAtomName(dpy, a) : "None", a); break; } break; default: if (float_atom != None && act_type == float_atom) { printf("%f", *((float*)ptr)); break; } printf("\t... of unknown type %s\n", XGetAtomName(dpy, act_type)); done = True; break; } ptr += act_format/8; if (done == True) break; if (j < nitems - 1) printf(", "); } printf("\n"); XFree(data); } else printf("\tFetch failure\n"); }
void setCalibration(int id, int minX, int maxX, int minY, int maxY, int axesSwap, int screenWidth, int screenHeight, int outputX, int outputY, int outputWidth, int outputHeight, int rotation) { float matrix[] = { 1., 0., 0., /* [0] [1] [2] */ 0., 1., 0., /* [3] [4] [5] */ 0., 0., 1. }; /* [6] [7] [8] */ int matrixMode = 0; /* Check if transformation matrix is supported */ long l; if((sizeof l) == 4 || (sizeof l) == 8) { /* We only support matrix mode on systems where longs are 32 or 64 bits long */ Atom retType; int retFormat; unsigned long retItems, retBytesAfter; unsigned char * data = NULL; if(XIGetProperty(display, id, XInternAtom(display, "Coordinate Transformation Matrix", 0), 0, 9 * 32, False, floatAtom, &retType, &retFormat, &retItems, &retBytesAfter, &data) != Success) { data = NULL; } if(data != NULL && retItems == 9) { matrixMode = 1; } if(data != NULL) { XFree(data); } } unsigned char flipHoriz = 0, flipVerti = 0; if(matrixMode) { if(debugMode) printf("Use matrix method\n"); /* Output rotation */ if(rotation & RR_Rotate_180) { matrix[0] = -1.; matrix[4] = -1; matrix[2] = 1.; matrix[5] = 1.; } else if(rotation & RR_Rotate_90) { matrix[0] = 0.; matrix[1] = -1.; matrix[3] = 1.; matrix[4] = 0.; matrix[2] = 1.; } else if(rotation & RR_Rotate_270) { matrix[0] = 0.; matrix[1] = 1.; matrix[3] = -1.; matrix[4] = 0.; matrix[5] = 1.; } /* Output Reflection */ if(rotation & RR_Reflect_X) { matrix[0]*= -1.; matrix[1]*= -1.; matrix[2]*= -1.; matrix[2]+= 1.; } if(rotation & RR_Reflect_Y) { matrix[3]*= -1.; matrix[4]*= -1.; matrix[5]*= -1.; matrix[5]+= 1.; } /* Output Size */ float widthRel = outputWidth / (float) screenWidth; float heightRel = outputHeight / (float) screenHeight; matrix[0] *= widthRel; matrix[1] *= widthRel; matrix[2] *= widthRel; matrix[3] *= heightRel; matrix[4] *= heightRel; matrix[5] *= heightRel; /* Output Position */ matrix[2] += outputX / (float) screenWidth; matrix[5] += outputY / (float) screenHeight; } else { if(debugMode) printf("Use legacy method\n"); /* No support for transformations, so use legacy method */ if(rotation & RR_Rotate_180) { flipHoriz = !flipHoriz; flipVerti = !flipVerti; } else if(rotation & RR_Rotate_90) { flipVerti = !flipVerti; axesSwap = !axesSwap; } else if(rotation & RR_Rotate_270) { flipHoriz = !flipHoriz; axesSwap = !axesSwap; } /* Output Reflection */ if(rotation & RR_Reflect_X) { flipHoriz = !flipHoriz; } if(rotation & RR_Reflect_Y) { flipVerti = !flipVerti; } if(axesSwap) { swap(&maxX, &maxY); swap(&minX, &minY); } int leftSpace, rightSpace, topSpace, bottomSpace; leftSpace = outputX; rightSpace = screenWidth - outputX - outputWidth; topSpace = outputY; bottomSpace = screenHeight - outputY - outputHeight; if(flipHoriz) swap(&leftSpace, &rightSpace); if(flipVerti) swap(&topSpace, &bottomSpace); float fctX = ((float) (maxX - minX)) / ((float) outputWidth); float fctY = ((float) (maxY - minY)) / ((float) outputHeight); minX = minX - (int) (leftSpace * fctX); maxX = maxX + (int) (rightSpace * fctX); minY = minY - (int) (topSpace * fctY); maxY = maxY + (int) (bottomSpace * fctY); } XDevice *dev = XOpenDevice(display, id); if(dev) { if(matrixMode) { if((sizeof l) == 4) { XChangeDeviceProperty(display, dev, XInternAtom(display, "Coordinate Transformation Matrix", 0), floatAtom, 32, PropModeReplace, (unsigned char*) matrix, 9); } else if((sizeof l) == 8) { /* Xlib needs the floats long-aligned, so let's align them. */ float matrix2[] = { matrix[0], 0., matrix[1], 0., matrix[2], 0., matrix[3], 0., matrix[4], 0., matrix[5], 0., matrix[6], 0., matrix[7], 0., matrix[8], 0. }; XChangeDeviceProperty(display, dev, XInternAtom(display, "Coordinate Transformation Matrix", 0), floatAtom, 32, PropModeReplace, (unsigned char*) matrix2, 9); } } long calib[] = { minX, maxX, minY, maxY }; //TODO instead of long, use platform 32 bit type XChangeDeviceProperty(display, dev, XInternAtom(display, "Evdev Axis Calibration", 0), XA_INTEGER, 32, PropModeReplace, (unsigned char*) calib, 4); unsigned char flipData[] = {flipHoriz, flipVerti}; XChangeDeviceProperty(display, dev, XInternAtom(display, "Evdev Axis Inversion", 0), XA_INTEGER, 8, PropModeReplace, flipData, 2); unsigned char cAxesSwap = (unsigned char) axesSwap; XChangeDeviceProperty(display, dev, XInternAtom(display, "Evdev Axes Swap", 0), XA_INTEGER, 8, PropModeReplace, &cAxesSwap, 1); XCloseDevice(display, dev); } }