Просмотр исходного кода

Merge pull request #854 from kariem2k/next

Gamepad support for Linux
Sean Paul Taylor 13 лет назад
Родитель
Сommit
331923777f
1 измененных файлов с 1478 добавлено и 1004 удалено
  1. 1478 1004
      gameplay/src/PlatformLinux.cpp

+ 1478 - 1004
gameplay/src/PlatformLinux.cpp

@@ -13,11 +13,66 @@
 #include <sys/time.h>
 #include <GL/glxew.h>
 #include <poll.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <fstream>
 
 #define TOUCH_COUNT_MAX     4
+#define MAX_GAMEPADS 4
 
 using namespace std;
 
+enum GamepadAxisInfoFlags
+{
+    GP_AXIS_SKIP = 0x1,
+    GP_AXIS_IS_DPAD = 0x2,
+    GP_AXIS_IS_NEG = 0x4,
+    GP_AXIS_IS_XAXIS = 0x8,
+    GP_AXIS_IS_TRIGGER = 0x10
+};
+
+enum GamepadAxisInfoNormalizeFunction
+{
+    NEG_TO_POS,
+    ZERO_TO_POS
+};
+
+struct GamepadJoystickAxisInfo
+{
+    int axisIndex;
+    unsigned int joystickIndex;
+    unsigned long flags;
+    int mappedPosArg;
+    int mappedNegArg;
+    float deadZone;
+    GamepadAxisInfoNormalizeFunction mapFunc;
+};
+
+struct GamepadInfoEntry
+{
+    unsigned int vendorId;
+    unsigned int productId;
+    const char* productName;
+    unsigned int numberOfJS;
+    unsigned int numberOfAxes;
+    unsigned int numberOfButtons;
+    unsigned int numberOfTriggers;
+
+    GamepadJoystickAxisInfo* axes;
+    long* buttons;
+};
+
+
+struct ConnectedGamepadDevInfo
+{
+    dev_t deviceId;
+    gameplay::GamepadHandle fd;
+    const GamepadInfoEntry& gamepadInfo;
+};
+
 struct timespec __timespec;
 static double __timeStart;
 static double __timeAbsolute;
@@ -35,1166 +90,1585 @@ static int __windowSize[2];
 static GLXContext __context;
 static Window __attachToWindow;
 static Atom __atomWmDeleteWindow;
+static list<ConnectedGamepadDevInfo> __connectedGamepads;
 
-namespace gameplay
-{
 
-// Gets the Keyboard::Key enumeration constant that corresponds to the given X11 key symbol.
-static Keyboard::Key getKey(KeySym sym)
+// Gets the gameplay::Keyboard::Key enumeration constant that corresponds to the given X11 key symbol.
+static gameplay::Keyboard::Key getKey(KeySym sym)
 {
     switch (sym)
     {
-    case XK_Sys_Req:
-        return Keyboard::KEY_SYSREQ;
-    case XK_Break:
-        return Keyboard::KEY_BREAK;
-    case XK_Menu :
-        return Keyboard::KEY_MENU;
-    case XK_KP_Enter:
-        return Keyboard::KEY_KP_ENTER;
-    case XK_Pause:
-        return Keyboard::KEY_PAUSE;
-    case XK_Scroll_Lock:
-        return Keyboard::KEY_SCROLL_LOCK;
-    case XK_Print:
-        return Keyboard::KEY_PRINT;
-    case XK_Escape:
-        return Keyboard::KEY_ESCAPE;
-    case XK_BackSpace:
-        return Keyboard::KEY_BACKSPACE;
-    case XK_Tab:
-        return Keyboard::KEY_TAB;
-    case XK_Return:
-        return Keyboard::KEY_RETURN;
-    case XK_Caps_Lock:
-        return Keyboard::KEY_CAPS_LOCK;
-    case XK_Shift_L:
-    case XK_Shift_R:
-        return Keyboard::KEY_SHIFT;
-    case XK_Control_L:
-    case XK_Control_R:
-        return Keyboard::KEY_CTRL;
-    case XK_Alt_L:
-    case XK_Alt_R:
-        return Keyboard::KEY_ALT;
-    case XK_Hyper_L:
-    case XK_Hyper_R:
-        return Keyboard::KEY_HYPER;
-    case XK_Insert:
-        return Keyboard::KEY_INSERT;
-    case XK_Home:
-        return Keyboard::KEY_HOME;
-    case XK_Page_Up:
-        return Keyboard::KEY_PG_UP;
-    case XK_Delete:
-        return Keyboard::KEY_DELETE;
-    case XK_End:
-        return Keyboard::KEY_END;
-    case XK_Page_Down:
-        return Keyboard::KEY_PG_DOWN;
-    case XK_Left:
-        return Keyboard::KEY_LEFT_ARROW;
-    case XK_Right:
-        return Keyboard::KEY_RIGHT_ARROW;
-    case XK_Up:
-        return Keyboard::KEY_UP_ARROW;
-    case XK_Down:
-        return Keyboard::KEY_DOWN_ARROW;
-    case XK_Num_Lock:
-        return Keyboard::KEY_NUM_LOCK;
-    case XK_KP_Add:
-        return Keyboard::KEY_KP_PLUS;
-    case XK_KP_Subtract:
-        return Keyboard::KEY_KP_MINUS;
-    case XK_KP_Multiply:
-        return Keyboard::KEY_KP_MULTIPLY;
-    case XK_KP_Divide:
-        return Keyboard::KEY_KP_DIVIDE;
-    case XK_KP_Home:
-        return Keyboard::KEY_KP_HOME;
-    case XK_KP_Up:
-        return Keyboard::KEY_KP_UP;
-    case XK_KP_Page_Up:
-        return Keyboard::KEY_KP_PG_UP;
-    case XK_KP_Left:
-        return Keyboard::KEY_KP_LEFT;
-    case XK_KP_5:
-        return Keyboard::KEY_KP_FIVE;
-    case XK_KP_Right:
-        return Keyboard::KEY_KP_RIGHT;
-    case XK_KP_End:
-        return Keyboard::KEY_KP_END;
-    case XK_KP_Down:
-        return Keyboard::KEY_KP_DOWN;
-    case XK_KP_Page_Down:
-        return Keyboard::KEY_KP_PG_DOWN;
-    case XK_KP_Insert:
-        return Keyboard::KEY_KP_INSERT;
-    case XK_KP_Delete:
-        return Keyboard::KEY_KP_DELETE;
-    case XK_F1:
-        return Keyboard::KEY_F1;
-    case XK_F2:
-        return Keyboard::KEY_F2;
-    case XK_F3:
-        return Keyboard::KEY_F3;
-    case XK_F4:
-        return Keyboard::KEY_F4;
-    case XK_F5:
-        return Keyboard::KEY_F5;
-    case XK_F6:
-        return Keyboard::KEY_F6;
-    case XK_F7:
-        return Keyboard::KEY_F7;
-    case XK_F8:
-        return Keyboard::KEY_F8;
-    case XK_F9:
-        return Keyboard::KEY_F9;
-    case XK_F10:
-        return Keyboard::KEY_F10;
-    case XK_F11:
-        return Keyboard::KEY_F11;
-    case XK_F12:
-        return Keyboard::KEY_F12;
-    case XK_KP_Space:
-    case XK_space:
-        return Keyboard::KEY_SPACE;
-    case XK_parenright:
-        return Keyboard::KEY_RIGHT_PARENTHESIS;
-    case XK_0:
-        return Keyboard::KEY_ZERO;
-    case XK_exclam:
-        return Keyboard::KEY_EXCLAM;
-    case XK_1:
-        return Keyboard::KEY_ONE;
-    case XK_at:
-        return Keyboard::KEY_AT;
-    case XK_2:
-        return Keyboard::KEY_TWO;
-    case XK_numbersign:
-        return Keyboard::KEY_NUMBER;
-    case XK_3:
-        return Keyboard::KEY_THREE;
-    case XK_dollar:
-        return Keyboard::KEY_DOLLAR;
-    case XK_4:
-        return Keyboard::KEY_FOUR;
-    case XK_percent:
-    case XK_asciicircum :
-        return Keyboard::KEY_CIRCUMFLEX;
-        return Keyboard::KEY_PERCENT;
-    case XK_5:
-        return Keyboard::KEY_FIVE;
-    case XK_6:
-        return Keyboard::KEY_SIX;
-    case XK_ampersand:
-        return Keyboard::KEY_AMPERSAND;
-    case XK_7:
-        return Keyboard::KEY_SEVEN;
-    case XK_asterisk:
-        return Keyboard::KEY_ASTERISK;
-    case XK_8:
-        return Keyboard::KEY_EIGHT;
-    case XK_parenleft:
-        return Keyboard::KEY_LEFT_PARENTHESIS;
-    case XK_9:
-        return Keyboard::KEY_NINE;
-    case XK_equal:
-        return Keyboard::KEY_EQUAL;
-    case XK_plus:
-        return Keyboard::KEY_PLUS;
-    case XK_less:
-        return Keyboard::KEY_LESS_THAN;
-    case XK_comma:
-        return Keyboard::KEY_COMMA;
-    case XK_underscore:
-        return Keyboard::KEY_UNDERSCORE;
-    case XK_minus:
-        return Keyboard::KEY_MINUS;
-    case XK_greater:
-        return Keyboard::KEY_GREATER_THAN;
-    case XK_period:
-        return Keyboard::KEY_PERIOD;
-    case XK_colon:
-        return Keyboard::KEY_COLON;
-    case XK_semicolon:
-        return Keyboard::KEY_SEMICOLON;
-    case XK_question:
-        return Keyboard::KEY_QUESTION;
-    case XK_slash:
-        return Keyboard::KEY_SLASH;
-    case XK_grave:
-        return Keyboard::KEY_GRAVE;
-    case XK_asciitilde:
-        return Keyboard::KEY_TILDE;
-    case XK_braceleft:
-        return Keyboard::KEY_LEFT_BRACE;
-    case XK_bracketleft:
-        return Keyboard::KEY_LEFT_BRACKET;
-    case XK_bar:
-        return Keyboard::KEY_BAR;
-    case XK_backslash:
-        return Keyboard::KEY_BACK_SLASH;
-    case XK_braceright:
-        return Keyboard::KEY_RIGHT_BRACE;
-    case XK_bracketright:
-        return Keyboard::KEY_RIGHT_BRACKET;
-    case XK_quotedbl:
-        return Keyboard::KEY_QUOTE;
-    case XK_apostrophe:
-        return Keyboard::KEY_APOSTROPHE;
-    case XK_EuroSign:
-        return Keyboard::KEY_EURO;
-    case XK_sterling:
-        return Keyboard::KEY_POUND;
-    case XK_yen:
-        return Keyboard::KEY_YEN;
-    case XK_periodcentered:
-        return Keyboard::KEY_MIDDLE_DOT;
-    case XK_A:
-        return Keyboard::KEY_CAPITAL_A;
-    case XK_a:
-        return Keyboard::KEY_A;
-    case XK_B:
-        return Keyboard::KEY_CAPITAL_B;
-    case XK_b:
-        return Keyboard::KEY_B;
-    case XK_C:
-        return Keyboard::KEY_CAPITAL_C;
-    case XK_c:
-        return Keyboard::KEY_C;
-    case XK_D:
-        return Keyboard::KEY_CAPITAL_D;
-    case XK_d:
-        return Keyboard::KEY_D;
-    case XK_E:
-        return Keyboard::KEY_CAPITAL_E;
-    case XK_e:
-        return Keyboard::KEY_E;
-    case XK_F:
-        return Keyboard::KEY_CAPITAL_F;
-    case XK_f:
-        return Keyboard::KEY_F;
-    case XK_G:
-        return Keyboard::KEY_CAPITAL_G;
-    case XK_g:
-        return Keyboard::KEY_G;
-    case XK_H:
-        return Keyboard::KEY_CAPITAL_H;
-    case XK_h:
-        return Keyboard::KEY_H;
-    case XK_I:
-        return Keyboard::KEY_CAPITAL_I;
-    case XK_i:
-        return Keyboard::KEY_I;
-    case XK_J:
-        return Keyboard::KEY_CAPITAL_J;
-    case XK_j:
-        return Keyboard::KEY_J;
-    case XK_K:
-        return Keyboard::KEY_CAPITAL_K;
-    case XK_k:
-        return Keyboard::KEY_K;
-    case XK_L:
-        return Keyboard::KEY_CAPITAL_L;
-    case XK_l:
-        return Keyboard::KEY_L;
-    case XK_M:
-        return Keyboard::KEY_CAPITAL_M;
-    case XK_m:
-        return Keyboard::KEY_M;
-    case XK_N:
-        return Keyboard::KEY_CAPITAL_N;
-    case XK_n:
-        return Keyboard::KEY_N;
-    case XK_O:
-        return Keyboard::KEY_CAPITAL_O;
-    case XK_o:
-        return Keyboard::KEY_O;
-    case XK_P:
-        return Keyboard::KEY_CAPITAL_P;
-    case XK_p:
-        return Keyboard::KEY_P;
-    case XK_Q:
-        return Keyboard::KEY_CAPITAL_Q;
-    case XK_q:
-        return Keyboard::KEY_Q;
-    case XK_R:
-        return Keyboard::KEY_CAPITAL_R;
-    case XK_r:
-        return Keyboard::KEY_R;
-    case XK_S:
-        return Keyboard::KEY_CAPITAL_S;
-    case XK_s:
-        return Keyboard::KEY_S;
-    case XK_T:
-        return Keyboard::KEY_CAPITAL_T;
-    case XK_t:
-        return Keyboard::KEY_T;
-    case XK_U:
-        return Keyboard::KEY_CAPITAL_U;
-    case XK_u:
-        return Keyboard::KEY_U;
-    case XK_V:
-        return Keyboard::KEY_CAPITAL_V;
-    case XK_v:
-        return Keyboard::KEY_V;
-    case XK_W:
-        return Keyboard::KEY_CAPITAL_W;
-    case XK_w:
-        return Keyboard::KEY_W;
-    case XK_X:
-        return Keyboard::KEY_CAPITAL_X;
-    case XK_x:
-        return Keyboard::KEY_X;
-    case XK_Y:
-        return Keyboard::KEY_CAPITAL_Y;
-    case XK_y:
-        return Keyboard::KEY_Y;
-    case XK_Z:
-        return Keyboard::KEY_CAPITAL_Z;
-    case XK_z:
-        return Keyboard::KEY_Z;
-    default:
-        return Keyboard::KEY_NONE;
+        case XK_Sys_Req:
+            return gameplay::Keyboard::KEY_SYSREQ;
+        case XK_Break:
+            return gameplay::Keyboard::KEY_BREAK;
+        case XK_Menu :
+            return gameplay::Keyboard::KEY_MENU;
+        case XK_KP_Enter:
+            return gameplay::Keyboard::KEY_KP_ENTER;
+        case XK_Pause:
+            return gameplay::Keyboard::KEY_PAUSE;
+        case XK_Scroll_Lock:
+            return gameplay::Keyboard::KEY_SCROLL_LOCK;
+        case XK_Print:
+            return gameplay::Keyboard::KEY_PRINT;
+        case XK_Escape:
+            return gameplay::Keyboard::KEY_ESCAPE;
+        case XK_BackSpace:
+            return gameplay::Keyboard::KEY_BACKSPACE;
+        case XK_Tab:
+            return gameplay::Keyboard::KEY_TAB;
+        case XK_Return:
+            return gameplay::Keyboard::KEY_RETURN;
+        case XK_Caps_Lock:
+            return gameplay::Keyboard::KEY_CAPS_LOCK;
+        case XK_Shift_L:
+        case XK_Shift_R:
+            return gameplay::Keyboard::KEY_SHIFT;
+        case XK_Control_L:
+        case XK_Control_R:
+            return gameplay::Keyboard::KEY_CTRL;
+        case XK_Alt_L:
+        case XK_Alt_R:
+            return gameplay::Keyboard::KEY_ALT;
+        case XK_Hyper_L:
+        case XK_Hyper_R:
+            return gameplay::Keyboard::KEY_HYPER;
+        case XK_Insert:
+            return gameplay::Keyboard::KEY_INSERT;
+        case XK_Home:
+            return gameplay::Keyboard::KEY_HOME;
+        case XK_Page_Up:
+            return gameplay::Keyboard::KEY_PG_UP;
+        case XK_Delete:
+            return gameplay::Keyboard::KEY_DELETE;
+        case XK_End:
+            return gameplay::Keyboard::KEY_END;
+        case XK_Page_Down:
+            return gameplay::Keyboard::KEY_PG_DOWN;
+        case XK_Left:
+            return gameplay::Keyboard::KEY_LEFT_ARROW;
+        case XK_Right:
+            return gameplay::Keyboard::KEY_RIGHT_ARROW;
+        case XK_Up:
+            return gameplay::Keyboard::KEY_UP_ARROW;
+        case XK_Down:
+            return gameplay::Keyboard::KEY_DOWN_ARROW;
+        case XK_Num_Lock:
+            return gameplay::Keyboard::KEY_NUM_LOCK;
+        case XK_KP_Add:
+            return gameplay::Keyboard::KEY_KP_PLUS;
+        case XK_KP_Subtract:
+            return gameplay::Keyboard::KEY_KP_MINUS;
+        case XK_KP_Multiply:
+            return gameplay::Keyboard::KEY_KP_MULTIPLY;
+        case XK_KP_Divide:
+            return gameplay::Keyboard::KEY_KP_DIVIDE;
+        case XK_KP_Home:
+            return gameplay::Keyboard::KEY_KP_HOME;
+        case XK_KP_Up:
+            return gameplay::Keyboard::KEY_KP_UP;
+        case XK_KP_Page_Up:
+            return gameplay::Keyboard::KEY_KP_PG_UP;
+        case XK_KP_Left:
+            return gameplay::Keyboard::KEY_KP_LEFT;
+        case XK_KP_5:
+            return gameplay::Keyboard::KEY_KP_FIVE;
+        case XK_KP_Right:
+            return gameplay::Keyboard::KEY_KP_RIGHT;
+        case XK_KP_End:
+            return gameplay::Keyboard::KEY_KP_END;
+        case XK_KP_Down:
+            return gameplay::Keyboard::KEY_KP_DOWN;
+        case XK_KP_Page_Down:
+            return gameplay::Keyboard::KEY_KP_PG_DOWN;
+        case XK_KP_Insert:
+            return gameplay::Keyboard::KEY_KP_INSERT;
+        case XK_KP_Delete:
+            return gameplay::Keyboard::KEY_KP_DELETE;
+        case XK_F1:
+            return gameplay::Keyboard::KEY_F1;
+        case XK_F2:
+            return gameplay::Keyboard::KEY_F2;
+        case XK_F3:
+            return gameplay::Keyboard::KEY_F3;
+        case XK_F4:
+            return gameplay::Keyboard::KEY_F4;
+        case XK_F5:
+            return gameplay::Keyboard::KEY_F5;
+        case XK_F6:
+            return gameplay::Keyboard::KEY_F6;
+        case XK_F7:
+            return gameplay::Keyboard::KEY_F7;
+        case XK_F8:
+            return gameplay::Keyboard::KEY_F8;
+        case XK_F9:
+            return gameplay::Keyboard::KEY_F9;
+        case XK_F10:
+            return gameplay::Keyboard::KEY_F10;
+        case XK_F11:
+            return gameplay::Keyboard::KEY_F11;
+        case XK_F12:
+            return gameplay::Keyboard::KEY_F12;
+        case XK_KP_Space:
+        case XK_space:
+            return gameplay::Keyboard::KEY_SPACE;
+        case XK_parenright:
+            return gameplay::Keyboard::KEY_RIGHT_PARENTHESIS;
+        case XK_0:
+            return gameplay::Keyboard::KEY_ZERO;
+        case XK_exclam:
+            return gameplay::Keyboard::KEY_EXCLAM;
+        case XK_1:
+            return gameplay::Keyboard::KEY_ONE;
+        case XK_at:
+            return gameplay::Keyboard::KEY_AT;
+        case XK_2:
+            return gameplay::Keyboard::KEY_TWO;
+        case XK_numbersign:
+            return gameplay::Keyboard::KEY_NUMBER;
+        case XK_3:
+            return gameplay::Keyboard::KEY_THREE;
+        case XK_dollar:
+            return gameplay::Keyboard::KEY_DOLLAR;
+        case XK_4:
+            return gameplay::Keyboard::KEY_FOUR;
+        case XK_percent:
+        case XK_asciicircum :
+            return gameplay::Keyboard::KEY_CIRCUMFLEX;
+            return gameplay::Keyboard::KEY_PERCENT;
+        case XK_5:
+            return gameplay::Keyboard::KEY_FIVE;
+        case XK_6:
+            return gameplay::Keyboard::KEY_SIX;
+        case XK_ampersand:
+            return gameplay::Keyboard::KEY_AMPERSAND;
+        case XK_7:
+            return gameplay::Keyboard::KEY_SEVEN;
+        case XK_asterisk:
+            return gameplay::Keyboard::KEY_ASTERISK;
+        case XK_8:
+            return gameplay::Keyboard::KEY_EIGHT;
+        case XK_parenleft:
+            return gameplay::Keyboard::KEY_LEFT_PARENTHESIS;
+        case XK_9:
+            return gameplay::Keyboard::KEY_NINE;
+        case XK_equal:
+            return gameplay::Keyboard::KEY_EQUAL;
+        case XK_plus:
+            return gameplay::Keyboard::KEY_PLUS;
+        case XK_less:
+            return gameplay::Keyboard::KEY_LESS_THAN;
+        case XK_comma:
+            return gameplay::Keyboard::KEY_COMMA;
+        case XK_underscore:
+            return gameplay::Keyboard::KEY_UNDERSCORE;
+        case XK_minus:
+            return gameplay::Keyboard::KEY_MINUS;
+        case XK_greater:
+            return gameplay::Keyboard::KEY_GREATER_THAN;
+        case XK_period:
+            return gameplay::Keyboard::KEY_PERIOD;
+        case XK_colon:
+            return gameplay::Keyboard::KEY_COLON;
+        case XK_semicolon:
+            return gameplay::Keyboard::KEY_SEMICOLON;
+        case XK_question:
+            return gameplay::Keyboard::KEY_QUESTION;
+        case XK_slash:
+            return gameplay::Keyboard::KEY_SLASH;
+        case XK_grave:
+            return gameplay::Keyboard::KEY_GRAVE;
+        case XK_asciitilde:
+            return gameplay::Keyboard::KEY_TILDE;
+        case XK_braceleft:
+            return gameplay::Keyboard::KEY_LEFT_BRACE;
+        case XK_bracketleft:
+            return gameplay::Keyboard::KEY_LEFT_BRACKET;
+        case XK_bar:
+            return gameplay::Keyboard::KEY_BAR;
+        case XK_backslash:
+            return gameplay::Keyboard::KEY_BACK_SLASH;
+        case XK_braceright:
+            return gameplay::Keyboard::KEY_RIGHT_BRACE;
+        case XK_bracketright:
+            return gameplay::Keyboard::KEY_RIGHT_BRACKET;
+        case XK_quotedbl:
+            return gameplay::Keyboard::KEY_QUOTE;
+        case XK_apostrophe:
+            return gameplay::Keyboard::KEY_APOSTROPHE;
+        case XK_EuroSign:
+            return gameplay::Keyboard::KEY_EURO;
+        case XK_sterling:
+            return gameplay::Keyboard::KEY_POUND;
+        case XK_yen:
+            return gameplay::Keyboard::KEY_YEN;
+        case XK_periodcentered:
+            return gameplay::Keyboard::KEY_MIDDLE_DOT;
+        case XK_A:
+            return gameplay::Keyboard::KEY_CAPITAL_A;
+        case XK_a:
+            return gameplay::Keyboard::KEY_A;
+        case XK_B:
+            return gameplay::Keyboard::KEY_CAPITAL_B;
+        case XK_b:
+            return gameplay::Keyboard::KEY_B;
+        case XK_C:
+            return gameplay::Keyboard::KEY_CAPITAL_C;
+        case XK_c:
+            return gameplay::Keyboard::KEY_C;
+        case XK_D:
+            return gameplay::Keyboard::KEY_CAPITAL_D;
+        case XK_d:
+            return gameplay::Keyboard::KEY_D;
+        case XK_E:
+            return gameplay::Keyboard::KEY_CAPITAL_E;
+        case XK_e:
+            return gameplay::Keyboard::KEY_E;
+        case XK_F:
+            return gameplay::Keyboard::KEY_CAPITAL_F;
+        case XK_f:
+            return gameplay::Keyboard::KEY_F;
+        case XK_G:
+            return gameplay::Keyboard::KEY_CAPITAL_G;
+        case XK_g:
+            return gameplay::Keyboard::KEY_G;
+        case XK_H:
+            return gameplay::Keyboard::KEY_CAPITAL_H;
+        case XK_h:
+            return gameplay::Keyboard::KEY_H;
+        case XK_I:
+            return gameplay::Keyboard::KEY_CAPITAL_I;
+        case XK_i:
+            return gameplay::Keyboard::KEY_I;
+        case XK_J:
+            return gameplay::Keyboard::KEY_CAPITAL_J;
+        case XK_j:
+            return gameplay::Keyboard::KEY_J;
+        case XK_K:
+            return gameplay::Keyboard::KEY_CAPITAL_K;
+        case XK_k:
+            return gameplay::Keyboard::KEY_K;
+        case XK_L:
+            return gameplay::Keyboard::KEY_CAPITAL_L;
+        case XK_l:
+            return gameplay::Keyboard::KEY_L;
+        case XK_M:
+            return gameplay::Keyboard::KEY_CAPITAL_M;
+        case XK_m:
+            return gameplay::Keyboard::KEY_M;
+        case XK_N:
+            return gameplay::Keyboard::KEY_CAPITAL_N;
+        case XK_n:
+            return gameplay::Keyboard::KEY_N;
+        case XK_O:
+            return gameplay::Keyboard::KEY_CAPITAL_O;
+        case XK_o:
+            return gameplay::Keyboard::KEY_O;
+        case XK_P:
+            return gameplay::Keyboard::KEY_CAPITAL_P;
+        case XK_p:
+            return gameplay::Keyboard::KEY_P;
+        case XK_Q:
+            return gameplay::Keyboard::KEY_CAPITAL_Q;
+        case XK_q:
+            return gameplay::Keyboard::KEY_Q;
+        case XK_R:
+            return gameplay::Keyboard::KEY_CAPITAL_R;
+        case XK_r:
+            return gameplay::Keyboard::KEY_R;
+        case XK_S:
+            return gameplay::Keyboard::KEY_CAPITAL_S;
+        case XK_s:
+            return gameplay::Keyboard::KEY_S;
+        case XK_T:
+            return gameplay::Keyboard::KEY_CAPITAL_T;
+        case XK_t:
+            return gameplay::Keyboard::KEY_T;
+        case XK_U:
+            return gameplay::Keyboard::KEY_CAPITAL_U;
+        case XK_u:
+            return gameplay::Keyboard::KEY_U;
+        case XK_V:
+            return gameplay::Keyboard::KEY_CAPITAL_V;
+        case XK_v:
+            return gameplay::Keyboard::KEY_V;
+        case XK_W:
+            return gameplay::Keyboard::KEY_CAPITAL_W;
+        case XK_w:
+            return gameplay::Keyboard::KEY_W;
+        case XK_X:
+            return gameplay::Keyboard::KEY_CAPITAL_X;
+        case XK_x:
+            return gameplay::Keyboard::KEY_X;
+        case XK_Y:
+            return gameplay::Keyboard::KEY_CAPITAL_Y;
+        case XK_y:
+            return gameplay::Keyboard::KEY_Y;
+        case XK_Z:
+            return gameplay::Keyboard::KEY_CAPITAL_Z;
+        case XK_z:
+            return gameplay::Keyboard::KEY_Z;
+        default:
+            return gameplay::Keyboard::KEY_NONE;
     }
 }
 
 /**
  * Returns the unicode value for the given keycode or zero if the key is not a valid printable character.
  */
-static int getUnicode(Keyboard::Key key)
+static int getUnicode(gameplay::Keyboard::Key key)
 {
-
     switch (key)
     {
-    case Keyboard::KEY_BACKSPACE:
-        return 0x0008;
-    case Keyboard::KEY_TAB:
-        return 0x0009;
-    case Keyboard::KEY_RETURN:
-    case Keyboard::KEY_KP_ENTER:
-        return 0x000A;
-    case Keyboard::KEY_ESCAPE:
-        return 0x001B;
-    case Keyboard::KEY_SPACE:
-    case Keyboard::KEY_EXCLAM:
-    case Keyboard::KEY_QUOTE:
-    case Keyboard::KEY_NUMBER:
-    case Keyboard::KEY_DOLLAR:
-    case Keyboard::KEY_PERCENT:
-    case Keyboard::KEY_CIRCUMFLEX:
-    case Keyboard::KEY_AMPERSAND:
-    case Keyboard::KEY_APOSTROPHE:
-    case Keyboard::KEY_LEFT_PARENTHESIS:
-    case Keyboard::KEY_RIGHT_PARENTHESIS:
-    case Keyboard::KEY_ASTERISK:
-    case Keyboard::KEY_PLUS:
-    case Keyboard::KEY_COMMA:
-    case Keyboard::KEY_MINUS:
-    case Keyboard::KEY_PERIOD:
-    case Keyboard::KEY_SLASH:
-    case Keyboard::KEY_ZERO:
-    case Keyboard::KEY_ONE:
-    case Keyboard::KEY_TWO:
-    case Keyboard::KEY_THREE:
-    case Keyboard::KEY_FOUR:
-    case Keyboard::KEY_FIVE:
-    case Keyboard::KEY_SIX:
-    case Keyboard::KEY_SEVEN:
-    case Keyboard::KEY_EIGHT:
-    case Keyboard::KEY_NINE:
-    case Keyboard::KEY_COLON:
-    case Keyboard::KEY_SEMICOLON:
-    case Keyboard::KEY_LESS_THAN:
-    case Keyboard::KEY_EQUAL:
-    case Keyboard::KEY_GREATER_THAN:
-    case Keyboard::KEY_QUESTION:
-    case Keyboard::KEY_AT:
-    case Keyboard::KEY_CAPITAL_A:
-    case Keyboard::KEY_CAPITAL_B:
-    case Keyboard::KEY_CAPITAL_C:
-    case Keyboard::KEY_CAPITAL_D:
-    case Keyboard::KEY_CAPITAL_E:
-    case Keyboard::KEY_CAPITAL_F:
-    case Keyboard::KEY_CAPITAL_G:
-    case Keyboard::KEY_CAPITAL_H:
-    case Keyboard::KEY_CAPITAL_I:
-    case Keyboard::KEY_CAPITAL_J:
-    case Keyboard::KEY_CAPITAL_K:
-    case Keyboard::KEY_CAPITAL_L:
-    case Keyboard::KEY_CAPITAL_M:
-    case Keyboard::KEY_CAPITAL_N:
-    case Keyboard::KEY_CAPITAL_O:
-    case Keyboard::KEY_CAPITAL_P:
-    case Keyboard::KEY_CAPITAL_Q:
-    case Keyboard::KEY_CAPITAL_R:
-    case Keyboard::KEY_CAPITAL_S:
-    case Keyboard::KEY_CAPITAL_T:
-    case Keyboard::KEY_CAPITAL_U:
-    case Keyboard::KEY_CAPITAL_V:
-    case Keyboard::KEY_CAPITAL_W:
-    case Keyboard::KEY_CAPITAL_X:
-    case Keyboard::KEY_CAPITAL_Y:
-    case Keyboard::KEY_CAPITAL_Z:
-    case Keyboard::KEY_LEFT_BRACKET:
-    case Keyboard::KEY_BACK_SLASH:
-    case Keyboard::KEY_RIGHT_BRACKET:
-    case Keyboard::KEY_UNDERSCORE:
-    case Keyboard::KEY_GRAVE:
-    case Keyboard::KEY_A:
-    case Keyboard::KEY_B:
-    case Keyboard::KEY_C:
-    case Keyboard::KEY_D:
-    case Keyboard::KEY_E:
-    case Keyboard::KEY_F:
-    case Keyboard::KEY_G:
-    case Keyboard::KEY_H:
-    case Keyboard::KEY_I:
-    case Keyboard::KEY_J:
-    case Keyboard::KEY_K:
-    case Keyboard::KEY_L:
-    case Keyboard::KEY_M:
-    case Keyboard::KEY_N:
-    case Keyboard::KEY_O:
-    case Keyboard::KEY_P:
-    case Keyboard::KEY_Q:
-    case Keyboard::KEY_R:
-    case Keyboard::KEY_S:
-    case Keyboard::KEY_T:
-    case Keyboard::KEY_U:
-    case Keyboard::KEY_V:
-    case Keyboard::KEY_W:
-    case Keyboard::KEY_X:
-    case Keyboard::KEY_Y:
-    case Keyboard::KEY_Z:
-    case Keyboard::KEY_LEFT_BRACE:
-    case Keyboard::KEY_BAR:
-    case Keyboard::KEY_RIGHT_BRACE:
-    case Keyboard::KEY_TILDE:
-        return key;
-    default:
-        return 0;
+        case gameplay::Keyboard::KEY_BACKSPACE:
+            return 0x0008;
+        case gameplay::Keyboard::KEY_TAB:
+            return 0x0009;
+        case gameplay::Keyboard::KEY_RETURN:
+        case gameplay::Keyboard::KEY_KP_ENTER:
+            return 0x000A;
+        case gameplay::Keyboard::KEY_ESCAPE:
+            return 0x001B;
+        case gameplay::Keyboard::KEY_SPACE:
+        case gameplay::Keyboard::KEY_EXCLAM:
+        case gameplay::Keyboard::KEY_QUOTE:
+        case gameplay::Keyboard::KEY_NUMBER:
+        case gameplay::Keyboard::KEY_DOLLAR:
+        case gameplay::Keyboard::KEY_PERCENT:
+        case gameplay::Keyboard::KEY_CIRCUMFLEX:
+        case gameplay::Keyboard::KEY_AMPERSAND:
+        case gameplay::Keyboard::KEY_APOSTROPHE:
+        case gameplay::Keyboard::KEY_LEFT_PARENTHESIS:
+        case gameplay::Keyboard::KEY_RIGHT_PARENTHESIS:
+        case gameplay::Keyboard::KEY_ASTERISK:
+        case gameplay::Keyboard::KEY_PLUS:
+        case gameplay::Keyboard::KEY_COMMA:
+        case gameplay::Keyboard::KEY_MINUS:
+        case gameplay::Keyboard::KEY_PERIOD:
+        case gameplay::Keyboard::KEY_SLASH:
+        case gameplay::Keyboard::KEY_ZERO:
+        case gameplay::Keyboard::KEY_ONE:
+        case gameplay::Keyboard::KEY_TWO:
+        case gameplay::Keyboard::KEY_THREE:
+        case gameplay::Keyboard::KEY_FOUR:
+        case gameplay::Keyboard::KEY_FIVE:
+        case gameplay::Keyboard::KEY_SIX:
+        case gameplay::Keyboard::KEY_SEVEN:
+        case gameplay::Keyboard::KEY_EIGHT:
+        case gameplay::Keyboard::KEY_NINE:
+        case gameplay::Keyboard::KEY_COLON:
+        case gameplay::Keyboard::KEY_SEMICOLON:
+        case gameplay::Keyboard::KEY_LESS_THAN:
+        case gameplay::Keyboard::KEY_EQUAL:
+        case gameplay::Keyboard::KEY_GREATER_THAN:
+        case gameplay::Keyboard::KEY_QUESTION:
+        case gameplay::Keyboard::KEY_AT:
+        case gameplay::Keyboard::KEY_CAPITAL_A:
+        case gameplay::Keyboard::KEY_CAPITAL_B:
+        case gameplay::Keyboard::KEY_CAPITAL_C:
+        case gameplay::Keyboard::KEY_CAPITAL_D:
+        case gameplay::Keyboard::KEY_CAPITAL_E:
+        case gameplay::Keyboard::KEY_CAPITAL_F:
+        case gameplay::Keyboard::KEY_CAPITAL_G:
+        case gameplay::Keyboard::KEY_CAPITAL_H:
+        case gameplay::Keyboard::KEY_CAPITAL_I:
+        case gameplay::Keyboard::KEY_CAPITAL_J:
+        case gameplay::Keyboard::KEY_CAPITAL_K:
+        case gameplay::Keyboard::KEY_CAPITAL_L:
+        case gameplay::Keyboard::KEY_CAPITAL_M:
+        case gameplay::Keyboard::KEY_CAPITAL_N:
+        case gameplay::Keyboard::KEY_CAPITAL_O:
+        case gameplay::Keyboard::KEY_CAPITAL_P:
+        case gameplay::Keyboard::KEY_CAPITAL_Q:
+        case gameplay::Keyboard::KEY_CAPITAL_R:
+        case gameplay::Keyboard::KEY_CAPITAL_S:
+        case gameplay::Keyboard::KEY_CAPITAL_T:
+        case gameplay::Keyboard::KEY_CAPITAL_U:
+        case gameplay::Keyboard::KEY_CAPITAL_V:
+        case gameplay::Keyboard::KEY_CAPITAL_W:
+        case gameplay::Keyboard::KEY_CAPITAL_X:
+        case gameplay::Keyboard::KEY_CAPITAL_Y:
+        case gameplay::Keyboard::KEY_CAPITAL_Z:
+        case gameplay::Keyboard::KEY_LEFT_BRACKET:
+        case gameplay::Keyboard::KEY_BACK_SLASH:
+        case gameplay::Keyboard::KEY_RIGHT_BRACKET:
+        case gameplay::Keyboard::KEY_UNDERSCORE:
+        case gameplay::Keyboard::KEY_GRAVE:
+        case gameplay::Keyboard::KEY_A:
+        case gameplay::Keyboard::KEY_B:
+        case gameplay::Keyboard::KEY_C:
+        case gameplay::Keyboard::KEY_D:
+        case gameplay::Keyboard::KEY_E:
+        case gameplay::Keyboard::KEY_F:
+        case gameplay::Keyboard::KEY_G:
+        case gameplay::Keyboard::KEY_H:
+        case gameplay::Keyboard::KEY_I:
+        case gameplay::Keyboard::KEY_J:
+        case gameplay::Keyboard::KEY_K:
+        case gameplay::Keyboard::KEY_L:
+        case gameplay::Keyboard::KEY_M:
+        case gameplay::Keyboard::KEY_N:
+        case gameplay::Keyboard::KEY_O:
+        case gameplay::Keyboard::KEY_P:
+        case gameplay::Keyboard::KEY_Q:
+        case gameplay::Keyboard::KEY_R:
+        case gameplay::Keyboard::KEY_S:
+        case gameplay::Keyboard::KEY_T:
+        case gameplay::Keyboard::KEY_U:
+        case gameplay::Keyboard::KEY_V:
+        case gameplay::Keyboard::KEY_W:
+        case gameplay::Keyboard::KEY_X:
+        case gameplay::Keyboard::KEY_Y:
+        case gameplay::Keyboard::KEY_Z:
+        case gameplay::Keyboard::KEY_LEFT_BRACE:
+        case gameplay::Keyboard::KEY_BAR:
+        case gameplay::Keyboard::KEY_RIGHT_BRACE:
+        case gameplay::Keyboard::KEY_TILDE:
+            return key;
+        default:
+            return 0;
     }
 }
-
-extern void print(const char* format, ...)
-{
-    GP_ASSERT(format);
-    va_list argptr;
-    va_start(argptr, format);
-    vfprintf(stderr, format, argptr);
-    va_end(argptr);
-}
-
-Platform::Platform(Game* game) : _game(game)
-{
-}
-
-Platform::~Platform()
+#include <linux/joystick.h> //included here so i avoid the naming conflict between KEY_* defined in input.h and the ones defined in gameplay/Keyboard.h 
+namespace gameplay
 {
-}
+    extern void print(const char* format, ...)
+    {
+        GP_ASSERT(format);
+        va_list argptr;
+        va_start(argptr, format);
+        vfprintf(stderr, format, argptr);
+        va_end(argptr);
+    }
 
-Platform* Platform::create(Game* game, void* attachToWindow)
-{
+    Platform::Platform(Game* game) : _game(game)
+    {
+    }
 
-    GP_ASSERT(game);
-    
-    __attachToWindow = (Window)attachToWindow;
-    FileSystem::setResourcePath("./");
-    Platform* platform = new Platform(game);
-    
-    // Get the display and initialize
-    __display = XOpenDisplay(NULL);
-    if (__display == NULL)
+    Platform::~Platform()
     {
-        perror("XOpenDisplay");
-        return NULL;
     }
-     
-    // Get the window configuration values
-    const char *title = NULL;
-    int __x = 0, __y = 0, __width = 1280, __height = 800, __samples = 0;
-    bool fullscreen = false;
-    if (game->getConfig())
+
+    Platform* Platform::create(Game* game, void* attachToWindow)
     {
-        Properties* config = game->getConfig()->getNamespace("window", true);
-        if (config)
+
+        GP_ASSERT(game);
+
+        __attachToWindow = (Window)attachToWindow;
+        FileSystem::setResourcePath("./");
+        Platform* platform = new Platform(game);
+
+        // Get the display and initialize
+        __display = XOpenDisplay(NULL);
+        if (__display == NULL)
+        {
+            perror("XOpenDisplay");
+            return NULL;
+        }
+
+        // Get the window configuration values
+        const char *title = NULL;
+        int __x = 0, __y = 0, __width = 1280, __height = 800, __samples = 0;
+        bool fullscreen = false;
+        if (game->getConfig())
         {
-            // Read window title.
-            title = config->getString("title");
-
-            // Read window rect.
-            int x = config->getInt("x");
-            int y = config->getInt("y");
-            int width = config->getInt("width");
-            int height = config->getInt("height");
-            int samples = config->getInt("samples");
-            fullscreen = config->getBool("fullscreen");
-
-            if (fullscreen && width == 0 && height == 0)
+            Properties* config = game->getConfig()->getNamespace("window", true);
+            if (config)
             {
-                // Use the screen resolution if fullscreen is true but width and height were not set in the config
-                int screen_num = DefaultScreen(__display);
-                width = DisplayWidth(__display, screen_num);
-                height = DisplayHeight(__display, screen_num);
+                // Read window title.
+                title = config->getString("title");
+
+                // Read window rect.
+                int x = config->getInt("x");
+                int y = config->getInt("y");
+                int width = config->getInt("width");
+                int height = config->getInt("height");
+                int samples = config->getInt("samples");
+                fullscreen = config->getBool("fullscreen");
+
+                if (fullscreen && width == 0 && height == 0)
+                {
+                    // Use the screen resolution if fullscreen is true but width and height were not set in the config
+                    int screen_num = DefaultScreen(__display);
+                    width = DisplayWidth(__display, screen_num);
+                    height = DisplayHeight(__display, screen_num);
+                }
+                if (x != 0) __x = x;
+                if (y != 0) __y = y;
+                if (width != 0) __width = width;
+                if (height != 0) __height = height;
+                if (samples != 0) __samples = samples;
             }
-            if (x != 0) __x = x;
-            if (y != 0) __y = y;
-            if (width != 0) __width = width;
-            if (height != 0) __height = height;
-            if (samples != 0) __samples = samples;
+        }
+
+        // GLX version
+        GLint majorGLX, minorGLX = 0;
+        glXQueryVersion(__display, &majorGLX, &minorGLX);
+        if (majorGLX == 1 && minorGLX < 2)
+        {
+            perror("GLX 1.2 or greater is required.");
+            XCloseDisplay(__display);
+            return NULL;
+        }
+        else
+        {
+            printf( "GLX version: %d.%d\n", majorGLX , minorGLX);
+        }
+
+        // Get the GLX Functions
+        glXCreateContextAttribsARB = (GLXContext(*)(Display* dpy, GLXFBConfig config, GLXContext share_context, Bool direct,  const int *attrib_list))glXGetProcAddressARB((GLubyte*)"glXCreateContextAttribsARB");
+        glXChooseFBConfig = (GLXFBConfig*(*)(Display *dpy, int screen, const int *attrib_list, int *nelements))glXGetProcAddressARB((GLubyte*)"glXChooseFBConfig");
+        glXGetVisualFromFBConfig = (XVisualInfo*(*)(Display *dpy, GLXFBConfig config))glXGetProcAddressARB((GLubyte*)"glXGetVisualFromFBConfig");
+        glXGetFBConfigAttrib = (int(*)(Display *dpy, GLXFBConfig config, int attribute, int *value))glXGetProcAddressARB((GLubyte*)"glXGetFBConfigAttrib");
+        glXSwapIntervalEXT = (void(*)(Display* dpy, GLXDrawable drawable, int interval))glXGetProcAddressARB((GLubyte*)"glXSwapIntervalEXT");
+        glXSwapIntervalMESA = (int(*)(unsigned int interval))glXGetProcAddressARB((GLubyte*)"glXSwapIntervalMESA");
+
+        // Get the configs
+        int configAttribs[] = 
+        {
+            GLX_RENDER_TYPE,    GLX_RGBA_BIT,
+            GLX_DRAWABLE_TYPE,  GLX_WINDOW_BIT,
+            GLX_X_RENDERABLE,   True,
+            GLX_DEPTH_SIZE,     24,
+            GLX_STENCIL_SIZE,   8,
+            GLX_RED_SIZE,       8,
+            GLX_GREEN_SIZE,     8,
+            GLX_BLUE_SIZE,      8,
+            GLX_DOUBLEBUFFER,   True,
+            GLX_SAMPLE_BUFFERS, __samples > 0 ? 1 : 0,
+            GLX_SAMPLES,        __samples,
+            0
+        };
+        __multiSampling = __samples > 0;
+
+        GLXFBConfig* configs;
+        int configCount = 0;
+        configs = glXChooseFBConfig(__display, DefaultScreen(__display), configAttribs, &configCount);
+        if ( configCount == 0 || configs == 0 )
+        {
+            perror( "glXChooseFBConfig" );
+            return NULL;
+        }
+
+        // Create the windows
+        XVisualInfo* visualInfo;
+        visualInfo = glXGetVisualFromFBConfig(__display, configs[0]);
+
+        XSetWindowAttributes winAttribs;
+        long eventMask;
+        eventMask = ExposureMask | VisibilityChangeMask | StructureNotifyMask |
+            KeyPressMask | KeyReleaseMask | PointerMotionMask |
+            ButtonPressMask | ButtonReleaseMask |
+            EnterWindowMask | LeaveWindowMask;
+        winAttribs.event_mask = eventMask;
+        winAttribs.border_pixel = 0;
+        winAttribs.bit_gravity = StaticGravity;
+        winAttribs.colormap = XCreateColormap(__display, RootWindow(__display, visualInfo->screen), visualInfo->visual, AllocNone);
+
+        GLint winMask;
+        winMask = CWBorderPixel | CWBitGravity | CWEventMask| CWColormap;
+
+        __window = XCreateWindow(__display, DefaultRootWindow(__display), __x, __y, __width, __height, 0,
+                visualInfo->depth, InputOutput, visualInfo->visual, winMask,
+                &winAttribs);
+
+        // Tell the window manager that it should send the delete window notification through ClientMessage
+        __atomWmDeleteWindow = XInternAtom(__display, "WM_DELETE_WINDOW", False);
+        XSetWMProtocols(__display, __window, &__atomWmDeleteWindow, 1);
+
+        XMapWindow(__display, __window);
+
+        // Send fullscreen atom message to the window; most window managers respect WM_STATE messages
+        // Note: fullscreen mode will use native desktop resolution and won't care about width/height specified
+        if (fullscreen)
+        {
+            XEvent xev;
+            Atom atomWm_state = XInternAtom(__display, "_NET_WM_STATE", False);
+            Atom atomFullscreen = XInternAtom(__display, "_NET_WM_STATE_FULLSCREEN", False);
+
+            memset(&xev, 0, sizeof(xev));
+            xev.type = ClientMessage;
+            xev.xclient.window = __window;
+            xev.xclient.message_type = atomWm_state;
+            xev.xclient.format = 32;
+            xev.xclient.data.l[0] = 1;
+            xev.xclient.data.l[1] = atomFullscreen;
+            xev.xclient.data.l[2] = 0;
+
+            XSendEvent(__display, DefaultRootWindow(__display), false, SubstructureNotifyMask | SubstructureRedirectMask, &xev);
+        }
+
+        XStoreName(__display, __window, title ? title : "");
+
+        __context = glXCreateContext(__display, visualInfo, NULL, True);
+        if (!__context)
+        {
+            perror("glXCreateContext");
+            return NULL;
+        }
+        glXMakeCurrent(__display, __window, __context);
+
+        // Use OpenGL 2.x with GLEW
+        glewExperimental = GL_TRUE;
+        GLenum glewStatus = glewInit();
+        if (glewStatus != GLEW_OK)
+        {
+            perror("glewInit");
+            return NULL;
+        }
+
+        // GL Version
+        int versionGL[2] = {-1, -1};
+        glGetIntegerv(GL_MAJOR_VERSION, versionGL);
+        glGetIntegerv(GL_MINOR_VERSION, versionGL + 1);
+        printf("GL version: %d.%d\n", versionGL[0], versionGL[1]);
+
+        // TODO: Get this workings
+        if (glXSwapIntervalEXT)
+            glXSwapIntervalEXT(__display, __window, __vsync ? 1 : 0);
+        else if(glXSwapIntervalMESA)
+            glXSwapIntervalMESA(__vsync ? 1 : 0);
+
+        return platform;
+    }
+
+    void cleanupX11()
+    {
+        if (__display)
+        {
+            glXMakeCurrent(__display, None, NULL);
+
+            if (__context)
+                glXDestroyContext(__display, __context);
+            if (__window)
+                XDestroyWindow(__display, __window);
+
+            XCloseDisplay(__display);
         }
     }
 
-    // GLX version
-    GLint majorGLX, minorGLX = 0;
-    glXQueryVersion(__display, &majorGLX, &minorGLX);
-    if (majorGLX == 1 && minorGLX < 2)
+    double timespec2millis(struct timespec *a)
     {
-        perror("GLX 1.2 or greater is required.");
-        XCloseDisplay(__display);
-        return NULL;
+        GP_ASSERT(a);
+        return (1000.0 * a->tv_sec) + (0.000001 * a->tv_nsec);
     }
-    else
+
+    void updateWindowSize()
     {
-        printf( "GLX version: %d.%d\n", majorGLX , minorGLX);
+        GP_ASSERT(__display);
+        GP_ASSERT(__window);
+        XWindowAttributes windowAttrs;
+        XGetWindowAttributes(__display, __window, &windowAttrs);
+        __windowSize[0] = windowAttrs.width;
+        __windowSize[1] = windowAttrs.height;
     }
-    
-    // Get the GLX Functions
-    glXCreateContextAttribsARB = (GLXContext(*)(Display* dpy, GLXFBConfig config, GLXContext share_context, Bool direct,  const int *attrib_list))glXGetProcAddressARB((GLubyte*)"glXCreateContextAttribsARB");
-    glXChooseFBConfig = (GLXFBConfig*(*)(Display *dpy, int screen, const int *attrib_list, int *nelements))glXGetProcAddressARB((GLubyte*)"glXChooseFBConfig");
-    glXGetVisualFromFBConfig = (XVisualInfo*(*)(Display *dpy, GLXFBConfig config))glXGetProcAddressARB((GLubyte*)"glXGetVisualFromFBConfig");
-    glXGetFBConfigAttrib = (int(*)(Display *dpy, GLXFBConfig config, int attribute, int *value))glXGetProcAddressARB((GLubyte*)"glXGetFBConfigAttrib");
-    glXSwapIntervalEXT = (void(*)(Display* dpy, GLXDrawable drawable, int interval))glXGetProcAddressARB((GLubyte*)"glXSwapIntervalEXT");
-    glXSwapIntervalMESA = (int(*)(unsigned int interval))glXGetProcAddressARB((GLubyte*)"glXSwapIntervalMESA");
-
-    // Get the configs
-    int configAttribs[] = 
+
+
+    //Will need to be dynamic, also should be handled in Gamepad class
+    static const GamepadInfoEntry gamepadLookupTable[] = 
     {
-        GLX_RENDER_TYPE,    GLX_RGBA_BIT,
-        GLX_DRAWABLE_TYPE,  GLX_WINDOW_BIT,
-        GLX_X_RENDERABLE,   True,
-        GLX_DEPTH_SIZE,     24,
-        GLX_STENCIL_SIZE,   8,
-        GLX_RED_SIZE,       8,
-        GLX_GREEN_SIZE,     8,
-        GLX_BLUE_SIZE,      8,
-        GLX_DOUBLEBUFFER,   True,
-        GLX_SAMPLE_BUFFERS, __samples > 0 ? 1 : 0,
-        GLX_SAMPLES,        __samples,
-        0
+        {0x0,0x0,"GENERIC XBOX360",2,6,20,2, 
+                                             (GamepadJoystickAxisInfo[]) {
+                                                                     {0,0,GP_AXIS_IS_XAXIS,0,0,2240,NEG_TO_POS},
+                                                                     {1,0,GP_AXIS_IS_NEG,0,0,2240,NEG_TO_POS},
+                                                                     {2,1,GP_AXIS_IS_XAXIS,0,0,2240,NEG_TO_POS},
+                                                                     {3,1,GP_AXIS_IS_NEG,0,0,2240,NEG_TO_POS},
+                                                                     {4,2,GP_AXIS_IS_TRIGGER,0,0,2240,ZERO_TO_POS},
+                                                                     {5,2,GP_AXIS_IS_TRIGGER,1,0,2240,ZERO_TO_POS},
+                                                                     {-1,0,0,0,0,0,NEG_TO_POS}
+                                                                 },
+                                             (long[]) {
+                                                                          -1,    
+                                                                          -1,  
+                                                                          -1,  
+                                                                          -1, 
+                                                                          -1, 
+                                                                          Gamepad::BUTTON_UP,
+                                                                          Gamepad::BUTTON_DOWN,
+                                                                          Gamepad::BUTTON_LEFT,
+                                                                          Gamepad::BUTTON_RIGHT,
+                                                                          Gamepad::BUTTON_MENU2,
+                                                                          Gamepad::BUTTON_MENU1,
+                                                                          Gamepad::BUTTON_L3,
+                                                                          Gamepad::BUTTON_R3,
+                                                                          Gamepad::BUTTON_L1,
+                                                                          Gamepad::BUTTON_R1,
+                                                                          Gamepad::BUTTON_MENU3,
+                                                                          Gamepad::BUTTON_A,
+                                                                          Gamepad::BUTTON_B,
+                                                                          Gamepad::BUTTON_X,
+                                                                          Gamepad::BUTTON_Y
+                                                                         }
+        },
+        {0x79,0x6,"DragonRise Inc. Generic USB Joystick",2,7,12,0, 
+                                             (GamepadJoystickAxisInfo[]) {
+                                                                     {0,1, GP_AXIS_IS_XAXIS,0,0,2240,NEG_TO_POS},
+                                                                     {1,1,GP_AXIS_IS_NEG,0,0,2240,NEG_TO_POS},
+                                                                     {2,0,GP_AXIS_SKIP,0,0,2240,NEG_TO_POS},
+                                                                     {3,0,GP_AXIS_IS_XAXIS,0,0,2240,NEG_TO_POS},
+                                                                     {4,0,GP_AXIS_IS_NEG,0,0,2240,NEG_TO_POS},
+                                                                     {5,2,GP_AXIS_IS_DPAD, Gamepad::BUTTON_RIGHT, Gamepad::BUTTON_LEFT,2240,NEG_TO_POS},
+                                                                     {6,2,GP_AXIS_IS_DPAD, Gamepad::BUTTON_DOWN, Gamepad::BUTTON_UP,2240,NEG_TO_POS},
+                                                                     {-1,0,0,0,0,0,NEG_TO_POS}
+                                                                 },
+                                             (long[]) {
+                                                                          Gamepad::BUTTON_Y,    
+                                                                          Gamepad::BUTTON_B,  
+                                                                          Gamepad::BUTTON_A,  
+                                                                          Gamepad::BUTTON_X, 
+                                                                          Gamepad::BUTTON_L1, 
+                                                                          Gamepad::BUTTON_R1, 
+                                                                          Gamepad::BUTTON_L2,    
+                                                                          Gamepad::BUTTON_R2,   
+                                                                          Gamepad::BUTTON_MENU1,   
+                                                                          Gamepad::BUTTON_MENU2,   
+                                                                          Gamepad::BUTTON_L3,
+                                                                          Gamepad::BUTTON_R3,
+                                                                         }
+        },
+        {0x54c,0x268,"Sony Corp. Batoh Device / PlayStation 3 Controller",2,27,19,2, 
+                                             (GamepadJoystickAxisInfo[]) {
+                                                                     {0,0,GP_AXIS_IS_XAXIS,0,0,2240,NEG_TO_POS},
+                                                                     {1,0,GP_AXIS_IS_NEG,0,0,2240,NEG_TO_POS},
+                                                                     {2,1,GP_AXIS_IS_XAXIS,0,0,2240,NEG_TO_POS},
+                                                                     {3,1,GP_AXIS_IS_NEG,0,0,2240,NEG_TO_POS},
+                                                                     {12,1,GP_AXIS_IS_TRIGGER,0,0,2240,ZERO_TO_POS},
+                                                                     {13,2,GP_AXIS_IS_TRIGGER,1,0,2240,ZERO_TO_POS},
+                                                                     {-1,0,0,0,0,0,NEG_TO_POS}
+                                                                 },
+                                             (long[]) {
+                                                                          Gamepad::BUTTON_MENU1,    
+                                                                          Gamepad::BUTTON_L3,  
+                                                                          Gamepad::BUTTON_R3,  
+                                                                          Gamepad::BUTTON_MENU2, 
+                                                                          Gamepad::BUTTON_UP, 
+                                                                          Gamepad::BUTTON_RIGHT, 
+                                                                          Gamepad::BUTTON_DOWN,    
+                                                                          Gamepad::BUTTON_LEFT,   
+                                                                          Gamepad::BUTTON_L2,  //Use Trigger Instead of BUTTON_L2? or both should be called
+                                                                          Gamepad::BUTTON_R2,  //Use Trigger Instead of BUTTON_R2? or both should be called                                                                        
+                                                                          Gamepad::BUTTON_L1,
+                                                                          Gamepad::BUTTON_R1,
+                                                                          Gamepad::BUTTON_Y,    
+                                                                          Gamepad::BUTTON_B,  
+                                                                          Gamepad::BUTTON_A,  
+                                                                          Gamepad::BUTTON_X, 
+                                                                          Gamepad::BUTTON_MENU3, 
+                                                                          -1,
+                                                                          -1
+                                                                         }
+        }
     };
-    __multiSampling = __samples > 0;
 
-    GLXFBConfig* configs;
-    int configCount = 0;
-    configs = glXChooseFBConfig(__display, DefaultScreen(__display), configAttribs, &configCount);
-    if ( configCount == 0 || configs == 0 )
+    bool isGamepadDevRegistered(dev_t devId)
     {
-        perror( "glXChooseFBConfig" );
-        return NULL;
+        for(list<ConnectedGamepadDevInfo>::iterator it = __connectedGamepads.begin(); it != __connectedGamepads.end();++it)
+        {
+            if(devId == (*it).deviceId) return true;
+        }
+        return false;
     }
 
-    // Create the windows
-    XVisualInfo* visualInfo;
-    visualInfo = glXGetVisualFromFBConfig(__display, configs[0]);
-    
-    XSetWindowAttributes winAttribs;
-    long eventMask;
-    eventMask = ExposureMask | VisibilityChangeMask | StructureNotifyMask |
-                KeyPressMask | KeyReleaseMask | PointerMotionMask |
-                ButtonPressMask | ButtonReleaseMask |
-                EnterWindowMask | LeaveWindowMask;
-    winAttribs.event_mask = eventMask;
-    winAttribs.border_pixel = 0;
-    winAttribs.bit_gravity = StaticGravity;
-    winAttribs.colormap = XCreateColormap(__display, RootWindow(__display, visualInfo->screen), visualInfo->visual, AllocNone);
-
-    GLint winMask;
-    winMask = CWBorderPixel | CWBitGravity | CWEventMask| CWColormap;
-   
-    __window = XCreateWindow(__display, DefaultRootWindow(__display), __x, __y, __width, __height, 0,
-                            visualInfo->depth, InputOutput, visualInfo->visual, winMask,
-                            &winAttribs);
-
-    // Tell the window manager that it should send the delete window notification through ClientMessage
-    __atomWmDeleteWindow = XInternAtom(__display, "WM_DELETE_WINDOW", False);
-    XSetWMProtocols(__display, __window, &__atomWmDeleteWindow, 1);
-
-    XMapWindow(__display, __window);
-
-    // Send fullscreen atom message to the window; most window managers respect WM_STATE messages
-    // Note: fullscreen mode will use native desktop resolution and won't care about width/height specified
-    if (fullscreen)
+    void closeGamepad(const ConnectedGamepadDevInfo& gamepadDevInfo)
     {
-        XEvent xev;
-        Atom atomWm_state = XInternAtom(__display, "_NET_WM_STATE", False);
-        Atom atomFullscreen = XInternAtom(__display, "_NET_WM_STATE_FULLSCREEN", False);
-
-        memset(&xev, 0, sizeof(xev));
-        xev.type = ClientMessage;
-        xev.xclient.window = __window;
-        xev.xclient.message_type = atomWm_state;
-        xev.xclient.format = 32;
-        xev.xclient.data.l[0] = 1;
-        xev.xclient.data.l[1] = atomFullscreen;
-        xev.xclient.data.l[2] = 0;
-
-        XSendEvent(__display, DefaultRootWindow(__display), false, SubstructureNotifyMask | SubstructureRedirectMask, &xev);
+        ::close(gamepadDevInfo.fd);
     }
-    
-    XStoreName(__display, __window, title ? title : "");
 
-    __context = glXCreateContext(__display, visualInfo, NULL, True);
-    if (!__context)
+    void unregisterGamepad(GamepadHandle handle)
     {
-        perror("glXCreateContext");
-        return NULL;
+        for(list<ConnectedGamepadDevInfo>::iterator it = __connectedGamepads.begin(); it != __connectedGamepads.end();++it)
+        {
+            if(handle == (*it).fd)
+            {
+                closeGamepad(*it);
+                __connectedGamepads.erase(it);
+                return;
+            }
+        }
     }
-    glXMakeCurrent(__display, __window, __context);
 
-    // Use OpenGL 2.x with GLEW
-    glewExperimental = GL_TRUE;
-    GLenum glewStatus = glewInit();
-    if (glewStatus != GLEW_OK)
+    void closeAllGamepads()
     {
-        perror("glewInit");
-        return NULL;
+        for(list<ConnectedGamepadDevInfo>::iterator it = __connectedGamepads.begin(); it != __connectedGamepads.end();++it)
+        {
+            closeGamepad(*it);
+            __connectedGamepads.erase(it);
+        }
     }
 
-    // GL Version
-    int versionGL[2] = {-1, -1};
-    glGetIntegerv(GL_MAJOR_VERSION, versionGL);
-    glGetIntegerv(GL_MINOR_VERSION, versionGL + 1);
-    printf("GL version: %d.%d\n", versionGL[0], versionGL[1]);
-
-    // TODO: Get this workings
-    if (glXSwapIntervalEXT)
-        glXSwapIntervalEXT(__display, __window, __vsync ? 1 : 0);
-    else if(glXSwapIntervalMESA)
-        glXSwapIntervalMESA(__vsync ? 1 : 0);
- 
-    return platform;
-}
+    const GamepadInfoEntry& getGamepadMappedInfo(unsigned int vendorId, unsigned int productId, unsigned int numberOfAxes, unsigned int numberOfButtons)
+    {
+        for(int i=0;i<sizeof(gamepadLookupTable)/sizeof(GamepadInfoEntry);i++)
+        {
+            const GamepadInfoEntry& curEntry = gamepadLookupTable[i];
+            if(curEntry.vendorId == vendorId && curEntry.productId == productId)
+            {
+                return curEntry;
+            }
+        }
 
-void cleanupX11()
-{
-    if (__display)
+        for(int i=0;i<sizeof(gamepadLookupTable)/sizeof(GamepadInfoEntry);i++)
+        {
+            const GamepadInfoEntry& curEntry = gamepadLookupTable[i];
+            if(curEntry.vendorId == 0 && curEntry.productId == 0 && curEntry.numberOfAxes == numberOfAxes && curEntry.numberOfButtons == numberOfButtons)
+            {
+                return curEntry;
+            }
+        }
+
+        return gamepadLookupTable[0];
+    }
+
+    const GamepadInfoEntry& getGamepadMappedInfo(const GamepadHandle handle)
     {
-        glXMakeCurrent(__display, None, NULL);
+        GP_ASSERT(pad);
 
-        if (__context)
-             glXDestroyContext(__display, __context);
-        if (__window)
-             XDestroyWindow(__display, __window);
+        for(list<ConnectedGamepadDevInfo>::iterator it = __connectedGamepads.begin(); it != __connectedGamepads.end();++it)
+        {
+            if(handle == (*it).fd)
+            {
+                return it->gamepadInfo;
+            }
+        }
+        GP_WARN("Gamepad not connected but yet trying to get its data. Falling back to generic one.");
+        return gamepadLookupTable[0];
+    }
 
-         XCloseDisplay(__display);
+    const GamepadJoystickAxisInfo* tryGetGamepadMappedAxisInfo(const GamepadInfoEntry& gpinfo, unsigned int axisNumber)
+    {
+        if(axisNumber >= 0 && axisNumber < gpinfo.numberOfAxes)
+        {
+            int i = 0;
+            while(true)
+            {
+                const GamepadJoystickAxisInfo* curAxisInfo = &gpinfo.axes[i++];
+                if(curAxisInfo->axisIndex == axisNumber)
+                    return curAxisInfo;
+                else if(curAxisInfo->axisIndex < 0)
+                    return NULL;
+            }
+        }
+        return NULL;
     }
-}
 
-double timespec2millis(struct timespec *a)
-{
-    GP_ASSERT(a);
-    return (1000.0 * a->tv_sec) + (0.000001 * a->tv_nsec);
-}
+    bool tryGetGamepadMappedButton(const GamepadInfoEntry& gpinfo, unsigned long btnNumber, long& outMap)
+    {
+        if(btnNumber >= 0 && btnNumber < gpinfo.numberOfButtons )
+        {
+            if(gpinfo.buttons[btnNumber] >= 0)
+            {
+                outMap = gpinfo.buttons[btnNumber];
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        GP_WARN("Unmapped gamepad button: %u.",btnNumber);
+        return false;
+    }
 
-void updateWindowSize()
-{
-    GP_ASSERT(__display);
-    GP_ASSERT(__window);
-    XWindowAttributes windowAttrs;
-    XGetWindowAttributes(__display, __window, &windowAttrs);
-    __windowSize[0] = windowAttrs.width;
-    __windowSize[1] = windowAttrs.height;
-}
+    unsigned int readIntegerGamepadIdPropery(const char* sysFSIdPath, const char* propertyName)
+    {
+        unsigned int ret = 0;
+        try {
+            ifstream propStream;
+            propStream.open((string(sysFSIdPath) + propertyName).c_str(),ifstream::in);
+            propStream >> std::hex >> ret;
+            propStream.close();
+        } catch (exception e) {
+            GP_WARN("Could not read propery from SysFS for Gamepad: %s", propertyName);
+        }
+        return ret;
+    }
 
-int Platform::enterMessagePump()
-{
-    GP_ASSERT(_game);
-
-    updateWindowSize();
- 
-    static const float ACCELEROMETER_X_FACTOR = 90.0f / __windowSize[0];
-    static const float ACCELEROMETER_Y_FACTOR = 90.0f / __windowSize[1];
-    static int lx = 0;
-    static int ly = 0;
-    static bool shiftDown = false;
-    static bool capsOn = false;
-    static XEvent evt;
-
-    // Get the initial time.
-    clock_gettime(CLOCK_REALTIME, &__timespec);
-    __timeStart = timespec2millis(&__timespec);
-    __timeAbsolute = 0L;
-
-    // Run the game.
-    _game->run();
-
-    // Setup select for message handling (to allow non-blocking)
-    int x11_fd = ConnectionNumber(__display);
-    
-    pollfd xpolls[1];
-    xpolls[0].fd = x11_fd;
-    xpolls[0].events = POLLIN|POLLPRI;
-  
-    // Message loop.
-    while (true)
+    bool isBlackListed(unsigned int vendorId, unsigned int productId)
+    {
+        switch(vendorId)
+        {
+            case 0x0e0f: //virtual machine devices
+                if(productId == 0x0003) // Virtual Mouse
+                    return true;
+        }
+        return false;
+    }
+
+    void handleConnectedGamepad(dev_t devId, const char* devPath, const char* sysFSIdPath)
+    {
+        GP_ASSERT(devPath);
+
+        unsigned int vendorId =readIntegerGamepadIdPropery(sysFSIdPath,"vendor");
+        unsigned int productId =readIntegerGamepadIdPropery(sysFSIdPath,"product");
+
+        if(isBlackListed(vendorId,productId)) return;
+
+        GamepadHandle handle = ::open(devPath,O_RDONLY | O_NONBLOCK);
+        if(handle < 0)
+        {
+            GP_WARN("Could not open Gamepad device.");
+            return;
+        }
+
+        if(!(fcntl(handle, F_GETFL) != -1 || errno != EBADF))
+            return;
+
+        char axesNum, btnsNum, name[256];
+        ioctl(handle, JSIOCGNAME(256), name);
+        ioctl (handle, JSIOCGAXES, &axesNum);
+        ioctl (handle, JSIOCGBUTTONS, &btnsNum);
+
+        const GamepadInfoEntry& gpInfo = getGamepadMappedInfo(vendorId,productId,(unsigned int)axesNum,(unsigned int)btnsNum);
+        unsigned int numJS = gpInfo.numberOfJS;
+        unsigned int numTR = gpInfo.numberOfTriggers;
+
+
+        Platform::gamepadEventConnectedInternal(handle,btnsNum,numJS,numTR,vendorId,productId,"",name);
+
+        ConnectedGamepadDevInfo info = {devId,handle,gpInfo}; 
+        __connectedGamepads.push_back(info);
+    }
+
+    static float normalizeJoystickAxis(int axisValue, int deadZone, bool zeroToOne)
     {
-        poll( xpolls, 1, 16 );
-        // handle all pending events in one block
-        while (XPending(__display))
+        int absAxisValue = 0;
+        if(zeroToOne)
+            absAxisValue = (axisValue + 32767) / 2.0;
+        else
+             absAxisValue = abs(axisValue);
+
+        if (absAxisValue < deadZone)
+        {
+            return 0.0f;
+        }
+        else
         {
-           XNextEvent(__display, &evt);
-        
-            switch (evt.type)
+            int maxVal = 0;
+            int value = 0;
+            if(!zeroToOne)
             {
-            case ClientMessage:
+                value = axisValue;
+                if (value < 0)
                 {
-                    // Handle destroy window message correctly
-                    if (evt.xclient.data.l[0] == __atomWmDeleteWindow)
-                    {
-                        _game->exit();
-                    }
+                    value = -1;
+                    maxVal = 32768;
                 }
-                break;
-            case DestroyNotify :
+                else if (value > 0)
                 {
-                    cleanupX11();
-                    exit(0);
+                    value = 1;
+                    maxVal = 32767;
                 }
-                break;
-
-            case Expose:
+                else
                 {
-                    updateWindowSize();
+                    return 0.0f;
                 }
-                break;
+            }
+            else
+            {
+                value = 1;
+                maxVal = 32767;
+            }
+
+            float ret = value * (absAxisValue - deadZone) / (float)(maxVal - deadZone);
+            return ret;
+        }
+    }
+
+    void enumGamepads()
+    {
+        const int maxDevs = 16;
+        const char* devPathFormat = "/dev/input/js%u";
+        const char* sysfsPathFormat = "/sys/class/input/js%u/device/id/";
+        char curDevPath[20];
 
-            case KeyPress:
+        for(int i=0;i<maxDevs;i++)
+        {
+            sprintf(curDevPath,devPathFormat,i);
+            struct stat gpstat;
+            if(::stat(curDevPath,&gpstat) == 0)
+            {
+                dev_t devid = gpstat.st_rdev;
+                if(!isGamepadDevRegistered(devid))
                 {
-                    KeySym sym = XLookupKeysym(&evt.xkey, (evt.xkey.state & shiftDown) ? 1 : 0);
+                    char cursysFSPath[35];
+                    sprintf(cursysFSPath,sysfsPathFormat,i);
+                    handleConnectedGamepad(devid,curDevPath,cursysFSPath);
+                }
+            }
+        }
+    }
 
+    void gamepadHandlingLoop()
+    {
+        enumGamepads();
+    }
 
-                    //TempSym needed because XConvertCase operates on two keysyms: One lower and the other upper, we are only interested in the upper case
-                    KeySym tempSym;
-                    if (capsOn && !shiftDown)
-                        XConvertCase(sym,  &tempSym, &sym);
+    int Platform::enterMessagePump()
+    {
+        GP_ASSERT(_game);
 
-                    Keyboard::Key key = getKey(sym);
-                    gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_PRESS, key);
+        updateWindowSize();
 
-                    if (key == Keyboard::KEY_CAPS_LOCK)
-                        capsOn = !capsOn;
-                    if (key == Keyboard::KEY_SHIFT)
-                        shiftDown = true;
+        static const float ACCELEROMETER_X_FACTOR = 90.0f / __windowSize[0];
+        static const float ACCELEROMETER_Y_FACTOR = 90.0f / __windowSize[1];
+        static int lx = 0;
+        static int ly = 0;
+        static bool shiftDown = false;
+        static bool capsOn = false;
+        static XEvent evt;
 
-                    if (int character = getUnicode(key))
-                        gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_CHAR, character);
+        // Get the initial time.
+        clock_gettime(CLOCK_REALTIME, &__timespec);
+        __timeStart = timespec2millis(&__timespec);
+        __timeAbsolute = 0L;
 
-                }
-                break;
+        // Run the game.
+        _game->run();
 
-            case KeyRelease:
-                {
-                    //detect and drop repeating keystrokes (no other way to do this using the event interface)
-                    XEvent next;
-                    if ( XPending(__display) )
-                    {
-                        XPeekEvent(__display,&next);
-                        if ( next.type == KeyPress
-                            && next.xkey.time == evt.xkey.time
-                            && next.xkey.keycode == evt.xkey.keycode )
-                        {
-                            XNextEvent(__display,&next);
-                            continue;
-                        }
-                    }
-                    
-                    KeySym sym = XLookupKeysym(&evt.xkey, 0);
-                    Keyboard::Key key = getKey(sym);
-                    gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_RELEASE, key);
+        // Setup select for message handling (to allow non-blocking)
+        int x11_fd = ConnectionNumber(__display);
 
-                    if (key == Keyboard::KEY_SHIFT)
-                        shiftDown = false;
-                }
-                break;
+        pollfd xpolls[1];
+        xpolls[0].fd = x11_fd;
+        xpolls[0].events = POLLIN|POLLPRI;
 
-            case ButtonPress:
-                {
-                    gameplay::Mouse::MouseEvent mouseEvt;
-                    switch (evt.xbutton.button)
-                    {
-                        case 1:
-                            mouseEvt = gameplay::Mouse::MOUSE_PRESS_LEFT_BUTTON;
-                            break;
-                        case 2:
-                            mouseEvt = gameplay::Mouse::MOUSE_PRESS_MIDDLE_BUTTON;
-                            break;
-                        case 3:
-                            mouseEvt = gameplay::Mouse::MOUSE_PRESS_RIGHT_BUTTON;
-                            break;
-                        case 4:
-                        case 5:
-                            gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_WHEEL,
-                                                                   evt.xbutton.x, evt.xbutton.y,
-                                                                   evt.xbutton.button == Button4 ? 1 : -1);
-                            break;
-                        default:
-                            break;
-                    }
-                    if (!gameplay::Platform::mouseEventInternal(mouseEvt, evt.xbutton.x, evt.xbutton.y, 0))
-                    {
-                        gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_PRESS, evt.xbutton.x, evt.xbutton.y, 0);
-                    }
-                }
-                break;
+        // Message loop.
+        while (true)
+        {
+            poll( xpolls, 1, 16 );
+            // handle all pending events in one block
+            while (XPending(__display))
+            {
+                XNextEvent(__display, &evt);
 
-            case ButtonRelease:
-                {
-                    gameplay::Mouse::MouseEvent mouseEvt;
-                    switch (evt.xbutton.button)
-                    {
-                        case 1:
-                            mouseEvt = gameplay::Mouse::MOUSE_RELEASE_LEFT_BUTTON;
-                            break;
-                        case 2:
-                            mouseEvt = gameplay::Mouse::MOUSE_RELEASE_MIDDLE_BUTTON;
-                            break;
-                        case 3:
-                            mouseEvt = gameplay::Mouse::MOUSE_RELEASE_RIGHT_BUTTON;
-                            break;
-                        default:
-                            break;
-                    }
-                    if (!gameplay::Platform::mouseEventInternal(mouseEvt, evt.xbutton.x, evt.xbutton.y, 0))
-                    {
-                        gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_RELEASE, evt.xbutton.x, evt.xbutton.y, 0);
-                    }
-                }
-                break;
-        
-            case MotionNotify:
+                switch (evt.type)
                 {
-                    int x = evt.xmotion.x;
-                    int y = evt.xmotion.y;
+                    case ClientMessage:
+                        {
+                            // Handle destroy window message correctly
+                            if (evt.xclient.data.l[0] == __atomWmDeleteWindow)
+                            {
+                                _game->exit();
+                            }
+                        }
+                        break;
+                    case DestroyNotify :
+                        {
+                            cleanupX11();
+                            exit(0);
+                        }
+                        break;
 
-                    if (__mouseCaptured)
-                    {
-                        if (x == __mouseCapturePointX && y == __mouseCapturePointY)
+                    case Expose:
                         {
-                            // Discard the first MotionNotify following capture
-                            // since it contains bogus x,y data.
-                            break;
+                            updateWindowSize();
                         }
+                        break;
+
+                    case KeyPress:
+                        {
+                            KeySym sym = XLookupKeysym(&evt.xkey, (evt.xkey.state & shiftDown) ? 1 : 0);
 
-                        // Convert to deltas
-                        x -= __mouseCapturePointX;
-                        y -= __mouseCapturePointY;
 
-                        // Warp mouse back to center of screen.
-                        XWarpPointer(__display, None, __window, 0, 0, 0, 0, __mouseCapturePointX, __mouseCapturePointY);
-                    }
+                            //TempSym needed because XConvertCase operates on two keysyms: One lower and the other upper, we are only interested in the upper case
+                            KeySym tempSym;
+                            if (capsOn && !shiftDown)
+                                XConvertCase(sym,  &tempSym, &sym);
 
-                    if (!gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_MOVE, x, y, 0))
-                    {
-                        if (evt.xmotion.state & Button1Mask)
+                            Keyboard::Key key = getKey(sym);
+                            gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_PRESS, key);
+
+                            if (key == Keyboard::KEY_CAPS_LOCK)
+                                capsOn = !capsOn;
+                            if (key == Keyboard::KEY_SHIFT)
+                                shiftDown = true;
+
+                            if (int character = getUnicode(key))
+                                gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_CHAR, character);
+
+                        }
+                        break;
+
+                    case KeyRelease:
                         {
-                            gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_MOVE, x, y, 0);
+                            //detect and drop repeating keystrokes (no other way to do this using the event interface)
+                            XEvent next;
+                            if ( XPending(__display) )
+                            {
+                                XPeekEvent(__display,&next);
+                                if ( next.type == KeyPress
+                                        && next.xkey.time == evt.xkey.time
+                                        && next.xkey.keycode == evt.xkey.keycode )
+                                {
+                                    XNextEvent(__display,&next);
+                                    continue;
+                                }
+                            }
+
+                            KeySym sym = XLookupKeysym(&evt.xkey, 0);
+                            Keyboard::Key key = getKey(sym);
+                            gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_RELEASE, key);
+
+                            if (key == Keyboard::KEY_SHIFT)
+                                shiftDown = false;
                         }
-                        else if (evt.xmotion.state & Button3Mask)
+                        break;
+
+                    case ButtonPress:
                         {
-                            // Update the pitch and roll by adding the scaled deltas.
-                            __roll += (float)(x - lx) * ACCELEROMETER_X_FACTOR;
-                            __pitch += -(float)(y - ly) * ACCELEROMETER_Y_FACTOR;
+                            gameplay::Mouse::MouseEvent mouseEvt;
+                            switch (evt.xbutton.button)
+                            {
+                                case 1:
+                                    mouseEvt = gameplay::Mouse::MOUSE_PRESS_LEFT_BUTTON;
+                                    break;
+                                case 2:
+                                    mouseEvt = gameplay::Mouse::MOUSE_PRESS_MIDDLE_BUTTON;
+                                    break;
+                                case 3:
+                                    mouseEvt = gameplay::Mouse::MOUSE_PRESS_RIGHT_BUTTON;
+                                    break;
+                                case 4:
+                                case 5:
+                                    gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_WHEEL,
+                                            evt.xbutton.x, evt.xbutton.y,
+                                            evt.xbutton.button == Button4 ? 1 : -1);
+                                    break;
+                                default:
+                                    break;
+                            }
+                            if (!gameplay::Platform::mouseEventInternal(mouseEvt, evt.xbutton.x, evt.xbutton.y, 0))
+                            {
+                                gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_PRESS, evt.xbutton.x, evt.xbutton.y, 0);
+                            }
+                        }
+                        break;
 
-                            // Clamp the values to the valid range.
-                            __roll = max(min(__roll, 90.0f), -90.0f);
-                            __pitch = max(min(__pitch, 90.0f), -90.0f);
+                    case ButtonRelease:
+                        {
+                            gameplay::Mouse::MouseEvent mouseEvt;
+                            switch (evt.xbutton.button)
+                            {
+                                case 1:
+                                    mouseEvt = gameplay::Mouse::MOUSE_RELEASE_LEFT_BUTTON;
+                                    break;
+                                case 2:
+                                    mouseEvt = gameplay::Mouse::MOUSE_RELEASE_MIDDLE_BUTTON;
+                                    break;
+                                case 3:
+                                    mouseEvt = gameplay::Mouse::MOUSE_RELEASE_RIGHT_BUTTON;
+                                    break;
+                                default:
+                                    break;
+                            }
+                            if (!gameplay::Platform::mouseEventInternal(mouseEvt, evt.xbutton.x, evt.xbutton.y, 0))
+                            {
+                                gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_RELEASE, evt.xbutton.x, evt.xbutton.y, 0);
+                            }
+                        }
+                        break;
 
-                            // Update the last X/Y values.
-                            lx = x;
-                            ly = y;
+                    case MotionNotify:
+                        {
+                            int x = evt.xmotion.x;
+                            int y = evt.xmotion.y;
+
+                            if (__mouseCaptured)
+                            {
+                                if (x == __mouseCapturePointX && y == __mouseCapturePointY)
+                                {
+                                    // Discard the first MotionNotify following capture
+                                    // since it contains bogus x,y data.
+                                    break;
+                                }
+
+                                // Convert to deltas
+                                x -= __mouseCapturePointX;
+                                y -= __mouseCapturePointY;
+
+                                // Warp mouse back to center of screen.
+                                XWarpPointer(__display, None, __window, 0, 0, 0, 0, __mouseCapturePointX, __mouseCapturePointY);
+                            }
+
+                            if (!gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_MOVE, x, y, 0))
+                            {
+                                if (evt.xmotion.state & Button1Mask)
+                                {
+                                    gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_MOVE, x, y, 0);
+                                }
+                                else if (evt.xmotion.state & Button3Mask)
+                                {
+                                    // Update the pitch and roll by adding the scaled deltas.
+                                    __roll += (float)(x - lx) * ACCELEROMETER_X_FACTOR;
+                                    __pitch += -(float)(y - 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 = x;
+                                    ly = y;
+                                }
+                            }
                         }
-                    }
+                        break;
+
+                    default:
+                        break;
                 }
-                break;
-            
-            default:
-                break;
             }
-        }
 
-        if (_game)
-        {
-            // Game state will be uninitialized if game was closed through Game::exit()
-            if (_game->getState() == Game::UNINITIALIZED)
-                break;
-            
-            _game->frame();
+            gamepadHandlingLoop();
+
+            if (_game)
+            {
+                // Game state will be uninitialized if game was closed through Game::exit()
+                if (_game->getState() == Game::UNINITIALIZED)
+                    break;
+
+                _game->frame();
+            }
+
+            glXSwapBuffers(__display, __window);
         }
 
-        glXSwapBuffers(__display, __window);
+        cleanupX11();
+
+        return 0;
     }
 
-    cleanupX11();
+    void Platform::signalShutdown()
+    {
+    }
 
-    return 0;
-}
-    
-void Platform::signalShutdown()
-{
-    // nothing to do  
-}
+    bool Platform::canExit()
+    {
+        return true;
+    }
 
-bool Platform::canExit()
-{
-    return true;
-}
-    
-unsigned int Platform::getDisplayWidth()
-{
-    return __windowSize[0];
-}
+    unsigned int Platform::getDisplayWidth()
+    {
+        return __windowSize[0];
+    }
 
-unsigned int Platform::getDisplayHeight()
-{
-    return __windowSize[1];
-}
+    unsigned int Platform::getDisplayHeight()
+    {
+        return __windowSize[1];
+    }
 
-double Platform::getAbsoluteTime()
-{
+    double Platform::getAbsoluteTime()
+    {
 
-    clock_gettime(CLOCK_REALTIME, &__timespec);
-    double now = timespec2millis(&__timespec);
-    __timeAbsolute = now - __timeStart;
+        clock_gettime(CLOCK_REALTIME, &__timespec);
+        double now = timespec2millis(&__timespec);
+        __timeAbsolute = now - __timeStart;
 
-    return __timeAbsolute;
-}
+        return __timeAbsolute;
+    }
 
-void Platform::setAbsoluteTime(double time)
-{
-    __timeAbsolute = time;
-}
+    void Platform::setAbsoluteTime(double time)
+    {
+        __timeAbsolute = time;
+    }
 
-bool Platform::isVsync()
-{
-    return __vsync;
-}
+    bool Platform::isVsync()
+    {
+        return __vsync;
+    }
 
-void Platform::setVsync(bool enable)
-{
-    if (glXSwapIntervalEXT)
-        glXSwapIntervalEXT(__display, __window, __vsync ? 1 : 0);
-    else if(glXSwapIntervalMESA)
-        glXSwapIntervalMESA(__vsync ? 1 : 0);
+    void Platform::setVsync(bool enable)
+    {
+        if (glXSwapIntervalEXT)
+            glXSwapIntervalEXT(__display, __window, __vsync ? 1 : 0);
+        else if(glXSwapIntervalMESA)
+            glXSwapIntervalMESA(__vsync ? 1 : 0);
 
-    __vsync = enable;
-}
+        __vsync = enable;
+    }
 
-void Platform::swapBuffers()
-{
-    glXSwapBuffers(__display, __window);
-}
+    void Platform::swapBuffers()
+    {
+        glXSwapBuffers(__display, __window);
+    }
 
-void Platform::sleep(long ms)
-{
-    usleep(ms * 1000);
-}
+    void Platform::sleep(long ms)
+    {
+        usleep(ms * 1000);
+    }
 
-void Platform::setMultiSampling(bool enabled)
-{
-    if (enabled == __multiSampling)
+    void Platform::setMultiSampling(bool enabled)
     {
-        return;
+        if (enabled == __multiSampling)
+        {
+            return;
+        }
+        
+            //todo
+            
+            __multiSampling = enabled;
     }
-
-    //todo
-
-    __multiSampling = enabled;
-}
-
-bool Platform::isMultiSampling()
-{
-    return __multiSampling;
-}
+    
+        bool Platform::isMultiSampling()
+        {
+            return __multiSampling;
+        }
 
-void Platform::setMultiTouch(bool enabled)
-{
-    // not supported
-}
+    void Platform::setMultiTouch(bool enabled)
+    {
+        // not supported
+    }
 
-bool Platform::isMultiTouch()
-{
-    false;
-}
+    bool Platform::isMultiTouch()
+    {
+        false;
+    }
 
-void Platform::getAccelerometerValues(float* pitch, float* roll)
-{
-    GP_ASSERT(pitch);
-    GP_ASSERT(roll);
+    void Platform::getAccelerometerValues(float* pitch, float* roll)
+    {
+        GP_ASSERT(pitch);
+        GP_ASSERT(roll);
 
-    *pitch = __pitch;
-    *roll = __roll;
-}
+        *pitch = __pitch;
+        *roll = __roll;
+    }
 
-bool Platform::hasMouse()
-{
-    return true;
-}
+    bool Platform::hasMouse()
+    {
+        return true;
+    }
 
-void Platform::setMouseCaptured(bool captured)
-{
-    if (captured != __mouseCaptured)
+    void Platform::setMouseCaptured(bool captured)
     {
-        if (captured)
+        if (captured != __mouseCaptured)
         {
-            // Hide the cursor and warp it to the center of the screen
-            __mouseCapturePointX = getDisplayWidth() / 2;
-            __mouseCapturePointY = getDisplayHeight() / 2;
+            if (captured)
+            {
+                // Hide the cursor and warp it to the center of the screen
+                __mouseCapturePointX = getDisplayWidth() / 2;
+                __mouseCapturePointY = getDisplayHeight() / 2;
+
+                setCursorVisible(false);
+                XWarpPointer(__display, None, __window, 0, 0, 0, 0, __mouseCapturePointX, __mouseCapturePointY);
+            }
+            else
+            {
+                // Restore cursor
+                XWarpPointer(__display, None, __window, 0, 0, 0, 0, __mouseCapturePointX, __mouseCapturePointY);
+                setCursorVisible(true);
+            }
 
-            setCursorVisible(false);
-            XWarpPointer(__display, None, __window, 0, 0, 0, 0, __mouseCapturePointX, __mouseCapturePointY);
+            __mouseCaptured = captured;
         }
-        else
+    }
+
+    bool Platform::isMouseCaptured()
+    {
+        return __mouseCaptured;
+    }
+
+    void Platform::setCursorVisible(bool visible)
+    {
+        if (visible != __cursorVisible)
         {
-            // Restore cursor
-            XWarpPointer(__display, None, __window, 0, 0, 0, 0, __mouseCapturePointX, __mouseCapturePointY);
-            setCursorVisible(true);
+            if (visible)
+            {
+                Cursor invisibleCursor;
+                Pixmap bitmapNoData;
+                XColor black;
+                static char noData[] = {0, 0, 0, 0, 0, 0, 0, 0};
+                black.red = black.green = black.blue = 0;
+                bitmapNoData = XCreateBitmapFromData(__display, __window, noData, 8, 8);
+                invisibleCursor = XCreatePixmapCursor(__display, bitmapNoData, bitmapNoData, &black, &black, 0, 0);
+
+                XDefineCursor(__display, __window, invisibleCursor);
+                XFreeCursor(__display, invisibleCursor);
+                XFreePixmap(__display, bitmapNoData);
+            }
+            else
+            {
+                XUndefineCursor(__display, __window);
+            }
+            XFlush(__display);
+            __cursorVisible = visible;
         }
+    }
 
-        __mouseCaptured = captured;
+    bool Platform::isCursorVisible()
+    {
+        return __cursorVisible;
     }
-}
 
-bool Platform::isMouseCaptured()
-{
-    return __mouseCaptured;
-}
+    void Platform::displayKeyboard(bool display)
+    {
+        // not supported
+    }
 
-void Platform::setCursorVisible(bool visible)
-{
-    if (visible != __cursorVisible)
+    void Platform::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
+    {
+        if (!Form::touchEventInternal(evt, x, y, contactIndex))
+        {
+            Game::getInstance()->touchEvent(evt, x, y, contactIndex);
+            Game::getInstance()->getScriptController()->touchEvent(evt, x, y, contactIndex);
+        }
+    }
+
+    void Platform::keyEventInternal(Keyboard::KeyEvent evt, int key)
     {
-        if (visible)
+        if (!Form::keyEventInternal(evt, key))
+        {
+            Game::getInstance()->keyEvent(evt, key);
+            Game::getInstance()->getScriptController()->keyEvent(evt, key);
+        }
+    }
+
+    bool Platform::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
+    {
+        if (Form::mouseEventInternal(evt, x, y, wheelDelta))
+        {
+            return true;
+        }
+        else if (Game::getInstance()->mouseEvent(evt, x, y, wheelDelta))
         {
-            Cursor invisibleCursor;
-            Pixmap bitmapNoData;
-            XColor black;
-            static char noData[] = {0, 0, 0, 0, 0, 0, 0, 0};
-            black.red = black.green = black.blue = 0;
-            bitmapNoData = XCreateBitmapFromData(__display, __window, noData, 8, 8);
-            invisibleCursor = XCreatePixmapCursor(__display, bitmapNoData, bitmapNoData, &black, &black, 0, 0);
-
-            XDefineCursor(__display, __window, invisibleCursor);
-            XFreeCursor(__display, invisibleCursor);
-            XFreePixmap(__display, bitmapNoData);
+            return true;
         }
         else
         {
-            XUndefineCursor(__display, __window);
+            return Game::getInstance()->getScriptController()->mouseEvent(evt, x, y, wheelDelta);
         }
-        XFlush(__display);
-        __cursorVisible = visible;
     }
-}
+    
+        void Platform::gamepadEventConnectedInternal(GamepadHandle handle,  unsigned int buttonCount, unsigned int joystickCount, unsigned int triggerCount,
+                unsigned int vendorId, unsigned int productId, const char* vendorString, const char* productString)
+        {
+            Gamepad::add(handle, buttonCount, joystickCount, triggerCount, vendorId, productId, vendorString, productString);
+        }
 
-bool Platform::isCursorVisible()
-{
-    return __cursorVisible;
-}
+    void Platform::gamepadEventDisconnectedInternal(GamepadHandle handle)
+    {
+        Gamepad::remove(handle);
+    }
 
-void Platform::displayKeyboard(bool display)
-{
-    // not supported
-}
+    void Platform::shutdownInternal()
+    {
+        closeAllGamepads();
+        Game::getInstance()->shutdown();
+    }
 
-void Platform::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
-{
-    if (!Form::touchEventInternal(evt, x, y, contactIndex))
+    bool Platform::isGestureSupported(Gesture::GestureEvent evt)
     {
-        Game::getInstance()->touchEvent(evt, x, y, contactIndex);
-        Game::getInstance()->getScriptController()->touchEvent(evt, x, y, contactIndex);
+        return false;
     }
-}
 
-void Platform::keyEventInternal(Keyboard::KeyEvent evt, int key)
-{
-    if (!Form::keyEventInternal(evt, key))
+    void Platform::registerGesture(Gesture::GestureEvent evt)
     {
-        Game::getInstance()->keyEvent(evt, key);
-        Game::getInstance()->getScriptController()->keyEvent(evt, key);
     }
-}
 
-bool Platform::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
-{
-    if (Form::mouseEventInternal(evt, x, y, wheelDelta))
+    void Platform::unregisterGesture(Gesture::GestureEvent evt)
     {
-        return true;
     }
-    else if (Game::getInstance()->mouseEvent(evt, x, y, wheelDelta))
+
+    bool Platform::isGestureRegistered(Gesture::GestureEvent evt)
     {
-        return true;
+        return false;
     }
-    else
+
+    void Platform::pollGamepadState(Gamepad* gamepad)
     {
-        return Game::getInstance()->getScriptController()->mouseEvent(evt, x, y, wheelDelta);
-    }
-}
-
-void Platform::gamepadEventConnectedInternal(GamepadHandle handle,  unsigned int buttonCount, unsigned int joystickCount, unsigned int triggerCount,
-                                             unsigned int vendorId, unsigned int productId, const char* vendorString, const char* productString)
-{
-    Gamepad::add(handle, buttonCount, joystickCount, triggerCount, vendorId, productId, vendorString, productString);
-}
+        GP_ASSERT(gamepad);
 
-void Platform::gamepadEventDisconnectedInternal(GamepadHandle handle)
-{
-    Gamepad::remove(handle);
-}
+        struct js_event jevent;
+        const GamepadInfoEntry& gpInfo = getGamepadMappedInfo(gamepad->_handle);
 
-void Platform::shutdownInternal()
-{
-    Game::getInstance()->shutdown();
-}
+        while (read(gamepad->_handle, &jevent, sizeof(struct js_event)) > 0)
+        {
+            switch (jevent.type)
+            {
+                case JS_EVENT_BUTTON:
+                case JS_EVENT_BUTTON | JS_EVENT_INIT:
+                    {
+                        long curMappingIndex = -1;
+                        if(tryGetGamepadMappedButton(gpInfo, jevent.number, curMappingIndex))
+                        {
+                            if (jevent.value)
+                                gamepad->_buttons |= (1 << curMappingIndex);
+                            else
+                                gamepad->_buttons &= ~(1 << curMappingIndex);
+                        }
+                        break;
+                    }
+                case JS_EVENT_AXIS:
+                case JS_EVENT_AXIS | JS_EVENT_INIT:
+                    {
+                        if(jevent.number < gpInfo.numberOfAxes)
+                        {
+                            const GamepadJoystickAxisInfo* jsInfo = tryGetGamepadMappedAxisInfo(gpInfo,jevent.number);
+                            if(jsInfo)
+                            {
+                                float val = normalizeJoystickAxis(jevent.value,jsInfo->deadZone,jsInfo->mapFunc == ZERO_TO_POS);
+                                if(!(jsInfo->flags & GP_AXIS_SKIP))
+                                {
+                                    if((jsInfo->flags & GP_AXIS_IS_NEG))
+                                        val = -1.0f * val;
+
+                                    bool not_js_axis = false;
+                                    if((jsInfo->flags & GP_AXIS_IS_DPAD))
+                                    {
+                                        if(jevent.value != 0)
+                                            gamepad->_buttons |= (1 << (jevent.value > 0 ? jsInfo->mappedPosArg : jsInfo->mappedNegArg));
+                                        else
+                                        {
+                                            gamepad->_buttons &= ~(1 << jsInfo->mappedPosArg);
+                                            gamepad->_buttons &= ~(1 << jsInfo->mappedNegArg);
+                                        }
+                                        not_js_axis = true;
+                                    }
+                                    if((jsInfo->flags & GP_AXIS_IS_TRIGGER))
+                                    {
+                                        gamepad->_triggers[jsInfo->mappedPosArg] = val;
+                                        not_js_axis = true;
+                                    }
+
+                                    if(!not_js_axis)
+                                    {
+                                        if(jsInfo->flags & GP_AXIS_IS_XAXIS)
+                                            gamepad->_joysticks[jsInfo->joystickIndex].x = val;
+                                        else
+                                            gamepad->_joysticks[jsInfo->joystickIndex].y = val;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    break;
 
-bool Platform::isGestureSupported(Gesture::GestureEvent evt)
-{
-    return false;
-}
+                default: 
+                    GP_WARN("unhandled gamepad event: %x\n", jevent.type);
+            }
+        }
+        if(errno == ENODEV)
+        {
+            unregisterGamepad(gamepad->_handle);
+            gamepadEventDisconnectedInternal(gamepad->_handle);
+        }
 
-void Platform::registerGesture(Gesture::GestureEvent evt)
-{
-}
+    }
 
-void Platform::unregisterGesture(Gesture::GestureEvent evt)
-{
-}
-    
-bool Platform::isGestureRegistered(Gesture::GestureEvent evt)
-{
-    return false;
-}
+    bool Platform::launchURL(const char* url)
+    {
+        if (url == NULL || *url == '\0')
+            return false;
 
-void Platform::pollGamepadState(Gamepad* gamepad)
-{
-}
+        int len = strlen(url);
 
-bool Platform::launchURL(const char* url)
-{
-    if (url == NULL || *url == '\0')
-        return false;
+        char* cmd = new char[11 + len];
+        sprintf(cmd, "xdg-open %s", url);
+        int r = system(cmd);
+        SAFE_DELETE_ARRAY(cmd);
 
-    int len = strlen(url);
-    
-    char* cmd = new char[11 + len];
-    sprintf(cmd, "xdg-open %s", url);
-    int r = system(cmd);
-    SAFE_DELETE_ARRAY(cmd);
-    
-    return (r == 0);
-}
+        return (r == 0);
+    }
 
 }