Hi,
It's the old xinput patch and I just fix it without any crash this
time, I think, just to see how things should work in first place (to
implement basic NSTabletPoint etc). Currently only pressure is
working. The code is still very experimental. It registers all
possible input sources for all windows and it shouldn't do that. Need
a standard panel that any app can bring up to configure this. One
thing I found is the display could be flickering a lot, may be due to
the dense of subpixel events. Devices like Intuos can produce a lot
more events in a second than mouse, so app should filter them (and
it's app not the backend, should this be configurable?). Now I wonder
if it is possible to keep used events in an extra pool some how so
there's no need to reallocate them or if that's a good idea at all or
if that would actually speed thing up. Would reduce time to alloc and
memset etc. ?

Thanks,
Banlu

-- 
    .----.     Banlu Kemiyatorn
  /.../\...\   漫画家
 |.../  \...|  http://qstx.blogspot.com (Free Software Advocacy & Development)
 |../    \..|  http://feedbat.blogspot.com (Studio Work For Hire)
  \/      \/   http://groundzerostudiocomplex.blogspot.com (Studio Research)
Index: Source/x11/GNUmakefile
===================================================================
--- Source/x11/GNUmakefile	(revision 31820)
+++ Source/x11/GNUmakefile	(working copy)
@@ -53,6 +53,7 @@
 XGServerWindow.m \
 XGDragView.m \
 XIMInputServer.m \
+XGXI.m \
 XWindowBuffer.m\
 XGGLFormat.m\
 XGGLContext.m
Index: Source/x11/XGServerWindow.m
===================================================================
--- Source/x11/XGServerWindow.m	(revision 31820)
+++ Source/x11/XGServerWindow.m	(working copy)
@@ -1979,6 +1979,16 @@
     | VisibilityChangeMask
     );
 
+#ifdef USE_XINPUT
+  {
+	  int n;
+	  for (n = 0; n < _num_xidevs; n++)
+	  {
+		  [_xidevs[n] selectXExtensionEventForWindow:window->ident];
+	  }
+  }
+#endif
+
   /*
    * Initial attributes for any GNUstep window tell Window Maker not to
    * create an app icon for us.
Index: Source/x11/XGServer.m
===================================================================
--- Source/x11/XGServer.m	(revision 31820)
+++ Source/x11/XGServer.m	(working copy)
@@ -68,6 +68,10 @@
 #include "x11/XGOpenGL.h"
 #endif 
 
+#ifdef USE_XINPUT
+#include "x11/XGXI.h"
+#endif
+
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <X11/keysym.h>
@@ -453,6 +457,60 @@
   [self _setupRootWindow];
   inputServer = [[XIMInputServer allocWithZone: [self zone]] 
                   initWithDelegate: nil display: dpy name: @"XIM"];
+
+#ifdef USE_XINPUT
+  {
+	  int xi_opcode;
+	  int event, error;
+
+	  if (!XQueryExtension(dpy, "XInputExtension", &xi_opcode, &event, &error)) {
+		  NSLog(@"X Input extension not available.\n");
+		  return self;
+	  }
+	  else
+	  {
+		  /* store version FIXME
+		  XExtensionVersion   *version;
+		  version = XGetExtensionVersion(dpy, INAME);
+		  */
+	  }
+
+	  int n;
+	  id dev;
+
+	  _xidev_info_list = XListInputDevices(dpy, &_num_xidevs);
+
+	  _xidevs = malloc(sizeof(void *) * _num_xidevs);
+	  memset(_xidevs, 0, _num_xidevs * sizeof(void *));
+
+	  procXInputEvent = malloc(sizeof(void *) * _num_xidevs);
+	  memset(procXInputEvent, 0, _num_xidevs * sizeof(void *));
+
+	  for (n = 0; n < _num_xidevs; n++)
+	  {
+		  if (_xidev_info_list[n].id != 13) continue;
+
+		  dev = [[GSInputDevice alloc] initWithDeviceInfo:&_xidev_info_list[n]
+											displayServer:self
+												proximity:YES];
+		  if (dev)
+		  {
+			  _xidevs[n] = dev;
+			  NSLog(@"add device %@",[dev name]);
+			  /* bleh */
+			  [dev setScreenSize:NSMakeSize(DisplayWidth(dpy, screen_number),DisplayHeight(dpy, screen_number))];
+			  procXInputEvent[n] = (BOOL (*)(id, SEL, XEvent*))[dev methodForSelector:@selector(processEvent:)];
+		  }
+		  else
+		  {
+			  _xidevs[n] = nil;
+			  procXInputEvent[n] = 0;
+		  }
+	  }
+
+  }
+#endif
+
   return self;
 }
 
@@ -478,6 +536,20 @@
 - (void) dealloc
 {
   NSDebugLog(@"Destroying X11 Server");
+#ifdef USE_XINPUT
+  XFreeDeviceList(_xidev_info_list);
+  {
+	  int n;
+	  for (n = 0; n < _num_xidevs; n++)
+	  {
+		  DESTROY(_xidevs[n]);
+	  }
+
+  }
+  free(_xidevs);
+  free(procXInputEvent);
+#endif
+
   DESTROY(inputServer);
   [self _destroyServerWindows];
   NSFreeMapTable(screenList);
Index: Source/x11/XGServerEvent.m
===================================================================
--- Source/x11/XGServerEvent.m	(revision 31820)
+++ Source/x11/XGServerEvent.m	(working copy)
@@ -59,6 +59,12 @@
 #include <X11/keysym.h>
 #include <X11/Xproto.h>
 
+#if USE_XINPUT
+#include <X11/extensions/XInput.h>
+#include "x11/XGXI.h"
+#endif
+
+
 #if LIB_FOUNDATION_LIBRARY
 # include <Foundation/NSPosixFileDescriptor.h>
 #elif defined(NeXT_PDO)
@@ -299,6 +305,8 @@
     {
       XNextEvent(dpy, &xEvent);
 
+//NSLog(@"%d", xEvent.type);
+
 #ifdef USE_XIM
       if (XFilterEvent(&xEvent, None)) 
         {
@@ -307,7 +315,24 @@
         }
 #endif
 
+#ifdef USE_XINPUT
+  {
+	  int n;
+	  for (n = 0; n < _num_xidevs; n++)
+	  {
+		  if (_xidevs[n] && procXInputEvent[n](_xidevs[n], procSel, &xEvent))
+		  {
+//			NSLog(@"%@ proceed",[_xidevs[n] name]);
+			  goto processed_xinput_event;
+		  }
+	  }
+	  (*procEvent)(self, procSel, &xEvent);
+processed_xinput_event:;
+  }
+
+#else
       (*procEvent)(self, procSel, &xEvent);
+#endif
     }
 }
 
@@ -2604,3 +2629,28 @@
 
 @end
 
+#ifdef USE_XINPUT
+@interface XGServer (XInput)
+- (NSArray *) inputDevices;
+- (unsigned int) processModifierFlags:(unsigned int)state;
+- (void) sendXInputEvent:(NSEvent *)e;
+@end
+
+@implementation XGServer (XInput)
+- (unsigned int) processModifierFlags:(unsigned int)state
+{
+	return process_modifier_flags(state);
+}
+
+- (NSArray *) inputDevices
+{
+	return [NSArray arrayWithObjects:_xidevs count:_num_xidevs];
+}
+
+- (void) sendXInputEvent:(NSEvent *)e
+{
+	[event_queue addObject: e];
+}
+@end
+#endif
+
Index: Source/x11/XGXI.m
===================================================================
--- Source/x11/XGXI.m	(revision 0)
+++ Source/x11/XGXI.m	(revision 0)
@@ -0,0 +1,700 @@
+/*
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+   Author:  Banlu Kemiyatorn <obj...@gmail.com>
+
+   This file is part of GNUstep.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+   
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <AppKit/NSEvent.h>
+#include "x11/XGServer.h"
+#include "x11/XGXI.h"
+
+@implementation GSInputDevice
+
+#define GS_XINPUT_DEVICE_INVALID_TYPE -1
+
+static int    _gsMotionType = GS_XINPUT_DEVICE_INVALID_TYPE;
+static int    _gsButtonPressType = GS_XINPUT_DEVICE_INVALID_TYPE;
+static int    _gsButtonReleaseType = GS_XINPUT_DEVICE_INVALID_TYPE;
+static int    _gsKeyPressType = GS_XINPUT_DEVICE_INVALID_TYPE;
+static int    _gsKeyReleaseType = GS_XINPUT_DEVICE_INVALID_TYPE;
+static int    _gsProximityInType = GS_XINPUT_DEVICE_INVALID_TYPE;
+static int    _gsProximityOutType = GS_XINPUT_DEVICE_INVALID_TYPE;
+
+- (id) initWithDeviceInfo:(void *)info
+			displayServer:(GSDisplayServer *)server
+				proximity:(BOOL)willHandleProximity
+{
+	XAnyClassPtr any;
+	XValuatorInfoPtr viptr;
+	XAxisInfoPtr aiptr;
+	XButtonInfoPtr biptr;
+
+
+	dinfo = (XDeviceInfo *)info;
+	__server = server;
+	getState =  (unsigned int (*)(id, SEL, unsigned int))[server methodForSelector:@selector(processModifierFlags:)];
+
+	Display *dpy = [__server xDisplay];
+	XInputClassInfo *cinfo;
+	int n,m;
+
+	xdevice = XOpenDevice(dpy, dinfo->id);
+	use = dinfo->use;
+	_name = [[NSString alloc] initWithCString:dinfo->name];
+
+
+	/* FIXME */
+	if (!xdevice)
+	{
+		RELEASE(self);
+		return nil;
+	}
+
+	NSLog(@"initializing %@",_name);
+
+	deviceID = dinfo->id;
+
+	any = (XAnyClassPtr) (dinfo->inputclassinfo);
+
+	for (n=0; n < dinfo->num_classes; n++)
+	{
+		switch (any->class)
+		{
+			case KeyClass:
+				break;
+			case ButtonClass:
+				biptr = (XButtonInfoPtr) any;
+				if (buttonStates)
+				{
+					NSLog(@"eh... why many button class info?");
+				}
+				else
+				{
+					num_buttons = biptr->num_buttons;
+					buttonStates = malloc(sizeof(gs_input_device_state_t) * num_buttons);
+					bzero(buttonStates, sizeof(gs_input_device_state_t) * num_buttons);
+					for (m = 0; m < num_buttons; m++)
+					{
+						buttonStates[m].clickTime = 300;
+						buttonStates[m].clickSlip = 8;
+						/* FIXME then initialize all neccessary informations */
+					}
+
+				}
+				break;
+			case ValuatorClass:
+				viptr = (XValuatorInfoPtr) any;
+				aiptr = (XAxisInfoPtr) ((char *) viptr + sizeof (XValuatorInfo));
+
+				/* x y axes */
+				area.origin.x = aiptr->min_value;
+				area.size.width = aiptr->max_value - area.origin.x;
+				aiptr++;
+				area.origin.y = aiptr->min_value;
+				area.size.height = aiptr->max_value - area.origin.y;
+				/* pressure */
+				aiptr++;
+				pressure.location = aiptr->min_value;
+				pressure.length = aiptr->max_value - pressure.location;
+				/* tilt */
+				aiptr++;
+				tiltArea.origin.x = aiptr->min_value;
+				tiltArea.size.width = aiptr->max_value - tiltArea.origin.x;
+				aiptr++;
+				tiltArea.origin.y = aiptr->min_value;
+				tiltArea.size.height = aiptr->max_value - tiltArea.origin.y;
+
+				break;
+			default:
+				break;
+		}
+		any = (XAnyClassPtr) ((char *) any + any->length);
+	}
+
+	for(cinfo = xdevice->classes, n = 0, nevent = 0; n < xdevice->num_classes && nevent < GS_XINPUT_DEVICE_MAX_CLASSES; n++,cinfo++)
+	{
+		switch (cinfo->input_class)
+		{
+			case KeyClass:
+				NSLog(@"KeyClass");
+				DeviceKeyPress(xdevice, _gsKeyPressType, eventList[nevent]);
+				nevent++;
+
+				DeviceButtonPressGrab(xdevice, 0, eventList[nevent]);
+				nevent++;
+
+				DeviceKeyRelease(xdevice, _gsKeyReleaseType, eventList[nevent]);
+				nevent++;
+				break;
+			case ButtonClass:
+				NSLog(@"ButtonClass");
+				DeviceButtonPress(xdevice, _gsButtonPressType, eventList[nevent]);
+				nevent++;
+				DeviceButtonRelease(xdevice, _gsButtonReleaseType, eventList[nevent]);
+				nevent++;
+				break;
+			case ValuatorClass:
+				NSLog(@"ValuatorClass");
+				DeviceMotionNotify(xdevice, _gsMotionType, eventList[nevent]);
+				nevent++;
+				break;
+			case FeedbackClass:
+				NSLog(@"FeedbackClass");
+				break;
+			case ProximityClass:
+				NSLog(@"ProximityClass");
+				if (willHandleProximity)
+				{
+					_handleProx = YES;
+					ProximityIn(xdevice, _gsProximityInType, eventList[nevent]);
+					nevent++;
+					ProximityOut(xdevice, _gsProximityOutType, eventList[nevent]);
+					nevent++;
+				}
+				break;
+			case FocusClass:
+				NSLog(@"FocusClass");
+				break;
+			case OtherClass:
+				NSLog(@"OtherClass");
+				break;
+			default:
+				NSLog(@"Unknown XInput class %x",cinfo->input_class);
+		}
+	}
+
+
+	NSLog(@"..registered %d events",nevent);
+	return self;
+}
+
+- (void) dealloc
+{
+	RELEASE(_name);
+	if (xdevice)
+	{
+		XCloseDevice([__server xDisplay],xdevice);
+	}
+	if (buttonStates)
+	{
+		free(buttonStates);
+	}
+	[super dealloc];
+}
+
+- (void) selectXExtensionEventForWindow:(Window)win
+{
+	Display *dpy = [__server xDisplay];
+	if (XSelectExtensionEvent(dpy, win, eventList, nevent))
+	{
+		NSLog(@"Cannot select extended events for win %d.",win);
+	}
+	else NSLog(@"window %d enable> %@",win,_name);
+}
+
+- (NSString *) description
+{
+	return [NSString stringWithFormat:@"%d : %@ frame:%@ pressure:%@ tilt:%@",[self deviceID],[self name],NSStringFromRect(area),NSStringFromRange(pressure),NSStringFromRect(tiltArea)];
+}
+
+- (int) deviceID
+{
+	return xdevice->device_id;
+}
+
+- (NSString *) name
+{
+	return _name;
+}
+
+- (BOOL) isExtensionDevice
+{
+	return (use == IsXExtensionDevice);
+}
+
+- (BOOL) isPointer
+{
+	return (use == IsXPointer);
+}
+
+- (BOOL) isKeyboard
+{
+	return (use == IsXKeyboard);
+}
+
+- (BOOL) hasButton
+{
+}
+
+- (int) numberOfButtons
+{
+}
+
+- (BOOL) hasKey
+{
+}
+
+- (int) numberOfKeys
+{
+}
+
+- (int) minKeycode
+{
+}
+
+- (int) maxKeycode
+{
+}
+
+- (void) setHandleProximity:(BOOL)prox
+{
+	_handleProx = prox;
+}
+
+- (BOOL) willHandleProximity
+{
+	return _handleProx;
+}
+
+
+- (BOOL) hasAxis
+{
+}
+
+- (int) numberOfAxes
+{
+}
+
+- (BOOL) isRelative
+{
+}
+
+- (int) motionBuffer
+{
+}
+
+- (int) minValueForAxis:(int)axis
+{
+}
+
+- (int) maxValueForAxis:(int)axis
+{
+}
+
+- (int) resolutionForAxis:(int)axis
+{
+}
+
+- (void) setScreenSize:(NSSize)size
+{
+	screenSize = size;
+	resV = NSHeight(area)/screenSize.height;
+	resH = NSWidth(area)/screenSize.width;
+}
+
+- (NSSize) screenSize
+{
+	return screenSize;
+}
+
+- (BOOL) processEvent:(XEvent *) event
+{
+	unsigned int state;
+	unsigned int eventFlags = 0;
+	NSEventType eventType;
+	NSPoint eventLocation;
+	float press;
+	NSEvent *nsevent;
+	float deltaX,deltaY;
+	NSGraphicsContext *context;
+	context = GSCurrentContext();
+
+#define MOTIONSTATES buttonStates[motion->button]
+#define BUTTONSTATES buttonStates[button->button]
+
+	/** DEVICE MOTION **/
+	if (event->type == _gsMotionType)
+	{
+
+		XDeviceMotionEvent *motion = (XDeviceMotionEvent *)event;
+
+		if (motion->deviceid != deviceID)
+		{
+			return NO;
+		}
+
+		if (gswindow == 0 || lastWindow != motion->window)
+		{
+			gswindow = [XGServer _windowForXWindow:motion->window];
+		}
+
+		if (gswindow == 0)
+		{
+			return YES;
+		}
+
+		state = motion->state;
+		lastMotionTime = motion->time;
+
+		if (state & Button1Mask)
+		{
+			eventType = NSLeftMouseDragged;
+		}
+		else if (state & Button2Mask)
+		{
+			eventType = NSRightMouseDragged;
+		}
+		else if (state & Button3Mask)
+		{
+			eventType = NSOtherMouseDragged;
+		}
+		else
+		{
+			eventType = NSMouseMoved;
+		}
+
+		if (state & ShiftMask)
+		{
+			eventFlags = NSShiftKeyMask;
+		}
+		if (state & LockMask)
+		{
+			eventFlags |= NSAlphaShiftKeyMask;
+		}
+		if (state & ControlMask)
+		{
+			eventFlags |= NSControlKeyMask;
+		}
+		if (state & Mod1Mask)
+		{
+			eventFlags |= NSAlternateKeyMask;
+		}
+
+		eventLocation.x = (float)motion->axis_data[0]/resH - NSMinX(gswindow->xframe);
+		eventLocation.y = (screenSize.height - (float)motion->axis_data[1]/resV) - (screenSize.height - (motion->y_root - motion->y + NSHeight(gswindow->xframe)));
+
+		deltaX = - eventLocation.x;
+		deltaY = - eventLocation.y;
+		eventLocation = NSMakePoint(motion->x,
+				NSHeight(gswindow->xframe) - motion->y);
+		deltaX += eventLocation.x;
+		deltaY += eventLocation.y;
+
+		press = (float)motion->axis_data[2];
+		/* a work-around to solve some problem drivers */
+		if (press > pressure.length + pressure.location)
+		{
+			pressure.location += press - (pressure.length + pressure.location);
+		}
+		else if (press < pressure.location)
+		{
+			pressure.location = press;
+		}
+		press = (press - pressure.location)/pressure.length;
+
+		nsevent = [NSEvent mouseEventWithType: eventType
+									 location: eventLocation
+								modifierFlags: eventFlags
+									timestamp: motion->time
+								 windowNumber: gswindow->number
+									  context: context
+								  eventNumber: motion->serial
+								   clickCount: clickCount
+									 pressure: press
+								 buttonNumber: 0
+									   deltaX: eventLocation.x - lastLocation.x
+									   deltaY: eventLocation.y - lastLocation.y
+									   deltaZ: press - lastPressure];
+
+		lastLocation = eventLocation;
+		lastPressure = press;
+
+		[__server sendXInputEvent:nsevent];
+
+		return YES;
+	}
+	else if (event->type == MotionNotify && lastMotionTime == event->xmotion.time)
+	{
+		/* filter a consequence motion event */
+		return YES;
+	}
+	/** DEVICE PRESS **/
+	else if (event->type == _gsButtonPressType)
+	{
+		/*
+		NSLog(@"Tablet Button Press");
+		*/
+
+		XDeviceButtonEvent *button = (XDeviceButtonEvent *)event;
+
+		if (button->deviceid != deviceID)
+		{
+			return NO;
+		}
+
+		/* FIXME add a way to destroy lastWindow value */
+		if (gswindow == 0 || lastWindow != button->window)
+		{
+			gswindow = [XGServer _windowForXWindow:button->window];
+		}
+
+		if (gswindow == 0)
+		{
+			/* simply ignore the event and for the rest
+			 * if receiving window isn't found.
+			 */
+			return YES;
+		}
+
+		state = button->state;
+		lastButtonTime = button->time;
+
+		/* convert point from device's geometry to the receiving window */
+		eventLocation.x = (float)button->axis_data[0]/resH - NSMinX(gswindow->xframe);
+		eventLocation.y = (screenSize.height - (float)button->axis_data[1]/resV) - (screenSize.height - (button->y_root - button->y + NSHeight(gswindow->xframe)));
+		deltaX = - eventLocation.x;
+		deltaY = - eventLocation.y;
+		eventLocation = NSMakePoint(button->x,
+				NSHeight(gswindow->xframe) - button->y);
+		deltaX += eventLocation.x;
+		deltaY += eventLocation.y;
+
+
+		if (button->time >= BUTTONSTATES.lastClick + BUTTONSTATES.clickTime)
+		{
+			clickCount = 1;
+		}
+		else if (button->window != BUTTONSTATES.lastClickWindow)
+		{
+			clickCount = 1;
+		}
+		else if (
+				fabsf(BUTTONSTATES.lastClickPoint.x - eventLocation.x)
+					< BUTTONSTATES.clickSlip &&
+				fabsf(BUTTONSTATES.lastClickPoint.y - eventLocation.y)
+					< BUTTONSTATES.clickSlip)
+		{
+			clickCount++;
+		}
+
+		BUTTONSTATES.lastClick = button->time;
+		BUTTONSTATES.lastClickWindow = button->window;
+		BUTTONSTATES.lastClickPoint = eventLocation;
+
+		if (button->button == 1)
+		{
+			eventType = NSLeftMouseDown;
+		}
+		else if (button->button == 3)
+		{
+			eventType = NSRightMouseDown;
+		}
+		else
+		{
+			eventType = NSOtherMouseDown;
+		}
+
+		if (state & ShiftMask)
+		{
+			eventFlags = NSShiftKeyMask;
+		}
+		if (state & LockMask)
+		{
+			eventFlags |= NSAlphaShiftKeyMask;
+		}
+		if (state & ControlMask)
+		{
+			eventFlags |= NSControlKeyMask;
+		}
+		if (state & Mod1Mask)
+		{
+			eventFlags |= NSAlternateKeyMask;
+		}
+
+		press = (float)button->axis_data[2];
+		/* a work-around to solve some problem drivers */
+		if (press > pressure.length + pressure.location)
+		{
+			pressure.location += press - (pressure.length + pressure.location);
+		}
+		else if (press < pressure.location)
+		{
+			pressure.location = press;
+		}
+		press = (press - pressure.location)/pressure.length;
+
+		nsevent = [NSEvent mouseEventWithType: eventType
+									 location: eventLocation
+								modifierFlags: eventFlags
+									timestamp: button->time
+								 windowNumber: gswindow->number
+									  context: context
+								  eventNumber: button->serial
+								   clickCount: clickCount
+									 pressure: press
+								 buttonNumber: 0
+									   deltaX: eventLocation.x - lastLocation.x
+									   deltaY: eventLocation.y - lastLocation.y
+									   deltaZ: press - lastPressure];
+
+		lastLocation = eventLocation;
+		lastPressure = press;
+
+		[__server sendXInputEvent:nsevent];
+
+		return YES;
+	}
+	else if (event->type == ButtonPress && lastButtonTime == event->xbutton.time)
+	{
+		/* filter a consequence button press event */
+		return YES;
+	}
+	/** DEVICE RELEASE **/
+	else if (event->type == _gsButtonReleaseType)
+	{
+		/*
+		NSLog(@"Tablet Button Release");
+		*/
+
+		XDeviceButtonEvent *button = (XDeviceButtonEvent *)event;
+
+		if (button->deviceid != deviceID)
+		{
+			return NO;
+		}
+
+		if (gswindow == 0 || lastWindow != button->window)
+		{
+			gswindow = [XGServer _windowForXWindow:button->window];
+		}
+
+		if (gswindow == 0)
+		{
+			/* ignore */
+			return YES;
+		}
+
+		state = button->state;
+		lastButtonTime = button->time;
+
+		eventLocation.x = (float)button->axis_data[0]/resH - NSMinX(gswindow->xframe);
+		eventLocation.y = (screenSize.height - (float)button->axis_data[1]/resV) - (screenSize.height - (button->y_root - button->y + NSHeight(gswindow->xframe)));
+		deltaX = - eventLocation.x;
+		deltaY = - eventLocation.y;
+		eventLocation = NSMakePoint(button->x,
+				NSHeight(gswindow->xframe) - button->y);
+		deltaX += eventLocation.x;
+		deltaY += eventLocation.y;
+
+		if (button->button == 1)
+		{
+			eventType = NSLeftMouseUp;
+		}
+		else if (button->button == 3)
+		{
+			eventType = NSRightMouseUp;
+		}
+		else
+		{
+			eventType = NSOtherMouseUp;
+		}
+
+		if (state & ShiftMask)
+		{
+			eventFlags = NSShiftKeyMask;
+		}
+		if (state & LockMask)
+		{
+			eventFlags |= NSAlphaShiftKeyMask;
+		}
+		if (state & ControlMask)
+		{
+			eventFlags |= NSControlKeyMask;
+		}
+		if (state & Mod1Mask)
+		{
+			eventFlags |= NSAlternateKeyMask;
+		}
+
+
+		press = (float)button->axis_data[2];
+		if (press > pressure.length + pressure.location)
+		{
+			pressure.location += press - (pressure.length + pressure.location);
+		}
+		else if (press < pressure.location)
+		{
+			pressure.location = press;
+		}
+		press = (press - pressure.location)/pressure.length;
+
+		nsevent = [NSEvent mouseEventWithType: eventType
+									 location: eventLocation
+								modifierFlags: eventFlags
+									timestamp: button->time
+								 windowNumber: gswindow->number
+									  context: context
+								  eventNumber: button->serial
+								   clickCount: clickCount
+									 pressure: press
+								 buttonNumber: 0
+									   deltaX: eventLocation.x - lastLocation.x
+									   deltaY: eventLocation.y - lastLocation.y
+									   deltaZ: press - lastPressure];
+
+		lastLocation = eventLocation;
+		lastPressure = press;
+
+		[__server sendXInputEvent:nsevent];
+
+		return YES;
+	}
+	else if (event->type == ButtonRelease && lastButtonTime == event->xbutton.time)
+	{
+		/* filter a consequence button release event */
+		return YES;
+	}
+#if 0
+	else if (event->type == _gsKeyPressType)
+	{
+		return NO;
+	}
+	else if (event->type == _gsKeyReleaseType)
+	{
+		return;
+	}
+#endif
+	else if (event->type == _gsProximityInType)
+	{
+		XProximityInEvent *prox = (XProximityInEvent *)event;
+		NSLog(@"Device %d Prox In",prox->deviceid);
+		return YES;
+	}
+	else if (event->type == _gsProximityOutType)
+	{
+		XProximityOutEvent *prox = (XProximityOutEvent *)event;
+		NSLog(@"Device %d Prox Out",prox->deviceid);
+		return YES;
+	}
+	else
+		return NO;
+}
+@end
+
+
Index: config.h.in
===================================================================
--- config.h.in	(revision 31820)
+++ config.h.in	(working copy)
@@ -126,6 +126,9 @@
 /* Define to enable XIM support */
 #undef USE_XIM
 
+/* Define to enable XInput support */
+#undef USE_XINPUT
+
 /* Define if you have X11 XRender extension */
 #undef XRENDER
 
Index: configure.ac
===================================================================
--- configure.ac	(revision 31820)
+++ configure.ac	(working copy)
@@ -285,6 +285,21 @@
 fi
 
 #--------------------------------------------------------------------
+# XInput support
+#--------------------------------------------------------------------
+AC_ARG_ENABLE(xinput,
+  [  --disable-xinput        Disable XInput support],,
+  enable_xinput=yes)
+
+PKG_XI=no
+PKG_CHECK_MODULES(XI, xi, have_xi=yes, have_xi=no)
+
+if test "x$enable_xinput" = "xyes"; then
+	  XI_LIBS="-lXi"
+	  AC_DEFINE(USE_XINPUT,1,[Define to enable XInput support])
+fi
+
+#--------------------------------------------------------------------
 # Functions
 #--------------------------------------------------------------------
 AC_HAVE_FUNCS(usleep)
@@ -594,6 +609,9 @@
   if test "$ac_cv_lib_Xext" = no; then
     AC_MSG_ERROR([libXext not found - required for building x11 server])
   fi
+  if test "x$enable_xinput" = "xyes"; then
+    LIBS="$LIBS $XI_LIBS"
+  fi
   if test "x$WITH_GLX" = "xyes"; then
     LIBS="$LIBS $GLX_LIBS"
     CPPFLAGS="$CPPFLAGS $GLX_CFLAGS"
Index: Headers/x11/XGXI.h
===================================================================
--- Headers/x11/XGXI.h	(revision 0)
+++ Headers/x11/XGXI.h	(revision 0)
@@ -0,0 +1,134 @@
+/*
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+   Author:  Banlu Kemiyatorn <obj...@gmail.com>
+
+   This file is part of GNUstep.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+   
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef XGXI_h
+#define XGXI_h
+
+#include <X11/Xlib.h>
+#include <X11/extensions/XInput.h>
+#include <X11/Xutil.h>
+#include "config.h"
+#include "x11/XGServerWindow.h"
+
+#define GS_XINPUT_DEVICE_MAX_CLASSES 13
+
+typedef struct _gs_input_device_state_t
+{
+	Time lastClick;
+	NSPoint lastClickPoint;
+	Window lastClickWindow;
+
+	Time clickTime;
+	float clickSlip;
+} gs_input_device_state_t;
+
+@class XGServer;
+
+@interface GSInputDevice : NSObject
+{
+@public
+	int num_buttons;
+	gs_input_device_state_t *buttonStates;
+
+	/* generic time */
+	Time lastButtonTime;
+	Time lastMotionTime;
+	NSPoint lastLocation;
+
+	int clickCount;
+
+@private
+	BOOL _isEnable;
+
+	XGServer *__server;
+	unsigned int (*getState)(id, SEL, unsigned int);
+	Window lastWindow;
+	gswindow_device_t *gswindow;
+
+	BOOL _handleProx;
+
+	NSSize screenSize;
+
+	NSRect area;
+	NSRect tiltArea;
+	NSRange pressure;
+
+	float lastPressure;
+
+	float resV,resH;
+
+	NSString *_name;
+	int use;
+	XID deviceID;
+	XDeviceInfo *dinfo;
+	XDevice *xdevice;
+	XEventClass eventList[GS_XINPUT_DEVICE_MAX_CLASSES];
+	int nevent;
+}
+
+- (id) initWithDeviceInfo:(void *)info
+			displayServer:(GSDisplayServer *)server
+				proximity:(BOOL)willHandleProximity;
+- (NSString *) description;
+- (int) deviceID;
+- (NSString *) name;
+- (BOOL) isExtensionDevice;
+- (BOOL) isPointer;
+- (BOOL) isKeyboard;
+- (BOOL) hasButton;
+- (int) numberOfButtons;
+- (BOOL) hasKey;
+- (int) numberOfKeys;
+- (int) minKeycode;
+- (int) maxKeycode;
+- (void) setHandleProximity:(BOOL)prox;
+- (BOOL) willHandleProximity;
+- (BOOL) hasAxis;
+- (int) numberOfAxes;
+- (BOOL) isRelative;
+- (int) motionBuffer;
+- (int) minValueForAxis:(int)axis;
+- (int) maxValueForAxis:(int)axis;
+- (int) resolutionForAxis:(int)axis;
+- (BOOL) isEnable;
+- (void) setEnable:(BOOL)enable;
+
+- (void) setScreenSize:(NSSize)size;
+- (NSSize) screenSize;
+
+- (Time) lastClick;
+- (Time) lastTime;
+@end
+
+@interface GSInputDevice (XInput)
+- (void) selectXExtensionEventForWindow:(Window)win;
+- (NSEvent*) mouseEventForXDeviceMotionEvent: (XDeviceMotionEvent *)motion
+							   modifierFlags: (unsigned int)flags
+								windowDevice: (gswindow_device_t *)gswindow
+									 context: (NSGraphicsContext*)context
+								  clickCount: (int)clickNum
+								buttonNumber: (int)buttonNum;
+@end
+
+
+#endif
+
Index: Headers/x11/XGServer.h
===================================================================
--- Headers/x11/XGServer.h	(revision 31820)
+++ Headers/x11/XGServer.h	(working copy)
@@ -35,6 +35,11 @@
 #include <X11/Xutil.h>
 #include "x11/XGGeneric.h"
 
+#ifdef USE_XINPUT
+#include <X11/extensions/XInput.h>
+@class GSInputDevice;
+#endif
+
 /*
  * Enumerated type to say how we should draw pixels to the X display - used
  * to select different drawing mechanisms to try to optimise.
@@ -56,6 +61,12 @@
   Window	    grabWindow;
   struct XGGeneric  generic;
   id                inputServer;
+#ifdef USE_XINPUT
+  XDeviceInfo *_xidev_info_list;
+  int _num_xidevs;
+  GSInputDevice **_xidevs;
+  BOOL (**procXInputEvent)(id, SEL, XEvent *);
+#endif
 }
 
 + (Display*) currentXDisplay;
_______________________________________________
Gnustep-dev mailing list
Gnustep-dev@gnu.org
http://lists.gnu.org/mailman/listinfo/gnustep-dev

Reply via email to