Files
PDModdingCommunity_PD-Loader/source-code/source/plugins/TLAC/Input/Divaller/Divaller.cpp
T
2022-06-25 17:25:45 +08:00

273 lines
7.5 KiB
C++

#include "Divaller.h"
#include "../../framework.h"
#include "DivallerButton.h"
#include "DivallerState.h"
#include <stdio.h>
#include <string>
#include <iostream>
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<UCHAR *>(*(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;
};
}