Sleepiness!
On Mon, Jan 24, 2011 at 3:41 AM, Banlu Kemiyatorn <[email protected]> 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)
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)
@@ -1962,13 +1962,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 +1981,11 @@
| VisibilityChangeMask
);
+#ifdef USE_XINPUT
+ //FIXME
+ [xInputServer 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 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,942 @@
+/*
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+ Author: Banlu Kemiyatorn <[email protected]>
+
+ 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] = {0};
+
+/*
+static double gsxiValuatorValueOfTypeOnDevice(
+ XIValuatorState *state,
+ GSInputAxisType type,
+ GSInputDevice *device)
+{
+ if ((type >> 3) <= state->mask_len && XIMaskIsSet(state->mask,type))
+ {
+ device->_classOrder[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 gsxiTypeOfLabel(Atom label)
+{
+ int n;
+ for (n = GSInputAxisTypeNone + 1; n < GSInputAxisTypeLast; n++)
+ {
+ if (gsxiInputLabel[n] == label)
+ return n;
+ }
+
+ return GSInputAxisTypeNone;
+}
+
+static NSString * gsxiNameOfType(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, [gsxiNameOfType(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) selectXExtensionEventForWindow:(Window)win
+{
+ int n;
+ for (n = RESERVED_XIDEV; n < _num_xidev; n++)
+ {
+ [_xidevs[n] selectXExtensionEventForWindow:win];
+ }
+}
+
+- (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;
+
+ if (event->deviceid == 2 || event->deviceid == 3) /* only process core devices for now */
+ {
+ 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");
+ break;
+ }
+
+ XFreeEventData(_dpy, cookie);
+
+ if (e != nil)
+ {
+ e->_sourceid = event->sourceid;
+ [_xgServer postEvent:e atStart:NO];
+ }
+
+ return YES;
+ }
+
+ XFreeEventData(_dpy, cookie);
+ 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 = gsxiTypeOfLabel(vInfo->label);
+
+ if (vInfo->number + 1 > _vMax)
+ {
+ _vMax = vInfo->number + 1;
+ _classOrder = realloc(_classOrder, sizeof(int) * _vMax);
+ }
+
+ _classOrder[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
+{
+ RELEASE(_name);
+ /*
+ if (_xdevice)
+ {
+ XCloseDevice(_dpy,_xdevice);
+ }
+ */
+ free(_classOrder);
+ if (_buttonStates)
+ {
+ int n;
+ for (n = 0; n < _num_buttons; n++)
+ {
+ DESTROY(_buttonStates[n].name);
+ }
+ free(_buttonStates);
+ }
+ [super dealloc];
+}
+
+- (void) selectXExtensionEventForWindow:(Window)win
+{
+ XIEventMask eventMask;
+ eventMask.deviceid = XIAllDevices;
+ 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, win, &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(_classOrder[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(_classOrder[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,197 @@
+/*
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+ Author: Banlu Kemiyatorn <[email protected]>
+
+ 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 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*);
+
+ int *_classOrder;
+ int _vMax; /* maximum valuator number */
+@private
+ BOOL _isEnable;
+
+ unsigned int (*_getState)(id, SEL, unsigned int);
+ Window _lastWindow;
+ gswindow_device_t *_gswindow;
+
+ BOOL _handleProx;
+
+ NSSize _screenSize;
+
+ 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;
+
+ NSString *_name;
+ int _use;
+
+ XIDeviceInfo *_xidInfo;
+}
+
+
+- (id) initWithDeviceInfo:(XIDeviceInfo *)info
+ screen:(int)screen
+ proximity:(BOOL)willHandleProximity
+ inputServer:(GSInputDeviceServer *)xiServer;
+- (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;
+@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
[email protected]
http://lists.gnu.org/mailman/listinfo/gnustep-dev