diff --git a/source-code/source/plugins/TLAC/Input/Bindings/DVLBinding.cpp b/source-code/source/plugins/TLAC/Input/Bindings/DVLBinding.cpp new file mode 100644 index 0000000..7ea3d8a --- /dev/null +++ b/source-code/source/plugins/TLAC/Input/Bindings/DVLBinding.cpp @@ -0,0 +1,29 @@ +#include "DVLBinding.h" + +namespace TLAC::Input +{ + #define DivallerInstanceCheckDefault(checkFunc) (Divaller::InstanceInitialized() ? Divaller::GetInstance()->checkFunc : false) + + DivallerBinding::DivallerBinding(DivallerButton button) : Button(button) + { + } + + DivallerBinding::~DivallerBinding() + { + } + + bool DivallerBinding::IsDown() + { + return DivallerInstanceCheckDefault(IsDown(Button)); + } + + bool DivallerBinding::IsTapped() + { + return DivallerInstanceCheckDefault(IsTapped(Button)); + } + + bool DivallerBinding::IsReleased() + { + return DivallerInstanceCheckDefault(IsReleased(Button)); + } +} \ No newline at end of file diff --git a/source-code/source/plugins/TLAC/Input/Bindings/DVLBinding.h b/source-code/source/plugins/TLAC/Input/Bindings/DVLBinding.h new file mode 100644 index 0000000..f3503fa --- /dev/null +++ b/source-code/source/plugins/TLAC/Input/Bindings/DVLBinding.h @@ -0,0 +1,19 @@ +#pragma once +#include "IInputBinding.h" +#include "../Divaller/Divaller.h" + +namespace TLAC::Input +{ + class DivallerBinding : public IInputBinding + { + public: + DivallerButton Button; + + DivallerBinding(DivallerButton button); + ~DivallerBinding(); + + bool IsDown() override; + bool IsTapped() override; + bool IsReleased() override; + }; +} \ No newline at end of file diff --git a/source-code/source/plugins/TLAC/Input/Divaller/Divaller.cpp b/source-code/source/plugins/TLAC/Input/Divaller/Divaller.cpp new file mode 100644 index 0000000..e1472fc --- /dev/null +++ b/source-code/source/plugins/TLAC/Input/Divaller/Divaller.cpp @@ -0,0 +1,272 @@ +#include "Divaller.h" +#include "../../framework.h" +#include "DivallerButton.h" +#include "DivallerState.h" +#include +#include +#include + +namespace TLAC::Input +{ + Divaller *Divaller::instance; + + Divaller::Divaller() + { + memset(outputBuffer, 0, sizeof(outputBuffer)); + outputBuffer[0] = 0x44; + outputBuffer[1] = 0x4c; + outputBuffer[2] = 0x61; + } + + Divaller::~Divaller() + { + CloseHandle(hDeviceHandle); + } + + bool Divaller::TryInitializeInstance() + { + if (InstanceInitialized()) + return true; + + Divaller *divaller = new Divaller(); + + BOOL success = divaller->Initialize(); + instance = success ? divaller : nullptr; + + if (!success) + delete divaller; + + return success; + } + + bool Divaller::Initialize() + { + HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (hDevInfo == INVALID_HANDLE_VALUE) + { + printf("[TLAC] Divaller::Initialize(): SetupDiGetClassDevs returned INVALID_HANDLE_VALUE\n"); + return false; + } + LPCWSTR devPath = NULL; + for (size_t i = 0;; i++) + { + SP_DEVICE_INTERFACE_DATA device_interface_data = {0}; + device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + BOOL success = SetupDiEnumDeviceInterfaces( + hDevInfo, + NULL, + &GUID_DEVINTERFACE_USB_DEVICE, + (DWORD)i, + &device_interface_data); + if (!success) + { + break; + } + ULONG required_length = 0; + success = SetupDiGetDeviceInterfaceDetail( + hDevInfo, + &device_interface_data, + NULL, + 0, + &required_length, + NULL); + + UINT8 *interface_data = (UINT8 *)calloc(required_length, sizeof(UINT8)); + + PSP_DEVICE_INTERFACE_DETAIL_DATA device_interface_detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA)interface_data; + device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + + ULONG actual_length = required_length; + success = SetupDiGetDeviceInterfaceDetail( + hDevInfo, + &device_interface_data, + device_interface_detail_data, + actual_length, + &required_length, + NULL); + + if (!success) + { + continue; + } + if ( + wcsstr(device_interface_detail_data->DevicePath, L"vid_0e8f") == 0 || + wcsstr(device_interface_detail_data->DevicePath, L"pid_2213") == 0) + { + continue; + } + devPath = device_interface_detail_data->DevicePath; + break; + } + if (devPath == NULL) + { + SetupDiDestroyDeviceInfoList(hDevInfo); + return false; + } + hDeviceHandle = CreateFile( + devPath, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL); + if (hDeviceHandle == INVALID_HANDLE_VALUE) + { + printf("[TLAC] Divaller::Initialize(): Open device failed.\n"); + SetupDiDestroyDeviceInfoList(hDevInfo); + return false; + } + + if (!WinUsb_Initialize(hDeviceHandle, &hInterfaceHandle)) + { + printf("[TLAC] Divaller::Initialize(): WinUsb_Initialize failed.\n"); + std::cout << GetLastError() << std::endl; + SetupDiDestroyDeviceInfoList(hDevInfo); + CloseHandle(hDeviceHandle); + return false; + } + + USB_INTERFACE_DESCRIPTOR USBInterfaceDescriptor; + if (!WinUsb_QueryInterfaceSettings(hInterfaceHandle, 0, &USBInterfaceDescriptor)) + { + std::cout << GetLastError() << std::endl; + SetupDiDestroyDeviceInfoList(hDevInfo); + CloseHandle(hDeviceHandle); + return false; + } + SetupDiDestroyDeviceInfoList(hDevInfo); + return true; + } + + bool Divaller::PollInput() + { + lastState = currentState; + ULONG len = 0; + memset(currentState.state, 0, sizeof(currentState.state)); + BOOL bResult = WinUsb_ReadPipe(hInterfaceHandle, (UCHAR)132, currentState.state, _countof(currentState.state), &len, nullptr); + if (!bResult || currentState.state[0] != 0x42 || currentState.state[1] != 0x56 || currentState.state[2] != 0x5a) + { + printf("[TLAC] Divaller::PollInput(): WinUsb_ReadPipe failed.\n"); + std::cout << GetLastError() << std::endl; + } + SetLED(); + return bResult; + } + + bool Divaller::SetLED() + { + outputBuffer[3] &= 0x0F; // Reset Button LED + outputBuffer[3] |= (!(*buttonLed >> 1 & 0x0001)) << 4; // SQUARE + outputBuffer[3] |= (!(*buttonLed >> 3 & 0x0001)) << 5; // CIRCLE + outputBuffer[3] |= (!(*buttonLed & 0x0001)) << 6; // TRIANGLE + outputBuffer[3] |= (!(*buttonLed >> 2 & 0x0001)) << 7; // CROSS + if (*sliderLedInit && !sliderLedData) + { + sliderLedData = reinterpret_cast(*(uint64_t *)(0x14cc5de40 + 0x68) + 0x189c); + } + if (sliderLedData) + { + for (int n = 0; n < 32; n++) + { + // LED number + 3 bytes header + color offset + outputBuffer[(31 - n) * 3 + 3 + 3] = sliderLedData[n * 3 + 1]; // BLUE + outputBuffer[(31 - n) * 3 + 3 + 2] = sliderLedData[n * 3 + 2]; // RED + outputBuffer[(31 - n) * 3 + 3 + 1] = sliderLedData[n * 3 + 3]; // GREEN + } + } + + ULONG len = 0; + BOOL bResult = WinUsb_WritePipe(hInterfaceHandle, (UCHAR)0x03, outputBuffer, 100, &len, NULL); + if (!bResult) + { + printf("[TLAC] Divaller::SetLED(): WinUsb_WritePipe failed.\n"); + std::cout << GetLastError() << std::endl; + } + return bResult; + } + + bool Divaller::IsDown(DivallerButton button) + { + switch (button) + { + case DivallerButton::DVL_L1: + return (currentState.state[5] >> 0) & 1; + case DivallerButton::DVL_L2: + return (currentState.state[4] >> 7) & 1; + case DivallerButton::DVL_L3: + return (currentState.state[4] >> 6) & 1; + case DivallerButton::DVL_FN: + return (currentState.state[3] >> 1) & 1; + case DivallerButton::DVL_TRIANGLE: + return (currentState.state[3] >> 4) & 1; + case DivallerButton::DVL_SQUARE: + return (currentState.state[3] >> 2) & 1; + case DivallerButton::DVL_CROSS: + return (currentState.state[3] >> 5) & 1; + case DivallerButton::DVL_CIRCLE: + return (currentState.state[3] >> 3) & 1; + } + return false; + } + + bool Divaller::IsUp(DivallerButton button) + { + return !IsDown(button); + } + + bool Divaller::IsTapped(DivallerButton button) + { + return IsDown(button) && WasUp(button); + } + + bool Divaller::IsReleased(DivallerButton button) + { + return IsUp(button) && WasDown(button); + } + + bool Divaller::WasDown(DivallerButton button) + { + switch (button) + { + case DivallerButton::DVL_L1: + return (lastState.state[5] >> 0) & 1; + case DivallerButton::DVL_L2: + return (lastState.state[4] >> 7) & 1; + case DivallerButton::DVL_L3: + return (lastState.state[4] >> 6) & 1; + case DivallerButton::DVL_FN: + return (lastState.state[3] >> 1) & 1; + case DivallerButton::DVL_TRIANGLE: + return (lastState.state[3] >> 4) & 1; + case DivallerButton::DVL_SQUARE: + return (lastState.state[3] >> 2) & 1; + case DivallerButton::DVL_CROSS: + return (lastState.state[3] >> 5) & 1; + case DivallerButton::DVL_CIRCLE: + return (lastState.state[3] >> 3) & 1; + } + return false; + } + + bool Divaller::WasUp(DivallerButton button) + { + return !WasDown(button); + } + + uint32_t Divaller::GetSlider() + { + uint32_t i = 0; + i |= currentState.state[5] >> 4; + i |= currentState.state[6] << 4; + i |= currentState.state[7] << 12; + i |= currentState.state[8] << 20; + i |= currentState.state[9] << 28; + // Reverse the bit order of uint32 + i = (i & 0xaaaaaaaa) >> 1 | (i & 0x55555555) << 1; + i = (i & 0xcccccccc) >> 2 | (i & 0x33333333) << 2; + i = (i & 0xf0f0f0f0) >> 4 | (i & 0x0f0f0f0f) << 4; + i = (i & 0xff00ff00) >> 8 | (i & 0x00ff00ff) << 8; + return i >> 16 | i << 16; + }; +} diff --git a/source-code/source/plugins/TLAC/Input/Divaller/Divaller.h b/source-code/source/plugins/TLAC/Input/Divaller/Divaller.h new file mode 100644 index 0000000..399736c --- /dev/null +++ b/source-code/source/plugins/TLAC/Input/Divaller/Divaller.h @@ -0,0 +1,52 @@ +#pragma once +#include "../IInputDevice.h" +#include "DivallerState.h" +#include "DivallerButton.h" +#include +#include +#include +#include + +namespace TLAC::Input +{ + + class Divaller : public IInputDevice + { + public: + Divaller(); + ~Divaller(); + + static bool TryInitializeInstance(); + + bool Initialize(); + bool PollInput() override; + bool SetLED(); + bool IsDown(DivallerButton button); + bool IsUp(DivallerButton button); + bool IsTapped(DivallerButton button); + bool IsReleased(DivallerButton button); + + bool WasDown(DivallerButton button); + bool WasUp(DivallerButton button); + uint32_t GetSlider(); + static inline bool InstanceInitialized() { return instance != nullptr; }; + static inline Divaller *GetInstance() { return instance; }; + static inline void DeleteInstance() + { + delete instance; + instance = nullptr; + }; + + private: + static Divaller *instance; + DivallerState lastState; + DivallerState currentState; + WINUSB_INTERFACE_HANDLE hInterfaceHandle; + HANDLE hDeviceHandle; + UCHAR outputBuffer[100]; + int *buttonLed = reinterpret_cast(0x14119b950); + uint64_t *partionLed = reinterpret_cast(*(uint64_t*)0x140eda330 + 0xc9); + uint64_t *sliderLedInit = reinterpret_cast((uint64_t*)0x14cc5dea8); + UCHAR *sliderLedData = nullptr; + }; +} diff --git a/source-code/source/plugins/TLAC/Input/Divaller/DivallerButton.h b/source-code/source/plugins/TLAC/Input/Divaller/DivallerButton.h new file mode 100644 index 0000000..fccce61 --- /dev/null +++ b/source-code/source/plugins/TLAC/Input/Divaller/DivallerButton.h @@ -0,0 +1,32 @@ +#pragma once + +namespace TLAC::Input +{ + enum DivallerButton : int + { + DVL_SQUARE = 0, + DVL_CROSS = 1, + DVL_CIRCLE = 2, + DVL_TRIANGLE = 3, + + DVL_FN = 4, + + DVL_L1 = 5, + DVL_L2 = 6, + DVL_L3 = 7, + + DVL_R1 = 8, + DVL_R2 = 9, + DVL_R3 = 10, + + DVL_UP = 11, + DVL_LEFT = 12, + DVL_DOWN = 13, + DVL_RIGHT = 14, + + DVL_PAD = 11, + DVL_SHARE = 12, + DVL_HOME = 13, + DVL_OPTION = 14 + }; +} \ No newline at end of file diff --git a/source-code/source/plugins/TLAC/Input/Divaller/DivallerState.h b/source-code/source/plugins/TLAC/Input/Divaller/DivallerState.h new file mode 100644 index 0000000..6844d00 --- /dev/null +++ b/source-code/source/plugins/TLAC/Input/Divaller/DivallerState.h @@ -0,0 +1,10 @@ +#pragma once +#include "../../framework.h" +namespace TLAC::Input +{ + + struct DivallerState + { + uint8_t state[24]; + }; +} \ No newline at end of file