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