updated!

2011/1/24 Banlu Kemiyatorn <obj...@gmail.com>:
> Sleepiness!
>
> On Mon, Jan 24, 2011 at 3:41 AM, Banlu Kemiyatorn <obj...@gmail.com> wrote:
>> Hi,
>> This is a patch to enable xinput2 support which is incomplete but it
>> turns on tilt and pressure. I am not going to finish it for a while
>> but still suggest to have it reviewed and maintained in trunk so
>> someone may have enough interest to fix and finish and improve it to
>> support other devices. I don't have enough gut to work on this alone
>> anymore.
>>
>> need --enable-xinput2 to get it working.
>>
>> * The patch has only been tested with Wacom Intuos 4
>> * Proximity is not working nor planned, I don't know how to get it
>> working since my Intuos 4 device didn't provide any axis for it in
>> xinput2 driver. It works in xinput1 though. If someone want it I'd
>> suggest you to add that to xorg instead rather implementing support
>> for xinput1.
>> * GSInputEvent, a subclass of NSEvent which I'd like to use it to
>> support special devices. I also want to expose GSInputDevice and
>> GSInputDeviceServer's interfaces and have it working with Windows'
>> drivers but I don't use Windows or have it here.
>>
>> --
>>     .----.     Banlu Kemiyatorn
>>   /.../\...\   漫画家
>>  |.../  \...|  http://qstx.blogspot.com (Free Software Advocacy & 
>> Development)
>>  |../    \..|  http://feedbat.blogspot.com (Studio Work For Hire)
>>   \/      \/   http://groundzerostudiocomplex.blogspot.com (Studio Research)
>>
>
>
>
> --
>    .----.     Banlu Kemiyatorn
>  /.../\...\   漫画家
>  |.../  \...|  http://qstx.blogspot.com (Free Software Advocacy & Development)
>  |../    \..|  http://feedbat.blogspot.com (Studio Work For Hire)
>  \/      \/   http://groundzerostudiocomplex.blogspot.com (Studio Research)
>



-- 
    .----.     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 31909)
+++ 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 31909)
+++ Source/x11/XGServerWindow.m	(working copy)
@@ -63,6 +63,11 @@
 #include "x11/XGDragView.h"
 #include "x11/XGInputServer.h"
 
+#ifdef USE_XINPUT
+/* should be public interface for GSInputServer */
+#include "x11/XGXI.h"
+#endif
+
 #define	ROOT generic.appRootWindow
 
 
@@ -1962,13 +1967,15 @@
   /* Set the X event mask
    */
   XSelectInput(dpy, window->ident, ExposureMask
+    | StructureNotifyMask
+#ifndef USE_XINPUT
     | KeyPressMask
     | KeyReleaseMask
     | ButtonPressMask
     | ButtonReleaseMask
     | ButtonMotionMask
-    | StructureNotifyMask
     | PointerMotionMask
+#endif
     | EnterWindowMask
     | LeaveWindowMask
     | FocusChangeMask
@@ -1979,6 +1986,12 @@
     | VisibilityChangeMask
     );
 
+#ifdef USE_XINPUT
+  //FIXME
+  [xInputServer selectEventsOfUseType:GSInputMasterPointer forWindowDevice:window];
+  [xInputServer selectEventsOfUseType:GSInputMasterKeyboard forWindowDevice:window];
+#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 31909)
+++ 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,12 @@
   [self _setupRootWindow];
   inputServer = [[XIMInputServer allocWithZone: [self zone]] 
                   initWithDelegate: nil display: dpy name: @"XIM"];
+
+#ifdef USE_XINPUT
+  xInputServer = [[GSInputDeviceServer allocWithZone: [self zone]]
+		initWithDisplayServer:self screen:defScreen];
+#endif
+
   return self;
 }
 
@@ -478,6 +488,7 @@
 - (void) dealloc
 {
   NSDebugLog(@"Destroying X11 Server");
+
   DESTROY(inputServer);
   [self _destroyServerWindows];
   NSFreeMapTable(screenList);
Index: Source/x11/XGServerEvent.m
===================================================================
--- Source/x11/XGServerEvent.m	(revision 31909)
+++ 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)
@@ -98,6 +104,11 @@
 static SEL procSel = 0;
 static void (*procEvent)(id, SEL, XEvent*) = 0;
 
+#ifdef USE_XINPUT
+static SEL gsxiProcSel = 0;
+static BOOL (*gsxiProcEvent)(id, SEL, XEvent*) = 0;
+#endif
+
 #ifdef XSHM
 @interface NSGraphicsContext (SharedMemory)
 -(void) gotShmCompletion: (Drawable)d;
@@ -257,6 +268,15 @@
       procEvent = (void (*)(id, SEL, XEvent*))
         [self methodForSelector: procSel];
     }
+
+#ifdef USE_XINPUT
+  if (gsxiProcSel == 0)
+    {
+      gsxiProcSel = @selector(processEvent:);
+      gsxiProcEvent = (BOOL (*)(id, SEL, XEvent*))
+        [xInputServer methodForSelector: gsxiProcSel];
+    }
+#endif
 }
 
 #if LIB_FOUNDATION_LIBRARY
@@ -299,6 +319,8 @@
     {
       XNextEvent(dpy, &xEvent);
 
+//NSLog(@"%d", xEvent.type);
+
 #ifdef USE_XIM
       if (XFilterEvent(&xEvent, None)) 
         {
@@ -307,7 +329,11 @@
         }
 #endif
 
-      (*procEvent)(self, procSel, &xEvent);
+#ifdef USE_XINPUT
+	if (!(*gsxiProcEvent)(xInputServer, procSel, &xEvent))
+#endif
+	  (*procEvent)(self, procSel, &xEvent);
+
     }
 }
 
Index: Source/x11/XGXI.m
===================================================================
--- Source/x11/XGXI.m	(revision 0)
+++ Source/x11/XGXI.m	(revision 0)
@@ -0,0 +1,981 @@
+/*
+   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"
+
+static Atom gsxiInputLabel[GSInputAxisTypeLast];
+
+/*
+static double gsxiValuatorValueOfTypeOnDevice(
+		XIValuatorState *state,
+	       	GSInputAxisType type,
+		GSInputDevice *device)
+{
+	if ((type >> 3) <= state->mask_len && XIMaskIsSet(state->mask,type))
+	{
+		device->_vClassOrder[type]
+	}
+	return 0.
+}
+*/
+
+/*
+static void gsxiEventGroupAppendDevice(GSXIEventGroup *aGroup ,GSInputDevice *aDevice)
+{
+	if (aGroup->deviceList == NULL)
+	{
+		aGroup->deviceList = (GSInputDevice **)malloc(sizeof(void *) * 2);
+		aGroup->deviceList[0] = aDevice;
+		aGroup->deviceList[1] = NULL;
+		return;
+	}
+
+	int n;
+	for (n = 1; aGroup->deviceList[n] != NULL; n++);
+
+	aGroup->deviceList = (GSInputDevice **)realloc(aGroup->deviceList, sizeof(void *) * (n + 2));
+	aGroup->deviceList[n] = aDevice;
+	aGroup->deviceList[n+1] = NULL;
+}
+*/
+
+static NSString* gsxiNameOfXIEventType(int evtype)
+{
+	switch (evtype)
+	{
+		case XI_DeviceChanged:
+			return @"DeviceChanged";       
+		case XI_KeyPress:
+			return @"KeyPress";            
+		case XI_KeyRelease:
+			return @"KeyRelease";          
+		case XI_ButtonPress:
+			return @"ButtonPress";         
+		case XI_ButtonRelease:
+			return @"ButtonRelease";       
+		case XI_Motion:
+			return @"Motion";              
+		case XI_Enter:
+			return @"Enter";               
+		case XI_Leave:
+			return @"Leave";               
+		case XI_FocusIn:
+			return @"FocusIn";             
+		case XI_FocusOut:
+			return @"FocusOut";            
+		case XI_HierarchyChanged:
+			return @"HierarchyChanged";    
+		case XI_PropertyEvent:
+			return @"PropertyEvent";       
+		case XI_RawKeyPress:
+			return @"RawKeyPress";         
+		case XI_RawKeyRelease:
+			return @"RawKeyRelease";       
+		case XI_RawButtonPress:
+			return @"RawButtonPress";      
+		case XI_RawButtonRelease:
+			return @"RawButtonRelease";    
+		case XI_RawMotion:
+			return @"RawMotion";           
+		default:
+			return @"Unknow type";
+	}
+}
+
+static GSInputAxisType gsxiTypeOfLabelAtom(Atom label)
+{
+	int n;
+	for (n = GSInputAxisTypeNone + 1; n < GSInputAxisTypeLast; n++)
+	{
+		if (gsxiInputLabel[n] == label)
+			return n;
+	}
+
+	return GSInputAxisTypeNone;
+}
+
+static NSString * gsxiNameOfUseType(GSInputUseType type)
+{
+	switch (type)
+	{
+		case GSInputMasterPointer:
+			return @"Master Pointer";
+			break;
+		case GSInputMasterKeyboard:
+			return @"Master Keyboard";
+			break;
+		case GSInputSlavePointer:
+			return @"Slave Pointer";
+			break;
+		case GSInputSlaveKeyboard:
+			return @"Slave Keyboard";
+			break;
+		case GSInputFloatingSlave:
+			return @"Floating Slave";
+			break;
+	}
+	return @"Unknown Use";
+}
+
+static NSString * gsxiNameOfAxisType(GSInputAxisType type)
+{
+	switch (type)
+	{
+		case GSInputAxisTypeNone:
+			return @"No Type";
+		case GSInputAxisTypeX:
+			return @"Abs X";
+		case GSInputAxisTypeY:
+			return @"Abs Y";
+		case GSInputAxisTypePressure:
+			return @"Abs Pressure";
+		case GSInputAxisTypeTiltX:
+			return @"Abs Tilt X";
+		case GSInputAxisTypeTiltY:
+			return @"Abs Tilt Y";
+		case GSInputAxisTypeWheel:
+			return @"Abs Wheel";
+
+	}
+	return @"Unknown Type";
+}
+
+
+/* FIXME this should fill gs_input_device_state_t */
+
+static NSUInteger gsxiGetButtonSetEventTypeAndFlagForDeviceEvent(
+		GSInputDevice *device,
+		NSEventType *eventType,
+		NSUInteger *eventFlags,
+		XIDeviceEvent *event)
+{
+	NSUInteger retButton;
+
+	*eventFlags = 0;
+	unsigned int len = event->buttons.mask_len;
+
+	if (len == 0)
+	{
+		*eventType = NSMouseMoved;
+		retButton = 0;
+	}
+	else if (XIMaskIsSet (event->buttons.mask, 0))
+	{
+		*eventType = NSMouseMoved;
+		retButton = 0;
+		NSLog(@"000 set?");
+	}
+	else if (XIMaskIsSet (event->buttons.mask, 1))
+	{
+		*eventType = NSLeftMouseDragged;
+		retButton = 1;
+	}
+	else if (XIMaskIsSet (event->buttons.mask, 2))
+	{
+		*eventType = NSOtherMouseDragged;
+		retButton = 2;
+	}
+	else if (XIMaskIsSet (event->buttons.mask, 3))
+	{
+		*eventType = NSRightMouseDragged;
+		retButton = 3;
+	}
+	else
+	{
+		int i;
+/*		len = MIN(len * 8, device->_num_buttons); */ /* could it be that new button just appear at the runtime? */
+		len *= 8;
+		for (i = 4 ; i < len; i++)
+		{
+			if (XIMaskIsSet (event->buttons.mask, i))
+			{
+				*eventType = NSOtherMouseDragged;
+				retButton = i;
+				break;
+			}
+		}
+
+		if (i == len)
+		{
+			*eventType = NSMouseMoved;
+			retButton = 0;
+		}
+	}
+
+	/* FIXME event->mods */
+	*eventFlags = event->mods.effective;
+
+	return retButton;
+}
+
+@implementation GSInputEvent
+- (NSUInteger) deviceID
+{
+	return [_device deviceid];
+}
+
+- (NSUInteger) pointingDeviceID
+{
+	return _sourceid;
+}
+
+- (NSPoint) tilt
+{
+	return _tilt;
+}
+
+- (NSPoint) tits
+{
+	NSLog(@"Warning: Typo detected.");
+	return [self tilt];
+}
+@end
+
+@implementation GSInputDeviceServer
+
+static int RESERVED_XIDEV = 2;
+static int xi_opcode = 0;
+
+- (id) initWithDisplayServer:(XGServer *)server screen:(int)screen
+{
+	_xgServer = server;
+	_dpy = [server xDisplay];
+
+	int major = XI_2_Major,
+	    minor = XI_2_Minor;
+
+	int fev,fer;
+	if (!XQueryExtension(_dpy, "XInputExtension", &xi_opcode ,&fev, &fer)) {
+		NSLog(@"X Input extension not available.");
+		RELEASE(self);
+		return nil;
+	}
+
+	if (XIQueryVersion(_dpy, &major, &minor) != Success ||
+			(major * 1000 + minor) < (XI_2_Major * 1000 + XI_2_Minor))
+	{
+		NSLog(@"XI2 Version not supported.\n");
+		RELEASE(self);
+		return nil;
+	}
+
+	/* create handlers */
+	_xidInfoList = XIQueryDevice(_dpy, XIAllDevices, &_num_xidev);
+
+	if (_num_xidev > 0)
+		RESERVED_XIDEV = _xidInfoList->deviceid;
+	else
+	{
+		NSLog(@"XI2 No Device.\n");
+		RELEASE(self);
+		return nil;
+	}
+
+	int n;
+	for (n = GSInputAxisTypeNone + 1; n < GSInputAxisTypeLast; n++)
+	{
+		gsxiInputLabel[n] = XInternAtom(_dpy, [gsxiNameOfAxisType(n) cString], NO);
+	}
+
+	_num_xidev += RESERVED_XIDEV;
+
+	_xidevs = malloc(sizeof(void *) * _num_xidev);
+	memset(_xidevs, 0, _num_xidev * sizeof(void *));
+
+	for (n = RESERVED_XIDEV; n < _num_xidev; n++)
+	{
+		_xidevs[n] = [[GSInputDevice alloc] initWithDeviceInfo:&_xidInfoList[n - RESERVED_XIDEV]
+			screen:screen
+			proximity:YES
+			inputServer:self];
+
+		if (_xidevs[n] != nil)
+		{
+			[_xidevs[n] setScreenSize:
+				NSMakeSize(DisplayWidth(_dpy, screen),
+					   DisplayHeight(_dpy, screen))];
+		}
+	}
+
+
+	return self;
+}
+
+- (void) dealloc
+{
+	int n;
+	for (n = RESERVED_XIDEV; n < _num_xidev; n++)
+	{
+		DESTROY(_xidevs[n]);
+	}
+
+	free(_xidevs);
+	_xidevs = NULL;
+
+	XIFreeDeviceInfo(_xidInfoList);
+
+	[super dealloc];
+}
+
+/* FIXME - should register only for certain devices */
+/*
+- (void) selectAllCoreEventsForWindowDevice:(gswindow_device_t *)windev
+{
+	int n;
+	for (n = RESERVED_XIDEV; n < _num_xidev; n++)
+	{
+		[_xidevs[n] selectAllExtensionEventsForWindowDevice:windev];
+	}
+}
+*/
+
+- (void) selectEventsOfUseType:(GSInputUseType)useType
+	forWindowDevice:(gswindow_device_t *)windev
+{
+	int n;
+	for (n = RESERVED_XIDEV; n < _num_xidev; n++)
+	{
+		if ([_xidevs[n] useType] == useType)
+			[_xidevs[n] selectAllExtensionEventsForWindowDevice:windev];
+	}
+}
+
+- (BOOL) processEvent:(XEvent *)xev
+{
+
+	/*
+	if (xev->type == gsxiMotionGroup.type && gsxiMotionGroup.deviceList != NULL)
+	{
+		XDeviceMotionEvent *motion = (XDeviceMotionEvent *)xev;
+
+		GSInputDevice *device = _xidevs[motion->deviceid];
+
+	}
+	*/
+
+	XGenericEventCookie *cookie = &xev->xcookie;
+	if (XGetEventData(_dpy, cookie) &&
+			cookie->type == GenericEvent &&
+			cookie->extension == xi_opcode)
+	{
+		XIDeviceEvent *event = cookie->data;
+		GSInputDevice *device = _xidevs[event->sourceid];
+		GSInputEvent *e = nil;
+
+		switch (cookie->evtype)
+		{
+			case XI_DeviceChanged:
+				break;
+			case XI_HierarchyChanged:
+				break;
+			case XI_ButtonPress:
+			case XI_ButtonRelease:
+				e = [device processButtonEvent:event];
+				break;
+			case XI_RawKeyPress:
+			case XI_RawKeyRelease:
+			case XI_RawButtonPress:
+			case XI_RawButtonRelease:
+			case XI_RawMotion:
+				break;
+			case XI_Motion:
+				/* processMotionEvent: */
+				e = (*device->_gsxiMotionProcEvent)(device, device->_gsxiMotionProcSel, event);
+				break;
+			case XI_Enter:
+			case XI_Leave:
+			case XI_FocusIn:
+			case XI_FocusOut:
+				break;
+			case XI_PropertyEvent:
+				break;
+			default:
+				NSLog(@"eh %d",cookie->evtype);
+				break;
+		}
+
+		XFreeEventData(_dpy, cookie);
+
+		if (e != nil)
+		{
+			e->_sourceid = event->sourceid;
+			[_xgServer postEvent:e atStart:NO];
+		}
+
+		return YES;
+
+
+	}
+	else XFreeEventData(_dpy, cookie);
+
+	return NO;
+}
+@end
+
+@implementation GSInputDevice
+
+#define GS_XINPUT_DEVICE_INVALID_TYPE -1
+
+
+/*
+BOOL gsxiProcessMotionEventForDevice(XEvent *ev, GSInputDevice *device)
+{
+	return NO;
+}
+*/
+
+/*
+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:(XIDeviceInfo *)info
+	screen:(int)screen
+	proximity:(BOOL)willHandleProximity
+	inputServer:(GSInputDeviceServer *)xiServer
+{
+	_xidInfo = info;
+
+	/* we should only need this for motion, shouldn't we? */
+	_gsxiMotionProcSel = @selector(processMotionEvent:);
+	_gsxiMotionProcEvent = (NSEvent * (*)(id, SEL, XEvent*))
+		[self methodForSelector: _gsxiMotionProcSel];
+
+	_dpy = xiServer->_dpy;
+	_screenNo = screen;
+
+	XIAnyClassInfo **classes = info->classes;
+	int numClass = info->num_classes;
+	int i,j;
+
+	for (i = 0; i < numClass; i++)
+	{
+		switch (classes[i]->type)
+		{
+			case XIButtonClass:
+				{
+					XIButtonClassInfo *bInfo = (XIButtonClassInfo*)classes[i];
+					char *name;
+
+					_num_buttons = bInfo->num_buttons;
+					_buttonStates = malloc(sizeof(gs_input_device_state_t) * _num_buttons);
+					memset(_buttonStates, 0, sizeof(gs_input_device_state_t) * _num_buttons);
+
+					for (j = 0; j < bInfo->num_buttons; j++)
+					{
+						if (bInfo->labels[j])
+						{
+							name = XGetAtomName(_dpy, bInfo->labels[j]);
+							_buttonStates[j].name = [[NSString alloc] initWithCString:name encoding:NSISOLatin1StringEncoding];
+							XFree(name);
+						}
+						else _buttonStates[j].name = @"None";
+					}
+
+					for (j = 0; j < bInfo->state.mask_len * 8; j++)
+					{
+						if (XIMaskIsSet(bInfo->state.mask, j))
+						{
+							_buttonStates[j].state = YES;
+						}
+					}
+				}
+
+				break;
+			case XIKeyClass:
+				break;
+			case XIValuatorClass:
+				{
+					XIValuatorClassInfo *vInfo = (XIValuatorClassInfo*)classes[i];
+					GSInputAxisType type = gsxiTypeOfLabelAtom(vInfo->label);
+
+					if (vInfo->number + 1 > _vMax)
+					{
+						_vMax = vInfo->number + 1;
+						_vClassOrder = realloc(_vClassOrder, sizeof(int) * _vMax);
+					}
+
+					_vClassOrder[vInfo->number] = type;
+
+					switch (type)
+					{
+						case GSInputAxisTypeNone:
+							break;
+						case GSInputAxisTypeX:
+							_areaX = vInfo->min;
+							_areaW = vInfo->max - vInfo->min;
+							break;
+						case GSInputAxisTypeY:
+							_areaY = vInfo->min;
+							_areaH = vInfo->max - vInfo->min;
+							break;
+						case GSInputAxisTypePressure:
+							_pressMin = vInfo->min;
+							_pressMax = vInfo->max;
+							break;
+						case GSInputAxisTypeTiltX:
+							_tiltXMin = vInfo->min;
+							_tiltXMax = vInfo->max;
+							break;
+						case GSInputAxisTypeTiltY:
+							_tiltYMin = vInfo->min;
+							_tiltYMax = vInfo->max;
+							break;
+						case GSInputAxisTypeWheel:
+							_wheelMin = vInfo->min;
+							_wheelMax = vInfo->max;
+							break;
+					}
+				}
+				break;
+		}
+	}
+
+	return self;
+}
+
+- (void) dealloc
+{
+	/*
+	if (_xdevice)
+	{
+		XCloseDevice(_dpy,_xdevice);
+	}
+	*/
+	free(_vClassOrder);
+	if (_buttonStates)
+	{
+		int n;
+		for (n = 0; n < _num_buttons; n++)
+		{
+			DESTROY(_buttonStates[n].name);
+		}
+		free(_buttonStates);
+	}
+	[super dealloc];
+}
+
+- (GSInputUseType) useType
+{
+	return _xidInfo->use;
+}
+
+- (void) selectAllExtensionEventsForWindowDevice:(gswindow_device_t *)windev
+{
+//	gswindow_device_t *windev = [XGServer _windowWithTag:[win windowNum]];
+
+	XIEventMask eventMask;
+	eventMask.deviceid = _xidInfo->deviceid;
+	eventMask.mask_len = XIMaskLen(XI_LASTEVENT);
+	eventMask.mask = calloc(eventMask.mask_len, sizeof(char));
+
+	XISetMask(eventMask.mask, XI_ButtonPress);
+	XISetMask(eventMask.mask, XI_ButtonRelease);
+	XISetMask(eventMask.mask, XI_Motion);
+	XISetMask(eventMask.mask, XI_KeyPress);
+	XISetMask(eventMask.mask, XI_KeyRelease);
+	XISetMask(eventMask.mask, XI_Enter);
+	XISetMask(eventMask.mask, XI_Leave);
+	XISetMask(eventMask.mask, XI_FocusIn);
+	XISetMask(eventMask.mask, XI_FocusOut);
+	XISetMask(eventMask.mask, XI_PropertyEvent);
+
+	XISelectEvents(_dpy, windev->ident, &eventMask, 1);
+	free(eventMask.mask);
+}
+
+- (NSString *) description
+{
+//	return [NSString stringWithFormat:@"%d : %@ frame:%@ pressure:%@ tilt:%@",[self deviceID],[self name],NSStringFromRect(_area),NSStringFromRange(_pressure),NSStringFromRect(_tiltArea)];
+	return @"doh";
+}
+
+- (int) deviceID
+{
+	return _xidInfo->deviceid;
+}
+
+- (NSString *) name
+{
+	return [NSString stringWithCString:_xidInfo->name];
+}
+
+- (BOOL) isExtensionDevice
+{
+	return NO;
+//	return (_use == IsXExtensionDevice);
+}
+
+- (BOOL) isPointer
+{
+	return NO;
+	//return (_use == IsXPointer);
+}
+
+- (BOOL) isKeyboard
+{
+	return NO;
+	//return (_use == IsXKeyboard);
+}
+
+- (BOOL) hasButton
+{
+	//NYI
+	return 0;
+}
+
+- (int) numberOfButtons
+{
+	//NYI
+	return 0;
+}
+
+- (BOOL) hasKey
+{
+	//NYI
+	return 0;
+}
+
+- (int) numberOfKeys
+{
+	//NYI
+	return 0;
+}
+
+- (int) minKeycode
+{
+	//NYI
+	return 0;
+}
+
+- (int) maxKeycode
+{
+	//NYI
+	return 0;
+}
+
+- (void) setHandleProximity:(BOOL)prox
+{
+	_handleProx = prox;
+}
+
+- (BOOL) willHandleProximity
+{
+	return _handleProx;
+}
+
+
+- (BOOL) hasAxis
+{
+	//NYI
+	return 0;
+}
+
+- (int) numberOfAxes
+{
+	//NYI
+	return 0;
+}
+
+- (BOOL) isRelative
+{
+	//NYI
+	return 0;
+}
+
+- (int) motionBuffer
+{
+	//NYI
+	return 0;
+}
+
+- (int) minValueForAxis:(int)axis
+{
+	//NYI
+	return 0;
+}
+
+- (int) maxValueForAxis:(int)axis
+{
+	//NYI
+	return 0;
+}
+
+- (int) resolutionForAxis:(int)axis
+{
+	//NYI
+	return 0;
+}
+
+- (void) setScreenSize:(NSSize)size
+{
+	_screenSize = size;
+	/*
+	_resV = _areaH/size.height;
+	_resH = _areaW/size.width;
+	*/
+}
+
+- (NSSize) screenSize
+{
+	return _screenSize;
+}
+
+- (NSEvent *) processButtonEvent:(XIDeviceEvent*)button
+{
+	NSUInteger pressButton;
+	NSUInteger eventFlags;
+
+	NSEventType eventType;
+	int evtype = button->evtype; /* must be XI_ButtonPress or Release */
+
+	unsigned int len = button->buttons.mask_len;
+	NSUInteger buttonNo = button->detail;
+
+	switch (buttonNo)
+	{
+		case 1:
+			eventType = (evtype == XI_ButtonPress ? NSLeftMouseDown : NSLeftMouseUp);
+			break;
+		case 3:
+			eventType = (evtype == XI_ButtonPress ? NSRightMouseDown : NSRightMouseUp);
+			break;
+		default:
+			eventType = (evtype == XI_ButtonPress ? NSOtherMouseDown : NSOtherMouseUp);
+			break;
+	}
+
+	/* FIXME event->mods */
+	eventFlags = button->mods.effective;
+
+	if (_gswindow == NULL || _lastWindow != button->event)
+	{
+		_gswindow = [XGServer _windowForXWindow:button->event];
+
+		if (_gswindow == NULL)
+		{
+			return nil;
+		}
+	}
+
+	NSPoint eventLocation;
+	double pressure = (evtype == XI_ButtonPress ? 1.0 : 0.0);
+	double tiltX,tiltY;
+
+	eventLocation.x = button->event_x;
+	eventLocation.y = NSHeight(_gswindow->xframe) - button->event_y;
+
+	len = MIN(_vMax, button->valuators.mask_len * 8);
+	double *value = button->valuators.values;
+
+	int i;
+	for (i = 0; i < len; i++)
+	{
+		if (XIMaskIsSet(button->valuators.mask, i))
+		{
+			switch(_vClassOrder[i])
+			{
+				case GSInputAxisTypeX:
+					break;
+				case GSInputAxisTypeY:
+					break;
+				case GSInputAxisTypePressure:
+					pressure = *value;
+
+					/* this is for dealing with buggy driver
+					if (pressure < _pressMin) _pressMin = pressure;
+					else if (pressure > _pressMax) _pressMax = pressure;
+					*/
+
+					double pressLen = _pressMax - _pressMin;
+
+					if (pressLen > 0)
+					{
+						pressure = (pressure - _pressMin) / pressLen;
+					}
+					else
+					{
+						pressure = 1.0;
+					}
+
+					break;
+				case GSInputAxisTypeTiltX:
+					tiltX = *value;
+					tiltX /= _tiltXMax;
+					break;
+				case GSInputAxisTypeTiltY:
+					tiltY = *value;
+					tiltY /= _tiltYMax;
+					break;
+				case GSInputAxisTypeWheel:
+					break;
+				case GSInputAxisTypeNone:
+				default:
+					break;
+			}
+
+			value++;
+		}
+	}
+
+	_lastLocation = eventLocation;
+
+	GSInputEvent *nsevent = [GSInputEvent mouseEventWithType: eventType
+		location: eventLocation
+		modifierFlags: 0
+		timestamp: button->time
+		windowNumber: _gswindow->number
+		context: GSCurrentContext()
+		eventNumber: button->serial
+		clickCount: _clickCount
+		pressure: pressure
+		buttonNumber: buttonNo
+		deltaX: 0
+		deltaY: 0
+		deltaZ: 0.];
+
+	nsevent->_tilt = NSMakePoint(tiltX,tiltY);
+
+	return nsevent;
+}
+
+- (NSEvent *) processMotionEvent:(XIDeviceEvent*)motion
+{
+	if (_gswindow == NULL || _lastWindow != motion->event)
+	{
+		/* FIXME this api should be cleaned up? if XGServer suppose to act like a singleton for many displays? */
+		_gswindow = [XGServer _windowForXWindow:motion->event];
+	}
+
+	if (_gswindow == NULL)
+	{
+		return nil; /* Hmmm how about root window event? */
+	}
+
+
+	NSEventType eventType;
+	NSUInteger eventFlags;
+	NSUInteger buttonNo;
+
+	buttonNo = gsxiGetButtonSetEventTypeAndFlagForDeviceEvent(self, &eventType, &eventFlags, motion);
+
+	/* TODO if the event parsing found that the valuator order is static for the event type, it could subsitute _gsxiMotionProcEvent with another simpler one */
+
+	NSPoint eventLocation;
+	CGFloat deltaX,deltaY;
+	double pressure;
+	double tiltX,tiltY;
+
+	if (eventType == NSLeftMouseDragged || eventType == NSRightMouseDragged || eventType == NSOtherMouseDragged)
+	{
+		pressure = 1.0;
+	}
+	else pressure = 0.0;
+
+	eventLocation.x = motion->event_x;
+	eventLocation.y = NSHeight(_gswindow->xframe) - motion->event_y;
+
+	int i;
+	int len = MIN(_vMax, motion->valuators.mask_len * 8);
+	double *value = motion->valuators.values;
+
+	for (i = 0; i < len; i++)
+	{
+		if (XIMaskIsSet(motion->valuators.mask, i))
+		{
+			switch(_vClassOrder[i])
+			{
+				case GSInputAxisTypeX:
+					break;
+				case GSInputAxisTypeY:
+					break;
+				case GSInputAxisTypePressure:
+					pressure = *value;
+					/*
+					if (pressure < _pressMin) _pressMin = pressure;
+					else if (pressure > _pressMax) _pressMax = pressure;
+					*/
+					double pressLen = _pressMax - _pressMin;
+
+					if (pressLen > 0)
+					{
+						pressure = (pressure - _pressMin) / pressLen;
+					}
+					else
+					{
+						pressure = 1.0;
+					}
+
+					break;
+				case GSInputAxisTypeTiltX:
+					tiltX = *value;
+					tiltX /= _tiltXMax;
+					break;
+				case GSInputAxisTypeTiltY:
+					tiltY = *value;
+					tiltY /= _tiltYMax;
+					break;
+				case GSInputAxisTypeWheel:
+					break;
+				case GSInputAxisTypeNone:
+				default:
+					break;
+			}
+
+			value++;
+		}
+	}
+
+	deltaX = eventLocation.x - _lastLocation.x;
+	deltaY = _lastLocation.y - eventLocation.y;
+
+	_lastLocation = eventLocation;
+
+	GSInputEvent *nsevent = [GSInputEvent mouseEventWithType: eventType
+		location: eventLocation
+		modifierFlags: 0
+		timestamp: motion->time
+		windowNumber: _gswindow->number
+		context: GSCurrentContext()
+		eventNumber: motion->serial
+		clickCount: _clickCount
+		pressure: pressure
+		buttonNumber: buttonNo
+		deltaX: deltaX
+		deltaY: deltaY
+		deltaZ: 0.];
+	nsevent->_tilt = NSMakePoint(tiltX,tiltY);
+
+	return nsevent;
+}
+
+@end
+
+
Index: config.h.in
===================================================================
--- config.h.in	(revision 31909)
+++ 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 31909)
+++ configure.ac	(working copy)
@@ -285,6 +285,24 @@
 fi
 
 #--------------------------------------------------------------------
+# XInput support
+#--------------------------------------------------------------------
+AC_ARG_ENABLE(xinput2,
+  [  --enable-xinput2        Enable XInput2 support],enable_xinput2=yes,)
+
+PKG_XI=no
+PKG_CHECK_MODULES(XI, xi, have_xi=yes, have_xi=no)
+
+if test "x$enable_xinput2" = "xyes"; then
+  if test "$have_xi" = no; then
+    AC_MSG_WARN([cannot find xi!])
+  else
+    XI_LIBS="-lXi"
+    AC_DEFINE(USE_XINPUT,1,[Define to enable XInput2 support])
+  fi
+fi
+
+#--------------------------------------------------------------------
 # Functions
 #--------------------------------------------------------------------
 AC_HAVE_FUNCS(usleep)
@@ -594,6 +612,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_xinput2" = "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,215 @@
+/*
+   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/XInput2.h>
+#include <X11/Xutil.h>
+#include "config.h"
+#include "x11/XGServerWindow.h"
+
+#include <AppKit/NSEvent.h>
+
+
+#define GS_XINPUT_DEVICE_MAX_CLASSES 13
+
+/* expose this FIXME */
+typedef enum _GSInputAxisType
+{
+	GSInputAxisTypeNone,
+	GSInputAxisTypeX,
+	GSInputAxisTypeY,
+	GSInputAxisTypePressure,
+	GSInputAxisTypeTiltX,
+	GSInputAxisTypeTiltY,
+	GSInputAxisTypeWheel,
+	//GSInputAxisTypeProximity,
+	GSInputAxisTypeLast
+} GSInputAxisType;
+
+typedef enum _GSInputUseType
+{
+	GSInputMasterPointer =  XIMasterPointer,
+	GSInputMasterKeyboard = XIMasterKeyboard,
+	GSInputSlavePointer = XISlavePointer,
+	GSInputSlaveKeyboard = XISlaveKeyboard,
+	GSInputFloatingSlave = XIFloatingSlave,
+} GSInputUseType;
+
+typedef struct _gs_input_device_state_t
+{
+	BOOL state;
+	NSString *name;
+	Time lastClick;
+	NSPoint lastClickPoint;
+	Window lastClickWindow;
+
+	Time clickTime;
+	float clickSlip;
+} gs_input_device_state_t;
+
+
+@class GSInputDevice;
+@interface GSInputEvent : NSEvent
+{
+	@public
+	GSInputDevice *_device;
+	int _sourceid;
+	NSPoint _tilt;
+}
+@end
+
+@class GSInputDeviceServer;
+
+@interface GSInputDevice : NSObject
+{
+@public
+	XGServer *_xgServer;
+	Display *_dpy;
+	int _screenNo;
+
+	int _num_buttons;
+	gs_input_device_state_t *_buttonStates;
+
+	NSPoint _lastLocation;
+
+	int _clickCount;
+
+	SEL _gsxiMotionProcSel;
+	NSEvent * (*_gsxiMotionProcEvent)(id, SEL, XEvent*);
+
+@private
+	BOOL _isEnable;
+
+	unsigned int (*_getState)(id, SEL, unsigned int);
+	Window _lastWindow;
+	gswindow_device_t *_gswindow;
+
+	BOOL _handleProx;
+
+	NSSize _screenSize;
+
+	int *_vClassOrder; /* valuator class order */
+	int _vMax; /* maximum valuator number */
+
+	double _areaX;
+	double _areaY;
+	double _areaW;
+	double _areaH;
+
+	double _tiltXMin;
+	double _tiltXMax;
+	double _tiltYMin;
+	double _tiltYMax;
+
+	double _pressMin;
+	double _pressMax;
+
+	double _wheelMin;
+	double _wheelMax;
+
+//	float _resV,_resH;
+
+	int _use;
+
+	XIDeviceInfo *_xidInfo;
+}
+
+
+- (id) initWithDeviceInfo:(XIDeviceInfo *)info
+	screen:(int)screen
+	proximity:(BOOL)willHandleProximity
+	inputServer:(GSInputDeviceServer *)xiServer;
+- (NSString *) description;
+- (GSInputUseType) useType;
+
+
+/***/
+- (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;
+@end
+
+/*
+typedef struct _GSXIEventGroup
+{
+	int type;
+	GSInputDevice **deviceList;
+} GSXIEventGroup;
+*/
+
+@interface GSInputDeviceServer : NSObject
+{
+	XIDeviceInfo *_xidInfoList;
+	GSDisplayServer *_xgServer;
+@public
+	int _num_xidev;
+	GSInputDevice **_xidevs;
+	Display *_dpy;
+
+/*
+	GSXIEventGroup gsxiMotionGroup;
+	GSXIEventGroup gsxiButtonPressGroup;
+	GSXIEventGroup gsxiButtonReleaseGroup;
+	GSXIEventGroup gsxiKeyPressGroup;
+	GSXIEventGroup gsxiKeyReleaseGroup;
+	GSXIEventGroup gsxiProximityInGroup;
+	GSXIEventGroup gsxiProximityOutGroup;
+*/
+}
+- (id) initWithDisplayServer:(XGServer *)server screen:(int)screen;
+- (BOOL) processEvent:(XEvent *)xevent;
+@end
+
+
+#endif
Index: Headers/x11/XGServer.h
===================================================================
--- Headers/x11/XGServer.h	(revision 31909)
+++ 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,9 @@
   Window	    grabWindow;
   struct XGGeneric  generic;
   id                inputServer;
+#ifdef USE_XINPUT
+  id                xInputServer;
+#endif
 }
 
 + (Display*) currentXDisplay;
_______________________________________________
Gnustep-dev mailing list
Gnustep-dev@gnu.org
http://lists.gnu.org/mailman/listinfo/gnustep-dev

Reply via email to