Browse Source

Android: Added gamepad support.

Branimir Karadžić 11 years ago
parent
commit
527adf3c28
1 changed files with 155 additions and 50 deletions
  1. 155 50
      examples/common/entry/entry_android.cpp

+ 155 - 50
examples/common/entry/entry_android.cpp

@@ -28,6 +28,48 @@ extern "C"
 
 namespace entry
 {
+	struct GamepadRemap
+	{
+		uint16_t  m_keyCode;
+		Key::Enum m_key;
+	};
+
+	static GamepadRemap s_gamepadRemap[] =
+	{
+		{ AKEYCODE_DPAD_UP,       Key::GamepadUp        },
+		{ AKEYCODE_DPAD_DOWN,     Key::GamepadDown      },
+		{ AKEYCODE_DPAD_LEFT,     Key::GamepadLeft      },
+		{ AKEYCODE_DPAD_RIGHT,    Key::GamepadRight     },
+		{ AKEYCODE_BUTTON_START,  Key::GamepadStart     },
+		{ AKEYCODE_BACK,          Key::GamepadBack      },
+		{ AKEYCODE_BUTTON_THUMBL, Key::GamepadThumbL    },
+		{ AKEYCODE_BUTTON_THUMBR, Key::GamepadThumbR    },
+		{ AKEYCODE_BUTTON_L1,     Key::GamepadShoulderL },
+		{ AKEYCODE_BUTTON_R1,     Key::GamepadShoulderR },
+		{ AKEYCODE_GUIDE,         Key::GamepadGuide     },
+		{ AKEYCODE_BUTTON_A,      Key::GamepadA         },
+		{ AKEYCODE_BUTTON_B,      Key::GamepadB         },
+		{ AKEYCODE_BUTTON_X,      Key::GamepadX         },
+		{ AKEYCODE_BUTTON_Y,      Key::GamepadY         },
+	};
+
+	struct GamepadAxisRemap
+	{
+		int32_t m_event;
+		GamepadAxis::Enum m_axis;
+		bool m_convert;
+	};
+
+	static GamepadAxisRemap s_translateAxis[] =
+	{
+		{ AMOTION_EVENT_AXIS_X,        GamepadAxis::LeftX,  false },
+		{ AMOTION_EVENT_AXIS_Y,        GamepadAxis::LeftY,  false },
+		{ AMOTION_EVENT_AXIS_LTRIGGER, GamepadAxis::LeftZ,  false },
+		{ AMOTION_EVENT_AXIS_Z,        GamepadAxis::RightX, true  },
+		{ AMOTION_EVENT_AXIS_RZ,       GamepadAxis::RightY, false },
+		{ AMOTION_EVENT_AXIS_RTRIGGER, GamepadAxis::RightZ, false },
+	};
+
 	struct MainThreadEntry
 	{
 		int m_argc;
@@ -42,6 +84,15 @@ namespace entry
 			: m_window(NULL)
 			, m_count(0)
 		{
+			memset(m_value, 0, sizeof(m_value) );
+
+			// Deadzone values from xinput.h
+			m_deadzone[GamepadAxis::LeftX ] =
+			m_deadzone[GamepadAxis::LeftY ] = 7849;
+			m_deadzone[GamepadAxis::RightX] =
+			m_deadzone[GamepadAxis::RightY] = 8689;
+			m_deadzone[GamepadAxis::LeftZ ] =
+			m_deadzone[GamepadAxis::RightZ] = 30;
 		}
 
 		void run(android_app* _app)
@@ -180,86 +231,138 @@ namespace entry
 			}
 		}
 
+		bool filter(GamepadAxis::Enum _axis, int32_t* _value)
+		{
+			const int32_t old = m_value[_axis];
+			const int32_t deadzone = m_deadzone[_axis];
+			int32_t value = *_value;
+			value = value > deadzone || value < -deadzone ? value : 0;
+			m_value[_axis] = value;
+			*_value = value;
+			return old != value;
+		}
+
 		int32_t onInputEvent(AInputEvent* _event)
 		{
-			int32_t type = AInputEvent_getType(_event);
+			WindowHandle  defaultWindow = { 0 };
+			GamepadHandle handle        = { 0 };
+			const int32_t type       = AInputEvent_getType(_event);
+			const int32_t source     = AInputEvent_getSource(_event);
+			const int32_t actionBits = AMotionEvent_getAction(_event);
 
 			switch (type)
 			{
 			case AINPUT_EVENT_TYPE_MOTION:
 				{
-					float mx = AMotionEvent_getX(_event, 0);
-					float my = AMotionEvent_getY(_event, 0);
-					int32_t count = AMotionEvent_getPointerCount(_event);
+					if (0 != (source & (AINPUT_SOURCE_GAMEPAD|AINPUT_SOURCE_JOYSTICK) ) )
+					{
+						for (uint32_t ii = 0; ii < BX_COUNTOF(s_translateAxis); ++ii)
+						{
+							const float fval = AMotionEvent_getAxisValue(_event, s_translateAxis[ii].m_event, 0);
+							int32_t value = int32_t( (s_translateAxis[ii].m_convert ? fval * 2.0f + 1.0f : fval) * INT16_MAX);
+							GamepadAxis::Enum axis = s_translateAxis[ii].m_axis;
+							if (filter(axis, &value) )
+							{
+								m_eventQueue.postAxisEvent(defaultWindow, handle, axis, value);
+							}
+						}
 
-					int32_t actionBits = AMotionEvent_getAction(_event);
-					int32_t action     = (actionBits & AMOTION_EVENT_ACTION_MASK);
-					int32_t index      = (actionBits & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+						return 1;
+					}
+					else
+					{
+						float mx = AMotionEvent_getX(_event, 0);
+						float my = AMotionEvent_getY(_event, 0);
+						int32_t count = AMotionEvent_getPointerCount(_event);
 
-					WindowHandle defaultWindow = { 0 };
+						int32_t action = (actionBits & AMOTION_EVENT_ACTION_MASK);
+						int32_t index  = (actionBits & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
 
-					count = m_count;
+						count = m_count;
 
-					switch (action)
-					{
-					case AMOTION_EVENT_ACTION_DOWN:
-					case AMOTION_EVENT_ACTION_POINTER_DOWN:
-						m_count++;
-						break;
-
-					case AMOTION_EVENT_ACTION_UP:
-					case AMOTION_EVENT_ACTION_POINTER_UP:
-						m_count--;
-						break;
-
-					default:
-						break;
-					}
+						switch (action)
+						{
+						case AMOTION_EVENT_ACTION_DOWN:
+						case AMOTION_EVENT_ACTION_POINTER_DOWN:
+							m_count++;
+							break;
+
+						case AMOTION_EVENT_ACTION_UP:
+						case AMOTION_EVENT_ACTION_POINTER_UP:
+							m_count--;
+							break;
+
+						default:
+							break;
+						}
 
-					if (count != m_count)
-					{
-						m_eventQueue.postMouseEvent(defaultWindow
-							, (int32_t)mx
-							, (int32_t)my
-							, 0
-							, 1 == count ? MouseButton::Left : MouseButton::Right
-							, false
-							);
-
-						if (0 != m_count)
+						if (count != m_count)
 						{
 							m_eventQueue.postMouseEvent(defaultWindow
 								, (int32_t)mx
 								, (int32_t)my
 								, 0
-								, 1 == m_count ? MouseButton::Left : MouseButton::Right
-								, true
+								, 1 == count ? MouseButton::Left : MouseButton::Right
+								, false
 								);
+
+							if (0 != m_count)
+							{
+								m_eventQueue.postMouseEvent(defaultWindow
+									, (int32_t)mx
+									, (int32_t)my
+									, 0
+									, 1 == m_count ? MouseButton::Left : MouseButton::Right
+									, true
+									);
+							}
+						}
+
+						switch (action)
+						{
+						case AMOTION_EVENT_ACTION_MOVE:
+							if (0 == index)
+							{
+								m_eventQueue.postMouseEvent(defaultWindow
+									, (int32_t)mx
+									, (int32_t)my
+									, 0
+									);
+							}
+							break;
+
+						default:
+							break;
 						}
 					}
+				}
+				break;
 
-					switch (action)
+			case AINPUT_EVENT_TYPE_KEY:
+				{
+					int32_t keyCode = AKeyEvent_getKeyCode(_event);
+
+					if (0 != (source & (AINPUT_SOURCE_GAMEPAD|AINPUT_SOURCE_JOYSTICK) ) )
 					{
-					case AMOTION_EVENT_ACTION_MOVE:
-						if (0 == index)
+						for (uint32_t jj = 0; jj < BX_COUNTOF(s_gamepadRemap); ++jj)
 						{
-							m_eventQueue.postMouseEvent(defaultWindow
-								, (int32_t)mx
-								, (int32_t)my
-								, 0
-								);
+							if (keyCode == s_gamepadRemap[jj].m_keyCode)
+							{
+								m_eventQueue.postKeyEvent(defaultWindow, s_gamepadRemap[jj].m_key, 0, actionBits == AKEY_EVENT_ACTION_DOWN);
+								break;
+							}
 						}
-						break;
-
-					default:
-						break;
 					}
+
+					return 1;
 				}
 				break;
 
-			case AINPUT_EVENT_TYPE_KEY:
+			default:
+				DBG("type %d", type);
 				break;
 			}
+
 			return 0;
 		}
 
@@ -284,6 +387,8 @@ namespace entry
 		android_app* m_app;
 
 		int32_t m_count;
+		int32_t m_value[GamepadAxis::Count];
+		int32_t m_deadzone[GamepadAxis::Count];
 	};
 
 	static Context s_ctx;