#include "UnrealProject.h" #if PLATFORM_SPECIFIC_WIN == 0 #define _SOURCE_INPUT_MANAGER #include "InputManager.hpp" #include "AllowWindowsPlatformTypes.h" #pragma comment(lib, "dinput8.lib") #pragma comment (lib, "dxguid.lib") #define DIRECTINPUT_VERSION 0x0800 #include #include #include using namespace std; #define DUALSHOCK4PRODUCTDATA (0x05C4054CUL) #define DUALSHOCK4DEVTYPE (0x00010318UL) #define WIREDXBOXDEVTYPE (0x00010215UL) #define PI 3.14159265359f namespace Input { struct GUID_Impl { GUID instance; DWORD devType; unsigned long productData1; }; LPDIRECTINPUT8 g_DirectInput; HWND g_HWND; InputManager* InputManager::s_instance; bool InputManager::s_isInitialized = false; vector g_GUIDs; bool InputManager::IsInitialized() { return s_isInitialized; } bool InputManager::Initialize() { if (!IsInitialized()) { g_HWND = GetActiveWindow(); HRESULT hr; HINSTANCE hInstance = GetModuleHandle(nullptr); hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&g_DirectInput, NULL); if (FAILED(hr)) { return false; } s_instance = new InputManager(); s_isInitialized = true; return true; } return false; } void InputManager::Cleanup() { if (IsInitialized()) { delete s_instance; s_instance = nullptr; g_DirectInput->Release(); s_isInitialized = false; } } InputManager* InputManager::GetInstance() { if (!s_isInitialized) Initialize(); return s_instance; } // Implementation of Input Devices class Keyboard_Impl : public Keyboard { public: Keyboard_Impl() { HRESULT hr; hr = g_DirectInput->CreateDevice(GUID_SysKeyboard, &m_Device, NULL); if (FAILED(hr)) { } hr = m_Device->SetDataFormat(&c_dfDIKeyboard); if (FAILED(hr)) { } hr = m_Device->SetCooperativeLevel(g_HWND, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE); if (FAILED(hr)) { } } ~Keyboard_Impl() { m_Device->Unacquire(); } virtual void Update() override final { HRESULT hr; hr = m_Device->Acquire(); memcpy(m_PreviousState, m_CurrentState, sizeof(BYTE) * 256); m_Device->GetDeviceState(sizeof(m_CurrentState), (LPVOID)&m_CurrentState); } virtual bool GetKey(const InputKey a_Key) override final { return (m_CurrentState[a_Key] & 0x80) != 0; } virtual bool GetKeyDown(const InputKey a_Key) override final { return m_CurrentState[a_Key] & 0x80 && !(m_PreviousState[a_Key] & 0x80); } private: IDirectInputDevice8* m_Device; BYTE m_CurrentState[256]; BYTE m_PreviousState[256]; }; class Joystick_Impl : public Joystick { public: Joystick_Impl(IDirectInputDevice8* a_Device) { HRESULT hr; m_Device = a_Device; hr = m_Device->SetDataFormat(&c_dfDIJoystick); if (FAILED(hr)) { } hr = m_Device->SetCooperativeLevel(g_HWND, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); if (FAILED(hr)) { } } virtual ~Joystick_Impl() { m_Device->Unacquire(); m_Device->Release(); } virtual void Update() override final { HRESULT hr; m_PreviousState = m_CurrentState; hr = m_Device->Acquire(); if (FAILED(hr)) { m_IsValid = false; return; } hr = m_Device->GetDeviceState(sizeof(DIJOYSTATE), (LPVOID)&m_CurrentState); if (FAILED(hr)) { m_IsValid = false; return; } m_IsValid = true; } virtual bool IsValid() override final { return m_IsValid; } virtual bool GetButton(const InputJoystickButton a_JoystickButton) { return (m_CurrentState.rgbButtons[a_JoystickButton] & 0x80) != 0; } virtual bool GetButton(const InputJoystickPhysical a_JoystickButton) { return false; } virtual bool GetButtonDown(const InputJoystickButton a_JoystickButton) { return m_CurrentState.rgbButtons[a_JoystickButton] & 0x80 && !(m_PreviousState.rgbButtons[a_JoystickButton] & 0x80); } virtual bool GetButtonDown(const InputJoystickPhysical a_JoystickButton) { return false; } virtual bool GetButtonUp(const InputJoystickButton a_JoystickButton) { return m_PreviousState.rgbButtons[a_JoystickButton] & 0x80 && !(m_CurrentState.rgbButtons[a_JoystickButton] & 0x80); } virtual bool GetButtonUp(const InputJoystickPhysical a_JoystickButton) { return false; } virtual TeaLib::Math::Vector2f GetDelta(const InputJoystickAxis a_InputStick) { if (IsValid()) { switch (a_InputStick) { case Input::IJA_LSTICK: return TeaLib::Math::Vector2f((float)m_CurrentState.lX, (float)m_CurrentState.lY) / 32767.0f; case Input::IJA_RSTICK: return TeaLib::Math::Vector2f((float)m_CurrentState.lRx, (float)m_CurrentState.lRy) / 32767.0f; case Input::IJA_LRTRIGGER: return TeaLib::Math::Vector2f((float)m_CurrentState.lZ, (float)m_CurrentState.lRz) / 32767.0f; default: return TeaLib::Math::Vector2f(); } } return TeaLib::Math::Vector2f(); } virtual InputDeviceType GetDeviceType() { return IDT_NOTDEFINED; } protected: bool m_IsValid = false; IDirectInputDevice8* m_Device; DIJOYSTATE m_CurrentState, m_PreviousState; }; class JoystickDS4_Impl : public Joystick_Impl { public: JoystickDS4_Impl(IDirectInputDevice8* a_Device) : Joystick_Impl(a_Device) { m_PhysicalBindings[IJP_FACEDOWN] = IJB_DS4CROSS; m_PhysicalBindings[IJP_FACERIGHT] = IJB_DS4CIRCLE; m_PhysicalBindings[IJP_FACELEFT] = IJB_BUTTON0; m_PhysicalBindings[IJP_FACEUP] = IJB_BUTTON3; m_PhysicalBindings[IJP_DPADDOWN] = IJB_DS4DPADDOWN; m_PhysicalBindings[IJP_DPADRIGHT] = IJB_DS4DPADRIGHT; m_PhysicalBindings[IJP_DPADLEFT] = IJB_DS4DPADLEFT; m_PhysicalBindings[IJP_DPADUP] = IJB_DS4DPADUP; m_PhysicalBindings[IJP_SHOULDERRIGHT] = IJB_DS4R1; m_PhysicalBindings[IJP_SHOULDERLEFT] = IJB_DS4L1; m_PhysicalBindings[IJP_TRIGGERRIGHT] = IJB_DS4R2; m_PhysicalBindings[IJP_TRIGGERLEFT] = IJB_DS4L2; m_PhysicalBindings[IJP_START] = IJB_DS4OPTIONS; m_PhysicalBindings[IJP_SELECT] = IJB_DS4SHARE; m_PhysicalBindings[IJP_STICKLEFT] = IJB_DS4LEFTSTICK; m_PhysicalBindings[IJP_STICKRIGHT] = IJB_DS4RIGHTSTICK; } virtual bool GetButton(const InputJoystickButton a_JoystickButton) override final { if (a_JoystickButton < 200) return (m_CurrentState.rgbButtons[a_JoystickButton] & 0x80) != 0; else { switch (a_JoystickButton) { case Input::IJB_DS4DPADUP: if (m_CurrentState.rgdwPOV[0] < 36000 && m_CurrentState.rgdwPOV[0] > 27000 || m_CurrentState.rgdwPOV[0] < 9000) return true; break; case Input::IJB_DS4DPADRIGHT: if (m_CurrentState.rgdwPOV[0] > 0 && m_CurrentState.rgdwPOV[0] < 18000) return true; break; case Input::IJB_DS4DPADDOWN: if (m_CurrentState.rgdwPOV[0] > 9000 && m_CurrentState.rgdwPOV[0] < 27000) return true; break; case Input::IJB_DS4DPADLEFT: if (m_CurrentState.rgdwPOV[0] > 18000 && m_CurrentState.rgdwPOV[0] < 36000) return true; break; default: break; } return false; } } virtual bool GetButton(const InputJoystickPhysical a_JoystickButton) override final { return GetButton(m_PhysicalBindings[a_JoystickButton]); } virtual bool GetButtonDown(const InputJoystickButton a_JoystickButton) override final { if (a_JoystickButton < 200) return m_CurrentState.rgbButtons[a_JoystickButton] & 0x80 && !(m_PreviousState.rgbButtons[a_JoystickButton] & 0x80); else { switch (a_JoystickButton) { case Input::IJB_DS4DPADUP: if (m_CurrentState.rgdwPOV[0] == 0 && m_PreviousState.rgdwPOV[0] != 0) return true; break; case Input::IJB_DS4DPADRIGHT: if (m_CurrentState.rgdwPOV[0] == 9000 && m_PreviousState.rgdwPOV[0] != 9000) return true; break; case Input::IJB_DS4DPADDOWN: if (m_CurrentState.rgdwPOV[0] == 18000 && m_PreviousState.rgdwPOV[0] != 18000) return true; break; case Input::IJB_DS4DPADLEFT: if (m_CurrentState.rgdwPOV[0] == 27000 && m_PreviousState.rgdwPOV[0] != 27000) return true; break; default: break; } return false; } } virtual bool GetButtonDown(const InputJoystickPhysical a_JoystickButton) override final { return GetButtonDown(m_PhysicalBindings[a_JoystickButton]); } virtual bool GetButtonUp(const InputJoystickButton a_JoystickButton) override final { if (a_JoystickButton < 200) return m_PreviousState.rgbButtons[a_JoystickButton] & 0x80 && !(m_CurrentState.rgbButtons[a_JoystickButton] & 0x80); else { switch (a_JoystickButton) { case Input::IJB_DS4DPADUP: if (m_PreviousState.rgdwPOV[0] == 0 && m_CurrentState.rgdwPOV[0] != 0) return true; break; case Input::IJB_DS4DPADRIGHT: if (m_PreviousState.rgdwPOV[0] == 9000 && m_CurrentState.rgdwPOV[0] != 9000) return true; break; case Input::IJB_DS4DPADDOWN: if (m_PreviousState.rgdwPOV[0] == 18000 && m_CurrentState.rgdwPOV[0] != 18000) return true; break; case Input::IJB_DS4DPADLEFT: if (m_PreviousState.rgdwPOV[0] == 27000 && m_CurrentState.rgdwPOV[0] != 27000) return true; break; default: break; } return false; } } virtual bool GetButtonUp(const InputJoystickPhysical a_JoystickButton) override final { return GetButtonUp(m_PhysicalBindings[a_JoystickButton]); } virtual TeaLib::Math::Vector2f GetDelta(const InputJoystickAxis a_InputStick) override final { if (IsValid()) { float angle; switch (a_InputStick) { case Input::IJA_LSTICK: return TeaLib::Math::Vector2f((float)m_CurrentState.lX - 32767.0f, (float)m_CurrentState.lY - 32767.0f) / 32767.0f; case Input::IJA_RSTICK: return TeaLib::Math::Vector2f((float)m_CurrentState.lZ - 32767.0f, (float)m_CurrentState.lRz - 32767.0f) / 32767.0f; case Input::IJA_LRTRIGGER: return TeaLib::Math::Vector2f((float)m_CurrentState.lRx, (float)m_CurrentState.lRy) / 65534.0f; case Input::IJA_DPAD: if (m_PreviousState.rgdwPOV[0] < 90000) { angle = (((float)m_PreviousState.rgdwPOV[0] / 100.0f) * PI / 180.0f); return TeaLib::Math::Vector2f(sinf(angle), -cosf(angle)); } return TeaLib::Math::Vector2f(); default: return TeaLib::Math::Vector2f(); } } return TeaLib::Math::Vector2f(); } virtual InputDeviceType GetDeviceType() override final { return IDT_DS4; } private: map m_PhysicalBindings; }; class JoystickXbox360_Impl : public Joystick_Impl { public: JoystickXbox360_Impl(IDirectInputDevice8* a_Device) : Joystick_Impl(a_Device) { m_PhysicalBindings[IJP_FACEDOWN] = IJB_XBOXA; m_PhysicalBindings[IJP_FACERIGHT] = IJB_XBOXB; m_PhysicalBindings[IJP_FACELEFT] = IJB_XBOXX; m_PhysicalBindings[IJP_FACEUP] = IJB_XBOXY; m_PhysicalBindings[IJP_DPADDOWN] = IJB_XBOXDPADDOWN; m_PhysicalBindings[IJP_DPADRIGHT] = IJB_XBOXDPADRIGHT; m_PhysicalBindings[IJP_DPADLEFT] = IJB_XBOXDPADLEFT; m_PhysicalBindings[IJP_DPADUP] = IJB_XBOXDPADUP; m_PhysicalBindings[IJP_SHOULDERRIGHT] = IJB_XBOXRB; m_PhysicalBindings[IJP_SHOULDERLEFT] = IJB_XBOXLB; m_PhysicalBindings[IJP_TRIGGERRIGHT] = IJB_XBOXRT; m_PhysicalBindings[IJP_TRIGGERLEFT] = IJB_XBOXLT; m_PhysicalBindings[IJP_START] = IJB_XBOXSTART; m_PhysicalBindings[IJP_SELECT] = IJB_XBOXBACK; m_PhysicalBindings[IJP_STICKLEFT] = IJB_XBOXLEFTSTICK; m_PhysicalBindings[IJP_STICKRIGHT] = IJB_XBOXRIGHTSTICK; } virtual TeaLib::Math::Vector2f GetDelta(const InputJoystickAxis a_InputStick) override final { if (IsValid()) { float result; float angle; switch (a_InputStick) { case Input::IJA_LSTICK: return TeaLib::Math::Vector2f((float)m_CurrentState.lX - 32767.0f, (float)m_CurrentState.lY - 32767.0f) / 32767.0f; case Input::IJA_RSTICK: return TeaLib::Math::Vector2f((float)m_CurrentState.lRx - 32767.0f, (float)m_CurrentState.lRy - 32767.0f) / 32767.0f; case Input::IJA_LRTRIGGER: result = ((float)m_CurrentState.lZ - 32767.0f) / 32767.0f; return TeaLib::Math::Vector2f(result, result); case Input::IJA_DPAD: if (m_PreviousState.rgdwPOV[0] < 90000) { angle = (((float)m_PreviousState.rgdwPOV[0] / 100.0f) * PI / 180.0f); return TeaLib::Math::Vector2f(sinf(angle), -cosf(angle)); } return TeaLib::Math::Vector2f(); default: return TeaLib::Math::Vector2f(); } } return TeaLib::Math::Vector2f(); } virtual bool GetButton(const InputJoystickButton a_JoystickButton) override final { if (a_JoystickButton < 200) return (m_CurrentState.rgbButtons[a_JoystickButton] & 0x80) != 0; else { float val; switch (a_JoystickButton) { case Input::IJB_XBOXDPADUP: if (m_CurrentState.rgdwPOV[0] < 36000 && m_CurrentState.rgdwPOV[0] > 27000 || m_CurrentState.rgdwPOV[0] < 9000) return true; break; case Input::IJB_XBOXDPADRIGHT: if (m_CurrentState.rgdwPOV[0] > 0 && m_CurrentState.rgdwPOV[0] < 18000) return true; break; case Input::IJB_XBOXDPADDOWN: if (m_CurrentState.rgdwPOV[0] > 9000 && m_CurrentState.rgdwPOV[0] < 27000) return true; break; case Input::IJB_XBOXDPADLEFT: if (m_CurrentState.rgdwPOV[0] > 18000 && m_CurrentState.rgdwPOV[0] < 36000) return true; break; case Input::IJB_XBOXLT: val = ((float)m_CurrentState.lZ - 32767.0f) / 32767.0f;; return val > 0.1f; case Input::IJB_XBOXRT: val = ((float)m_CurrentState.lZ - 32767.0f) / 32767.0f;; return val < -0.1f; default: break; } return false; } } virtual bool GetButton(const InputJoystickPhysical a_JoystickButton) override final { return GetButton(m_PhysicalBindings[a_JoystickButton]); } virtual bool GetButtonDown(const InputJoystickButton a_JoystickButton) override final { if (a_JoystickButton < 200) return m_CurrentState.rgbButtons[a_JoystickButton] & 0x80 && !(m_PreviousState.rgbButtons[a_JoystickButton] & 0x80); else { float curr, prev; switch (a_JoystickButton) { case Input::IJB_XBOXDPADUP: if (m_CurrentState.rgdwPOV[0] == 0 && m_PreviousState.rgdwPOV[0] != 0) return true; break; case Input::IJB_XBOXDPADRIGHT: if (m_CurrentState.rgdwPOV[0] == 9000 && m_PreviousState.rgdwPOV[0] != 9000) return true; break; case Input::IJB_XBOXDPADDOWN: if (m_CurrentState.rgdwPOV[0] == 18000 && m_PreviousState.rgdwPOV[0] != 18000) return true; break; case Input::IJB_XBOXDPADLEFT: if (m_CurrentState.rgdwPOV[0] == 27000 && m_PreviousState.rgdwPOV[0] != 27000) return true; break; case Input::IJB_XBOXLT: curr = ((float)m_CurrentState.lZ - 32767.0f) / 32767.0f; prev = ((float)m_PreviousState.lZ - 32767.0f) / 32767.0f; return curr > 0.1f && prev <= 0.1f; case Input::IJB_XBOXRT: curr = ((float)m_CurrentState.lZ - 32767.0f) / 32767.0f; prev = ((float)m_PreviousState.lZ - 32767.0f) / 32767.0f; return curr < -0.1f && prev >= -0.1f; default: break; } return false; } } virtual bool GetButtonDown(const InputJoystickPhysical a_JoystickButton) override final { if (m_PhysicalBindings.find(a_JoystickButton) != m_PhysicalBindings.end()) return GetButtonDown(m_PhysicalBindings[a_JoystickButton]); return false; } virtual bool GetButtonUp(const InputJoystickButton a_JoystickButton) override final { if (a_JoystickButton < 200) return m_PreviousState.rgbButtons[a_JoystickButton] & 0x80 && !(m_CurrentState.rgbButtons[a_JoystickButton] & 0x80); else { float curr, prev; switch (a_JoystickButton) { case Input::IJB_XBOXDPADUP: if (m_PreviousState.rgdwPOV[0] == 0 && m_CurrentState.rgdwPOV[0] != 0) return true; break; case Input::IJB_XBOXDPADRIGHT: if (m_PreviousState.rgdwPOV[0] == 9000 && m_CurrentState.rgdwPOV[0] != 9000) return true; break; case Input::IJB_XBOXDPADDOWN: if (m_PreviousState.rgdwPOV[0] == 18000 && m_CurrentState.rgdwPOV[0] != 18000) return true; break; case Input::IJB_XBOXDPADLEFT: if (m_PreviousState.rgdwPOV[0] == 27000 && m_CurrentState.rgdwPOV[0] != 27000) return true; break; case Input::IJB_XBOXLT: curr = ((float)m_CurrentState.lZ - 32767.0f) / 32767.0f; prev = ((float)m_PreviousState.lZ - 32767.0f) / 32767.0f; return curr <= 0.1f && prev > 0.1f; case Input::IJB_XBOXRT: curr = ((float)m_CurrentState.lZ - 32767.0f) / 32767.0f; prev = ((float)m_PreviousState.lZ - 32767.0f) / 32767.0f; return curr >= -0.1f && prev < -0.1f; default: break; } return false; } } virtual bool GetButtonUp(const InputJoystickPhysical a_JoystickButton) override final { if (m_PhysicalBindings.find(a_JoystickButton) != m_PhysicalBindings.end()) return GetButtonUp(m_PhysicalBindings[a_JoystickButton]); return false; } virtual InputDeviceType GetDeviceType() override final { return IDT_XBOX; } private: map m_PhysicalBindings; }; InputManager::InputManager() : joystick(nullptr) { keyboard = new Keyboard_Impl(); } void InputManager::Update() { keyboard->Update(); if (joystick) { joystick->Update(); if (joystick->IsValid()) { for (auto it : m_joystickCallbacks) { switch (it.first.second) { case IME_PRESSED: if (joystick->GetButtonDown(it.first.first)) { it.second->Call(); } break; case IME_RELEASED: if (joystick->GetButtonUp(it.first.first)) { it.second->Call(); } break; case IME_REPEAT: if (joystick->GetButton(it.first.first)) { it.second->Call(); } break; } } } } } BOOL __stdcall JoystickEnumCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef) { InputManager* inputInstance = InputManager::GetInstance(); inputInstance->AddJoystickName(lpddi->tszProductName); GUID_Impl newGUID; newGUID.devType = lpddi->dwDevType; newGUID.instance = lpddi->guidInstance; newGUID.productData1 = lpddi->guidProduct.Data1; g_GUIDs.push_back(newGUID); return DIENUM_CONTINUE; } void InputManager::AddJoystickName(std::wstring a_name) { m_joystickNames.push_back(a_name); } void InputManager::SearchForJoystick() { m_joystickNames.clear(); g_GUIDs.clear(); g_DirectInput->EnumDevices(DI8DEVCLASS_GAMECTRL, &JoystickEnumCallback, NULL, DIEDFL_ATTACHEDONLY); } vector& InputManager::GetJoystickNames() { return m_joystickNames; } void InputManager::ConnectJoystickByIndex(size_t a_index) { if (joystick) delete joystick; if (a_index >= g_GUIDs.size()) return; HRESULT hr; IDirectInputDevice8* device; hr = g_DirectInput->CreateDevice(g_GUIDs[a_index].instance, &device, NULL); if (!FAILED(hr)) { if (g_GUIDs[a_index].devType == DUALSHOCK4DEVTYPE || g_GUIDs[a_index].productData1 == DUALSHOCK4PRODUCTDATA) joystick = new JoystickDS4_Impl(device); else if (g_GUIDs[a_index].devType == WIREDXBOXDEVTYPE) joystick = new JoystickXbox360_Impl(device); else joystick = new Joystick_Impl(device); } } InputManager::~InputManager() { delete keyboard; delete joystick; ClearCallbacks(); } void InputManager::ClearCallbacks() { for (auto it : m_joystickCallbacks) { delete it.second; } m_joystickCallbacks.clear(); } } #endif