Procházet zdrojové kódy

Adding keyboard (show / hide) support.

Ramprasad Madhavan před 14 roky
rodič
revize
3bede83e8e

+ 8 - 1
gameplay/src/Game.h

@@ -184,7 +184,14 @@ public:
      * Menu callback on menu events.
      */
     virtual void menu();
-
+    
+    /**
+     * Shows or hides the virtual keyboard (if supported).
+     *
+     * @param display true when virtual keyboard needs to be displayed; false otherwise.
+     */
+     inline void displayKeyboard(bool display);
+     
     /**
      * Keyboard callback on keyPress events.
      *

+ 5 - 0
gameplay/src/Game.inl

@@ -61,4 +61,9 @@ inline void Game::getAccelerometerValues(float* pitch, float* roll)
     Platform::getAccelerometerValues(pitch, roll);
 }
 
+inline void Game::displayKeyboard(bool display)
+{
+    Platform::displayKeyboard(display);
+}
+
 }

+ 7 - 0
gameplay/src/Platform.h

@@ -94,6 +94,13 @@ public:
      * Swaps the frame buffer on the device.
      */
     static void swapBuffers();
+    
+    /**
+     * Shows or hides the virtual keyboard (if supported).
+     *
+     * @param display true when virtual keyboard needs to be displayed and false otherwise.
+     */
+     static void displayKeyboard(bool display);
 
 private:
 

+ 144 - 66
gameplay/src/PlatformAndroid.cpp

@@ -16,6 +16,14 @@
 
 using namespace std;
 
+int __width;
+int __height;
+static EGLDisplay __eglDisplay = EGL_NO_DISPLAY;
+static EGLContext __eglContext = EGL_NO_CONTEXT;
+static EGLSurface __eglSurface = EGL_NO_SURFACE;
+static EGLConfig __eglConfig = 0;
+
+
 struct timespec __timespec;
 static long __timeStart;
 static long __timeAbsolute;
@@ -23,18 +31,15 @@ static bool __vsync = WINDOW_VSYNC;
 
 struct android_app* __state;
 extern std::string __assetsPath;
-int __width;
-int __height;
-static EGLDisplay __eglDisplay = EGL_NO_DISPLAY;
-static EGLContext __eglContext = EGL_NO_CONTEXT;
-static EGLSurface __eglSurface = EGL_NO_SURFACE;
-static EGLConfig __eglConfig = 0;
+
 ASensorManager* __sensorManager;
-const ASensor* __accelerometerSensor;
 ASensorEventQueue* __sensorEventQueue;
 ASensorEvent __sensorEvent;
+const ASensor* __accelerometerSensor;
+
 static int __orientationAngle;
 static bool __multiTouch = false;
+extern bool __displayKeyboard;
 
 static const char* __glExtensions;
 PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray = NULL;
@@ -45,6 +50,71 @@ PFNGLISVERTEXARRAYOESPROC glIsVertexArray = NULL;
 namespace gameplay
 {
 
+extern void displayKeyboard(android_app* state, bool pShow)
+{ 
+    
+    // The following functions is supposed to show / hide functins from a native activity.. but currently
+    // do not work. 
+    // ANativeActivity_showSoftInput(state->activity, ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT);
+    // ANativeActivity_hideSoftInput(state->activity, ANATIVEACTIVITY_HIDE_SOFT_INPUT_IMPLICIT_ONLY);
+    
+    // Show or hide the keyboard by calling the appropriate Java method through JNI instead.
+    // Attaches the current thread to the JVM.
+    jint lResult;
+    jint lFlags = 0;
+    JavaVM* lJavaVM = state->activity->vm;
+    JNIEnv* lJNIEnv = state->activity->env; 
+    JavaVMAttachArgs lJavaVMAttachArgs;
+    lJavaVMAttachArgs.version = JNI_VERSION_1_6;
+    lJavaVMAttachArgs.name = "NativeThread";
+    lJavaVMAttachArgs.group = NULL;
+    lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs); 
+    if (lResult == JNI_ERR)
+    { 
+        return; 
+    } 
+    // Retrieves NativeActivity. 
+    jobject lNativeActivity = state->activity->clazz;
+    jclass ClassNativeActivity = lJNIEnv->GetObjectClass(lNativeActivity);
+
+    // Retrieves Context.INPUT_METHOD_SERVICE.
+    jclass ClassContext = lJNIEnv->FindClass("android/content/Context");
+    jfieldID FieldINPUT_METHOD_SERVICE = lJNIEnv->GetStaticFieldID(ClassContext, "INPUT_METHOD_SERVICE", "Ljava/lang/String;");
+    jobject INPUT_METHOD_SERVICE = lJNIEnv->GetStaticObjectField(ClassContext, FieldINPUT_METHOD_SERVICE);
+    
+    // Runs getSystemService(Context.INPUT_METHOD_SERVICE).
+    jclass ClassInputMethodManager = lJNIEnv->FindClass("android/view/inputmethod/InputMethodManager");
+    jmethodID MethodGetSystemService = lJNIEnv->GetMethodID(ClassNativeActivity, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
+    jobject lInputMethodManager = lJNIEnv->CallObjectMethod(lNativeActivity, MethodGetSystemService, INPUT_METHOD_SERVICE);
+    
+    // Runs getWindow().getDecorView().
+    jmethodID MethodGetWindow = lJNIEnv->GetMethodID(ClassNativeActivity, "getWindow", "()Landroid/view/Window;");
+    jobject lWindow = lJNIEnv->CallObjectMethod(lNativeActivity, MethodGetWindow);
+    jclass ClassWindow = lJNIEnv->FindClass("android/view/Window");
+    jmethodID MethodGetDecorView = lJNIEnv->GetMethodID(ClassWindow, "getDecorView", "()Landroid/view/View;");
+    jobject lDecorView = lJNIEnv->CallObjectMethod(lWindow, MethodGetDecorView);
+    if (pShow)
+    {
+        // Runs lInputMethodManager.showSoftInput(...).
+        jmethodID MethodShowSoftInput = lJNIEnv->GetMethodID( ClassInputMethodManager, "showSoftInput", "(Landroid/view/View;I)Z");
+        jboolean lResult = lJNIEnv->CallBooleanMethod(lInputMethodManager, MethodShowSoftInput, lDecorView, lFlags); 
+    } 
+    else 
+    { 
+        // Runs lWindow.getViewToken() 
+        jclass ClassView = lJNIEnv->FindClass("android/view/View");
+        jmethodID MethodGetWindowToken = lJNIEnv->GetMethodID(ClassView, "getWindowToken", "()Landroid/os/IBinder;");
+        jobject lBinder = lJNIEnv->CallObjectMethod(lDecorView, MethodGetWindowToken); 
+        
+        // lInputMethodManager.hideSoftInput(...). 
+        jmethodID MethodHideSoftInput = lJNIEnv->GetMethodID(ClassInputMethodManager, "hideSoftInputFromWindow", "(Landroid/os/IBinder;I)Z"); 
+        jboolean lRes = lJNIEnv->CallBooleanMethod( lInputMethodManager, MethodHideSoftInput, lBinder, lFlags); 
+    }
+    
+    // Finished with the JVM.
+    lJavaVM->DetachCurrentThread(); 
+}
+
 // Gets the Keyboard::Key enumeration constant that corresponds to the given Android key code.
 extern Keyboard::Key getKey(int keycode, int metastate)
 {
@@ -286,7 +356,7 @@ Platform* Platform::create(Game* game)
         EGL_NONE
     };
 
-	const EGLint eglSurfaceAttrs[] =
+    const EGLint eglSurfaceAttrs[] =
     {
         EGL_RENDER_BUFFER,    EGL_BACK_BUFFER,
         EGL_NONE
@@ -344,7 +414,7 @@ Platform* Platform::create(Game* game)
 
     eglQuerySurface(__eglDisplay, __eglSurface, EGL_WIDTH, &__width);
     eglQuerySurface(__eglDisplay, __eglSurface, EGL_HEIGHT, &__height);
-	
+    
     WARN_VARG("Platform::create - WIDTH: %d HEIGHT = %d" , __width, __height);
     
     // Set vsync.
@@ -356,8 +426,8 @@ Platform* Platform::create(Game* game)
     if (strstr(__glExtensions, "GL_OES_vertex_array_object") || strstr(__glExtensions, "GL_ARB_vertex_array_object"))
     {
         WARN("Platform::create - VAOs supported");
-		
-		// Disable VAO extension for now.
+        
+        // Disable VAO extension for now.
         glBindVertexArray = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress("glBindVertexArrayOES");
         glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSOESPROC)eglGetProcAddress("glDeleteVertexArrays");
         glGenVertexArrays = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress("glGenVertexArraysOES");
@@ -389,49 +459,49 @@ long timespec2millis(struct timespec *a)
 int Platform::enterMessagePump()
 {
     static int state = 0;
-	
-	switch (state)
-	{
-		case 0:
-			// Get the initial time.
-			clock_gettime(CLOCK_REALTIME, &__timespec);
-			__timeStart = timespec2millis(&__timespec);
-			__timeAbsolute = 0L;
-			WARN_VARG("Platform::enterMessagePump() - WIDTH: %d HEIGHT = %d" , __width, __height);
-			_game->run(__width, __height);
-			
-			state = 1;
-			break;
-		case 1:
-			// Idle time (no events left to process) is spent rendering.
-			// We skip rendering when the app is paused.
-			if (_game->getState() != Game::PAUSED)
-			{
-				_game->frame();
-
-				// Post the new frame to the display.
-				// Note that there are a couple cases where eglSwapBuffers could fail
-				// with an error code that requires a certain level of re-initialization:
-				//
-				// 1) EGL_BAD_NATIVE_WINDOW - Called when the surface we're currently using
-				//    is invalidated. This would require us to destroy our EGL surface,
-				//    close our OpenKODE window, and start again.
-				//
-				// 2) EGL_CONTEXT_LOST - Power management event that led to our EGL context
-				//    being lost. Requires us to re-create and re-initalize our EGL context
-				//    and all OpenGL ES state.
-				//
-				// For now, if we get these, we'll simply exit.
-				int rc = eglSwapBuffers(__eglDisplay, __eglSurface);
-				if (rc != EGL_TRUE)
-				{
-					perror("eglSwapBuffers");
-					_game->exit();
-					break;
-				}
-			}
-			break;
-	}
+    
+    switch (state)
+    {
+        case 0:
+            // Get the initial time.
+            clock_gettime(CLOCK_REALTIME, &__timespec);
+            __timeStart = timespec2millis(&__timespec);
+            __timeAbsolute = 0L;
+            WARN_VARG("Platform::enterMessagePump() - WIDTH: %d HEIGHT = %d" , __width, __height);
+            _game->run(__width, __height);
+            
+            state = 1;
+            break;
+        case 1:
+            // Idle time (no events left to process) is spent rendering.
+            // We skip rendering when the app is paused.
+            if (_game->getState() != Game::PAUSED)
+            {
+                _game->frame();
+
+                // Post the new frame to the display.
+                // Note that there are a couple cases where eglSwapBuffers could fail
+                // with an error code that requires a certain level of re-initialization:
+                //
+                // 1) EGL_BAD_NATIVE_WINDOW - Called when the surface we're currently using
+                //    is invalidated. This would require us to destroy our EGL surface,
+                //    close our OpenKODE window, and start again.
+                //
+                // 2) EGL_CONTEXT_LOST - Power management event that led to our EGL context
+                //    being lost. Requires us to re-create and re-initalize our EGL context
+                //    and all OpenGL ES state.
+                //
+                // For now, if we get these, we'll simply exit.
+                int rc = eglSwapBuffers(__eglDisplay, __eglSurface);
+                if (rc != EGL_TRUE)
+                {
+                    perror("eglSwapBuffers");
+                    _game->exit();
+                    break;
+                }
+            }
+            break;
+    }
     
     return 0;
 }
@@ -479,18 +549,18 @@ bool Platform::isMultiTouch()
 void Platform::getAccelerometerValues(float* pitch, float* roll)
 {
     double tx, ty, tz;
-	ASensorEvent event;
-	
-	// By default, android accelerometer values are oriented to the portrait mode.
-	// flipping the x and y to get the desired landscape mode values.
-	tx = -__sensorEvent.acceleration.y;
-	ty = __sensorEvent.acceleration.x;
-	tz = -__sensorEvent.acceleration.z;
-	
-	if (pitch != NULL)
-		*pitch = atan(ty / sqrt(tx * tx + tz * tz)) * 180.0f * M_1_PI;
-	if (roll != NULL)
-		*roll = atan(tx / sqrt(ty * ty + tz * tz)) * 180.0f * M_1_PI;
+    ASensorEvent event;
+    
+    // By default, android accelerometer values are oriented to the portrait mode.
+    // flipping the x and y to get the desired landscape mode values.
+    tx = -__sensorEvent.acceleration.y;
+    ty = __sensorEvent.acceleration.x;
+    tz = -__sensorEvent.acceleration.z;
+    
+    if (pitch != NULL)
+        *pitch = atan(ty / sqrt(tx * tx + tz * tz)) * 180.0f * M_1_PI;
+    if (roll != NULL)
+        *roll = atan(tx / sqrt(ty * ty + tz * tz)) * 180.0f * M_1_PI;
 }
 
 void Platform::swapBuffers()
@@ -499,6 +569,14 @@ void Platform::swapBuffers()
         eglSwapBuffers(__eglDisplay, __eglSurface);
 }
 
+void Platform::displayKeyboard(bool display)
+{
+    if (display)
+        __displayKeyboard = true;
+    else
+        __displayKeyboard = false;
+}
+
 }
 
 #endif

+ 604 - 599
gameplay/src/PlatformMacOS.mm

@@ -1,599 +1,604 @@
-#ifdef __APPLE__
-
-#include "Base.h"
-#include "Platform.h"
-#include "FileSystem.h"
-#include "Game.h"
-
-#import <Cocoa/Cocoa.h>
-#import <QuartzCore/CVDisplayLink.h>
-#import <OpenGL/OpenGL.h>
-#import <mach/mach_time.h>
-
-using namespace std;
-using namespace gameplay;
-
-static const float ACCELEROMETER_X_FACTOR = 90.0f / WINDOW_WIDTH;
-static const float ACCELEROMETER_Y_FACTOR = 90.0f / WINDOW_HEIGHT;
-
-static long __timeStart;
-static long __timeAbsolute;
-static bool __vsync = WINDOW_VSYNC;
-static float __pitch;
-static float __roll;
-static int __lx;
-static int __ly;
-static bool __hasMouse = false;
-static bool __leftMouseDown = false;
-static bool __rightMouseDown = false;
-static bool __shiftDown = false;
-
-long getMachTimeInMilliseconds()
-{
-    static const int64_t kOneMillion = 1000 * 1000;
-    static mach_timebase_info_data_t s_timebase_info;
-    
-    if (s_timebase_info.denom == 0) 
-        (void) mach_timebase_info(&s_timebase_info);
-    
-    // mach_absolute_time() returns billionth of seconds, so divide by one million to get milliseconds
-    return (long)((mach_absolute_time() * s_timebase_info.numer) / (kOneMillion * s_timebase_info.denom));
-}
-
-
-@class View;
-
-@interface View : NSOpenGLView <NSWindowDelegate> 
-{
-    CVDisplayLinkRef displayLink;
-    NSRecursiveLock* lock;
-    Game* _game;
-}
-
-@end
-
-
-static View* __view = NULL;
-
-@implementation View
-
--(void)windowWillClose:(NSNotification*)note 
-{
-    [lock lock];
-    _game->exit();
-    [lock unlock];
-    [[NSApplication sharedApplication] terminate:self];
-}
-
-
-- (CVReturn) getFrameForTime:(const CVTimeStamp*)outputTime
-{
-    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
-    
-    [self update];
-    
-    [pool release];
-    
-    return kCVReturnSuccess;
-}
-
--(void) update
-{       
-    [lock lock];
-
-    [[self openGLContext] makeCurrentContext];
-    
-    CGLLockContext((CGLContextObj)[[self openGLContext] CGLContextObj]);
-    
-    if (_game && _game->getState() == Game::RUNNING)       
-        _game->frame();
-    
-    CGLFlushDrawable((CGLContextObj)[[self openGLContext] CGLContextObj]);
-    CGLUnlockContext((CGLContextObj)[[self openGLContext] CGLContextObj]);  
-    
-    [lock unlock];
-}
-
-static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, 
-                                      CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
-{
-    CVReturn result = [(View*)displayLinkContext getFrameForTime:outputTime];
-    return result;
-}
-
-- (id) initWithFrame: (NSRect) frame
-{    
-    lock = [[NSRecursiveLock alloc] init];
-    _game = Game::getInstance();
-    __timeStart = getMachTimeInMilliseconds();
-    NSOpenGLPixelFormatAttribute attrs[] = 
-    {
-        NSOpenGLPFAAccelerated,
-        NSOpenGLPFADoubleBuffer,
-        NSOpenGLPFAColorSize, 32,
-        NSOpenGLPFADepthSize, 24,
-        NSOpenGLPFAAlphaSize, 8,
-        NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersionLegacy,
-        0
-    };
-    
-    NSOpenGLPixelFormat* pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
-    if (!pf)
-        NSLog(@"OpenGL pixel format not supported.");
-    
-    self = [super initWithFrame:frame pixelFormat:[pf autorelease]];  
-    
-    return self;
-}
-
-- (void) prepareOpenGL
-{
-    [super prepareOpenGL];
-    
-    NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
-    NSString* path = [bundlePath stringByAppendingString:@"/Contents/Resources/"];
-    FileSystem::setResourcePath([path cStringUsingEncoding:NSASCIIStringEncoding]);
-    _game->run(WINDOW_WIDTH, WINDOW_HEIGHT);
-    
-    [[self window] setLevel: NSFloatingWindowLevel];
-    [[self window] makeKeyAndOrderFront: self];
-    [[self window] setTitle: [NSString stringWithUTF8String: ""]];
-    
-    // Make all the OpenGL calls to setup rendering and build the necessary rendering objects
-    [[self openGLContext] makeCurrentContext];
-    // Synchronize buffer swaps with vertical refresh rate
-    GLint swapInt = __vsync ? 1 : 0;
-    [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
-    
-    // Create a display link capable of being used with all active displays
-    CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
-    
-    // Set the renderer output callback function
-    CVDisplayLinkSetOutputCallback(displayLink, &MyDisplayLinkCallback, self);
-    
-    CGLContextObj cglContext = (CGLContextObj)[[self openGLContext] CGLContextObj];
-    CGLPixelFormatObj cglPixelFormat = (CGLPixelFormatObj)[[self pixelFormat] CGLPixelFormatObj];
-    CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat);
-    
-    // Activate the display link
-    CVDisplayLinkStart(displayLink);
-}
-
-- (void) dealloc
-{   
-    [lock lock];
-    
-    // Release the display link
-    CVDisplayLinkStop(displayLink);
-    CVDisplayLinkRelease(displayLink);
-    
-    _game->exit();
-    
-    [lock unlock];
-
-    [super dealloc];
-}
-
-- (void) mouseDown: (NSEvent*) event
-{
-    NSPoint point = [event locationInWindow];
-    __leftMouseDown = true;
-    _game->touchEvent(Touch::TOUCH_PRESS, point.x, WINDOW_HEIGHT - point.y, 0);
-}
-
-- (void) mouseUp: (NSEvent*) event
-{
-    NSPoint point = [event locationInWindow];
-    __leftMouseDown = false;
-    _game->touchEvent(Touch::TOUCH_RELEASE, point.x, WINDOW_HEIGHT - point.y, 0);
-}
-
-- (void) mouseDragged: (NSEvent*) event
-{
-    NSPoint point = [event locationInWindow];
-    if (__leftMouseDown)
-    {
-        _game->touchEvent(Touch::TOUCH_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
-    }
-}
-
-- (void) rightMouseDown: (NSEvent*) event
-{
-    __rightMouseDown = true;
-     NSPoint point = [event locationInWindow];
-    __lx = point.x;
-    __ly = WINDOW_HEIGHT - point.y;
-}
-
-- (void) rightMouseUp: (NSEvent*) event
-{
-   __rightMouseDown = false;
-}
-
-- (void) rightMouseDragged: (NSEvent*) event
-{
-    NSPoint point = [event locationInWindow];
-    if (__rightMouseDown)
-    {
-        // Update the pitch and roll by adding the scaled deltas.
-        __roll += -(float)(point.x - __lx) * ACCELEROMETER_X_FACTOR;
-        __pitch -= (float)(point.y - (WINDOW_HEIGHT - __ly)) * ACCELEROMETER_Y_FACTOR;
-    
-        // Clamp the values to the valid range.
-        __roll = max(min(__roll, 90.0f), -90.0f);
-        __pitch = max(min(__pitch, 90.0f), -90.0f);
-    
-        // Update the last X/Y values.
-        __lx = point.x;
-        __ly = (WINDOW_HEIGHT - point.y);
-    }
-}
-
-- (void) mouseEntered: (NSEvent*)event
-{
-    __hasMouse = true;
-}
-
-- (void) mouseExited: (NSEvent*)event
-{
-    __leftMouseDown = false;
-    __rightMouseDown = false;
-    __hasMouse = false;
-}
-
-- (BOOL)acceptsFirstResponder
-{
-    return YES;
-}
-
-int getKey(unsigned short keyCode, unsigned int modifierFlags)
-{
-    __shiftDown = (modifierFlags & NSShiftKeyMask);
-    switch(keyCode)
-    {
-        case 0x69:
-            return Keyboard::KEY_PRINT;
-        case 0x35:
-            return Keyboard::KEY_ESCAPE;
-        case 0x33:
-            return Keyboard::KEY_BACKSPACE;
-        case 0x30:
-            return Keyboard::KEY_TAB;
-        case 0x24:
-            return Keyboard::KEY_RETURN;
-        case 0x72:
-            return Keyboard::KEY_INSERT;
-        case 0x73:
-            return Keyboard::KEY_HOME;
-        case 0x74:
-            return Keyboard::KEY_PG_UP;
-        case 0x79:
-            return Keyboard::KEY_PG_DOWN;
-        case 0x75:
-            return Keyboard::KEY_DELETE;
-        case 0x77:
-            return Keyboard::KEY_END;
-        case 0x7B:
-            return Keyboard::KEY_LEFT_ARROW;
-        case 0x7C:
-            return Keyboard::KEY_RIGHT_ARROW;
-        case 0x7E:
-            return Keyboard::KEY_UP_ARROW;
-        case 0x7D:
-            return Keyboard::KEY_DOWN_ARROW;
-        case 0x47:
-            return Keyboard::KEY_NUM_LOCK;
-        case 0x45:
-            return Keyboard::KEY_KP_PLUS;
-        case 0x4E:
-            return Keyboard::KEY_KP_MINUS;
-        case 0x43:
-            return Keyboard::KEY_KP_MULTIPLY;
-        case 0x4B:
-            return Keyboard::KEY_KP_DIVIDE;
-        case 0x59:
-            return Keyboard::KEY_KP_HOME;
-        case 0x5B:
-            return Keyboard::KEY_KP_UP;
-        case 0x5C:
-            return Keyboard::KEY_KP_PG_UP;
-        case 0x56:
-            return Keyboard::KEY_KP_LEFT;
-        case 0x57:
-            return Keyboard::KEY_KP_FIVE;
-        case 0x58:
-            return Keyboard::KEY_KP_RIGHT;
-        case 0x53:
-            return Keyboard::KEY_KP_END;
-        case 0x54:
-            return Keyboard::KEY_KP_DOWN;
-        case 0x55:
-            return Keyboard::KEY_KP_PG_DOWN;
-        case 0x52:
-            return Keyboard::KEY_KP_INSERT;
-        case 0x41:
-            return Keyboard::KEY_KP_DELETE;
-        case 0x7A:
-            return Keyboard::KEY_F1;
-        case 0x78:
-            return Keyboard::KEY_F2;
-        case 0x63:
-            return Keyboard::KEY_F3;
-        case 0x76:
-            return Keyboard::KEY_F4;
-        case 0x60:
-            return Keyboard::KEY_F5;
-        case 0x61:
-            return Keyboard::KEY_F6;
-        case 0x62:
-            return Keyboard::KEY_F7;
-        case 0x64:
-            return Keyboard::KEY_F8;
-        case 0x65:
-            return Keyboard::KEY_F9;
-        case 0x6D:
-            return Keyboard::KEY_F10;
-        
-        // MACOS reserved:
-        //return Keyboard::KEY_F11;
-        //return Keyboard::KEY_F12;
-        // return Keyboard::KEY_PAUSE;
-        // return Keyboard::KEY_SCROLL_LOCK;
-            
-        case 0x31:
-            return Keyboard::KEY_SPACE;
-        case 0x1D:
-            return __shiftDown ? Keyboard::KEY_RIGHT_PARENTHESIS : Keyboard::KEY_ZERO;
-        case 0x12:
-            return __shiftDown ? Keyboard::KEY_EXCLAM : Keyboard::KEY_ONE;
-        case 0x13:
-            return __shiftDown ? Keyboard::KEY_AT : Keyboard::KEY_TWO;
-        case 0x14:
-            return __shiftDown ? Keyboard::KEY_NUMBER : Keyboard::KEY_THREE;
-        case 0x15:
-            return __shiftDown ? Keyboard::KEY_DOLLAR : Keyboard::KEY_FOUR;
-        case 0x17:
-            return __shiftDown ? Keyboard::KEY_PERCENT : Keyboard::KEY_FIVE;
-        case 0x16:
-            return __shiftDown ? Keyboard::KEY_CIRCUMFLEX : Keyboard::KEY_SIX;
-        case 0x1A:
-            return __shiftDown ? Keyboard::KEY_AMPERSAND : Keyboard::KEY_SEVEN;
-        case 0x1C:
-            return __shiftDown ? Keyboard::KEY_ASTERISK : Keyboard::KEY_EIGHT;
-        case 0x19:
-            return __shiftDown ? Keyboard::KEY_LEFT_PARENTHESIS : Keyboard::KEY_NINE;
-        case 0x18:
-            return __shiftDown ? Keyboard::KEY_EQUAL : Keyboard::KEY_PLUS;
-        case 0x2B:
-            return __shiftDown ? Keyboard::KEY_LESS_THAN : Keyboard::KEY_COMMA;
-        case 0x1B:
-            return __shiftDown ? Keyboard::KEY_UNDERSCORE : Keyboard::KEY_MINUS;
-        case 0x2F:
-            return __shiftDown ? Keyboard::KEY_GREATER_THAN : Keyboard::KEY_PERIOD;
-        case 0x29:
-            return __shiftDown ? Keyboard::KEY_COLON : Keyboard::KEY_SEMICOLON;
-        case 0x2C:
-            return __shiftDown ? Keyboard::KEY_QUESTION : Keyboard::KEY_SLASH;
-        case 0x32:
-            return __shiftDown ? Keyboard::KEY_GRAVE : Keyboard::KEY_TILDE;
-        case 0x21:
-            return __shiftDown ? Keyboard::KEY_LEFT_BRACE : Keyboard::KEY_LEFT_BRACKET;
-        case 0x2A:
-            return __shiftDown ? Keyboard::KEY_BAR : Keyboard::KEY_BACK_SLASH;
-        case 0x1E:
-            return __shiftDown ? Keyboard::KEY_RIGHT_BRACE : Keyboard::KEY_RIGHT_BRACKET;
-        case 0x27:
-            return __shiftDown ? Keyboard::KEY_QUOTE : Keyboard::KEY_APOSTROPHE;
-            
-        case 0x00:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_A : Keyboard::KEY_A;
-        case 0x0B:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_B : Keyboard::KEY_B;
-        case 0x08:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_C : Keyboard::KEY_C;
-        case 0x02:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_D : Keyboard::KEY_D;
-        case 0x0E:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_E : Keyboard::KEY_E;
-        case 0x03:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_F : Keyboard::KEY_F;
-        case 0x05:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_G : Keyboard::KEY_G;
-        case 0x04:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_H : Keyboard::KEY_H;
-        case 0x22:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_I : Keyboard::KEY_I;
-        case 0x26:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_J : Keyboard::KEY_J;
-        case 0x28:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_K : Keyboard::KEY_K;
-        case 0x25:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_L : Keyboard::KEY_L;
-        case 0x2E:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_M : Keyboard::KEY_M;
-        case 0x2D:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_N : Keyboard::KEY_N;
-        case 0x1F:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_O : Keyboard::KEY_O;
-        case 0x23:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_P : Keyboard::KEY_P;
-        case 0x0C:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_Q : Keyboard::KEY_Q;
-        case 0x0F:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_R : Keyboard::KEY_R;
-        case 0x01:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_S : Keyboard::KEY_S;
-        case 0x11:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_T : Keyboard::KEY_T;
-        case 0x20:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_U : Keyboard::KEY_U;
-        case 0x09:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_V : Keyboard::KEY_V;
-        case 0x0D:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_W : Keyboard::KEY_W;
-        case 0x07:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_X : Keyboard::KEY_X;
-        case 0x10:
-            return __shiftDown ? Keyboard::KEY_CAPITAL_Y : Keyboard::KEY_Y;
-        case 0x06:
-            return __shiftDown ? Keyboard::KEY_CAPITAL_Z : Keyboard::KEY_Z;
-
-        default:
-            return Keyboard::KEY_NONE;
-    }
-}
-
-- (void)flagsChanged: (NSEvent*)event
-{
-    unsigned int keyCode = [event keyCode];
-    unsigned int flags = [event modifierFlags];
-    switch (keyCode) 
-    {
-        case 0x39:
-            _game->keyEvent((flags & NSAlphaShiftKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_CAPS_LOCK);
-            break;
-        case 0x38:
-            _game->keyEvent((flags & NSShiftKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_LEFT_SHIFT);
-            break;
-        case 0x3C:
-            _game->keyEvent((flags & NSShiftKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_RIGHT_SHIFT);
-            break;
-        case 0x3A:
-            _game->keyEvent((flags & NSAlternateKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_LEFT_ALT);
-            break;
-        case 0x3D:
-            _game->keyEvent((flags & NSAlternateKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_RIGHT_ALT);
-            break;
-        case 0x3B:
-            _game->keyEvent((flags & NSControlKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_LEFT_CTRL);
-            break;
-        case 0x3E:
-            _game->keyEvent((flags & NSControlKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_RIGHT_CTRL);
-            break;
-        case 0x37:
-            _game->keyEvent((flags & NSCommandKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_LEFT_HYPER);
-            break;
-        case 0x36:
-            _game->keyEvent((flags & NSCommandKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_RIGHT_HYPER);
-            break;
-    }
-}
-
-- (void) keyDown: (NSEvent*) event
-{    
-    _game->keyEvent(Keyboard::KEY_PRESS, getKey([event keyCode], [event modifierFlags]));
-}
-
-- (void) keyUp: (NSEvent*) event
-{    
-    _game->keyEvent(Keyboard::KEY_RELEASE, getKey([event keyCode], [event modifierFlags]));
-}
-
-@end
-
-
-namespace gameplay
-{
-
-extern void printError(const char* format, ...)
-{
-    va_list argptr;
-    va_start(argptr, format);
-    vfprintf(stderr, format, argptr);
-    fprintf(stderr, "\n");
-    va_end(argptr);
-}
-    
-    
-Platform::Platform(Game* game)
-: _game(game)
-{
-}
-
-Platform::Platform(const Platform& copy)
-{
-    // hidden
-}
-
-Platform::~Platform()
-{
-}
-
-Platform* Platform::create(Game* game)
-{
-    Platform* platform = new Platform(game);
-    
-    return platform;
-}
-
-int Platform::enterMessagePump()
-{
-    NSAutoreleasePool* pool = [NSAutoreleasePool new];
-    NSApplication* NSApp = [NSApplication sharedApplication];
-    NSRect screenBounds = [[NSScreen mainScreen] frame];
-    NSRect viewBounds = NSMakeRect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
-    
-    __view = [[View alloc] initWithFrame:viewBounds];
-    
-    NSRect centered = NSMakeRect(NSMidX(screenBounds) - NSMidX(viewBounds),
-                                 NSMidY(screenBounds) - NSMidY(viewBounds),
-                                 viewBounds.size.width, 
-                                 viewBounds.size.height);
-    
-    NSWindow* window = [[NSWindow alloc]
-                        initWithContentRect:centered
-                        styleMask:NSTitledWindowMask | NSClosableWindowMask
-                        backing:NSBackingStoreBuffered
-                        defer:NO];
-    
-    [window setContentView:__view];
-    [window setDelegate:__view];
-    [__view release];
-    
-    [NSApp run];
-    
-    [pool release];
-    return EXIT_SUCCESS;
-}
-    
-long Platform::getAbsoluteTime()
-{
-    __timeAbsolute = getMachTimeInMilliseconds();
-    return __timeAbsolute;
-}
-
-void Platform::setAbsoluteTime(long time)
-{
-    __timeAbsolute = time;
-}
-
-bool Platform::isVsync()
-{
-    return __vsync;
-}
-
-void Platform::setVsync(bool enable)
-{
-    __vsync = enable;
-}
-
-int Platform::getOrientationAngle()
-{
-    return 0;
-}
-
-void Platform::getAccelerometerValues(float* pitch, float* roll)
-{
-    *pitch = __pitch;
-    *roll = __roll;
-}
-
-void Platform::swapBuffers()
-{
-    if (__view)
-        CGLFlushDrawable((CGLContextObj)[[__view openGLContext] CGLContextObj]);
-}
-
-}
-
-#endif
+#ifdef __APPLE__
+
+#include "Base.h"
+#include "Platform.h"
+#include "FileSystem.h"
+#include "Game.h"
+
+#import <Cocoa/Cocoa.h>
+#import <QuartzCore/CVDisplayLink.h>
+#import <OpenGL/OpenGL.h>
+#import <mach/mach_time.h>
+
+using namespace std;
+using namespace gameplay;
+
+static const float ACCELEROMETER_X_FACTOR = 90.0f / WINDOW_WIDTH;
+static const float ACCELEROMETER_Y_FACTOR = 90.0f / WINDOW_HEIGHT;
+
+static long __timeStart;
+static long __timeAbsolute;
+static bool __vsync = WINDOW_VSYNC;
+static float __pitch;
+static float __roll;
+static int __lx;
+static int __ly;
+static bool __hasMouse = false;
+static bool __leftMouseDown = false;
+static bool __rightMouseDown = false;
+static bool __shiftDown = false;
+
+long getMachTimeInMilliseconds()
+{
+    static const int64_t kOneMillion = 1000 * 1000;
+    static mach_timebase_info_data_t s_timebase_info;
+    
+    if (s_timebase_info.denom == 0) 
+        (void) mach_timebase_info(&s_timebase_info);
+    
+    // mach_absolute_time() returns billionth of seconds, so divide by one million to get milliseconds
+    return (long)((mach_absolute_time() * s_timebase_info.numer) / (kOneMillion * s_timebase_info.denom));
+}
+
+
+@class View;
+
+@interface View : NSOpenGLView <NSWindowDelegate> 
+{
+    CVDisplayLinkRef displayLink;
+    NSRecursiveLock* lock;
+    Game* _game;
+}
+
+@end
+
+
+static View* __view = NULL;
+
+@implementation View
+
+-(void)windowWillClose:(NSNotification*)note 
+{
+    [lock lock];
+    _game->exit();
+    [lock unlock];
+    [[NSApplication sharedApplication] terminate:self];
+}
+
+
+- (CVReturn) getFrameForTime:(const CVTimeStamp*)outputTime
+{
+    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+    
+    [self update];
+    
+    [pool release];
+    
+    return kCVReturnSuccess;
+}
+
+-(void) update
+{       
+    [lock lock];
+
+    [[self openGLContext] makeCurrentContext];
+    
+    CGLLockContext((CGLContextObj)[[self openGLContext] CGLContextObj]);
+    
+    if (_game && _game->getState() == Game::RUNNING)       
+        _game->frame();
+    
+    CGLFlushDrawable((CGLContextObj)[[self openGLContext] CGLContextObj]);
+    CGLUnlockContext((CGLContextObj)[[self openGLContext] CGLContextObj]);  
+    
+    [lock unlock];
+}
+
+static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, 
+                                      CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
+{
+    CVReturn result = [(View*)displayLinkContext getFrameForTime:outputTime];
+    return result;
+}
+
+- (id) initWithFrame: (NSRect) frame
+{    
+    lock = [[NSRecursiveLock alloc] init];
+    _game = Game::getInstance();
+    __timeStart = getMachTimeInMilliseconds();
+    NSOpenGLPixelFormatAttribute attrs[] = 
+    {
+        NSOpenGLPFAAccelerated,
+        NSOpenGLPFADoubleBuffer,
+        NSOpenGLPFAColorSize, 32,
+        NSOpenGLPFADepthSize, 24,
+        NSOpenGLPFAAlphaSize, 8,
+        NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersionLegacy,
+        0
+    };
+    
+    NSOpenGLPixelFormat* pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
+    if (!pf)
+        NSLog(@"OpenGL pixel format not supported.");
+    
+    self = [super initWithFrame:frame pixelFormat:[pf autorelease]];  
+    
+    return self;
+}
+
+- (void) prepareOpenGL
+{
+    [super prepareOpenGL];
+    
+    NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
+    NSString* path = [bundlePath stringByAppendingString:@"/Contents/Resources/"];
+    FileSystem::setResourcePath([path cStringUsingEncoding:NSASCIIStringEncoding]);
+    _game->run(WINDOW_WIDTH, WINDOW_HEIGHT);
+    
+    [[self window] setLevel: NSFloatingWindowLevel];
+    [[self window] makeKeyAndOrderFront: self];
+    [[self window] setTitle: [NSString stringWithUTF8String: ""]];
+    
+    // Make all the OpenGL calls to setup rendering and build the necessary rendering objects
+    [[self openGLContext] makeCurrentContext];
+    // Synchronize buffer swaps with vertical refresh rate
+    GLint swapInt = __vsync ? 1 : 0;
+    [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
+    
+    // Create a display link capable of being used with all active displays
+    CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
+    
+    // Set the renderer output callback function
+    CVDisplayLinkSetOutputCallback(displayLink, &MyDisplayLinkCallback, self);
+    
+    CGLContextObj cglContext = (CGLContextObj)[[self openGLContext] CGLContextObj];
+    CGLPixelFormatObj cglPixelFormat = (CGLPixelFormatObj)[[self pixelFormat] CGLPixelFormatObj];
+    CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat);
+    
+    // Activate the display link
+    CVDisplayLinkStart(displayLink);
+}
+
+- (void) dealloc
+{   
+    [lock lock];
+    
+    // Release the display link
+    CVDisplayLinkStop(displayLink);
+    CVDisplayLinkRelease(displayLink);
+    
+    _game->exit();
+    
+    [lock unlock];
+
+    [super dealloc];
+}
+
+- (void) mouseDown: (NSEvent*) event
+{
+    NSPoint point = [event locationInWindow];
+    __leftMouseDown = true;
+    _game->touchEvent(Touch::TOUCH_PRESS, point.x, WINDOW_HEIGHT - point.y, 0);
+}
+
+- (void) mouseUp: (NSEvent*) event
+{
+    NSPoint point = [event locationInWindow];
+    __leftMouseDown = false;
+    _game->touchEvent(Touch::TOUCH_RELEASE, point.x, WINDOW_HEIGHT - point.y, 0);
+}
+
+- (void) mouseDragged: (NSEvent*) event
+{
+    NSPoint point = [event locationInWindow];
+    if (__leftMouseDown)
+    {
+        _game->touchEvent(Touch::TOUCH_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
+    }
+}
+
+- (void) rightMouseDown: (NSEvent*) event
+{
+    __rightMouseDown = true;
+     NSPoint point = [event locationInWindow];
+    __lx = point.x;
+    __ly = WINDOW_HEIGHT - point.y;
+}
+
+- (void) rightMouseUp: (NSEvent*) event
+{
+   __rightMouseDown = false;
+}
+
+- (void) rightMouseDragged: (NSEvent*) event
+{
+    NSPoint point = [event locationInWindow];
+    if (__rightMouseDown)
+    {
+        // Update the pitch and roll by adding the scaled deltas.
+        __roll += -(float)(point.x - __lx) * ACCELEROMETER_X_FACTOR;
+        __pitch -= (float)(point.y - (WINDOW_HEIGHT - __ly)) * ACCELEROMETER_Y_FACTOR;
+    
+        // Clamp the values to the valid range.
+        __roll = max(min(__roll, 90.0f), -90.0f);
+        __pitch = max(min(__pitch, 90.0f), -90.0f);
+    
+        // Update the last X/Y values.
+        __lx = point.x;
+        __ly = (WINDOW_HEIGHT - point.y);
+    }
+}
+
+- (void) mouseEntered: (NSEvent*)event
+{
+    __hasMouse = true;
+}
+
+- (void) mouseExited: (NSEvent*)event
+{
+    __leftMouseDown = false;
+    __rightMouseDown = false;
+    __hasMouse = false;
+}
+
+- (BOOL)acceptsFirstResponder
+{
+    return YES;
+}
+
+int getKey(unsigned short keyCode, unsigned int modifierFlags)
+{
+    __shiftDown = (modifierFlags & NSShiftKeyMask);
+    switch(keyCode)
+    {
+        case 0x69:
+            return Keyboard::KEY_PRINT;
+        case 0x35:
+            return Keyboard::KEY_ESCAPE;
+        case 0x33:
+            return Keyboard::KEY_BACKSPACE;
+        case 0x30:
+            return Keyboard::KEY_TAB;
+        case 0x24:
+            return Keyboard::KEY_RETURN;
+        case 0x72:
+            return Keyboard::KEY_INSERT;
+        case 0x73:
+            return Keyboard::KEY_HOME;
+        case 0x74:
+            return Keyboard::KEY_PG_UP;
+        case 0x79:
+            return Keyboard::KEY_PG_DOWN;
+        case 0x75:
+            return Keyboard::KEY_DELETE;
+        case 0x77:
+            return Keyboard::KEY_END;
+        case 0x7B:
+            return Keyboard::KEY_LEFT_ARROW;
+        case 0x7C:
+            return Keyboard::KEY_RIGHT_ARROW;
+        case 0x7E:
+            return Keyboard::KEY_UP_ARROW;
+        case 0x7D:
+            return Keyboard::KEY_DOWN_ARROW;
+        case 0x47:
+            return Keyboard::KEY_NUM_LOCK;
+        case 0x45:
+            return Keyboard::KEY_KP_PLUS;
+        case 0x4E:
+            return Keyboard::KEY_KP_MINUS;
+        case 0x43:
+            return Keyboard::KEY_KP_MULTIPLY;
+        case 0x4B:
+            return Keyboard::KEY_KP_DIVIDE;
+        case 0x59:
+            return Keyboard::KEY_KP_HOME;
+        case 0x5B:
+            return Keyboard::KEY_KP_UP;
+        case 0x5C:
+            return Keyboard::KEY_KP_PG_UP;
+        case 0x56:
+            return Keyboard::KEY_KP_LEFT;
+        case 0x57:
+            return Keyboard::KEY_KP_FIVE;
+        case 0x58:
+            return Keyboard::KEY_KP_RIGHT;
+        case 0x53:
+            return Keyboard::KEY_KP_END;
+        case 0x54:
+            return Keyboard::KEY_KP_DOWN;
+        case 0x55:
+            return Keyboard::KEY_KP_PG_DOWN;
+        case 0x52:
+            return Keyboard::KEY_KP_INSERT;
+        case 0x41:
+            return Keyboard::KEY_KP_DELETE;
+        case 0x7A:
+            return Keyboard::KEY_F1;
+        case 0x78:
+            return Keyboard::KEY_F2;
+        case 0x63:
+            return Keyboard::KEY_F3;
+        case 0x76:
+            return Keyboard::KEY_F4;
+        case 0x60:
+            return Keyboard::KEY_F5;
+        case 0x61:
+            return Keyboard::KEY_F6;
+        case 0x62:
+            return Keyboard::KEY_F7;
+        case 0x64:
+            return Keyboard::KEY_F8;
+        case 0x65:
+            return Keyboard::KEY_F9;
+        case 0x6D:
+            return Keyboard::KEY_F10;
+        
+        // MACOS reserved:
+        //return Keyboard::KEY_F11;
+        //return Keyboard::KEY_F12;
+        // return Keyboard::KEY_PAUSE;
+        // return Keyboard::KEY_SCROLL_LOCK;
+            
+        case 0x31:
+            return Keyboard::KEY_SPACE;
+        case 0x1D:
+            return __shiftDown ? Keyboard::KEY_RIGHT_PARENTHESIS : Keyboard::KEY_ZERO;
+        case 0x12:
+            return __shiftDown ? Keyboard::KEY_EXCLAM : Keyboard::KEY_ONE;
+        case 0x13:
+            return __shiftDown ? Keyboard::KEY_AT : Keyboard::KEY_TWO;
+        case 0x14:
+            return __shiftDown ? Keyboard::KEY_NUMBER : Keyboard::KEY_THREE;
+        case 0x15:
+            return __shiftDown ? Keyboard::KEY_DOLLAR : Keyboard::KEY_FOUR;
+        case 0x17:
+            return __shiftDown ? Keyboard::KEY_PERCENT : Keyboard::KEY_FIVE;
+        case 0x16:
+            return __shiftDown ? Keyboard::KEY_CIRCUMFLEX : Keyboard::KEY_SIX;
+        case 0x1A:
+            return __shiftDown ? Keyboard::KEY_AMPERSAND : Keyboard::KEY_SEVEN;
+        case 0x1C:
+            return __shiftDown ? Keyboard::KEY_ASTERISK : Keyboard::KEY_EIGHT;
+        case 0x19:
+            return __shiftDown ? Keyboard::KEY_LEFT_PARENTHESIS : Keyboard::KEY_NINE;
+        case 0x18:
+            return __shiftDown ? Keyboard::KEY_EQUAL : Keyboard::KEY_PLUS;
+        case 0x2B:
+            return __shiftDown ? Keyboard::KEY_LESS_THAN : Keyboard::KEY_COMMA;
+        case 0x1B:
+            return __shiftDown ? Keyboard::KEY_UNDERSCORE : Keyboard::KEY_MINUS;
+        case 0x2F:
+            return __shiftDown ? Keyboard::KEY_GREATER_THAN : Keyboard::KEY_PERIOD;
+        case 0x29:
+            return __shiftDown ? Keyboard::KEY_COLON : Keyboard::KEY_SEMICOLON;
+        case 0x2C:
+            return __shiftDown ? Keyboard::KEY_QUESTION : Keyboard::KEY_SLASH;
+        case 0x32:
+            return __shiftDown ? Keyboard::KEY_GRAVE : Keyboard::KEY_TILDE;
+        case 0x21:
+            return __shiftDown ? Keyboard::KEY_LEFT_BRACE : Keyboard::KEY_LEFT_BRACKET;
+        case 0x2A:
+            return __shiftDown ? Keyboard::KEY_BAR : Keyboard::KEY_BACK_SLASH;
+        case 0x1E:
+            return __shiftDown ? Keyboard::KEY_RIGHT_BRACE : Keyboard::KEY_RIGHT_BRACKET;
+        case 0x27:
+            return __shiftDown ? Keyboard::KEY_QUOTE : Keyboard::KEY_APOSTROPHE;
+            
+        case 0x00:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_A : Keyboard::KEY_A;
+        case 0x0B:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_B : Keyboard::KEY_B;
+        case 0x08:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_C : Keyboard::KEY_C;
+        case 0x02:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_D : Keyboard::KEY_D;
+        case 0x0E:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_E : Keyboard::KEY_E;
+        case 0x03:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_F : Keyboard::KEY_F;
+        case 0x05:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_G : Keyboard::KEY_G;
+        case 0x04:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_H : Keyboard::KEY_H;
+        case 0x22:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_I : Keyboard::KEY_I;
+        case 0x26:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_J : Keyboard::KEY_J;
+        case 0x28:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_K : Keyboard::KEY_K;
+        case 0x25:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_L : Keyboard::KEY_L;
+        case 0x2E:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_M : Keyboard::KEY_M;
+        case 0x2D:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_N : Keyboard::KEY_N;
+        case 0x1F:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_O : Keyboard::KEY_O;
+        case 0x23:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_P : Keyboard::KEY_P;
+        case 0x0C:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_Q : Keyboard::KEY_Q;
+        case 0x0F:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_R : Keyboard::KEY_R;
+        case 0x01:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_S : Keyboard::KEY_S;
+        case 0x11:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_T : Keyboard::KEY_T;
+        case 0x20:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_U : Keyboard::KEY_U;
+        case 0x09:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_V : Keyboard::KEY_V;
+        case 0x0D:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_W : Keyboard::KEY_W;
+        case 0x07:
+             return __shiftDown ? Keyboard::KEY_CAPITAL_X : Keyboard::KEY_X;
+        case 0x10:
+            return __shiftDown ? Keyboard::KEY_CAPITAL_Y : Keyboard::KEY_Y;
+        case 0x06:
+            return __shiftDown ? Keyboard::KEY_CAPITAL_Z : Keyboard::KEY_Z;
+
+        default:
+            return Keyboard::KEY_NONE;
+    }
+}
+
+- (void)flagsChanged: (NSEvent*)event
+{
+    unsigned int keyCode = [event keyCode];
+    unsigned int flags = [event modifierFlags];
+    switch (keyCode) 
+    {
+        case 0x39:
+            _game->keyEvent((flags & NSAlphaShiftKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_CAPS_LOCK);
+            break;
+        case 0x38:
+            _game->keyEvent((flags & NSShiftKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_LEFT_SHIFT);
+            break;
+        case 0x3C:
+            _game->keyEvent((flags & NSShiftKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_RIGHT_SHIFT);
+            break;
+        case 0x3A:
+            _game->keyEvent((flags & NSAlternateKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_LEFT_ALT);
+            break;
+        case 0x3D:
+            _game->keyEvent((flags & NSAlternateKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_RIGHT_ALT);
+            break;
+        case 0x3B:
+            _game->keyEvent((flags & NSControlKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_LEFT_CTRL);
+            break;
+        case 0x3E:
+            _game->keyEvent((flags & NSControlKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_RIGHT_CTRL);
+            break;
+        case 0x37:
+            _game->keyEvent((flags & NSCommandKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_LEFT_HYPER);
+            break;
+        case 0x36:
+            _game->keyEvent((flags & NSCommandKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_RIGHT_HYPER);
+            break;
+    }
+}
+
+- (void) keyDown: (NSEvent*) event
+{    
+    _game->keyEvent(Keyboard::KEY_PRESS, getKey([event keyCode], [event modifierFlags]));
+}
+
+- (void) keyUp: (NSEvent*) event
+{    
+    _game->keyEvent(Keyboard::KEY_RELEASE, getKey([event keyCode], [event modifierFlags]));
+}
+
+@end
+
+
+namespace gameplay
+{
+
+extern void printError(const char* format, ...)
+{
+    va_list argptr;
+    va_start(argptr, format);
+    vfprintf(stderr, format, argptr);
+    fprintf(stderr, "\n");
+    va_end(argptr);
+}
+    
+    
+Platform::Platform(Game* game)
+: _game(game)
+{
+}
+
+Platform::Platform(const Platform& copy)
+{
+    // hidden
+}
+
+Platform::~Platform()
+{
+}
+
+Platform* Platform::create(Game* game)
+{
+    Platform* platform = new Platform(game);
+    
+    return platform;
+}
+
+int Platform::enterMessagePump()
+{
+    NSAutoreleasePool* pool = [NSAutoreleasePool new];
+    NSApplication* NSApp = [NSApplication sharedApplication];
+    NSRect screenBounds = [[NSScreen mainScreen] frame];
+    NSRect viewBounds = NSMakeRect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
+    
+    __view = [[View alloc] initWithFrame:viewBounds];
+    
+    NSRect centered = NSMakeRect(NSMidX(screenBounds) - NSMidX(viewBounds),
+                                 NSMidY(screenBounds) - NSMidY(viewBounds),
+                                 viewBounds.size.width, 
+                                 viewBounds.size.height);
+    
+    NSWindow* window = [[NSWindow alloc]
+                        initWithContentRect:centered
+                        styleMask:NSTitledWindowMask | NSClosableWindowMask
+                        backing:NSBackingStoreBuffered
+                        defer:NO];
+    
+    [window setContentView:__view];
+    [window setDelegate:__view];
+    [__view release];
+    
+    [NSApp run];
+    
+    [pool release];
+    return EXIT_SUCCESS;
+}
+    
+long Platform::getAbsoluteTime()
+{
+    __timeAbsolute = getMachTimeInMilliseconds();
+    return __timeAbsolute;
+}
+
+void Platform::setAbsoluteTime(long time)
+{
+    __timeAbsolute = time;
+}
+
+bool Platform::isVsync()
+{
+    return __vsync;
+}
+
+void Platform::setVsync(bool enable)
+{
+    __vsync = enable;
+}
+
+int Platform::getOrientationAngle()
+{
+    return 0;
+}
+
+void Platform::getAccelerometerValues(float* pitch, float* roll)
+{
+    *pitch = __pitch;
+    *roll = __roll;
+}
+
+void Platform::swapBuffers()
+{
+    if (__view)
+        CGLFlushDrawable((CGLContextObj)[[__view openGLContext] CGLContextObj]);
+}
+
+void Platform::displayKeyboard(bool display)
+{
+    // Do nothing.
+}
+
+}
+
+#endif

+ 9 - 0
gameplay/src/PlatformQNX.cpp

@@ -13,6 +13,7 @@
 #include <bps/navigator.h>
 #include <bps/accelerometer.h>
 #include <bps/orientation.h>
+#include <bps/virtualkeyboard.h>
 
 #define TOUCH_COUNT_MAX     4
 
@@ -879,6 +880,14 @@ void Platform::swapBuffers()
         eglSwapBuffers(__eglDisplay, __eglSurface);
 }
 
+void Platform::displayKeyboard(bool display)
+{
+    if (display)
+        virtualkeyboard_show();
+    else
+        virtualkeyboard_hide();
+}
+
 }
 
 #endif

+ 5 - 0
gameplay/src/PlatformWin32.cpp

@@ -586,6 +586,11 @@ void Platform::swapBuffers()
         SwapBuffers(__hdc);
 }
 
+void Platform::displayKeyboard(bool display)
+{
+    // Do nothing.
+}
+
 }
 
 #endif

+ 63 - 65
gameplay/src/gameplay-main-android.cpp

@@ -3,6 +3,7 @@
 #include "gameplay.h"
 #include <android/sensor.h>
 #include <android_native_app_glue.h>
+#include <jni.h>
 
 
 #include <android/log.h>
@@ -17,23 +18,26 @@ extern ASensorManager* __sensorManager;
 extern const ASensor* __accelerometerSensor;
 extern ASensorEventQueue* __sensorEventQueue;
 extern ASensorEvent __sensorEvent;
+bool __displayKeyboard = false;
+bool __initialized = false;
+
 
 namespace gameplay
 {
 extern Keyboard::Key getKey(int keycode, int metastate);
+extern void displayKeyboard(android_app* mApplication, bool pShow);
 }
 
-bool __initialized;
-
 /**
  * Process the next input event.
  */
-static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) 
+static int32_t engine_handle_input(struct android_app* app, AInputEvent* event)
 {
     Platform* platform = static_cast<Platform*>(app->userData);
     
     if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION)
     {
+        
         int32_t data = AMotionEvent_getAction(event);
         int contactIndex = data >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
         Touch::TouchEvent touchEvent;
@@ -56,21 +60,19 @@ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event)
     else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY)
     {
         int32_t action = AKeyEvent_getAction(event);
-		int32_t keycode = AKeyEvent_getKeyCode(event);
-		int32_t metastate = AKeyEvent_getMetaState(event); 
-		
-		WARN_VARG("Key event: action=%d keyCode=%d metaState=0x%x", action, keycode, metastate);
+        int32_t keycode = AKeyEvent_getKeyCode(event);
+        int32_t metastate = AKeyEvent_getMetaState(event); 
         
-		switch(action)
-		{
-			case AKEY_EVENT_ACTION_DOWN:
-				Game::getInstance()->keyEvent(Keyboard::KEY_PRESS, getKey(keycode, metastate));
-				break;
-					
-			case AKEY_EVENT_ACTION_UP:
-				Game::getInstance()->keyEvent(Keyboard::KEY_RELEASE, getKey(keycode, metastate));
-				break;
-		}
+        switch(action)
+        {
+            case AKEY_EVENT_ACTION_DOWN:
+                Game::getInstance()->keyEvent(Keyboard::KEY_PRESS, getKey(keycode, metastate));
+                break;
+                    
+            case AKEY_EVENT_ACTION_UP:
+                Game::getInstance()->keyEvent(Keyboard::KEY_RELEASE, getKey(keycode, metastate));
+                break;
+        }
     }
     return 0;
 }
@@ -83,37 +85,33 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd)
     switch (cmd) 
     {
         case APP_CMD_SAVE_STATE:
-            WARN("engine_handle_cmd - APP_CMD_SAVE_STATE");
             // TODO
             break;
         case APP_CMD_INIT_WINDOW:
-            WARN("engine_handle_cmd - APP_CMD_INIT_WINDOW");
-			// The window is being shown, get it ready.
+            // The window is being shown, get it ready.
             if (app->window != NULL)
             {
                 Game* game = Game::getInstance();
                 assert(game != NULL);
                 Platform* platform = Platform::create(game);
                 app->userData = platform;
-				__initialized = true;
+                __initialized = true;
             }
             break;
         case APP_CMD_TERM_WINDOW:
-		{
-			WARN("engine_handle_cmd - APP_CMD_TERM_WINDOW");
+        {
             Game::getInstance()->exit();
-			Platform* platform = static_cast<Platform*>(app->userData);
-			if (!platform)
-			{
-				return;
-			}
-			delete platform;
-			app->userData = NULL;
-			break;
-		}
+            Platform* platform = static_cast<Platform*>(app->userData);
+            if (!platform)
+            {
+                return;
+            }
+            delete platform;
+            app->userData = NULL;
+            break;
+        }
         case APP_CMD_GAINED_FOCUS:
-            WARN("engine_handle_cmd - APP_CMD_GAINED_FOCUS");
-			// When our app gains focus, we start monitoring the accelerometer.
+            // When our app gains focus, we start monitoring the accelerometer.
             if (__accelerometerSensor != NULL) {
                 ASensorEventQueue_enableSensor(__sensorEventQueue, __accelerometerSensor);
                 // We'd like to get 60 events per second (in us).
@@ -122,8 +120,7 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd)
             Game::getInstance()->resume();
             break;
         case APP_CMD_LOST_FOCUS:
-            WARN("engine_handle_cmd - APP_CMD_LOST_FOCUS");
-			// When our app loses focus, we stop monitoring the accelerometer.
+            // When our app loses focus, we stop monitoring the accelerometer.
             // This is to avoid consuming battery while not being used.
             if (__accelerometerSensor != NULL) {
                 ASensorEventQueue_disableSensor(__sensorEventQueue, __accelerometerSensor);
@@ -139,14 +136,14 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd)
  */
 void amain(struct android_app* state)
 {
-	ANativeActivity* activity = state->activity;
-	JNIEnv* env = activity->env;
+    ANativeActivity* activity = state->activity;
+    JNIEnv* env = activity->env;
 
     jclass clazz = env->GetObjectClass(activity->clazz);
     jmethodID methodID = env->GetMethodID(clazz, "getPackageName", "()Ljava/lang/String;");
     jobject result = env->CallObjectMethod(activity->clazz, methodID);
-	
-	const char* packageName;
+    
+    const char* packageName;
     jboolean isCopy;
     packageName = env->GetStringUTFChars((jstring)result, &isCopy);
     
@@ -160,49 +157,50 @@ void amain(struct android_app* state)
     state->onInputEvent = engine_handle_input;
     __state = state;
     
-	// Prepare to monitor accelerometer.
+    // Prepare to monitor accelerometer.
     __sensorManager = ASensorManager_getInstance();
     __accelerometerSensor = ASensorManager_getDefaultSensor(__sensorManager, ASENSOR_TYPE_ACCELEROMETER);
     __sensorEventQueue = ASensorManager_createEventQueue(__sensorManager, __state->looper, LOOPER_ID_USER, NULL, NULL);
-	
-	ANativeActivity_showSoftInput(state->activity, ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT);
-	
-	
-	__initialized = false;
-	while (true) 
+    
+    while (true)
     {
-		// Read all pending events.
+    
+        // Read all pending events.
         int ident;
         int events;
         struct android_poll_source* source;
         
-		bool _shouldPoll = !(__initialized && Game::getInstance()->getState() == Game::UNINITIALIZED) && (Game::getInstance()->getState() != Game::PAUSED); 
-		
-		while ((ident=ALooper_pollAll( _shouldPoll ? 0 : -1, NULL, &events, (void**)&source)) >= 0) 
+        bool _shouldPoll = !(__initialized && Game::getInstance()->getState() == Game::UNINITIALIZED) && (Game::getInstance()->getState() != Game::PAUSED); 
+        
+        while ((ident=ALooper_pollAll( _shouldPoll ? 0 : -1, NULL, &events, (void**)&source)) >= 0) 
         {
-			// Process this event.
+            // Process this event.
             if (source != NULL) 
                 source->process(__state, source);
             
             // If a sensor has data, process it now.
             if (ident == LOOPER_ID_USER && __accelerometerSensor != NULL)
                 ASensorEventQueue_getEvents(__sensorEventQueue, &__sensorEvent, 1);
-			
-			if (__state->destroyRequested != 0)
-				break;
+            
+            if (__state->destroyRequested != 0)
+                break;
         }
-		
-		Platform* platform = static_cast<Platform*>(state->userData);
-		if (platform)
-			platform->enterMessagePump();
-		
-		// Check if we are exiting.
+        
+        Platform* platform = static_cast<Platform*>(state->userData);
+        if (platform)
+            platform->enterMessagePump();
+            
+        
+        // Check if we are exiting.
         if ((__state->destroyRequested != 0) || (__initialized && Game::getInstance()->getState() == Game::UNINITIALIZED))
-            break;        
+            break;
+        
+        // Display the keyboard.
+        displayKeyboard(state, __displayKeyboard);
     }
-	
-	// We need to exit the process to cleanup global resources.
-	exit(0);
+    
+    // We need to exit the process to cleanup global resources.
+    exit(0);
 }
 
 #endif