Skip to main content
iOS Input via UIView         This snippet provides an alternative to obtaining user input for iOS applications via UIView; additionally, it provides a strategy for interacting between C++/Objective-C instances/objects.



InputPimpl.h
Copy to clipboard
#ifndef InputPimpl_h #define InputPimpl_h class InputPimpl { public: InputPimpl ( void ); virtual ~InputPimpl( void ); virtual void _notifyTapWasRecognized( float x0, float y0, uint numTouches , uint numTaps ) = 0; virtual void _notifyPanWasRecognized( float x0, float y0, uint numTouches , float xT, float yT , float xV, float yV ) = 0; virtual void _notifyPinchWasRecognized( float x0, float y0, uint numTouches , float scale, float velocity ) = 0; protected: void _setupGestureInput( void ); private: void * self; }; #endif

iOS_InputImpl.h
Copy to clipboard
#ifndef iOS_InputImpl_h #define iOS_InputImpl_h #import "InputPimpl.h" #import "iOS_InputVC.h" #import <UIKit/UIKit.h> //////////////////////////////////////////////////////////////////////// @interface iOS_InputImpl : NSObject <InputVCDelegate> { InputPimpl * _pimpl; } - (id) initWithPimpl:(InputPimpl *)pimpl; - (void) notifyTapWasRecognized:(TapGestureInfo *)info; - (void) notifyPinchWasRecognized:(PinchGestureInfo *)info; - (void) notifyPanWasRecognized:(PanGestureInfo *)info; @end #endif

iOS_InputImpl.mm
Copy to clipboard
#import "InputPimpl.h" #import "iOS_InputImpl.h" #import "iOS_UIManager.h" //////////////////////////////////////////////////////////////////////// @implementation iOS_InputImpl //////////////////////////////////////////////////////////////////////// InputPimpl::InputPimpl( void ) : self( NULL ) { } //////////////////////////////////////////////////////////////////////// InputPimpl::~InputPimpl( void ) { if ( self ) { [(id)self dealloc]; self = NULL; } } //////////////////////////////////////////////////////////////////////// void InputPimpl::_setupGestureInput( void ) { self = [[iOS_InputImpl alloc] initWithPimpl:this]; } //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// - (id) initWithPimpl:(InputPimpl *)pimpl { _pimpl = pimpl; [[iOS_UIManager getInstance] enableInputView:YES withDelegate:self]; } //////////////////////////////////////////////////////////////////////// - (void) dealloc { [super dealloc]; } //////////////////////////////////////////////////////////////////////// - (void) notifyTapWasRecognized:(TapGestureInfo *)info { _pimpl->_notifyTapWasRecognized( info.pointBegan.x, info.pointBegan.y , info.numTouches, info.numTaps ); } //////////////////////////////////////////////////////////////////////// - (void) notifyPanWasRecognized:(PanGestureInfo *)info { _pimpl->_notifyPanWasRecognized( info.pointBegan.x, info.pointBegan.y , info.numTouches , info.translation.x, info.translation.y , info.velocity.x, info.velocity.y ); } //////////////////////////////////////////////////////////////////////// - (void) notifyPinchWasRecognized:(PinchGestureInfo *)info { _pimpl->_notifyPinchWasRecognized( info.pointBegan.x, info.pointBegan.y , info.numTouches, info.scale , info.velocity ); } //////////////////////////////////////////////////////////////////////// @end

iOS_UIManager.h
Copy to clipboard
#ifndef iOS_UIManager_h #define iOS_UIManager_h #import <UIKit/UIKit.h> //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// @interface iOS_UIManager : NSObject { @private } //////////////////////////////////////////////////////////////////////// @property (nonatomic, retain) UIWindow * window; //////////////////////////////////////////////////////////////////////// + (id) getInstance; //////////////////////////////////////////////////////////////////////// - (void) enableInputView:(BOOL)value withDelegate:(id)theDelegate; //////////////////////////////////////////////////////////////////////// @end //////////////////////////////////////////////////////////////////////// #endif

iOS_UIManager.m
Copy to clipboard
#import "iOS_UIManager.h" #import "iOS_InputVC.h" //////////////////////////////////////////////////////////////////////// typedef enum { eVIEW_TAG_INPUT = 1 } EUIManagerViewTags; //////////////////////////////////////////////////////////////////////// @implementation iOS_UIManager @synthesize window; //////////////////////////////////////////////////////////////////////// static iOS_UIManager * msInstance = nil; + (iOS_UIManager *) getInstance { @synchronized(self) { if ( msInstance == nil ) { msInstance = [[self alloc] init]; } } return (msInstance); } //////////////////////////////////////////////////////////////////////// - (id) init { if ( self = [super init] ) { CGRect appRect = [[UIScreen mainScreen] applicationFrame]; self.window = [[[UIWindow alloc] initWithFrame:appRect] autorelease]; self.window.hidden = NO; self.window.backgroundColor = [UIColor clearColor]; } return self; } //////////////////////////////////////////////////////////////////////// - (void) dealloc { self.window = nil; [super dealloc]; } //////////////////////////////////////////////////////////////////////// - (void) enableInputView:(BOOL)value withDelegate:(id)theDelegate { if ( value ) { iOS_InputVC * inputVC = [[iOS_InputVC alloc] initWithNibName:nil bundle:nil]; inputVC.delegate = theDelegate; inputVC.view.tag = eVIEW_TAG_INPUT; [self.window setRootViewController:inputVC]; [self.window addSubview:inputVC.view]; [self.window bringSubviewToFront:inputVC.view]; [self.window makeKeyAndVisible]; [inputVC release]; } else { UIView * inputView = [self.window viewWithTag:eVIEW_TAG_INPUT]; if ( inputView ) { [inputView removeFromSuperview]; } } } //////////////////////////////////////////////////////////////////////// @end ////////////////////////////////////////////////////////////////////////

iOS_InputVC.h
Copy to clipboard
#ifndef iOS_InputVC_h #define iOS_InputVC_h //////////////////////////////////////////////////////////////////////// @interface GestureInfo : NSObject { } @property (nonatomic, assign) CGPoint pointBegan; @property (nonatomic, assign) NSUInteger numTouches; @end @interface TapGestureInfo : GestureInfo { } @property (nonatomic, assign) NSUInteger numTaps; @end @interface PanGestureInfo : GestureInfo { } @property (nonatomic, assign) CGPoint translation; @property (nonatomic, assign) CGPoint velocity; @end @interface PinchGestureInfo : GestureInfo { } @property (nonatomic, assign) CGFloat scale; @property (nonatomic, assign) CGFloat velocity; @end //////////////////////////////////////////////////////////////////////// @protocol InputVCDelegate <NSObject> @optional - (void) notifyTapWasRecognized:(TapGestureInfo *)info; - (void) notifyPanWasRecognized:(PanGestureInfo *)info; - (void) notifyPinchWasRecognized:(PinchGestureInfo *)info; @end //////////////////////////////////////////////////////////////////////// @interface iOS_InputVC : UIViewController { } @property (nonatomic, assign) id <InputVCDelegate> delegate; //////////////////////////////////////////////////////////////////////// @end //////////////////////////////////////////////////////////////////////// #endif

iOS_InputVC.mm
Copy to clipboard
#import "iOS_InputVC.h" #define SAFE_PERFORM_WITH_ARG(THE_OBJECT, THE_SELECTOR, THE_ARG) \ ((THE_OBJECT && [THE_OBJECT respondsToSelector:THE_SELECTOR]) \ ?[THE_OBJECT performSelector:THE_SELECTOR withObject:THE_ARG] : nil) //////////////////////////////////////////////////////////////////////// // PRIVATE METHODS @interface iOS_InputVC() - (void) enableTapRecognition; - (void) enablePanRecognition; - (void) enablePinchRecognition; - (void) handleTapGesture:(UITapGestureRecognizer *)sender; - (void) handlePanGesture:(UIPanGestureRecognizer *)sender; - (void) handlePinchGesture:(UIPanGestureRecognizer *)sender; @end //////////////////////////////////////////////////////////////////////// @implementation GestureInfo @synthesize pointBegan, numTouches; @end @implementation TapGestureInfo @synthesize numTaps; @end @implementation PanGestureInfo @synthesize translation, velocity; @end @implementation PinchGestureInfo @synthesize scale, velocity; @end //////////////////////////////////////////////////////////////////////// @implementation iOS_InputVC @synthesize delegate; //////////////////////////////////////////////////////////////////////// - (void) dealloc { self.delegate = nil; [super dealloc]; } //////////////////////////////////////////////////////////////////////// - (void) loadView { [super loadView]; CGRect appRect = [[UIScreen mainScreen] applicationFrame]; UIView * v = [[UIView alloc] initWithFrame: appRect]; v.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; v.backgroundColor = [UIColor clearColor]; v.opaque = YES; self.view = v; [v release]; } //////////////////////////////////////////////////////////////////////// - (void) viewDidLoad { [super viewDidLoad]; [self enableTapRecognition]; [self enablePanRecognition]; [self enablePinchRecognition]; } //////////////////////////////////////////////////////////////////////// - (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { return YES; } //////////////////////////////////////////////////////////////////////// - (void) enableTapRecognition { UITapGestureRecognizer * tapGR = nil; // Add a recognizer that looks for the standard one-touch single tap. tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)]; tapGR.numberOfTapsRequired = 1; tapGR.numberOfTouchesRequired = 1; [self.view addGestureRecognizer:tapGR]; [tapGR release]; // Add a recognizer that looks for the elusive four-touch triple tap. tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)]; tapGR.numberOfTouchesRequired = 4; tapGR.numberOfTapsRequired = 3; [self.view addGestureRecognizer:tapGR]; [tapGR release]; } //////////////////////////////////////////////////////////////////////// - (void) enablePanRecognition { UIPanGestureRecognizer * panGR = nil; // Add a recognizer that looks for a one-touch panning (dragging) gesture. panGR = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)]; [self.view addGestureRecognizer:panGR]; [panGR release]; } //////////////////////////////////////////////////////////////////////// - (void) enablePinchRecognition { UIPinchGestureRecognizer * pinchGR = nil; // Add a recognizer that looks for two touches moving towards or away from one another. // (commonly used to zoom-out when moving together and zoom-in when moving away). pinchGR = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchGesture:)]; [self.view addGestureRecognizer:pinchGR]; [pinchGR release]; } //////////////////////////////////////////////////////////////////////// - (void) handleTapGesture:(UITapGestureRecognizer *)sender; { TapGestureInfo * info = [[TapGestureInfo alloc] init]; info.pointBegan = [sender locationInView:self.view]; info.numTouches = [sender numberOfTouches]; info.numTaps = [sender numberOfTapsRequired]; SAFE_PERFORM_WITH_ARG( self.delegate, @selector(notifyTapWasRecognized:), info ); [info release]; } //////////////////////////////////////////////////////////////////////// - (void) handlePanGesture:(UIPanGestureRecognizer *)sender; { PanGestureInfo * info = [[PanGestureInfo alloc] init]; info.pointBegan = [sender locationInView:self.view]; info.numTouches = [sender numberOfTouches]; info.translation = [sender translationInView:self.view]; info.velocity = [sender velocityInView:self.view]; SAFE_PERFORM_WITH_ARG( self.delegate, @selector(notifyPanWasRecognized:), info ); [info release]; } //////////////////////////////////////////////////////////////////////// - (void) handlePinchGesture:(UIPinchGestureRecognizer *)sender; { PinchGestureInfo * info = [[PinchGestureInfo alloc] init]; info.pointBegan = [sender locationInView:self.view]; info.numTouches = [sender numberOfTouches]; info.scale = [sender scale]; info.velocity = [sender velocity]; SAFE_PERFORM_WITH_ARG( self.delegate, @selector(notifyPinchWasRecognized:), info ); [info release]; } //////////////////////////////////////////////////////////////////////// @end ////////////////////////////////////////////////////////////////////////

MyStateWithGestureSupport.h
Copy to clipboard
#ifndef MyStateWithGestureSupport_h #define MyStateWithGestureSupport_h #include "State.hpp" #include "InputPimpl.h" class MyStateWithGestureSupport : public State , private InputPimpl { public: MyStateWithGestureSupport ( void ); virtual ~MyStateWithGestureSupport( void ); DECLARE_STATE_CLASS( MyStateWithGestureSupport ); void enter ( void ); void createScene( void ); void exit ( void ); bool frameStarted ( Ogre::FrameEvent const& evt ); bool frameRenderingQueued( Ogre::FrameEvent const& evt ) { return true; } bool frameEnded ( Ogre::FrameEvent const& evt ) { return true; } virtual void _notifyTapWasRecognized( float x0, float y0, uint numTouches , uint numTaps ); virtual void _notifyPanWasRecognized( float x0, float y0, uint numTouches , float xT, float yT , float xV, float yV ); virtual void _notifyPinchWasRecognized( float x0, float y0, uint numTouches , float scale, float velocity ); }; #endif

MyStateWithGestureSupport.cpp
Copy to clipboard
#include "MyStateWithGestureSupport.h" #include "Framework.hpp" using namespace Ogre; MyStateWithGestureSupport::MyStateWithGestureSupport( void ) : _cubeEntity( NULL ) , _cubeNode ( NULL ) { } //////////////////////////////////////////////////////////////////// void MyStateWithGestureSupport::enter( void ) { Framework::getSingletonPtr()->m_pLog->logMessage( "\n~~ Entering MyStateWithGestureSupport ~~" ); _setupGestureInput(); createScene(); Framework::getSingletonPtr()->m_pLog->logMessage( "~~ Entered MyStateWithGestureSupport ~~\n" ); } //////////////////////////////////////////////////////////////////// void MyStateWithGestureSupport::createScene( void ) { _sceneMgr = Framework::getSingletonPtr()->m_pRoot->createSceneManager( ST_GENERIC, "GameSceneMgr" ); _sceneMgr->setAmbientLight(Ogre::ColourValue(0.7f, 0.7f, 0.7f)); _camera = _sceneMgr->createCamera( "GameCamera" ); _camera->setPosition( Vector3( 5.f, 60.f, 60.f ) ); _camera->lookAt ( Vector3( 5.f, 20.f, 0.f ) ); _camera->setNearClipDistance ( 5.f ); _camera->setAspectRatio( Real( Framework::getSingletonPtr()->m_pViewport->getActualWidth () ) / Real( Framework::getSingletonPtr()->m_pViewport->getActualHeight() ) ); Framework::getSingletonPtr()->m_pViewport->setCamera( _camera ); _sceneMgr->setSkyBox( true, "Examples/SpaceSkyBox" ); _sceneMgr->createLight( "Light" )->setPosition( 75.f, 75.f, 75.f ); _cubeEntity = _sceneMgr->createEntity( "Cube", "ogrehead.mesh" ); _cubeNode = _sceneMgr->getRootSceneNode()->createChildSceneNode( "CubeNode" ); _cubeNode->attachObject( _cubeEntity ); _cubeNode->setPosition ( Vector3( 0.f, 0.f, -25.f ) ); } //////////////////////////////////////////////////////////////////// bool MyStateWithGestureSupport::frameStarted( Ogre::FrameEvent const& evt) { return true; } //////////////////////////////////////////////////////////////////// void MyStateWithGestureSupport::exit( void ) { if ( _sceneMgr ) { if ( _camera ) { _sceneMgr->destroyCamera( _camera ); } Framework::getSingletonPtr()->m_pRoot->destroySceneManager( _sceneMgr ); } Framework::getSingletonPtr()->m_pLog->logMessage( "~~ Left TestStateA ~~\n" ); } //////////////////////////////////////////////////////////////////////// void MyStateWithGestureSupport::_notifyTapWasRecognized( float x0, float y0, uint numTouches , uint numTaps ) { Framework::getSingletonPtr()->m_pLog->logMessage( "[TAP]" ); } //////////////////////////////////////////////////////////////////////// void MyStateWithGestureSupport::_notifyPanWasRecognized( float x0, float y0, uint numTouches , float xT, float yT , float xV, float yV ) { Framework::getSingletonPtr()->m_pLog->logMessage( "[PAN]" ); } //////////////////////////////////////////////////////////////////////// void MyStateWithGestureSupport::_notifyPinchWasRecognized( float x0, float y0, uint numTouches , float scale, float velocity ) { Framework::getSingletonPtr()->m_pLog->logMessage( "[PINCH]" ); } ////////////////////////////////////////////////////////////////////////