Gamepad support for menus
This commit is contained in:
parent
04ef6c3fbe
commit
b3adacb71d
@ -8,11 +8,15 @@ namespace Components
|
|||||||
std::chrono::milliseconds XInput::timeAtFirstHeldMaxLookX = 0ms; // "For how much time in miliseconds has the player been holding a horizontal direction on their stick, fully" (-1.0 or 1.0)
|
std::chrono::milliseconds XInput::timeAtFirstHeldMaxLookX = 0ms; // "For how much time in miliseconds has the player been holding a horizontal direction on their stick, fully" (-1.0 or 1.0)
|
||||||
bool XInput::isHoldingMaxLookX = false;
|
bool XInput::isHoldingMaxLookX = false;
|
||||||
|
|
||||||
float XInput::lockedSensitivityMultiplier = 0.5f;
|
float XInput::lockedSensitivityMultiplier = 0.45f;
|
||||||
float XInput::generalXSensitivityMultiplier = 1.6f;
|
float XInput::generalXSensitivityMultiplier = 1.5f;
|
||||||
float XInput::generalYSensitivityMultiplier = 0.8f;
|
float XInput::generalYSensitivityMultiplier = 0.8f;
|
||||||
|
|
||||||
std::chrono::milliseconds XInput::msBeforeUnlockingSensitivity = 250ms;
|
float XInput::lastMenuNavigationDirection = .0f;
|
||||||
|
std::chrono::milliseconds XInput::lastNavigationTime = 0ms;
|
||||||
|
std::chrono::milliseconds XInput::msBetweenNavigations = 220ms;
|
||||||
|
|
||||||
|
std::chrono::milliseconds XInput::msBeforeUnlockingSensitivity = 350ms;
|
||||||
|
|
||||||
std::vector<XInput::ActionMapping> mappings = {
|
std::vector<XInput::ActionMapping> mappings = {
|
||||||
XInput::ActionMapping(XINPUT_GAMEPAD_A, "gostand"),
|
XInput::ActionMapping(XINPUT_GAMEPAD_A, "gostand"),
|
||||||
@ -31,6 +35,14 @@ namespace Components
|
|||||||
XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_DOWN, "actionslot 4"),
|
XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_DOWN, "actionslot 4"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::vector<XInput::MenuMapping> menuMappings = {
|
||||||
|
XInput::MenuMapping(XINPUT_GAMEPAD_A, Game::keyNum_t::K_KP_ENTER),
|
||||||
|
XInput::MenuMapping(XINPUT_GAMEPAD_B, Game::keyNum_t::K_ESCAPE),
|
||||||
|
XInput::MenuMapping(XINPUT_GAMEPAD_DPAD_RIGHT, Game::keyNum_t::K_KP_RIGHTARROW),
|
||||||
|
XInput::MenuMapping(XINPUT_GAMEPAD_DPAD_LEFT, Game::keyNum_t::K_KP_LEFTARROW),
|
||||||
|
XInput::MenuMapping(XINPUT_GAMEPAD_DPAD_UP, Game::keyNum_t::K_KP_UPARROW),
|
||||||
|
XInput::MenuMapping(XINPUT_GAMEPAD_DPAD_DOWN, Game::keyNum_t::K_KP_DOWNARROW)
|
||||||
|
};
|
||||||
|
|
||||||
void XInput::Vibrate(int leftVal, int rightVal)
|
void XInput::Vibrate(int leftVal, int rightVal)
|
||||||
{
|
{
|
||||||
@ -108,12 +120,12 @@ namespace Components
|
|||||||
viewStickX *= XInput::lockedSensitivityMultiplier;
|
viewStickX *= XInput::lockedSensitivityMultiplier;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
float coeff = std::clamp(hasBeenHoldingLeftXForMs.count()/(float)XInput::msBeforeUnlockingSensitivity.count(), 0.0F, 1.0F);
|
float coeff = std::clamp(hasBeenHoldingLeftXForMs.count() / (float)XInput::msBeforeUnlockingSensitivity.count(), 0.0F, 1.0F);
|
||||||
viewStickX *= XInput::lockedSensitivityMultiplier + coeff * (1.0f -XInput::lockedSensitivityMultiplier);
|
viewStickX *= XInput::lockedSensitivityMultiplier + coeff * (1.0f - XInput::lockedSensitivityMultiplier);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
XInput::isHoldingMaxLookX = false;
|
XInput::isHoldingMaxLookX = false;
|
||||||
XInput::timeAtFirstHeldMaxLookX = 0ms;
|
XInput::timeAtFirstHeldMaxLookX = 0ms;
|
||||||
}
|
}
|
||||||
@ -281,6 +293,67 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XInput::MenuNavigate() {
|
||||||
|
|
||||||
|
Game::menuDef_t* menuDef = Game::Menu_GetFocused(Game::uiContext);
|
||||||
|
|
||||||
|
#define SIGN(d) ((d > 0) - (d < 0))
|
||||||
|
|
||||||
|
if (menuDef) {
|
||||||
|
PollXInputDevices();
|
||||||
|
|
||||||
|
if (XInput::xiPlayerNum != -1)
|
||||||
|
{
|
||||||
|
XINPUT_STATE* xiState = &xiStates[xiPlayerNum];
|
||||||
|
|
||||||
|
// Up/Down
|
||||||
|
float moveStickX = abs(xiState->Gamepad.sThumbLX) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ? xiState->Gamepad.sThumbLX / (float)std::numeric_limits<SHORT>().max() : .0f;
|
||||||
|
float moveStickY = abs(xiState->Gamepad.sThumbLY) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ? xiState->Gamepad.sThumbLY / (float)std::numeric_limits<SHORT>().max() : .0f;
|
||||||
|
|
||||||
|
std::chrono::milliseconds now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||||
|
std::chrono::milliseconds timeSinceLastNavigation = now - lastNavigationTime;
|
||||||
|
bool canNavigate = timeSinceLastNavigation > msBetweenNavigations;
|
||||||
|
|
||||||
|
if (moveStickY > .0f) {
|
||||||
|
if (canNavigate || SIGN(moveStickY) != SIGN(lastMenuNavigationDirection)) {
|
||||||
|
Game::Menu_SetPrevCursorItem(Game::uiContext, menuDef, 1);
|
||||||
|
lastMenuNavigationDirection = moveStickY;
|
||||||
|
lastNavigationTime = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (moveStickY < .0f) {
|
||||||
|
if (canNavigate || SIGN(moveStickY) != SIGN(lastMenuNavigationDirection)) {
|
||||||
|
Game::Menu_SetNextCursorItem(Game::uiContext, menuDef, 1);
|
||||||
|
lastMenuNavigationDirection = moveStickY;
|
||||||
|
lastNavigationTime = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lastMenuNavigationDirection = .0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < menuMappings.size(); i++)
|
||||||
|
{
|
||||||
|
MenuMapping mapping = menuMappings[i];
|
||||||
|
auto action = mapping.keystroke;
|
||||||
|
|
||||||
|
if (mapping.wasPressed) {
|
||||||
|
if (xiState->Gamepad.wButtons & mapping.input) {
|
||||||
|
// Button still pressed, do not send info
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
menuMappings[i].wasPressed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(xiState->Gamepad.wButtons & mapping.input){
|
||||||
|
Game::UI_KeyEvent(0, mapping.keystroke, 1);
|
||||||
|
menuMappings[i].wasPressed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
XInput::XInput()
|
XInput::XInput()
|
||||||
{
|
{
|
||||||
// poll xinput devices every client frame
|
// poll xinput devices every client frame
|
||||||
@ -306,5 +379,6 @@ namespace Components
|
|||||||
Vibrate(3000, 3000);
|
Vibrate(3000, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Scheduler::OnFrame(MenuNavigate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,18 @@ namespace Components
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MenuMapping {
|
||||||
|
int input;
|
||||||
|
Game::keyNum_t keystroke;
|
||||||
|
bool wasPressed = false;
|
||||||
|
|
||||||
|
MenuMapping(int input, Game::keyNum_t keystroke)
|
||||||
|
{
|
||||||
|
this->keystroke = keystroke;
|
||||||
|
this->input = input;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static XINPUT_STATE xiStates[XUSER_MAX_COUNT];
|
static XINPUT_STATE xiStates[XUSER_MAX_COUNT];
|
||||||
static int xiPlayerNum;
|
static int xiPlayerNum;
|
||||||
@ -35,6 +47,10 @@ namespace Components
|
|||||||
static float generalXSensitivityMultiplier;
|
static float generalXSensitivityMultiplier;
|
||||||
static float generalYSensitivityMultiplier;
|
static float generalYSensitivityMultiplier;
|
||||||
|
|
||||||
|
static std::chrono::milliseconds lastNavigationTime;
|
||||||
|
static std::chrono::milliseconds msBetweenNavigations;
|
||||||
|
static float lastMenuNavigationDirection;
|
||||||
|
|
||||||
static void Vibrate(int leftVal = 0, int rightVal = 0);
|
static void Vibrate(int leftVal = 0, int rightVal = 0);
|
||||||
|
|
||||||
static void CL_FrameStub();
|
static void CL_FrameStub();
|
||||||
@ -42,6 +58,7 @@ namespace Components
|
|||||||
|
|
||||||
static void CL_CreateCmdStub();
|
static void CL_CreateCmdStub();
|
||||||
static void CL_GamepadMove(int, Game::usercmd_s*);
|
static void CL_GamepadMove(int, Game::usercmd_s*);
|
||||||
|
static void MenuNavigate();
|
||||||
|
|
||||||
static void MSG_WriteDeltaUsercmdKeyStub();
|
static void MSG_WriteDeltaUsercmdKeyStub();
|
||||||
|
|
||||||
|
@ -175,6 +175,8 @@ namespace Game
|
|||||||
Menus_FindByName_t Menus_FindByName = Menus_FindByName_t(0x487240);
|
Menus_FindByName_t Menus_FindByName = Menus_FindByName_t(0x487240);
|
||||||
Menu_IsVisible_t Menu_IsVisible = Menu_IsVisible_t(0x4D77D0);
|
Menu_IsVisible_t Menu_IsVisible = Menu_IsVisible_t(0x4D77D0);
|
||||||
Menus_MenuIsInStack_t Menus_MenuIsInStack = Menus_MenuIsInStack_t(0x47ACB0);
|
Menus_MenuIsInStack_t Menus_MenuIsInStack = Menus_MenuIsInStack_t(0x47ACB0);
|
||||||
|
Menu_HandleKey_t Menu_HandleKey = Menu_HandleKey_t(0x4C4A00);
|
||||||
|
Menu_GetFocused_t Menu_GetFocused = Menu_GetFocused_t(0x4AFF10);
|
||||||
|
|
||||||
MSG_Init_t MSG_Init = MSG_Init_t(0x45FCA0);
|
MSG_Init_t MSG_Init = MSG_Init_t(0x45FCA0);
|
||||||
MSG_ReadBit_t MSG_ReadBit = MSG_ReadBit_t(0x476D20);
|
MSG_ReadBit_t MSG_ReadBit = MSG_ReadBit_t(0x476D20);
|
||||||
@ -327,6 +329,7 @@ namespace Game
|
|||||||
UI_GetContext_t UI_GetContext = UI_GetContext_t(0x4F8940);
|
UI_GetContext_t UI_GetContext = UI_GetContext_t(0x4F8940);
|
||||||
UI_TextWidth_t UI_TextWidth = UI_TextWidth_t(0x6315C0);
|
UI_TextWidth_t UI_TextWidth = UI_TextWidth_t(0x6315C0);
|
||||||
UI_DrawText_t UI_DrawText = UI_DrawText_t(0x49C0D0);
|
UI_DrawText_t UI_DrawText = UI_DrawText_t(0x49C0D0);
|
||||||
|
UI_KeyEvent_t UI_KeyEvent = UI_KeyEvent_t(0x4970F0);
|
||||||
|
|
||||||
Win_GetLanguage_t Win_GetLanguage = Win_GetLanguage_t(0x45CBA0);
|
Win_GetLanguage_t Win_GetLanguage = Win_GetLanguage_t(0x45CBA0);
|
||||||
|
|
||||||
@ -1141,6 +1144,32 @@ namespace Game
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Menu_SetNextCursorItem(Game::UiContext* a1, Game::menuDef_t* a2, int unk)
|
||||||
|
{
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
push unk
|
||||||
|
push a2
|
||||||
|
mov eax, a1
|
||||||
|
mov ebx, 0x639FE0
|
||||||
|
call ebx
|
||||||
|
add esp, 0x8 // 2 args = 2x4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu_SetPrevCursorItem(Game::UiContext* a1, Game::menuDef_t* a2, int unk)
|
||||||
|
{
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
push unk
|
||||||
|
push a2
|
||||||
|
mov eax, a1
|
||||||
|
mov ebx, 0x639F20
|
||||||
|
call ebx
|
||||||
|
add esp, 0x8 // 2 args = 2x4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
__declspec(naked) void R_AddDebugLine(float* /*color*/, float* /*v1*/, float* /*v2*/)
|
__declspec(naked) void R_AddDebugLine(float* /*color*/, float* /*v1*/, float* /*v2*/)
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
|
@ -414,6 +414,15 @@ namespace Game
|
|||||||
typedef bool(__cdecl * Menus_MenuIsInStack_t)(UiContext *dc, menuDef_t *menu);
|
typedef bool(__cdecl * Menus_MenuIsInStack_t)(UiContext *dc, menuDef_t *menu);
|
||||||
extern Menus_MenuIsInStack_t Menus_MenuIsInStack;
|
extern Menus_MenuIsInStack_t Menus_MenuIsInStack;
|
||||||
|
|
||||||
|
typedef menuDef_t*(__cdecl* Menu_GetFocused_t)(UiContext* ctx);
|
||||||
|
extern Menu_GetFocused_t Menu_GetFocused;
|
||||||
|
|
||||||
|
typedef void(__cdecl* Menu_HandleKey_t)(UiContext* ctx, menuDef_t* menu, Game::keyNum_t key, int down);
|
||||||
|
extern Menu_HandleKey_t Menu_HandleKey;
|
||||||
|
|
||||||
|
typedef bool(__cdecl* UI_KeyEvent_t)(int clientNum, Game::keyNum_t key, int down);
|
||||||
|
extern UI_KeyEvent_t UI_KeyEvent;
|
||||||
|
|
||||||
typedef void(__cdecl * MSG_Init_t)(msg_t *buf, char *data, int length);
|
typedef void(__cdecl * MSG_Init_t)(msg_t *buf, char *data, int length);
|
||||||
extern MSG_Init_t MSG_Init;
|
extern MSG_Init_t MSG_Init;
|
||||||
|
|
||||||
@ -874,6 +883,8 @@ namespace Game
|
|||||||
|
|
||||||
XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize);
|
XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize);
|
||||||
void Menu_FreeItemMemory(Game::itemDef_s* item);
|
void Menu_FreeItemMemory(Game::itemDef_s* item);
|
||||||
|
void Menu_SetNextCursorItem(Game::UiContext* ctx, Game::menuDef_t* currentMenu, int unk = 1);
|
||||||
|
void Menu_SetPrevCursorItem(Game::UiContext* ctx, Game::menuDef_t* currentMenu, int unk = 1);
|
||||||
const char* TableLookup(StringTable* stringtable, int row, int column);
|
const char* TableLookup(StringTable* stringtable, int row, int column);
|
||||||
const char* UI_LocalizeMapName(const char* mapName);
|
const char* UI_LocalizeMapName(const char* mapName);
|
||||||
const char* UI_LocalizeGameType(const char* gameType);
|
const char* UI_LocalizeGameType(const char* gameType);
|
||||||
|
@ -173,6 +173,112 @@ namespace Game
|
|||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
enum keyNum_t
|
||||||
|
{
|
||||||
|
K_NONE = 0x0,
|
||||||
|
K_TAB = 0x9,
|
||||||
|
K_ENTER = 0xD,
|
||||||
|
K_ESCAPE = 0x1B,
|
||||||
|
K_SPACE = 0x20,
|
||||||
|
K_BACKSPACE = 0x7F,
|
||||||
|
K_ASCII_FIRST = 0x80,
|
||||||
|
K_ASCII_181 = 0x80,
|
||||||
|
K_ASCII_191 = 0x81,
|
||||||
|
K_ASCII_223 = 0x82,
|
||||||
|
K_ASCII_224 = 0x83,
|
||||||
|
K_ASCII_225 = 0x84,
|
||||||
|
K_ASCII_228 = 0x85,
|
||||||
|
K_ASCII_229 = 0x86,
|
||||||
|
K_ASCII_230 = 0x87,
|
||||||
|
K_ASCII_231 = 0x88,
|
||||||
|
K_ASCII_232 = 0x89,
|
||||||
|
K_ASCII_233 = 0x8A,
|
||||||
|
K_ASCII_236 = 0x8B,
|
||||||
|
K_ASCII_241 = 0x8C,
|
||||||
|
K_ASCII_242 = 0x8D,
|
||||||
|
K_ASCII_243 = 0x8E,
|
||||||
|
K_ASCII_246 = 0x8F,
|
||||||
|
K_ASCII_248 = 0x90,
|
||||||
|
K_ASCII_249 = 0x91,
|
||||||
|
K_ASCII_250 = 0x92,
|
||||||
|
K_ASCII_252 = 0x93,
|
||||||
|
K_END_ASCII_CHARS = 0x94,
|
||||||
|
K_COMMAND = 0x96,
|
||||||
|
K_CAPSLOCK = 0x97,
|
||||||
|
K_POWER = 0x98,
|
||||||
|
K_PAUSE = 0x99,
|
||||||
|
K_UPARROW = 0x9A,
|
||||||
|
K_DOWNARROW = 0x9B,
|
||||||
|
K_LEFTARROW = 0x9C,
|
||||||
|
K_RIGHTARROW = 0x9D,
|
||||||
|
K_ALT = 0x9E,
|
||||||
|
K_CTRL = 0x9F,
|
||||||
|
K_SHIFT = 0xA0,
|
||||||
|
K_INS = 0xA1,
|
||||||
|
K_DEL = 0xA2,
|
||||||
|
K_PGDN = 0xA3,
|
||||||
|
K_PGUP = 0xA4,
|
||||||
|
K_HOME = 0xA5,
|
||||||
|
K_END = 0xA6,
|
||||||
|
K_F1 = 0xA7,
|
||||||
|
K_F2 = 0xA8,
|
||||||
|
K_F3 = 0xA9,
|
||||||
|
K_F4 = 0xAA,
|
||||||
|
K_F5 = 0xAB,
|
||||||
|
K_F6 = 0xAC,
|
||||||
|
K_F7 = 0xAD,
|
||||||
|
K_F8 = 0xAE,
|
||||||
|
K_F9 = 0xAF,
|
||||||
|
K_F10 = 0xB0,
|
||||||
|
K_F11 = 0xB1,
|
||||||
|
K_F12 = 0xB2,
|
||||||
|
K_F13 = 0xB3,
|
||||||
|
K_F14 = 0xB4,
|
||||||
|
K_F15 = 0xB5,
|
||||||
|
K_KP_HOME = 0xB6,
|
||||||
|
K_KP_UPARROW = 0xB7,
|
||||||
|
K_KP_PGUP = 0xB8,
|
||||||
|
K_KP_LEFTARROW = 0xB9,
|
||||||
|
K_KP_5 = 0xBA,
|
||||||
|
K_KP_RIGHTARROW = 0xBB,
|
||||||
|
K_KP_END = 0xBC,
|
||||||
|
K_KP_DOWNARROW = 0xBD,
|
||||||
|
K_KP_PGDN = 0xBE,
|
||||||
|
K_KP_ENTER = 0xBF,
|
||||||
|
K_KP_INS = 0xC0,
|
||||||
|
K_KP_DEL = 0xC1,
|
||||||
|
K_KP_SLASH = 0xC2,
|
||||||
|
K_KP_MINUS = 0xC3,
|
||||||
|
K_KP_PLUS = 0xC4,
|
||||||
|
K_KP_NUMLOCK = 0xC5,
|
||||||
|
K_KP_STAR = 0xC6,
|
||||||
|
K_KP_EQUALS = 0xC7,
|
||||||
|
K_MOUSE1 = 0xC8,
|
||||||
|
K_MOUSE2 = 0xC9,
|
||||||
|
K_MOUSE3 = 0xCA,
|
||||||
|
K_MOUSE4 = 0xCB,
|
||||||
|
K_MOUSE5 = 0xCC,
|
||||||
|
K_MWHEELDOWN = 0xCD,
|
||||||
|
K_MWHEELUP = 0xCE,
|
||||||
|
K_AUX1 = 0xCF,
|
||||||
|
K_AUX2 = 0xD0,
|
||||||
|
K_AUX3 = 0xD1,
|
||||||
|
K_AUX4 = 0xD2,
|
||||||
|
K_AUX5 = 0xD3,
|
||||||
|
K_AUX6 = 0xD4,
|
||||||
|
K_AUX7 = 0xD5,
|
||||||
|
K_AUX8 = 0xD6,
|
||||||
|
K_AUX9 = 0xD7,
|
||||||
|
K_AUX10 = 0xD8,
|
||||||
|
K_AUX11 = 0xD9,
|
||||||
|
K_AUX12 = 0xDA,
|
||||||
|
K_AUX13 = 0xDB,
|
||||||
|
K_AUX14 = 0xDC,
|
||||||
|
K_AUX15 = 0xDD,
|
||||||
|
K_AUX16 = 0xDE,
|
||||||
|
K_LAST_KEY = 0xDF,
|
||||||
|
};
|
||||||
|
|
||||||
struct __declspec(align(4)) PhysPreset
|
struct __declspec(align(4)) PhysPreset
|
||||||
{
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
|
Loading…
Reference in New Issue
Block a user