/* Written for XI1 by Nikolas Doerfler (c) 2008 * * Rewritten for XI2 by Florian Echtler (c) 2009 */ #include #include "freeglut_internal.h" #if TARGET_HOST_POSIX_X11 && HAVE_X11_EXTENSIONS_XINPUT2_H #include #include #include #include /* import function from freeglut_main.c */ int fghGetXModifiers( int state ); /* extension opcode for XInput */ int xi_opcode = -1; /** * \brief Sets window up for XI2 events. */ void fgRegisterDevices( Display* dpy, Window* win ) { XIEventMask mask; unsigned char flags[2] = { 0, 0 }; int event, error; /*Display* dpy = fgDisplay.Display; Window* win = glutGetXWindow();*/ /* get XInput extension opcode */ if (!XQueryExtension( dpy, "XInputExtension", &xi_opcode, &event, &error )) { xi_opcode = -1; } /* Select for motion events */ mask.deviceid = XIAllMasterDevices; mask.mask_len = 2; mask.mask = flags; XISetMask(mask.mask, XI_Enter); XISetMask(mask.mask, XI_Motion); XISetMask(mask.mask, XI_ButtonPress); XISetMask(mask.mask, XI_ButtonRelease); XISetMask(mask.mask, XI_Leave); /*XISetMask(mask.mask, XI_KeyPress); XISetMask(mask.mask, XI_KeyRelease); XISetMask(mask.mask, XI_DeviceChanged); XISetMask(mask.mask, XI_RawEvent); XISetMask(mask.mask, XI_FocusIn); XISetMask(mask.mask, XI_FocusOut); XISetMask(mask.mask, XI_HierarchyChanged);*/ XISelectEvents( dpy, *win, &mask, 1 ); } void fgPrintXILeaveEvent(XILeaveEvent* event) { char* mode = ""; char* detail = ""; int i; printf(" windows: root 0x%lx event 0x%lx child 0x%ld\n", event->root, event->event, event->child); switch(event->mode) { case NotifyNormal: mode = "NotifyNormal"; break; case NotifyGrab: mode = "NotifyGrab"; break; case NotifyUngrab: mode = "NotifyUngrab"; break; case NotifyWhileGrabbed: mode = "NotifyWhileGrabbed"; break; } switch (event->detail) { case NotifyAncestor: detail = "NotifyAncestor"; break; case NotifyVirtual: detail = "NotifyVirtual"; break; case NotifyInferior: detail = "NotifyInferior"; break; case NotifyNonlinear: detail = "NotifyNonlinear"; break; case NotifyNonlinearVirtual: detail = "NotifyNonlinearVirtual"; break; case NotifyPointer: detail = "NotifyPointer"; break; case NotifyPointerRoot: detail = "NotifyPointerRoot"; break; case NotifyDetailNone: detail = "NotifyDetailNone"; break; } printf(" mode: %s (detail %s)\n", mode, detail); printf(" flags: %s %s\n", event->focus ? "[focus]" : "", event->same_screen ? "[same screen]" : ""); printf(" buttons:"); for (i = 0; i < event->buttons.mask_len * 8; i++) if (XIMaskIsSet(event->buttons.mask, i)) printf(" %d", i); printf("\n"); printf(" modifiers: locked 0x%x latched 0x%x base 0x%x\n", event->mods.locked, event->mods.latched, event->mods.base); printf(" group: locked 0x%x latched 0x%x base 0x%x\n", event->group.locked, event->group.latched, event->group.base); printf(" root x/y: %.2f / %.2f\n", event->root_x, event->root_y); printf(" event x/y: %.2f / %.2f\n", event->event_x, event->event_y); } void fgPrintXIDeviceEvent(XIDeviceEvent* event) { double *val; int i; printf(" device: %d (%d)\n", event->deviceid, event->sourceid); printf(" detail: %d\n", event->detail); printf(" buttons:"); for (i = 0; i < event->buttons.mask_len * 8; i++) if (XIMaskIsSet(event->buttons.mask, i)) printf(" %d", i); printf("\n"); printf(" modifiers: locked 0x%x latched 0x%x base 0x%x\n", event->mods.locked, event->mods.latched, event->mods.base); printf(" group: locked 0x%x latched 0x%x base 0x%x\n", event->group.locked, event->group.latched, event->group.base); printf(" valuators:"); val = event->valuators.values; for (i = 0; i < event->valuators.mask_len * 8; i++) if (XIMaskIsSet(event->valuators.mask, i)) printf(" %d: %.2f", i, *val++); printf("\n"); printf(" windows: root 0x%lx event 0x%lx child 0x%ld\n", event->root, event->event, event->child); printf(" root x/y: %.2f / %.2f\n", event->root_x, event->root_y); printf(" event x/y: %.2f / %.2f\n", event->event_x, event->event_y); } /** * \brief This function is called when an Extension Event is received * and calls the corresponding callback functions for these events. */ void fgHandleExtensionEvents( XEvent* base_ev ) { int i, button = 0; XGenericEventCookie* cookie = (XGenericEventCookie*)&(base_ev->xcookie); if ( XGetEventData( fgDisplay.Display, cookie ) && (cookie->type == GenericEvent) && (cookie->extension == xi_opcode) ) { XIDeviceEvent* event = (XIDeviceEvent*)(cookie->data); /*printf("XI2 event type: %d - %d\n", cookie->evtype, event->type );*/ SFG_Window* window = fgWindowByHandle( event->event ); if (!window) return; switch (cookie->evtype) { case XI_Enter: case XI_Leave: fgState.Modifiers = fghGetXModifiers( ((XIEnterEvent*)event)->mods.base ); INVOKE_WCB( *window, MultiEntry, ( event->deviceid, (event->evtype == XI_Enter ? GLUT_ENTERED : GLUT_LEFT) )); #if _DEBUG fgPrintXILeaveEvent((XILeaveEvent*)event); #endif break; case XI_ButtonPress: case XI_ButtonRelease: fgState.Modifiers = fghGetXModifiers( event->mods.base ); INVOKE_WCB( *window, MultiButton, ( event->deviceid, event->event_x, event->event_y, (event->detail)-1, (event->evtype == XI_ButtonPress ? GLUT_DOWN : GLUT_UP) )); INVOKE_WCB( *window, Mouse, ( (event->detail)-1, (event->evtype == XI_ButtonPress ? GLUT_DOWN : GLUT_UP), event->event_x, event->event_y )); break; case XI_Motion: fgState.Modifiers = fghGetXModifiers( event->mods.base ); for (i = 0; i < event->buttons.mask_len; i++) if (event->buttons.mask[i]) button = 1; if (button) { INVOKE_WCB( *window, MultiMotion, ( event->deviceid, event->event_x, event->event_y ) ); INVOKE_WCB( *window, Motion, ( event->event_x, event->event_y ) ); } else { INVOKE_WCB( *window, MultiPassive, ( event->deviceid, event->event_x, event->event_y ) ); INVOKE_WCB( *window, Passive, ( event->event_x, event->event_y ) ); } #if _DEBUG fgPrintXIDeviceEvent(event); #endif break; default: #if _DEBUG fgWarning( "Unknown XI2 device event:" ); fgPrintXIDeviceEvent( event ); #endif break; } fgState.Modifiers = INVALID_MODIFIERS; } XFreeEventData( fgDisplay.Display, cookie ); } #endif