Daniele Bartolini пре 10 година
родитељ
комит
034d97ac97
2 измењених фајлова са 151 додато и 0 уклоњено
  1. 1 0
      genie/crown.lua
  2. 150 0
      src/main/main_windows.cpp

+ 1 - 0
genie/crown.lua

@@ -367,6 +367,7 @@ function crown_project(_name, _kind, _defines)
 			links {
 				"OpenGL32",
 				"dbghelp",
+				"xinput",
 			}
 
 		configuration { "debug", "x32", "vs*"}

+ 150 - 0
src/main/main_windows.cpp

@@ -19,6 +19,7 @@
 #define WIN32_LEAN_AND_MEAN
 #endif
 #include <windowsx.h>
+#include <xinput.h>
 
 namespace crown
 {
@@ -119,6 +120,152 @@ static KeyboardButton::Enum win_translate_key(int32_t winkey)
 	}
 }
 
+struct XinputToJoypad
+{
+	WORD bit;
+	JoypadButton::Enum button;
+};
+
+static XinputToJoypad s_xinput_to_joypad[] =
+{
+	{ XINPUT_GAMEPAD_DPAD_UP,        JoypadButton::UP             },
+	{ XINPUT_GAMEPAD_DPAD_DOWN,      JoypadButton::DOWN           },
+	{ XINPUT_GAMEPAD_DPAD_LEFT,      JoypadButton::LEFT           },
+	{ XINPUT_GAMEPAD_DPAD_RIGHT,     JoypadButton::RIGHT          },
+	{ XINPUT_GAMEPAD_START,          JoypadButton::START          },
+	{ XINPUT_GAMEPAD_BACK,           JoypadButton::BACK           },
+	{ XINPUT_GAMEPAD_LEFT_THUMB,     JoypadButton::LEFT_THUMB     },
+	{ XINPUT_GAMEPAD_RIGHT_THUMB,    JoypadButton::RIGHT_THUMB    },
+	{ XINPUT_GAMEPAD_LEFT_SHOULDER,  JoypadButton::LEFT_SHOULDER  },
+	{ XINPUT_GAMEPAD_RIGHT_SHOULDER, JoypadButton::RIGHT_SHOULDER },
+	{ XINPUT_GAMEPAD_A,              JoypadButton::A              },
+	{ XINPUT_GAMEPAD_B,              JoypadButton::B              },
+	{ XINPUT_GAMEPAD_X,              JoypadButton::X              },
+	{ XINPUT_GAMEPAD_Y,              JoypadButton::Y              }
+};
+
+struct Joypad
+{
+	void init()
+	{
+		memset(&_state, 0, sizeof(_state));
+		memset(&_axis, 0, sizeof(_axis));
+		memset(&_connected, 0, sizeof(_connected));
+	}
+
+	void update(OsEventQueue& queue)
+	{
+		for (uint8_t i = 0; i < CROWN_MAX_JOYPADS; ++i)
+		{
+			XINPUT_STATE state;
+			memset(&state, 0, sizeof(state));
+
+			const DWORD result = XInputGetState(i, &state);
+			const bool connected = result == ERROR_SUCCESS;
+
+			if (connected != _connected[i])
+				queue.push_joypad_event(i, connected);
+
+			_connected[i] = connected;
+
+			if (!connected || state.dwPacketNumber == _state[i].dwPacketNumber)
+				continue;
+
+			XINPUT_GAMEPAD& gamepad = _state[i].Gamepad;
+
+			const WORD diff = state.Gamepad.wButtons ^ gamepad.wButtons;
+			const WORD curr = state.Gamepad.wButtons;
+			if (diff != 0)
+			{
+				for (uint8_t bb = 0; bb < CE_COUNTOF(s_xinput_to_joypad); ++bb)
+				{
+					WORD bit = s_xinput_to_joypad[bb].bit;
+					if (bit & diff)
+					{
+						queue.push_joypad_event(i, s_xinput_to_joypad[bb].button, (curr & bit) != 0);
+						gamepad.wButtons = curr;
+					}
+				}
+			}
+
+			if (state.Gamepad.sThumbLX != gamepad.sThumbLX)
+			{
+				int32_t value = state.Gamepad.sThumbLX;
+				value = value > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE || value < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE
+					? value : 0;
+
+				_axis[0].lx = (float)value / (float)INT16_MAX;
+				queue.push_joypad_event(i, JoypadAxis::LEFT, _axis[0].lx, _axis[0].ly, _axis[0].lz);
+
+				gamepad.sThumbLX = state.Gamepad.sThumbLX;
+			}
+			if (state.Gamepad.sThumbLY != gamepad.sThumbLY)
+			{
+				int32_t value = state.Gamepad.sThumbLY;
+				value = value > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE || value < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE
+					? value : 0;
+
+				_axis[0].ly = (float)value / (float)INT16_MAX;
+				queue.push_joypad_event(i, JoypadAxis::LEFT, _axis[0].lx, _axis[0].ly, _axis[0].lz);
+
+				gamepad.sThumbLY = state.Gamepad.sThumbLY;
+			}
+			if (state.Gamepad.bLeftTrigger != gamepad.bLeftTrigger)
+			{
+				int32_t value = state.Gamepad.bLeftTrigger;
+				value = value >XINPUT_GAMEPAD_TRIGGER_THRESHOLD ? value : 0;
+
+				_axis[0].lz = (float)value / (float)UINT8_MAX;
+				queue.push_joypad_event(i, JoypadAxis::LEFT, _axis[0].lx, _axis[0].ly, _axis[0].lz);
+
+				gamepad.bLeftTrigger = state.Gamepad.bLeftTrigger;
+			}
+			if (state.Gamepad.sThumbRX != gamepad.sThumbRX)
+			{
+				int32_t value = state.Gamepad.sThumbRX;
+				value = value > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE || value < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE
+					? value : 0;
+
+				_axis[0].rx = (float)value / (float)INT16_MAX;
+				queue.push_joypad_event(i, JoypadAxis::RIGHT, _axis[0].rx, _axis[0].ry, _axis[0].rz);
+
+				gamepad.sThumbRX = state.Gamepad.sThumbRX;
+			}
+			if (state.Gamepad.sThumbRY != gamepad.sThumbRY)
+			{
+				int32_t value = state.Gamepad.sThumbRY;
+				value = value > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE || value < -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE
+					? value : 0;
+
+				_axis[0].ry = (float)value / (float)INT16_MAX;
+				queue.push_joypad_event(i, JoypadAxis::RIGHT, _axis[0].rx, _axis[0].ry, _axis[0].rz);
+
+				gamepad.sThumbRY = state.Gamepad.sThumbRY;
+			}
+			if (state.Gamepad.bRightTrigger != gamepad.bRightTrigger)
+			{
+				int32_t value = state.Gamepad.bRightTrigger;
+				value = value > XINPUT_GAMEPAD_TRIGGER_THRESHOLD ? value : 0;
+
+				_axis[0].rz = (float)value / (float)UINT8_MAX;
+				queue.push_joypad_event(i, JoypadAxis::RIGHT, _axis[0].rx, _axis[0].ry, _axis[0].rz);
+
+				gamepad.bRightTrigger = state.Gamepad.bRightTrigger;
+			}
+		}
+	}
+
+	struct Axis
+	{
+		float lx, ly, lz;
+		float rx, ry, rz;
+	};
+
+	XINPUT_STATE _state[CROWN_MAX_JOYPADS];
+	Axis _axis[CROWN_MAX_JOYPADS];
+	bool _connected[CROWN_MAX_JOYPADS];
+};
+
 static bool s_exit = false;
 
 struct MainThreadArgs
@@ -186,6 +333,8 @@ struct WindowsDevice
 
 		while (!s_exit)
 		{
+			_joypad.update(_queue);
+
 			while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE) != 0)
 			{
 				TranslateMessage(&msg);
@@ -303,6 +452,7 @@ public:
 	HWND _hwnd;
 	HDC _hdc;
 	OsEventQueue _queue;
+	Joypad _joypad;
 };
 
 static WindowsDevice s_wdvc;