Skip to content

Instantly share code, notes, and snippets.

@Kaldaien
Created August 8, 2016 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kaldaien/9685f1af8e0b37e4dea184941f006a0a to your computer and use it in GitHub Desktop.
Save Kaldaien/9685f1af8e0b37e4dea184941f006a0a to your computer and use it in GitHub Desktop.
Unx_Calibrate Source Code
/**
* This file is part of UnX.
*
* UnX is free software : you can redistribute it
* and/or modify it under the terms of the GNU General Public License
* as published by The Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* UnX is distributed in the hope that it will be useful,
*
* But WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with UnX.
*
* If not, see <http://www.gnu.org/licenses/>.
*
**/
#include "stdafx.h"
#include "Resource.h"
#include <Windows.h>
#include <cstdint>
#include <Commctrl.h>
#include <comdef.h>
#include <dinput.h>
#pragma comment (lib, "dxguid.lib")
#include "parameter.h"
#include "input.h"
#include <mmsystem.h>
#pragma comment (lib, "winmm.lib")
struct unx_gamepad_s {
std::wstring tex_set = L"PlayStation_Glossy";
bool legacy = false;
struct combo_s {
std::wstring unparsed = L"";
int buttons = 0;
int button0 = 0xffffffff;
int button1 = 0xffffffff;
int button2 = 0xffffffff;
bool lt = false;
bool rt = false;
} f1, f2, f3, f4, f5, screenshot;
struct remap_s {
struct buttons_s {
int X = JOY_BUTTON1;
int A = JOY_BUTTON2;
int B = JOY_BUTTON3;
int Y = JOY_BUTTON4;
int LB = JOY_BUTTON5;
int RB = JOY_BUTTON6;
int LT = JOY_BUTTON7;
int RT = JOY_BUTTON8;
int BACK = JOY_BUTTON9;
int START = JOY_BUTTON10;
int LS = JOY_BUTTON11;
int RS = JOY_BUTTON12;
} buttons;
// Post-Process the button map above so we do not
// have to constantly perform the operations
// below when polling a controller...
int map [12];
static int indexToEnum (int idx) {
// For Axes
if (idx < 0) {
idx = (16 - idx);
}
return 1 << (idx - 1);
}
static int enumToIndex (unsigned int enum_val) {
int idx = 0;
// For Axes
bool axis = false;
if (enum_val >= (1 << 16))
axis = true;
while (enum_val > 0) {
enum_val >>= 1;
idx++;
}
if (axis) {
idx -= 16;
idx = -idx;
}
return idx;
}
} remap;
} gamepad;
typedef struct _XINPUT_GAMEPAD {
WORD wButtons;
BYTE bLeftTrigger;
BYTE bRightTrigger;
SHORT sThumbLX;
SHORT sThumbLY;
SHORT sThumbRX;
SHORT sThumbRY;
} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD;
typedef struct _XINPUT_STATE {
DWORD dwPacketNumber;
XINPUT_GAMEPAD Gamepad;
} XINPUT_STATE, *PXINPUT_STATE;
typedef DWORD (WINAPI *XInputGetState_pfn)(
_In_ DWORD dwUserIndex,
_Out_ XINPUT_STATE *pState
);
XInputGetState_pfn XInputGetState_Original = nullptr;
bool
IsControllerPluggedIn (UINT uJoyID)
{
if (uJoyID == (UINT)-1)
return true;
XINPUT_STATE xstate;
static DWORD last_poll = timeGetTime ();
static DWORD dwRet = XInputGetState_Original (uJoyID, &xstate);
// This function is actually a performance hazzard when no controllers
// are plugged in, so ... throttle the sucker.
if (last_poll < timeGetTime () - 500UL)
dwRet = XInputGetState_Original (uJoyID, &xstate);
if (dwRet == ERROR_DEVICE_NOT_CONNECTED)
return false;
return true;
}
DWORD
WINAPI
XInputGetState_Detour ( _In_ DWORD dwUserIndex,
_Out_ XINPUT_STATE *pState )
{
int slot = 0;
DWORD dwRet = XInputGetState_Original (slot, pState);
if (dwRet == ERROR_NOT_CONNECTED)
dwRet = 0;
return dwRet;
}
///////////////////////////////////////////////////////////////////////////////
//
// User32 Input APIs
//
///////////////////////////////////////////////////////////////////////////////
uint32_t
UNXCAL_GetControllerButtonCount (void)
{
JOYCAPSW caps;
if (JOYERR_NOERROR != joyGetDevCapsW (JOYSTICKID1, &caps, sizeof JOYCAPSW))
return 32;
return caps.wNumButtons;
}
uint32_t
UNXCAL_GetControllerAxisCount (void)
{
JOYCAPSW caps;
if (JOYERR_NOERROR != joyGetDevCapsW (JOYSTICKID1, &caps, sizeof JOYCAPSW))
return 6;
return caps.wNumAxes;
}
wchar_t*
UNXCAL_GetControllerDescription (void)
{
static wchar_t wszDescription [1024] = { L'\0' };
JOYCAPSW caps;
joyGetDevCapsW (JOYSTICKID1, &caps, sizeof JOYCAPSW);
wsprintfW (wszDescription, L"Device: '%s' (%lu buttons, %lu axes)", caps.szPname, caps.wNumButtons, caps.wNumAxes);
return wszDescription;
}
BYTE
UNX_PollAxis (int axis, const JOYINFOEX& joy_ex, const JOYCAPSW& caps)
{
switch (unx_gamepad_s::remap_s::enumToIndex (axis))
{
case -1:
return 255 * ((float)(joy_ex.dwXpos - caps.wXmin) /
(float)(caps.wXmax - caps.wXmin));
case -2:
return 255 * ((float)(joy_ex.dwYpos - caps.wYmin) /
(float)(caps.wYmax - caps.wYmin));
case -3:
return 255 * ((float)(joy_ex.dwZpos - caps.wZmin) /
(float)(caps.wZmax - caps.wZmin));
case -4:
return 255 * ((float)(joy_ex.dwUpos - caps.wUmin) /
(float)(caps.wUmax - caps.wUmin));
case -5:
return 255 * ((float)(joy_ex.dwVpos - caps.wVmin) /
(float)(caps.wVmax - caps.wVmin));
case -6:
return 255 * ((float)(joy_ex.dwRpos - caps.wRmin) /
(float)(caps.wRmax - caps.wRmin));
default:
return 255 * ((joy_ex.dwButtons & axis) ? 1 : 0);
}
}
void
UNXCAL_WaitForButtonRelease (void)
{
JOYINFOEX joy_ex { 0 };
joy_ex.dwSize = sizeof JOYINFOEX;
joy_ex.dwFlags = JOY_RETURNALL | JOY_RETURNPOVCTS |
JOY_RETURNCENTERED | JOY_USEDEADZONE | JOY_RETURNBUTTONS;
joyGetPosEx (JOYSTICKID1, &joy_ex);
while (true) {
static JOYCAPSW caps { 0 };
if (caps.wMaxButtons == 0)
joyGetDevCapsW (JOYSTICKID1, &caps, sizeof JOYCAPSW);
bool axis_active = false;
const int num_axes = 6;
for (int i = 0; i < num_axes; i++) {
BYTE polled = UNX_PollAxis (1 << (16 + i), joy_ex, caps);
if (polled > 192)
axis_active = true;
}
joyGetPosEx (JOYSTICKID1, &joy_ex);
if (joy_ex.dwButtons == 0 && (! axis_active))
return;
}
}
bool early_out = false;
bool try_axes = true;
int
UNXCAL_GetSingleButton (void)
{
JOYINFOEX joy_ex { 0 };
joy_ex.dwSize = sizeof JOYINFOEX;
joy_ex.dwFlags = JOY_RETURNALL | JOY_RETURNPOVCTS |
JOY_RETURNCENTERED | JOY_USEDEADZONE | JOY_RETURNBUTTONS;
joyGetPosEx (JOYSTICKID1, &joy_ex);
while (joy_ex.dwButtonNumber != 1 || (try_axes)) {
if (early_out)
return 0;
joy_ex.dwButtonNumber = 0;
joyGetPosEx (JOYSTICKID1, &joy_ex);
// Poll analog triggers
if (try_axes) {
static JOYCAPSW caps { 0 };
if (caps.wMaxButtons == 0)
joyGetDevCapsW (JOYSTICKID1, &caps, sizeof JOYCAPSW);
const int num_axes = 6;
for (int i = 0; i < num_axes; i++) {
BYTE polled = UNX_PollAxis (1 << (16 + i), joy_ex, caps);
if (polled > 192)
return -(i + 1);
}
}
if (joy_ex.dwButtonNumber == 1)
break;
}
return gamepad.remap.enumToIndex (joy_ex.dwButtons);
}
#include <Windowsx.h>
HANDLE hButtonThread = 0;
CRITICAL_SECTION cs_poll { 0 };
int polled_button = 0;
DWORD
WINAPI
GetButtonThread (LPVOID user)
{
EnterCriticalSection (&cs_poll);
UNXCAL_WaitForButtonRelease ();
polled_button =
UNXCAL_GetSingleButton ();
LeaveCriticalSection (&cs_poll);
return 0;
}
enum task_item_t {
Content = TDE_CONTENT,
ExpandedInfo = TDE_EXPANDED_INFORMATION,
Footer = TDE_FOOTER,
MainInstruction = TDE_MAIN_INSTRUCTION
};
void
UNX_TaskDialogUpdateText ( _In_ HWND hWnd, task_item_t item, std::wstring content )
{
SendMessage (hWnd, TDM_SET_ELEMENT_TEXT, TDE_CONTENT, (LPARAM)content.c_str ());
}
HRESULT
CALLBACK
TaskDialogCallback (
_In_ HWND hWnd,
_In_ UINT uNotification,
_In_ WPARAM wParam,
_In_ LPARAM lParam,
_In_ LONG_PTR dwRefData
)
{
static int idx = 0;
static int idx_max = 11;
static wchar_t* descriptions [] = { L" PlayStation: <A HREF=\"\">Square</A> "
L" Xbox: <A HREF=\"\">X</A>",
L" PlayStation: <A HREF=\"\">Cross</A> "
L" Xbox: <A HREF=\"\">A</A>",
L" PlayStation: <A HREF=\"\">Circle</A> "
L" Xbox: <A HREF=\"\">B</A>",
L" PlayStation: <A HREF=\"\">Triangle</A> "
L" Xbox: <A HREF=\"\">Y</A>",
L" PlayStation: <A HREF=\"\">L1</A> "
L" Xbox: <A HREF=\"\">LB</A>",
L" PlayStation: <A HREF=\"\">R1</A> "
L" Xbox: <A HREF=\"\">RB</A>",
L" PlayStation: <A HREF=\"\">L2</A> "
L" Xbox: <A HREF=\"\">LT</A>",
L" PlayStation: <A HREF=\"\">R2</A> "
L" Xbox: <A HREF=\"\">RT</A>",
L" PlayStation: <A HREF=\"\">Select</A> "
L" Xbox: <A HREF=\"\">Back</A>",
L" PlayStation: <A HREF=\"\">Start</A> "
L" Xbox: <A HREF=\"\">Start</A>",
L" PlayStation: <A HREF=\"\">L3</A> "
L" Xbox: <A HREF=\"\">LS</A>",
L" PlayStation: <A HREF=\"\">R3</A> "
L" Xbox: <A HREF=\"\">RS</A>" };
if (uNotification == TDN_DIALOG_CONSTRUCTED)
{
idx = 0;
UNX_TaskDialogUpdateText ( hWnd, Content, descriptions [0] );
polled_button =
idx;
SendMessage (hWnd, TDM_SET_PROGRESS_BAR_RANGE, 0L, MAKEWPARAM (0, idx_max));
SendMessage (hWnd, TDM_SET_PROGRESS_BAR_STATE, 0L, PBST_NORMAL);
SendMessage (hWnd, TDM_SET_PROGRESS_BAR_POS, idx, 0L);
static bool init = false;
if (! init) {
InitializeCriticalSectionAndSpinCount (&cs_poll, 10000UL);
init = true;
}
early_out = false;
hButtonThread =
CreateThread (nullptr, 0, GetButtonThread, nullptr, 0, nullptr);
}
if (uNotification == TDN_TIMER)
{
if (TryEnterCriticalSection (&cs_poll)) {
SendMessage (hWnd, TDM_CLICK_BUTTON, IDOK, 0);
LeaveCriticalSection (&cs_poll);
}
}
if (uNotification == TDN_BUTTON_CLICKED)
{
if (wParam == IDOK) {
early_out = true;
EnterCriticalSection (&cs_poll);
int* button = (int *)&gamepad.remap.buttons;
button [idx] = gamepad.remap.indexToEnum (polled_button);
LeaveCriticalSection (&cs_poll);
Sleep (100);
if (idx != idx_max) {
UNX_TaskDialogUpdateText (hWnd, Content, descriptions [++idx]);
polled_button =
idx;
SendMessage (hWnd, TDM_SET_PROGRESS_BAR_RANGE, 0L, MAKEWPARAM (0, idx_max));
SendMessage (hWnd, TDM_SET_PROGRESS_BAR_STATE, 0L, PBST_NORMAL);
SendMessage (hWnd, TDM_SET_PROGRESS_BAR_POS, idx, 0L);
early_out = false;
hButtonThread =
CreateThread (nullptr, 0, GetButtonThread, nullptr, 0, nullptr);
return S_FALSE;
} else {
return S_OK;
}
}
if (wParam == IDCANCEL) {
early_out = true;
EnterCriticalSection (&cs_poll);
early_out = false;
LeaveCriticalSection (&cs_poll);
Sleep (100);
UNX_TaskDialogUpdateText (hWnd, Content, descriptions [++idx]);
return S_OK;
}
}
return S_FALSE;
}
void
UnX::Calibrate::Init (void)
{
unx::ParameterFactory factory;
unx::INI::File* pad_cfg = new unx::INI::File (L"UnX_Gamepad.ini");
pad_cfg->parse ();
const size_t num_buttons = 16;
const size_t pad_lods = 2;
const wchar_t*
wszButtons [num_buttons] =
{ L"A", L"B", L"X", L"Y",
L"LB", L"RB",
L"LT", L"RT",
L"LS", L"RS",
L"UP", L"RIGHT", L"DOWN", L"LEFT",
L"START", L"SELECT" };
unx::ParameterBool* supports_XInput =
(unx::ParameterBool *)factory.create_parameter <bool> (L"Disable XInput?");
supports_XInput->register_to_ini (pad_cfg, L"Gamepad.Type", L"UsesXInput");
//if (((unx::iParameter *)supports_XInput)->load ()) {
//gamepad.legacy = (! supports_XInput->get_value ());
//} else {
//supports_XInput->store (true);
//}
//if (gamepad.legacy)
//{
unx::ParameterInt* A = (unx::ParameterInt *)factory.create_parameter <int> (L"A");
A->register_to_ini (pad_cfg, L"Gamepad.Remap", L"XInput_A");
if (((unx::iParameter *)A)->load ()) {
gamepad.remap.buttons.A = (gamepad.remap.indexToEnum (A->get_value ()));
} else {
A->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.A));
}
unx::ParameterInt* B = (unx::ParameterInt *)factory.create_parameter <int> (L"B");
B->register_to_ini (pad_cfg, L"Gamepad.Remap", L"XInput_B");
if (((unx::iParameter *)B)->load ()) {
gamepad.remap.buttons.B = (gamepad.remap.indexToEnum (B->get_value ()));
} else {
B->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.B));
}
unx::ParameterInt* X = (unx::ParameterInt *)factory.create_parameter <int> (L"X");
X->register_to_ini (pad_cfg, L"Gamepad.Remap", L"XInput_X");
if (((unx::iParameter *)X)->load ()) {
gamepad.remap.buttons.X = (gamepad.remap.indexToEnum (X->get_value ()));
} else {
X->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.X));
}
unx::ParameterInt* Y = (unx::ParameterInt *)factory.create_parameter <int> (L"Y");
Y->register_to_ini (pad_cfg, L"Gamepad.Remap", L"XInput_Y");
if (((unx::iParameter *)Y)->load ()) {
gamepad.remap.buttons.Y = (gamepad.remap.indexToEnum (Y->get_value ()));
} else {
Y->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.Y));
}
unx::ParameterInt* START = (unx::ParameterInt *)factory.create_parameter <int> (L"START");
START->register_to_ini (pad_cfg, L"Gamepad.Remap", L"XInput_Start");
if (((unx::iParameter *)START)->load ()) {
gamepad.remap.buttons.START = (gamepad.remap.indexToEnum (START->get_value ()));
} else {
START->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.START));
}
unx::ParameterInt* BACK = (unx::ParameterInt *)factory.create_parameter <int> (L"BACK");
BACK->register_to_ini (pad_cfg, L"Gamepad.Remap", L"XInput_Back");
if (((unx::iParameter *)BACK)->load ()) {
gamepad.remap.buttons.BACK = (gamepad.remap.indexToEnum (BACK->get_value ()));
} else {
BACK->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.BACK));
}
unx::ParameterInt* LB = (unx::ParameterInt *)factory.create_parameter <int> (L"LB");
LB->register_to_ini (pad_cfg, L"Gamepad.Remap", L"XInput_LB");
if (((unx::iParameter *)LB)->load ()) {
gamepad.remap.buttons.LB = (gamepad.remap.indexToEnum (LB->get_value ()));
} else {
LB->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.LB));
}
unx::ParameterInt* RB = (unx::ParameterInt *)factory.create_parameter <int> (L"RB");
RB->register_to_ini (pad_cfg, L"Gamepad.Remap", L"XInput_RB");
if (((unx::iParameter *)RB)->load ()) {
gamepad.remap.buttons.RB = (gamepad.remap.indexToEnum (RB->get_value ()));
} else {
RB->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.RB));
}
unx::ParameterInt* LT = (unx::ParameterInt *)factory.create_parameter <int> (L"LT");
LT->register_to_ini (pad_cfg, L"Gamepad.Remap", L"XInput_LT");
if (((unx::iParameter *)LT)->load ()) {
gamepad.remap.buttons.LT = (gamepad.remap.indexToEnum (LT->get_value ()));
} else {
LT->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.LT));
}
unx::ParameterInt* RT = (unx::ParameterInt *)factory.create_parameter <int> (L"RT");
RT->register_to_ini (pad_cfg, L"Gamepad.Remap", L"XInput_RT");
if (((unx::iParameter *)RT)->load ()) {
gamepad.remap.buttons.RT = (gamepad.remap.indexToEnum (RT->get_value ()));
} else {
RT->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.RT));
}
unx::ParameterInt* LS = (unx::ParameterInt *)factory.create_parameter <int> (L"LS");
LS->register_to_ini (pad_cfg, L"Gamepad.Remap", L"XInput_LS");
if (((unx::iParameter *)LS)->load ()) {
gamepad.remap.buttons.LS = (gamepad.remap.indexToEnum (LS->get_value ()));
} else {
LS->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.LS));
}
unx::ParameterInt* RS = (unx::ParameterInt *)factory.create_parameter <int> (L"RS");
RS->register_to_ini (pad_cfg, L"Gamepad.Remap", L"XInput_RS");
if (((unx::iParameter *)RS)->load ()) {
gamepad.remap.buttons.RS = (gamepad.remap.indexToEnum (RS->get_value ()));
} else {
RS->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.RS));
}
//}
unx::ParameterStringW* combo_ESC =
(unx::ParameterStringW *)
factory.create_parameter <std::wstring> (L"ESC Buttons");
unx::ParameterStringW* combo_F1 =
(unx::ParameterStringW *)
factory.create_parameter <std::wstring> (L"F1 Buttons");
combo_F1->register_to_ini (pad_cfg, L"Gamepad.PC", L"F1");
if (! combo_F1->load (gamepad.f1.unparsed)) {
combo_F1->store (
(gamepad.f1.unparsed = L"Select+Cross")
);
}
unx::ParameterStringW* combo_F2 =
(unx::ParameterStringW *)
factory.create_parameter <std::wstring> (L"F2 Buttons");
combo_F2->register_to_ini (pad_cfg, L"Gamepad.PC", L"F2");
if (! combo_F2->load (gamepad.f2.unparsed)) {
combo_F2->store (
(gamepad.f1.unparsed = L"Select+Circle")
);
}
unx::ParameterStringW* combo_F3 =
(unx::ParameterStringW *)
factory.create_parameter <std::wstring> (L"F3 Buttons");
combo_F3->register_to_ini (pad_cfg, L"Gamepad.PC", L"F3");
if (! combo_F3->load (gamepad.f3.unparsed)) {
combo_F3->store (
(gamepad.f3.unparsed = L"Select+Square")
);
}
unx::ParameterStringW* combo_F4 =
(unx::ParameterStringW *)
factory.create_parameter <std::wstring> (L"F4 Buttons");
combo_F4->register_to_ini (pad_cfg, L"Gamepad.PC", L"F4");
if (! combo_F4->load (gamepad.f4.unparsed)) {
combo_F4->store (
(gamepad.f4.unparsed = L"Select+L1")
);
}
unx::ParameterStringW* combo_F5 =
(unx::ParameterStringW *)
factory.create_parameter <std::wstring> (L"F5 Buttons");
combo_F5->register_to_ini (pad_cfg, L"Gamepad.PC", L"F5");
if (! combo_F5->load (gamepad.f5.unparsed)) {
combo_F5->store (
(gamepad.f5.unparsed = L"Select+R1")
);
}
unx::ParameterStringW* combo_SS =
(unx::ParameterStringW *)
factory.create_parameter <std::wstring> (L"Screenshot Buttons");
combo_SS->register_to_ini (pad_cfg, L"Gamepad.Steam", L"Screenshot");
if (! combo_SS->load (gamepad.screenshot.unparsed)) {
combo_SS->store (
(gamepad.screenshot.unparsed = L"Select+R3")
);
}
int nButtonPressed = 0;
TASKDIALOGCONFIG config = {0};
int idx = 0;
config.cbSize = sizeof (config);
config.hInstance = GetModuleHandle (nullptr);//hInstance;
config.hwndParent = GetDesktopWindow ();
config.pszWindowTitle = L"\"Untitled\" Project X (Controller Calibration)";
config.dwCommonButtons = TDCBF_CLOSE_BUTTON;
config.pButtons = nullptr;
config.cButtons = 0;
config.dwFlags = TDF_ENABLE_HYPERLINKS;
config.pfCallback = nullptr;
config.lpCallbackData = 0;
config.pszFooter = UNXCAL_GetControllerDescription ();
config.pszFooterIcon = TD_ERROR_ICON;
JOYCAPS joycaps;
if ((! joyGetNumDevs ()) || (JOYERR_NOERROR != joyGetDevCaps (JOYSTICKID1, &joycaps, sizeof joycaps)) ||
( UNXCAL_GetControllerButtonCount () < 12 &&
UNXCAL_GetControllerAxisCount () < 6 )) {
config.pszMainIcon = TD_WARNING_ICON;
if ( ( UNXCAL_GetControllerButtonCount () < 12 ||
UNXCAL_GetControllerAxisCount () < 6 ) ) {
config.pszMainInstruction = L"Incompatible Controller Detected";
config.pszContent = L"The game requires a controller with digital triggers or 6 analog axes for proper operation.\r\n\r\n"
L"\tPlease run your controller in XInput mode or set it up with digital triggers instead of analog.";
} else {
config.pszContent = L"Steam controllers are not DirectInput compatible.\r\n\r\n\tPlease review "
L"<A HREF=\"UnX_Gamepad.ini\">UnX_Gamepad.ini</A> for "
L"consistency.";
config.pszFooter = L"No DirectInput Compatible Controller Detected!";
}
config.pszVerificationText = L"Check this box if you use an XInput controller.";
bool XInput;
if (supports_XInput->load (XInput) && XInput)
config.dwFlags |= TDF_VERIFICATION_FLAG_CHECKED;
BOOL verified;
TaskDialogIndirect (&config, nullptr, nullptr, &verified);
supports_XInput->store (verified);
pad_cfg->write (L"UnX_Gamepad.ini");
delete pad_cfg;
return;
}
gamepad.legacy = true;
supports_XInput->store (false);
config.cbSize = sizeof (config);
config.hInstance = GetModuleHandle (nullptr);//hInstance;
config.hwndParent = GetDesktopWindow ();
config.pszWindowTitle = L"\"Untitled\" Project X (Controller Calibration)";
config.dwCommonButtons = TDCBF_OK_BUTTON | TDCBF_CANCEL_BUTTON;
config.pButtons = nullptr;
config.cButtons = 0;
config.dwFlags = TDF_CALLBACK_TIMER | TDF_ENABLE_HYPERLINKS | TDF_SHOW_PROGRESS_BAR/* | TDF_USE_HICON_MAIN*/;
config.pfCallback = TaskDialogCallback;
config.lpCallbackData = (LONG_PTR)&idx;
config.pszFooterIcon = TD_INFORMATION_ICON;
config.pszFooter = UNXCAL_GetControllerDescription ();
config.pszMainIcon = MAKEINTRESOURCE(IDI_UNX_CALIBRATE);// TD_INFORMATION_ICON;
config.pszMainInstruction = L"Please Press a Button on Your Controller";
TaskDialogIndirect (&config, nullptr, nullptr, nullptr);
A->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.A));
B->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.B));
X->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.X));
Y->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.Y));
START->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.START));
BACK->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.BACK));
LB->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.LB));
RB->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.RB));
LT->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.LT));
RT->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.RT));
LS->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.LS));
RS->store (gamepad.remap.enumToIndex (gamepad.remap.buttons.RS));
pad_cfg->write (L"UnX_Gamepad.ini");
delete pad_cfg;
// Post-Process our Remap Table
for (int i = 0; i < 12; i++) {
gamepad.remap.map [i] =
gamepad.remap.enumToIndex (
((int *)&gamepad.remap.buttons) [ i ]
) - 1;
}
}
void
UnX::Calibrate::Shutdown (void)
{
}
#define XINPUT_GAMEPAD_DPAD_UP 0x0001
#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002
#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004
#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008
#define XINPUT_GAMEPAD_START 0x0010
#define XINPUT_GAMEPAD_BACK 0x0020
#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040
#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080
#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100
#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200
#define XINPUT_GAMEPAD_LEFT_TRIGGER 0x10000
#define XINPUT_GAMEPAD_RIGHT_TRIGGER 0x20000
#define XINPUT_GAMEPAD_A 0x1000
#define XINPUT_GAMEPAD_B 0x2000
#define XINPUT_GAMEPAD_X 0x4000
#define XINPUT_GAMEPAD_Y 0x8000
struct button_map_state_s {
int buttons;
bool lt, rt;
};
button_map_state_s
UNX_ParseButtonCombo (std::wstring combo, int* out)
{
button_map_state_s state;
state.lt = false;
state.rt = false;
state.buttons = 0;
std::wstring map = combo;
if (! map.length ())
return state;
wchar_t* wszMap = _wcsdup (map.c_str ());
wchar_t* wszTok = wcstok (wszMap, L"+");
while (wszTok != nullptr) {
int button = 0x00;
if ((! lstrcmpiW (wszTok, L"LB")) || (! lstrcmpiW (wszTok, L"L1")))
button = XINPUT_GAMEPAD_LEFT_SHOULDER;
if ((! lstrcmpiW (wszTok, L"RB")) || (! lstrcmpiW (wszTok, L"R1")))
button = XINPUT_GAMEPAD_RIGHT_SHOULDER;
if ((! lstrcmpiW (wszTok, L"LT")) || (! lstrcmpiW (wszTok, L"L2")))
button = XINPUT_GAMEPAD_LEFT_TRIGGER;
if ((! lstrcmpiW (wszTok, L"RT")) || (! lstrcmpiW (wszTok, L"R2")))
button = XINPUT_GAMEPAD_RIGHT_TRIGGER;
if ((! lstrcmpiW (wszTok, L"LS")) || (! lstrcmpiW (wszTok, L"L3")))
button = XINPUT_GAMEPAD_LEFT_THUMB;
if ((! lstrcmpiW (wszTok, L"RS")) || (! lstrcmpiW (wszTok, L"R3")))
button = XINPUT_GAMEPAD_RIGHT_THUMB;
if ((! lstrcmpiW (wszTok, L"Start")))
button = XINPUT_GAMEPAD_START;
if ((! lstrcmpiW (wszTok, L"Back")) || (! lstrcmpiW (wszTok, L"Select")))
button = XINPUT_GAMEPAD_BACK;
if ((! lstrcmpiW (wszTok, L"A")) || (! lstrcmpiW (wszTok, L"Cross")))
button = XINPUT_GAMEPAD_A;
if ((! lstrcmpiW (wszTok, L"B")) || (! lstrcmpiW (wszTok, L"Circle")))
button = XINPUT_GAMEPAD_B;
if ((! lstrcmpiW (wszTok, L"X")) || (! lstrcmpiW (wszTok, L"Square")))
button = XINPUT_GAMEPAD_X;
if ((! lstrcmpiW (wszTok, L"Y")) || (! lstrcmpiW (wszTok, L"Triangle")))
button = XINPUT_GAMEPAD_Y;
if (button == XINPUT_GAMEPAD_LEFT_TRIGGER)
state.lt = true;
else if (button == XINPUT_GAMEPAD_RIGHT_TRIGGER)
state.rt = true;
else if (button != 0x00) {
out [state.buttons++] = button;
}
//dll_log.Log (L"Button%lu: %s", state.buttons-1, wszTok);
wszTok = wcstok (nullptr, L"+");
if (state.buttons > 1)
break;
}
free (wszMap);
return state;
}
#include <mmsystem.h>
void
UNX_SetupSpecialButtons (void)
{
button_map_state_s state =
UNX_ParseButtonCombo ( gamepad.f1.unparsed,
&gamepad.f1.button0 );
gamepad.f1.lt = state.lt;
gamepad.f1.rt = state.rt;
gamepad.f1.buttons = state.buttons;
state =
UNX_ParseButtonCombo ( gamepad.f2.unparsed,
&gamepad.f2.button0 );
gamepad.f2.lt = state.lt;
gamepad.f2.rt = state.rt;
gamepad.f2.buttons = state.buttons;
state =
UNX_ParseButtonCombo ( gamepad.f3.unparsed,
&gamepad.f3.button0 );
gamepad.f3.lt = state.lt;
gamepad.f3.rt = state.rt;
gamepad.f3.buttons = state.buttons;
state =
UNX_ParseButtonCombo ( gamepad.f4.unparsed,
&gamepad.f4.button0 );
gamepad.f4.lt = state.lt;
gamepad.f4.rt = state.rt;
gamepad.f4.buttons = state.buttons;
state =
UNX_ParseButtonCombo ( gamepad.f5.unparsed,
&gamepad.f5.button0 );
gamepad.f5.lt = state.lt;
gamepad.f5.rt = state.rt;
gamepad.f5.buttons = state.buttons;
state =
UNX_ParseButtonCombo ( gamepad.screenshot.unparsed,
&gamepad.screenshot.button0 );
gamepad.screenshot.lt = state.lt;
gamepad.screenshot.rt = state.rt;
gamepad.screenshot.buttons = state.buttons;
}
#include "ini.h"
#include "parameter.h"
#include <queue>
struct combo_button_s {
combo_button_s (
unx_gamepad_s::combo_s* combo_
) : combo (combo_) {
state = false;
last_state = false;
};
bool poll ( DWORD xi_ret,
XINPUT_GAMEPAD xi_gamepad )
{
last_state = state;
state =
(xi_ret == 0 &&
combo->buttons != 0 &&
((! combo->lt) || xi_gamepad.bLeftTrigger) &&
((! combo->rt) || xi_gamepad.bRightTrigger) &&
xi_gamepad.wButtons & (WORD)combo->button0 &&
xi_gamepad.wButtons & (WORD)combo->button1 &&
xi_gamepad.wButtons & (WORD)combo->button2);
return state;
}
bool wasJustPressed (void) {
return state && (! last_state);
}
unx_gamepad_s::combo_s*
combo;
bool state;
bool last_state;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment