Changeset 12939

Show
Ignore:
Timestamp:
02/03/12 16:15:37 (4 months ago)
Author:
robert
Message:

From Stephan Huber, "attached you'll find a first version of multi-touch-support for OS X (>=
10.6), which will forward all multi-touch events from a trackpad to the
corresponding osgGA-event-structures.

The support is switched off per default, but you can enable multi-touch
support via a new flag for GraphicsWindowCocoa::WindowData? or directly
via the GraphicsWindowCocoa?-class.

After switching multi-touch-support on, all mouse-events from the
trackpad get ignored, otherwise you'll have multiple events for the same
pointer which is very confusing (as the trackpad reports absolute
movement, and as a mouse relative movement).

I think this is not a problem, as multi-touch-input is a completely
different beast as a mouse, so you'll have to code your own
event-handlers anyway.

While coding this stuff, I asked myself if we should refactor
GUIEventAdapter/EventQueue and assign a specific event-type for
touch-input instead of using PUSH/DRAG/RELEASE. This will make it
clearer how to use the code, but will break the mouse-emulation for the
first touch-point and with that all existing manipulators. What do you
think? I am happy to code the proposed changes.

Additionally I created a small (and ugly) example osgmultitouch which
makes use of the osgGA::MultiTouchTrackballManipulator?, shows all
touch-points on a HUD and demonstrates how to get the touchpoints from
an osgGA::GUIEventAdapter.

There's even a small example video here: http://vimeo.com/31611842"

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • OpenSceneGraph/trunk/src/osgViewer/GraphicsWindowCocoa.mm

    r12927 r12939  
    270270        BOOL _handleTabletEvents; 
    271271 
     272        NSMutableDictionary* _touchPoints; 
     273        unsigned int _lastTouchPointId; 
     274         
    272275} 
    273276- (void)setGraphicsWindowCocoa: (osgViewer::GraphicsWindowCocoa*) win; 
     
    308311- (void)handleTabletEvents:(NSEvent*)theEvent; 
    309312 
     313#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6) 
     314- (osgGA::GUIEventAdapter::TouchPhase) convertTouchPhase: (NSTouchPhase) phase; 
     315- (unsigned int)computeTouchId: (NSTouch*) touch; 
     316- (void)touchesBeganWithEvent:(NSEvent *)event; 
     317- (void)touchesMovedWithEvent:(NSEvent *)event; 
     318- (void)touchesEndedWithEvent:(NSEvent *)event; 
     319- (void)touchesCancelledWithEvent:(NSEvent *)event; 
     320#endif 
     321 
     322- (BOOL)useMultiTouchOnly: (NSEvent*) event; 
     323 
    310324- (BOOL)acceptsFirstResponder; 
    311325- (BOOL)becomeFirstResponder; 
    312326- (BOOL)resignFirstResponder; 
    313327 
     328- (void)dealloc; 
     329 
    314330@end 
    315331 
     
    320336{ 
    321337    _win = win; 
     338    _touchPoints = NULL; 
     339} 
     340 
     341-(void) dealloc 
     342{ 
     343    if (_touchPoints) [_touchPoints release]; 
     344    [super dealloc]; 
    322345} 
    323346 
     
    335358{ 
    336359    return YES; 
     360} 
     361 
     362- (BOOL) useMultiTouchOnly: (NSEvent*) event 
     363{ 
     364#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6) 
     365    return ([self acceptsTouchEvents] && ([event subtype] == NSTouchEventSubtype)); 
     366#else 
     367    return false; 
     368#endif 
    337369} 
    338370 
     
    406438- (void) mouseMoved:(NSEvent*)theEvent 
    407439{ 
     440    // if multitouch is enabled, disable standard event handling 
     441    if ([self useMultiTouchOnly: theEvent]) 
     442        return; 
     443     
    408444    NSPoint converted_point = [self getLocalPoint: theEvent]; 
    409445    DEBUG_OUT("Mouse moved" << converted_point.x << "/" << converted_point.y); 
     
    415451- (void) mouseDown:(NSEvent*)theEvent 
    416452{ 
     453    // if multitouch is enabled, disable standard event handling 
     454    if ([self useMultiTouchOnly: theEvent]) 
     455        return; 
     456         
    417457    DEBUG_OUT("Mouse down"); 
    418458    // Because many Mac users have only a 1-button mouse, we should provide ways 
     
    444484- (void) mouseDragged:(NSEvent*)theEvent 
    445485{ 
     486    // if multitouch is enabled, disable standard event handling 
     487    if ([self useMultiTouchOnly: theEvent]) 
     488        return; 
     489     
    446490    if (!_win) return; 
    447491 
     
    456500- (void) mouseUp:(NSEvent*)theEvent 
    457501{ 
     502    // if multitouch is enabled, disable standard event handling 
     503    if ([self useMultiTouchOnly: theEvent]) 
     504        return; 
     505         
    458506    // Because many Mac users have only a 1-button mouse, we should provide ways 
    459507    // to access the button 2 and 3 actions of osgViewer. 
     
    738786} 
    739787 
     788#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6) 
     789 
     790- (osgGA::GUIEventAdapter::TouchPhase) convertTouchPhase: (NSTouchPhase) phase  
     791{ 
     792    switch(phase) { 
     793     
     794        case NSTouchPhaseBegan: 
     795            return osgGA::GUIEventAdapter::TOUCH_BEGAN; 
     796            break; 
     797        case NSTouchPhaseMoved: 
     798            return osgGA::GUIEventAdapter::TOUCH_MOVED; 
     799            break; 
     800 
     801        case NSTouchPhaseStationary: 
     802            return osgGA::GUIEventAdapter::TOUCH_STATIONERY; 
     803            break; 
     804 
     805        case NSTouchPhaseEnded: 
     806        case NSTouchPhaseCancelled: 
     807            return osgGA::GUIEventAdapter::TOUCH_ENDED; 
     808            break; 
     809    } 
     810     
     811    return osgGA::GUIEventAdapter::TOUCH_ENDED; 
     812 
     813} 
     814 
     815 
     816- (unsigned int)computeTouchId: (NSTouch*) touch  
     817{ 
     818    unsigned int result(0); 
     819     
     820    if(!_touchPoints) { 
     821        _touchPoints = [[NSMutableDictionary alloc] init]; 
     822        _lastTouchPointId = 0; 
     823    } 
     824     
     825    switch([touch phase]) 
     826    { 
     827     
     828        case NSTouchPhaseBegan: 
     829            if ([_touchPoints objectForKey: [touch identity]] == nil)  
     830            { 
     831                [_touchPoints setObject: [NSNumber numberWithInt: _lastTouchPointId] forKey: [touch identity]]; 
     832                result = _lastTouchPointId++; 
     833                break; 
     834            } 
     835            // missing "break" by intention! 
     836         
     837        case NSTouchPhaseMoved: 
     838        case NSTouchPhaseStationary: 
     839            { 
     840                NSNumber* n = [_touchPoints objectForKey: [touch identity]]; 
     841                result = [n intValue]; 
     842            } 
     843            break; 
     844        
     845        case NSTouchPhaseEnded: 
     846        case NSTouchPhaseCancelled: 
     847            { 
     848                NSNumber* n = [_touchPoints objectForKey: [touch identity]]; 
     849                result = [n intValue]; 
     850                [_touchPoints removeObjectForKey: [touch identity]]; 
     851                if([_touchPoints count] == 0) { 
     852                    _lastTouchPointId = 0; 
     853                } 
     854            } 
     855            break; 
     856             
     857        default: 
     858            break; 
     859    } 
     860         
     861    return result; 
     862} 
     863 
     864 
     865 
     866- (void)touchesBeganWithEvent:(NSEvent *)event 
     867{ 
     868    NSSet *allTouches = [event touchesMatchingPhase: NSTouchPhaseAny inView: self]; 
     869     
     870    osg::ref_ptr<osgGA::GUIEventAdapter> osg_event(NULL); 
     871     
     872    NSRect bounds = [self bounds]; 
     873    for(unsigned int i=0; i<[allTouches count]; i++) 
     874    { 
     875         
     876        NSTouch *touch = [[allTouches allObjects] objectAtIndex:i]; 
     877        NSPoint pos = [touch normalizedPosition]; 
     878        osg::Vec2 pixelPos(pos.x * bounds.size.width, (1-pos.y) * bounds.size.height); 
     879        unsigned int touch_id = [self computeTouchId: touch]; 
     880        if (!osg_event) { 
     881            osg_event = _win->getEventQueue()->touchBegan(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); 
     882        } else { 
     883            osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); 
     884        } 
     885    } 
     886} 
     887 
     888- (void)touchesMovedWithEvent:(NSEvent *)event 
     889{ 
     890    NSSet *allTouches = [event touchesMatchingPhase: NSTouchPhaseAny inView: self]; 
     891     
     892    osg::ref_ptr<osgGA::GUIEventAdapter> osg_event(NULL); 
     893    NSRect bounds = [self bounds]; 
     894     
     895    for(unsigned int i=0; i<[allTouches count]; i++) 
     896    { 
     897        NSTouch *touch = [[allTouches allObjects] objectAtIndex:i]; 
     898        NSPoint pos = [touch normalizedPosition]; 
     899        osg::Vec2 pixelPos(pos.x * bounds.size.width, (1 - pos.y) * bounds.size.height); 
     900        unsigned int touch_id = [self computeTouchId: touch]; 
     901        if (!osg_event) { 
     902            osg_event = _win->getEventQueue()->touchMoved(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); 
     903        } else { 
     904            osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); 
     905        } 
     906    } 
     907} 
     908 
     909 
     910- (void)touchesEndedWithEvent:(NSEvent *)event 
     911{ 
     912    NSSet *allTouches = [event touchesMatchingPhase: NSTouchPhaseAny inView: self]; 
     913     
     914    osg::ref_ptr<osgGA::GUIEventAdapter> osg_event(NULL); 
     915    NSRect bounds = [self bounds]; 
     916     
     917    for(unsigned int i=0; i<[allTouches count]; i++) 
     918    { 
     919        NSTouch *touch = [[allTouches allObjects] objectAtIndex:i]; 
     920        NSPoint pos = [touch normalizedPosition]; 
     921        osg::Vec2 pixelPos(pos.x * bounds.size.width, (1 - pos.y) * bounds.size.height); 
     922        unsigned int touch_id = [self computeTouchId: touch]; 
     923        if (!osg_event) { 
     924            osg_event = _win->getEventQueue()->touchEnded(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y(), 1); 
     925        } else { 
     926            osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y(), 1); 
     927        } 
     928 
     929    } 
     930} 
     931 
     932 
     933 
     934- (void)touchesCancelledWithEvent:(NSEvent *)event 
     935{ 
     936    [self touchesEndedWithEvent: event]; 
     937} 
     938 
     939 
     940#endif 
    740941 
    741942@end 
     
    10031204    setNSOpenGLContext(_context); 
    10041205 
    1005     GraphicsWindowCocoaGLView* theView = [[ GraphicsWindowCocoaGLView alloc ] initWithFrame:[ _window frame ] ]; 
    1006     [theView setAutoresizingMask:  (NSViewWidthSizable | NSViewHeightSizable) ]; 
    1007     [theView setGraphicsWindowCocoa: this]; 
    1008     [theView setOpenGLContext:_context]; 
    1009     _view = theView; 
    1010     OSG_DEBUG << "GraphicsWindowCocoa::realizeImplementation / view: " << theView << std::endl; 
     1206     
     1207    _view = [[ GraphicsWindowCocoaGLView alloc ] initWithFrame:[ _window frame ] ]; 
     1208    [_view setAutoresizingMask:  (NSViewWidthSizable | NSViewHeightSizable) ]; 
     1209    [_view setGraphicsWindowCocoa: this]; 
     1210    [_view setOpenGLContext:_context]; 
     1211     
     1212    // enable multitouch 
     1213    if (_multiTouchEnabled || (windowData && windowData->isMultiTouchEnabled())) 
     1214    { 
     1215        setMultiTouchEnabled(true); 
     1216    } 
     1217     
     1218    OSG_DEBUG << "GraphicsWindowCocoa::realizeImplementation / view: " << _view << std::endl; 
    10111219 
    10121220    if (_ownsWindow) { 
    1013         [_window setContentView: theView]; 
     1221        [_window setContentView: _view]; 
    10141222        setupNSWindow(_window); 
    1015         [theView release]; 
    1016  
     1223        [_view release]; 
     1224         
    10171225        MenubarController::instance()->attachWindow( new CocoaWindowAdapter(this) ); 
    10181226    } 
    10191227    else 
    10201228    { 
    1021         windowData->setCreatedNSView(theView); 
     1229        windowData->setCreatedNSView(_view); 
    10221230    } 
    10231231 
     
    14241632 
    14251633 
     1634bool GraphicsWindowCocoa::isMultiTouchEnabled() 
     1635{ 
     1636    return _multiTouchEnabled; 
     1637} 
     1638void GraphicsWindowCocoa::setMultiTouchEnabled(bool b) 
     1639{ 
     1640    _multiTouchEnabled = b; 
     1641     
     1642#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6) 
     1643    if (_view) [_view setAcceptsTouchEvents: b]; 
     1644#else 
     1645    if (b) { 
     1646        OSG_WARN << "GraphicsWindowCocoa :: multi-touch only available for OS X >= 10.6, please check your compile settings" << std::endl; 
     1647    } 
     1648#endif 
     1649} 
     1650 
     1651 
    14261652// ---------------------------------------------------------------------------------------------------------- 
    14271653// d'tor