Skip to content

Commit

Permalink
TSA: Map POV/D-pad inputs to the X/Y axes. (Non-DirectInput mode) [V]
Browse files Browse the repository at this point in the history
Essentially allowing D-pad controls for all games. The WinMM version
also covers controls in the resolution dialogs of TH14 and later.

Funded by an anonymous person.
  • Loading branch information
nmlgc committed May 12, 2018
1 parent b340ff4 commit 35f1668
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 1 deletion.
123 changes: 123 additions & 0 deletions thcrap_tsa/src/input.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* Touhou Community Reliant Automatic Patcher
* Team Shanghai Alice support plugin
*
* ----
*
* Input detours. Currently providing POV hat → X/Y axis mapping.
*/

#include <thcrap.h>
#include <stdbool.h>
#include <math.h>

// 180° / PI
#define DEG_TO_RAD(x) ((x) * 0.0174532925199432957692369076848f)

/// WinMM joystick API
/// ------------------
/*
* Thankfully, the joystick IDs are consistent and always refer to the same
* model of joystick, even across hot-swaps if you temporarily plug a
* different model into the same USB port. Even better for our purposes of
* remapping POV hats to the X/Y axes, the API also treats separate but
* identical controllers as matching the same ID.
*
* The "Preferred device" for older applications that can be set in the
* control panel will always be assigned to ID 0, even if it was unplugged in
* the meantime. Setting the Preferred device to (none) will not automatically
* re-assign another controller to ID 0.
*
* Also, IDs are always bound to the same USB port for the lifetime of a
* process, and controllers won't be recognized at all if they are hot-swapped
* into a different port than the one they were in before.
*/

typedef MMRESULT __stdcall joyGetPosEx_type(
UINT uJoyID,
JOYINFOEX *pji
);

DETOUR_CHAIN_DEF(joyGetPosEx);

typedef struct
{
uint32_t min;
uint32_t max;
} range_t;

// joyGetDevCaps() will necessarily be slower
typedef struct
{
// joyGetPosEx() will return bogus values on joysticks without a POV, so
// we must check if we even have one.
bool initialized;
bool has_pov;
range_t range_x;
range_t range_y;
} winmm_joy_caps_t;

winmm_joy_caps_t *joy_info = NULL;

MMRESULT __stdcall my_joyGetPosEx(UINT uJoyID, JOYINFOEX *pji)
{
if(!pji) {
return MMSYSERR_INVALPARAM;
}
pji->dwFlags |= JOY_RETURNPOV;

MMRESULT ret_pos = chain_joyGetPosEx(uJoyID, pji);
if(ret_pos != JOYERR_NOERROR) {
return ret_pos;
}

winmm_joy_caps_t *jc = &joy_info[uJoyID];
if(!jc->initialized) {
JOYCAPSW caps;
MMRESULT ret_caps = joyGetDevCapsW(uJoyID, &caps, sizeof(caps));
assert(ret_caps == JOYERR_NOERROR);

jc->initialized = true;
jc->has_pov = caps.wCaps & JOYCAPS_HASPOV;
jc->range_x.min = caps.wXmin;
jc->range_x.max = caps.wXmax;
jc->range_y.min = caps.wYmin;
jc->range_y.max = caps.wYmax;
} else if(!jc->has_pov) {
return ret_pos;
}

if(pji->dwPOV != JOY_POVCENTERED) {
uint32_t x_center = (jc->range_x.max - jc->range_x.min) / 2;
uint32_t y_center = (jc->range_y.max - jc->range_y.min) / 2;

float angle_deg = pji->dwPOV / 100.0f;
float angle_rad = DEG_TO_RAD(angle_deg);
// POV values ≠ unit circle angles, so...
float angle_sin = 1.0f - cosf(angle_rad);
float angle_cos = sinf(angle_rad) + 1.0f;
pji->dwXpos = (DWORD)(jc->range_x.min + (angle_cos * x_center));
pji->dwYpos = (DWORD)(jc->range_y.min + (angle_sin * y_center));
}
return ret_pos;
}
/// ------------------

__declspec(dllexport) void input_mod_detour(void)
{
// This conveniently returns the number of *possible* joysticks, *not* the
// number of joysticks currently connected.
UINT num_devs = joyGetNumDevs();
if(num_devs == 0) {
return;
}
joy_info = (winmm_joy_caps_t*)calloc(sizeof(winmm_joy_caps_t), num_devs);
if(!joy_info) {
return;
}

detour_chain("winmm.dll", 1,
"joyGetPosEx", my_joyGetPosEx, &chain_joyGetPosEx,
NULL
);
}
3 changes: 2 additions & 1 deletion thcrap_tsa/thcrap_tsa.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<Link>
<SubSystem>Windows</SubSystem>
<ModuleDefinitionFile>thcrap_tsa.def</ModuleDefinitionFile>
<AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>comctl32.lib;shlwapi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies Condition="$(UseDebugLibraries)==true">thcrap_d.lib;libpng16_d.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies Condition="$(UseDebugLibraries)!=true">thcrap.lib;libpng16.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
Expand All @@ -42,6 +42,7 @@
<ClCompile Include="src\gentext.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="src\input.c" />
<ClCompile Include="src\layout.c" />
<ClCompile Include="src\music.c" />
<ClCompile Include="src\png_ex.c" />
Expand Down

0 comments on commit 35f1668

Please sign in to comment.