extern "C" DWORD WINAPI XInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState) { //PrintLog("XInputGetState"); if(g_bDisable) return ERROR_DEVICE_NOT_CONNECTED; if((dwUserIndex+1 > g_Devices.size() || g_Devices[dwUserIndex].passthrough) && XInputInitialize()) return xinput.XInputGetState(dwUserIndex, pState); DInputDevice& device = g_Devices[dwUserIndex]; if (!pState || !(dwUserIndex < XUSER_MAX_COUNT)) return ERROR_BAD_ARGUMENTS; HRESULT hr = E_FAIL; if(hMsgWnd == NULL) CreateMsgWnd(); if(device.device == NULL && device.dwUserIndex == dwUserIndex) DeviceInitialize(device); if(!device.device) return ERROR_DEVICE_NOT_CONNECTED; //Update device state if enabled or we not use enable if(XInputIsEnabled.bEnabled || !XInputIsEnabled.bUseEnabled) hr = UpdateState(device); #if defined(DEBUG) | defined(_DEBUG) PrintLog("UpdateState %d %d",dwUserIndex,hr); #endif if(FAILED(hr)) return ERROR_DEVICE_NOT_CONNECTED; Mapping& mapping = g_Mappings[dwUserIndex]; XINPUT_STATE& xstate = *pState; xstate.Gamepad.wButtons = 0; xstate.Gamepad.bLeftTrigger = 0; xstate.Gamepad.bRightTrigger = 0; xstate.Gamepad.sThumbLX = 0; xstate.Gamepad.sThumbLY = 0; xstate.Gamepad.sThumbRX = 0; xstate.Gamepad.sThumbRY = 0; if(!XInputIsEnabled.bEnabled && XInputIsEnabled.bUseEnabled) return ERROR_SUCCESS; // timestamp packet xstate.dwPacketNumber=GetTickCount(); // --- Map buttons --- for (int i = 0; i < 10; ++i) { if (((int)mapping.Button[i] >= 0) && ButtonPressed(mapping.Button[i],device)) xstate.Gamepad.wButtons |= buttonIDs[i]; } // --- Map POV to the D-pad --- if (mapping.DpadPOV > 0 && mapping.PovIsButton == false) { //INT pov = POVState(mapping.DpadPOV,dwUserIndex,Gamepad[dwUserIndex].povrotation); int povdeg = device.state.rgdwPOV[mapping.DpadPOV-1]; if(povdeg >= 0) { // Up-left, up, up-right, up (at 360 degrees) if (IN_RANGE2(povdeg,mapping.pov[GAMEPAD_DPAD_LEFT]+1,mapping.pov[GAMEPAD_DPAD_UP]) || IN_RANGE2(povdeg,0,mapping.pov[GAMEPAD_DPAD_RIGHT]-1)) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_UP; // Up-right, right, down-right if (IN_RANGE(povdeg,0,mapping.pov[GAMEPAD_DPAD_DOWN])) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; // Down-right, down, down-left if (IN_RANGE(povdeg,mapping.pov[GAMEPAD_DPAD_RIGHT],mapping.pov[GAMEPAD_DPAD_LEFT])) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; // Down-left, left, up-left if (IN_RANGE(povdeg,mapping.pov[GAMEPAD_DPAD_DOWN],mapping.pov[GAMEPAD_DPAD_UP])) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; } } else if(mapping.PovIsButton == true) { for (int i = 0; i < 4; ++i) { if (((int)mapping.pov[i] >= 0) && ButtonPressed(mapping.pov[i],device)) { xstate.Gamepad.wButtons |= povIDs[i]; } } } // Created so we can refer to each axis with an ID LONG axis[] = { device.state.lX, device.state.lY, device.state.lZ, device.state.lRx, device.state.lRy, device.state.lRz, 0 }; LONG slider[] = { device.state.rglSlider[0], device.state.rglSlider[1] }; // --- Map triggers --- BYTE *targetTrigger[] = { & xstate.Gamepad.bLeftTrigger, & xstate.Gamepad.bRightTrigger }; for (size_t i = 0; i < 2; ++i) { MappingType triggerType = mapping.Trigger[i].type; if (triggerType == DIGITAL) { if(ButtonPressed(mapping.Trigger[i].id,device))*(targetTrigger[i]) = 255; } else { LONG *values; switch (triggerType) { case AXIS: case HAXIS: case CBUT: values = axis; break; case SLIDER: case HSLIDER: values = slider; break; default: values = axis; break; } LONG v = 0; if(mapping.Trigger[i].id > 0) v = values[mapping.Trigger[i].id -1]; else v = -values[-mapping.Trigger[i].id -1] - 1; /* FIXME: axis negative max should be -32768 --- v is the full range (-32767 .. +32767) that should be projected to 0...255 --- Full ranges AXIS: ( 0 to 255 from -32767 to 32767) using axis SLIDER: ( 0 to 255 from -32767 to 32767) using slider ------------------------------------------------------------------------------ --- Half ranges HAXIS: ( 0 to 255 from 0 to 32767) using axis HSLIDER: ( 0 to 255 from 0 to 32767) using slider */ LONG v2=0; LONG offset=0; LONG scaling=1; switch (triggerType) { // Full range case AXIS: case SLIDER: scaling = 255; offset = 32767; break; // Half range case HAXIS: case HSLIDER: case CBUT: // add ///////////////////////////////////////////////////////// scaling = 127; offset = 0; break; default: scaling = 1; offset = 0; break; } //v2 = (v + offset) / scaling; // Add deadzones //*(targetTrigger[i]) = (BYTE) deadzone(v2, 0, 255, device.triggerdz, 255); ///////////////////////////////////////////////////////////////////////////////////////// if (triggerType == CBUT) { if (ButtonPressed(mapping.Trigger[0].but,device) && ButtonPressed(mapping.Trigger[1].but,device)) { *(targetTrigger[0]) = 255; *(targetTrigger[1]) = 255; } if (ButtonPressed(mapping.Trigger[0].but,device) && !ButtonPressed(mapping.Trigger[1].but,device)) { v2 = (offset-v) / scaling; *(targetTrigger[0]) = 255; *(targetTrigger[1]) = 255 - (BYTE) deadzone(v2, 0, 255, device.triggerdz[1], 255); } if (!ButtonPressed(mapping.Trigger[0].but,device) && ButtonPressed(mapping.Trigger[1].but,device)) { v2 = (offset+v) / scaling; *(targetTrigger[0]) = 255 - (BYTE) deadzone(v2, 0, 255, device.triggerdz[0], 255); *(targetTrigger[1]) = 255; } if (!ButtonPressed(mapping.Trigger[0].but,device) && !ButtonPressed(mapping.Trigger[1].but,device)) { v2 = (offset+v) / scaling; *(targetTrigger[i]) = (BYTE) deadzone(v2, 0, 255, device.triggerdz[i], 255); } } else { v2 = (offset+v) / scaling; *(targetTrigger[i]) = (BYTE) deadzone(v2, 0, 255, device.triggerdz[i], 255); } ///////////////////////////////////////////////////////////////////////////////////////// } } // --- Map thumbsticks --- // Created so we can refer to each axis with an ID SHORT *targetAxis[4] = { & xstate.Gamepad.sThumbLX, & xstate.Gamepad.sThumbLY, & xstate.Gamepad.sThumbRX, & xstate.Gamepad.sThumbRY }; // NOTE: Could add symbolic constants as indexers, such as // THUMB_LX_AXIS, THUMB_LX_POSITIVE, THUMB_LX_NEGATIVE if(device.axistodpad==0) { for (INT i = 0; i < 4; ++i) { LONG *values = axis; // Analog input if (mapping.Axis[i].analogType == AXIS) values = axis; if (mapping.Axis[i].analogType == SLIDER) values = slider; if (mapping.Axis[i].analogType != NONE) { if(mapping.Axis[i].id > 0 ) { SHORT val = (SHORT) values[mapping.Axis[i].id - 1]; *(targetAxis[i])= (SHORT) clamp(val,-32767,32767); } else if(mapping.Axis[i].id < 0 ) { SHORT val = (SHORT) -values[-mapping.Axis[i].id - 1]; *(targetAxis[i]) = (SHORT) clamp(val,-32767,32767); } } // Digital input, positive direction if (mapping.Axis[i].hasDigital && mapping.Axis[i].positiveButtonID >= 0) { if (ButtonPressed(mapping.Axis[i].positiveButtonID,device)) *(targetAxis[i]) = 32767; } // Digital input, negative direction if (mapping.Axis[i].hasDigital && mapping.Axis[i].negativeButtonID >= 0) { if (ButtonPressed(mapping.Axis[i].negativeButtonID,device)) *(targetAxis[i]) = -32767; } } } //WILDS - Axis to D-Pad if(device.axistodpad==1) { //PrintLog("x: %d, y: %d, z: %d",Gamepad[dwUserIndex].state.lX,Gamepad[dwUserIndex].state.lY,Gamepad[dwUserIndex].state.lZ); if(device.state.lX - device.a2doffset > device.a2ddeadzone) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; if(device.state.lX - device.a2doffset < -device.a2ddeadzone) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; if(device.state.lY - device.a2doffset < -device.a2ddeadzone) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_UP; if(device.state.lY - device.a2doffset > device.a2ddeadzone) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; } //WILDS END for (int i = 0; i < 4; ++i) { if (device.antideadzone[i]) { SHORT antidz = device.antideadzone[i]; LONG val = *(targetAxis[i]); SHORT direction = val > 0 ? 1 : -1; val = (LONG)(abs(val) / (32767 / (32767 - antidz * 1.0)) + antidz); val = min(val, 32767); if(val == device.antideadzone[i] || val == -device.antideadzone[i]) val = 0; *(targetAxis[i]) = (SHORT) (direction * val); } if (device.axisdeadzone[i]) { SHORT dz = device.axisdeadzone[i]; LONG val = *(targetAxis[i]); if((val <= dz) && (val >= -dz) ) val = 0; *(targetAxis[i]) = (SHORT) clamp(val,-32767,32767); } // --- Do Linears --- if (device.axislinear[i]) { SHORT absval = (SHORT)((abs(*(targetAxis[i])) + (((32767.0 / 2.0) - (((abs((abs(*(targetAxis[i]))) - (32767.0 / 2.0)))))) * (device.axislinear[i] * 0.01)))); *(targetAxis[i]) = *(targetAxis[i]) > 0 ? absval : -absval; } } return ERROR_SUCCESS; }
DWORD Controller::GetState(XINPUT_STATE* pState) { // Passthrough? if (m_passthrough) return XInputModuleManager::Get().XInputGetState(m_passthroughindex, pState); if (!ControllerManager::Get().XInputEnabled()) { // Clear state if (pState) ZeroMemory(pState, sizeof(XINPUT_STATE)); return ERROR_SUCCESS; } HRESULT hr = UpdateState(); #if 0 PrintLog("UpdateState %u %u", dwUserIndex, hr); #endif if (FAILED(hr)) return ERROR_DEVICE_NOT_CONNECTED; pState->Gamepad.wButtons = 0; pState->Gamepad.bLeftTrigger = 0; pState->Gamepad.bRightTrigger = 0; pState->Gamepad.sThumbLX = 0; pState->Gamepad.sThumbLY = 0; pState->Gamepad.sThumbRX = 0; pState->Gamepad.sThumbRY = 0; // timestamp packet pState->dwPacketNumber = GetTickCount(); // --- Map POV to the D-pad --- if (m_mapping.DpadPOV > 0 && m_mapping.PovIsButton == false) { //INT pov = POVState(m_mapping.DpadPOV,dwUserIndex,Gamepad[dwUserIndex].povrotation); int povdeg = m_state.rgdwPOV[m_mapping.DpadPOV - 1]; if (povdeg >= 0) { // Up-left, up, up-right, up (at 360 degrees) if (IN_RANGE2(povdeg, m_mapping.pov[Config::DPAD_LEFT] + 1, m_mapping.pov[Config::DPAD_UP]) || IN_RANGE2(povdeg, 0, m_mapping.pov[Config::DPAD_RIGHT] - 1)) pState->Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_UP; // Up-right, right, down-right if (IN_RANGE(povdeg, 0, m_mapping.pov[Config::DPAD_DOWN])) pState->Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; // Down-right, down, down-left if (IN_RANGE(povdeg, m_mapping.pov[Config::DPAD_RIGHT], m_mapping.pov[Config::DPAD_LEFT])) pState->Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; // Down-left, left, up-left if (IN_RANGE(povdeg, m_mapping.pov[Config::DPAD_DOWN], m_mapping.pov[Config::DPAD_UP])) pState->Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; } } else if (m_mapping.PovIsButton == true) { for (int i = 0; i < _countof(m_mapping.pov); ++i) { if (ButtonPressed(m_mapping.pov[i])) { pState->Gamepad.wButtons |= Config::povIDs[i]; } } } // Created so we can refer to each axis with an ID s32 axis[] = { m_state.lX, m_state.lY, m_state.lZ, m_state.lRx, m_state.lRy, m_state.lRz }; s32 slider[] = { m_state.rglSlider[0], m_state.rglSlider[1] }; // --- Map buttons --- if (ButtonPressed(m_mapping.guide)) pState->Gamepad.wButtons |= 0x400; for (u32 i = 0; i < _countof(m_mapping.Button); ++i) { // Skip invalid mappings if (m_mapping.Button[i].id == 0) continue; Config::MappingType buttonType = m_mapping.Button[i].type; if (buttonType == Config::DIGITAL) { if (ButtonPressed(m_mapping.Button[i].id -1)) pState->Gamepad.wButtons |= Config::buttonIDs[i]; } else { s32 *values; switch (buttonType) { case Config::AXIS: case Config::HAXIS: case Config::CBUT: values = axis; break; case Config::SLIDER: case Config::HSLIDER: values = slider; break; default: values = axis; break; } s32 v = 0; if (m_mapping.Button[i].id > 0) { v = values[m_mapping.Button[i].id - 1]; } else if (m_mapping.Button[i].id < 0) { v = -values[-m_mapping.Button[i].id - 1] - 1; } s32 v2 = 0; s32 offset = 0; s32 scaling = 1; switch (buttonType) { // Full range case Config::AXIS: case Config::SLIDER: scaling = 255; offset = 32767; break; // Half range case Config::HAXIS: case Config::HSLIDER: case Config::CBUT: scaling = 127; offset = 0; break; default: scaling = 1; offset = 0; break; } v2 = (offset + v) / scaling; if (deadzone(v2, 0, 1, m_mapping.Button[i].buttondz, 1) > 0) { pState->Gamepad.wButtons |= Config::buttonIDs[i]; } } } // --- Map triggers --- u8 *targetTrigger[] = { &pState->Gamepad.bLeftTrigger, &pState->Gamepad.bRightTrigger }; for (u32 i = 0; i < _countof(m_mapping.Trigger); ++i) { // Skip invalid mappings if (m_mapping.Trigger[i].id == 0) continue; Config::MappingType triggerType = m_mapping.Trigger[i].type; if (triggerType == Config::DIGITAL) { if (ButtonPressed(m_mapping.Trigger[i].id - 1))*(targetTrigger[i]) = 255; } else { s32 *values; switch (triggerType) { case Config::AXIS: case Config::HAXIS: case Config::CBUT: values = axis; break; case Config::SLIDER: case Config::HSLIDER: values = slider; break; default: values = axis; break; } s32 v = 0; if (m_mapping.Trigger[i].id > 0) { v = values[m_mapping.Trigger[i].id - 1]; } else if (m_mapping.Trigger[i].id < 0) { v = -values[-m_mapping.Trigger[i].id - 1] - 1; } /* FIXME: axis negative max should be -32768 --- v is the full range (-32768 .. +32767) that should be projected to 0...255 --- Full ranges AXIS: ( 0 to 255 from -32768 to 32767) using axis SLIDER: ( 0 to 255 from -32768 to 32767) using slider ------------------------------------------------------------------------------ --- Half ranges HAXIS: ( 0 to 255 from 0 to 32767) using axis HSLIDER: ( 0 to 255 from 0 to 32767) using slider */ s32 v2 = 0; s32 offset = 0; s32 scaling = 1; switch (triggerType) { // Full range case Config::AXIS: case Config::SLIDER: scaling = 255; offset = 32767; break; // Half range case Config::HAXIS: case Config::HSLIDER: case Config::CBUT: // add ///////////////////////////////////////////////////////// scaling = 127; offset = 0; break; default: scaling = 1; offset = 0; break; } //v2 = (v + offset) / scaling; // Add deadzones //*(targetTrigger[i]) = (BYTE) deadzone(v2, 0, 255, pController->triggerdz, 255); ///////////////////////////////////////////////////////////////////////////////////////// if (triggerType == Config::CBUT) { if (ButtonPressed(m_mapping.Trigger[0].but) && ButtonPressed(m_mapping.Trigger[1].but)) { *(targetTrigger[0]) = 255; *(targetTrigger[1]) = 255; } if (ButtonPressed(m_mapping.Trigger[0].but) && !ButtonPressed(m_mapping.Trigger[1].but)) { v2 = (offset - v) / scaling; *(targetTrigger[0]) = 255; *(targetTrigger[1]) = 255 - (u8)deadzone(v2, 0, 255, m_mapping.Trigger[1].triggerdz, 255); } if (!ButtonPressed(m_mapping.Trigger[0].but) && ButtonPressed(m_mapping.Trigger[1].but)) { v2 = (offset + v) / scaling; *(targetTrigger[0]) = 255 - (u8)deadzone(v2, 0, 255, m_mapping.Trigger[0].triggerdz, 255); *(targetTrigger[1]) = 255; } if (!ButtonPressed(m_mapping.Trigger[0].but) && !ButtonPressed(m_mapping.Trigger[1].but)) { v2 = (offset + v) / scaling; *(targetTrigger[i]) = (u8)deadzone(v2, 0, 255, m_mapping.Trigger[i].triggerdz, 255); } } else { v2 = (offset + v) / scaling; *(targetTrigger[i]) = (u8)deadzone(v2, 0, 255, m_mapping.Trigger[i].triggerdz, 255); } ///////////////////////////////////////////////////////////////////////////////////////// } } // --- Map thumbsticks --- // Created so we can refer to each axis with an ID SHORT *targetAxis[4] = { &pState->Gamepad.sThumbLX, &pState->Gamepad.sThumbLY, &pState->Gamepad.sThumbRX, &pState->Gamepad.sThumbRY }; for (u32 i = 0; i < _countof(m_mapping.Axis); ++i) { if (m_mapping.Axis[i].axistodpad == 0) { // Skip invalid mappings if (m_mapping.Axis[i].id != 0) { u32 index = std::abs(m_mapping.Axis[i].id) - 1; s32 value = axis[index]; // Analog input if (m_mapping.Axis[i].analogType == Config::AXIS) value = axis[index]; if (m_mapping.Axis[i].analogType == Config::SLIDER) value = slider[index]; if (m_mapping.Axis[i].analogType != Config::NONE) { // [ 32768 steps | 32768 steps ] // DInput [ 0 32767 | 32768 65535 ] // XInput [ 32768 -1 | 0 32767 ] // //int xInput = dInputValue; s32 xInput = value; s32 deadZone = (s32)m_mapping.Axis[i].axisdeadzone; s32 antiDeadZone = (s32)m_mapping.Axis[i].antideadzone; s32 linear = (s32)m_mapping.Axis[i].axislinear; s32 min = -32768; s32 max = 32767; bool invert = m_mapping.Axis[i].id < 0; // If axis should be inverted, convert [-32768;32767] -> [32767;-32768] if (invert) xInput = -1 - xInput; // The following sections expect xInput values in range [0;32767] // So, convert to positive: [-32768;-1] -> [32767;0] bool negative = xInput < 0; if (negative) xInput = -1 - xInput; // If deadzone value is set then... if (deadZone > 0) { if (xInput > deadZone) { // [deadZone;32767] => [0;32767]; xInput = (s32)((float)(xInput - deadZone) / (float)(max - deadZone) * (float)max); } else { xInput = 0; } } // If anti-deadzone value is set then... if (antiDeadZone > 0) { if (xInput > 0) { // [0;32767] => [antiDeadZone;32767]; xInput = (s32)((float)(xInput) / (float)max * (float)(max - antiDeadZone) + antiDeadZone); } } // If linear value is set then... if (linear != 0 && xInput > 0) { // [antiDeadZone;32767] => [0;32767]; float xInputF = (float)(xInput - antiDeadZone) / (float)(max - antiDeadZone) * (float)max; float linearF = (float)linear / 100.f; xInputF = ConvertToFloat((short)xInputF); float x = -xInputF; if (linearF < 0.f) x = 1.f + x; float v = ((float)sqrt(1.f - x * x)); if (linearF < 0.f) v = 1.f - v; xInputF = xInputF + (2.f - v - xInputF - 1.f) * abs(linearF); xInput = ConvertToShort(xInputF); // [0;32767] => [antiDeadZone;32767]; xInput = (s32)((float)(xInput) / (float)max * (float)(max - antiDeadZone) + antiDeadZone); } // If originally negative, convert back: [32767;0] -> [-32768;-1] if (negative) xInput = -1 - xInput; *(targetAxis[i]) = (s16)clamp(xInput, min, max); //return (short)xInput; } } // Map axis to Button: Digital input, positive direction if (m_mapping.Axis[i].hasDigital && m_mapping.Axis[i].positiveButtonID >= 0) { if (ButtonPressed(m_mapping.Axis[i].positiveButtonID)) *(targetAxis[i]) = 32767; } // Map axis to Button: Digital input, negative direction if (m_mapping.Axis[i].hasDigital && m_mapping.Axis[i].negativeButtonID >= 0) { if (ButtonPressed(m_mapping.Axis[i].negativeButtonID)) *(targetAxis[i]) = -32768; } } else { //PrintLog("x: %d, y: %d, z: %d",Gamepad[dwUserIndex].state.lX,Gamepad[dwUserIndex].state.lY,Gamepad[dwUserIndex].state.lZ); if (m_state.lX - m_mapping.Axis[i].a2doffset > m_mapping.Axis[i].a2ddeadzone) pState->Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; if (m_state.lX - m_mapping.Axis[i].a2doffset < -m_mapping.Axis[i].a2ddeadzone) pState->Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; if (m_state.lY - m_mapping.Axis[i].a2doffset < -m_mapping.Axis[i].a2ddeadzone) pState->Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_UP; if (m_state.lY - m_mapping.Axis[i].a2doffset > m_mapping.Axis[i].a2ddeadzone) pState->Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; } } return ERROR_SUCCESS; }