From 77441c19fd77f87c8f569d3d3ceaf27cb579ef2d Mon Sep 17 00:00:00 2001 From: elasota Date: Sun, 29 Dec 2019 17:39:19 -0500 Subject: [PATCH] XInput support --- GlidePort.sln | 10 + GpApp/Externs.h | 4 + GpApp/GliderDefines.h | 6 +- GpApp/GliderStructs.h | 8 +- GpApp/Input.cpp | 111 ++++++++--- GpApp/InterfaceInit.cpp | 4 + GpApp/Main.cpp | 25 ++- GpApp/Settings.cpp | 7 + GpCommon/EGpInputDriverType.h | 8 + GpCommon/GpInputDriverProperties.h | 13 ++ GpCommon/GpVOSEvent.h | 88 +++++++++ GpCommon/IGpInputDriver.h | 2 + GpD3D/GpAppEnvironment.cpp | 18 +- GpD3D/GpAppEnvironment.h | 4 + GpD3D/GpD3D.vcxproj | 11 +- GpD3D/GpD3D.vcxproj.filters | 24 +-- GpD3D/GpDisplayDriverFactory.cpp | 8 +- GpD3D/GpDisplayDriverFactory.h | 2 +- GpD3D/GpGlobalConfig.h | 8 +- GpD3D/GpInputDriverFactory.cpp | 23 +++ GpD3D/GpInputDriverFactory.h | 18 ++ GpD3D/GpMain.cpp | 38 +++- GpD3D/GpMain_Win32.cpp | 13 ++ GpInputDriver_XInput/GpInputDriverXInput.cpp | 183 ++++++++++++++++++ GpInputDriver_XInput/GpInputDriverXInput.h | 32 +++ .../GpInputDriver_XInput.vcxproj | 130 +++++++++++++ .../GpInputDriver_XInput.vcxproj.filters | 27 +++ PortabilityLayer/InputManager.cpp | 33 +++- PortabilityLayer/InputManager.h | 7 +- PortabilityLayer/PLCore.cpp | 31 ++- PortabilityLayer/PLKeyEncoding.h | 36 ++-- 31 files changed, 856 insertions(+), 76 deletions(-) create mode 100644 GpCommon/EGpInputDriverType.h create mode 100644 GpCommon/GpInputDriverProperties.h create mode 100644 GpD3D/GpInputDriverFactory.cpp create mode 100644 GpD3D/GpInputDriverFactory.h create mode 100644 GpInputDriver_XInput/GpInputDriverXInput.cpp create mode 100644 GpInputDriver_XInput/GpInputDriverXInput.h create mode 100644 GpInputDriver_XInput/GpInputDriver_XInput.vcxproj create mode 100644 GpInputDriver_XInput/GpInputDriver_XInput.vcxproj.filters diff --git a/GlidePort.sln b/GlidePort.sln index f078dfc..7baaef6 100644 --- a/GlidePort.sln +++ b/GlidePort.sln @@ -31,6 +31,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GpDisplayDriver_D3D11", "Gp EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImportCharSet", "ImportCharSet\ImportCharSet.vcxproj", "{B3D152CB-CD52-4CD6-9213-710ADE1B8EB0}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GpInputDriver_XInput", "GpInputDriver_XInput\GpInputDriver_XInput.vcxproj", "{17B96F07-EF92-47CD-95A5-8E6EE38AB564}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -151,6 +153,14 @@ Global {B3D152CB-CD52-4CD6-9213-710ADE1B8EB0}.Release|x64.Build.0 = Release|x64 {B3D152CB-CD52-4CD6-9213-710ADE1B8EB0}.Release|x86.ActiveCfg = Release|Win32 {B3D152CB-CD52-4CD6-9213-710ADE1B8EB0}.Release|x86.Build.0 = Release|Win32 + {17B96F07-EF92-47CD-95A5-8E6EE38AB564}.Debug|x64.ActiveCfg = Debug|x64 + {17B96F07-EF92-47CD-95A5-8E6EE38AB564}.Debug|x64.Build.0 = Debug|x64 + {17B96F07-EF92-47CD-95A5-8E6EE38AB564}.Debug|x86.ActiveCfg = Debug|Win32 + {17B96F07-EF92-47CD-95A5-8E6EE38AB564}.Debug|x86.Build.0 = Debug|Win32 + {17B96F07-EF92-47CD-95A5-8E6EE38AB564}.Release|x64.ActiveCfg = Release|x64 + {17B96F07-EF92-47CD-95A5-8E6EE38AB564}.Release|x64.Build.0 = Release|x64 + {17B96F07-EF92-47CD-95A5-8E6EE38AB564}.Release|x86.ActiveCfg = Release|Win32 + {17B96F07-EF92-47CD-95A5-8E6EE38AB564}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/GpApp/Externs.h b/GpApp/Externs.h index 06fede8..f6b8a27 100644 --- a/GpApp/Externs.h +++ b/GpApp/Externs.h @@ -89,6 +89,10 @@ typedef struct // long encrypted, fakeLong; long wasLeftMap, wasRightMap; long wasBattMap, wasBandMap; + long wasGPLeftMap, wasGPRightMap; + long wasGPBattMap, wasGPBandMap; + long wasGPFlipMap; + long wasGPFaceLeftMap, wasGPFaceRightMap; short wasVolume; short prefVersion; short wasMaxFiles; diff --git a/GpApp/GliderDefines.h b/GpApp/GliderDefines.h index 175eb3d..c389e76 100644 --- a/GpApp/GliderDefines.h +++ b/GpApp/GliderDefines.h @@ -551,8 +551,8 @@ #define kGliderBurningHigh 26 #define kShadowHigh 9 #define kShadowTop 306 -#define kFaceRight TRUE -#define kFaceLeft FALSE +static const Boolean kFaceRight = TRUE; // Conflicts with GP input driver +static const Boolean kFaceLeft = FALSE; // Conflicts with GP input driver #define kPlayer1 TRUE #define kPlayer2 FALSE #define kNumGliderSrcRects 31 @@ -623,3 +623,5 @@ #define kScoreboardPictID 1997 #define kDemoLength 6702 + +#define kGamepadDeadzone 4096 // Out of 32768 diff --git a/GpApp/GliderStructs.h b/GpApp/GliderStructs.h index 2f5fc1f..7b6b132 100644 --- a/GpApp/GliderStructs.h +++ b/GpApp/GliderStructs.h @@ -6,7 +6,7 @@ #include "PLQDOffscreen.h" - +#include "GpVOSEvent.h" typedef struct { @@ -208,6 +208,10 @@ typedef struct Rect clip, enteredRect; Int32 leftKey, rightKey; Int32 battKey, bandKey; + Int32 gamepadLeftKey, gamepadRightKey; + Int32 gamepadBattKey, gamepadBandKey; + Int32 gamepadFlipKey; + Int32 gamepadFaceLeftKey, gamepadFaceRightKey; short hVel, vVel; short wasHVel, wasVVel; short vDesiredVel, hDesiredVel; @@ -215,7 +219,7 @@ typedef struct Boolean facing, tipped; Boolean sliding, ignoreLeft, ignoreRight; Boolean fireHeld, which; - Boolean heldLeft, heldRight; + Boolean heldLeft, heldRight, heldFlip; Boolean dontDraw, ignoreGround; } gliderType, *gliderPtr; diff --git a/GpApp/Input.cpp b/GpApp/Input.cpp index 881e77a..7ebc4f1 100644 --- a/GpApp/Input.cpp +++ b/GpApp/Input.cpp @@ -9,6 +9,7 @@ #include "PLDialogs.h" #include "PLKeyEncoding.h" #include "Externs.h" +#include "InputManager.h" #include "MainWindow.h" #include "RectUtils.h" @@ -197,10 +198,14 @@ void DoHeliumEngaged (gliderPtr thisGlider) #if BUILD_ARCADE_VERSION - if ((BitTst(theKeys, thisGlider->leftKey)) || - (BitTst(theKeys, thisGlider->rightKey)) || - (BitTst(theKeys, thisGlider->battKey)) || - (BitTst(theKeys, thisGlider->bandKey))) + if ((BitTst(theKeys, thisGlider->leftKey)) || + (BitTst(theKeys, thisGlider->gamepadLeftKey)) || + (BitTst(theKeys, thisGlider->rightKey)) || + (BitTst(theKeys, thisGlider->gamepadRightKey)) || + (BitTst(theKeys, thisGlider->battKey)) || + (BitTst(theKeys, thisGlider->gamepadBattKey)) || + (BitTst(theKeys, thisGlider->bandKey)) || + (BitTst(theKeys, thisGlider->gamepadBandKey))) { playing = false; paused = false; @@ -302,38 +307,96 @@ void GetInput (gliderPtr thisGlider) } else { + bool continuousFlipState = false; + bool holdFlipState = false; + bool leftState = false; + bool rightState = false; + + if (BitTst(theKeys, thisGlider->rightKey) || BitTst(theKeys, thisGlider->gamepadRightKey)) // right key + { + PL_NotYetImplemented_TODO("FixDemo"); // Flips aren't recorded in the demo properly + + if (BitTst(theKeys, thisGlider->leftKey) || BitTst(theKeys, thisGlider->gamepadLeftKey)) + continuousFlipState = true; + else + rightState = true; + } + else if (BitTst(theKeys, thisGlider->leftKey) || BitTst(theKeys, thisGlider->gamepadLeftKey)) // left key + leftState = true; + else + thisGlider->tipped = false; + + if (BitTst(theKeys, thisGlider->gamepadRightKey)) + rightState = true; + + if (BitTst(theKeys, thisGlider->gamepadLeftKey)) + leftState = true; + + if (BitTst(theKeys, thisGlider->gamepadFaceLeftKey) && thisGlider->facing == kFaceRight) + continuousFlipState = true; + + if (BitTst(theKeys, thisGlider->gamepadFaceRightKey) && thisGlider->facing == kFaceLeft) + continuousFlipState = true; + + if (BitTst(theKeys, thisGlider->gamepadFlipKey)) + holdFlipState = true; + + if (thisGlider->which == kPlayer1 || thisGlider->which == kPlayer2) + { + unsigned int playerNum = 0; + if (thisGlider->which == kPlayer1) + playerNum = 0; + else if (thisGlider->which == kPlayer2) + playerNum = 1; + + int16_t inputAxis = PortabilityLayer::InputManager::GetInstance()->GetGamepadAxis(playerNum, GpGamepadAxes::kLeftStickX); + if (inputAxis <= -kGamepadDeadzone) + leftState = true; + else if (inputAxis >= kGamepadDeadzone) + rightState = true; + } + + // gamepad flip key + //if (BitTst(theKeys, thisGlider->gamepadFlipKey)) + // holdFlipState = true; + thisGlider->heldLeft = false; thisGlider->heldRight = false; - if (BitTst(theKeys, thisGlider->rightKey)) // right key + if (continuousFlipState) { - #ifdef CREATEDEMODATA - LogDemoKey(0); - #endif - if (BitTst(theKeys, thisGlider->leftKey)) + leftState = false; + rightState = false; + ToggleGliderFacing(thisGlider); + } + else if (holdFlipState) + { + if (!thisGlider->heldFlip) { ToggleGliderFacing(thisGlider); - thisGlider->heldLeft = true; - } - else - { - thisGlider->hDesiredVel += kNormalThrust; - thisGlider->tipped = (thisGlider->facing == kFaceLeft); - thisGlider->heldRight = true; + thisGlider->heldFlip = true; } } - else if (BitTst(theKeys, thisGlider->leftKey)) // left key + else + thisGlider->heldFlip = false; + + if (rightState && !leftState) + { + thisGlider->hDesiredVel += kNormalThrust; + thisGlider->tipped = (thisGlider->facing == kFaceLeft); + thisGlider->heldRight = true; + } + + if (leftState && !rightState) { - #ifdef CREATEDEMODATA - LogDemoKey(1); - #endif thisGlider->hDesiredVel -= kNormalThrust; thisGlider->tipped = (thisGlider->facing == kFaceRight); thisGlider->heldLeft = true; } - else + + if (!leftState && !rightState) thisGlider->tipped = false; - - if ((BitTst(theKeys, thisGlider->battKey)) && (batteryTotal != 0) && + + if ((BitTst(theKeys, thisGlider->battKey) || BitTst(theKeys, thisGlider->gamepadBattKey)) && (batteryTotal != 0) && (thisGlider->mode == kGliderNormal)) { #ifdef CREATEDEMODATA @@ -347,7 +410,7 @@ void GetInput (gliderPtr thisGlider) else batteryWasEngaged = false; - if ((BitTst(theKeys, thisGlider->bandKey)) && (bandsTotal > 0) && + if ((BitTst(theKeys, thisGlider->bandKey) || BitTst(theKeys, thisGlider->gamepadBandKey)) && (bandsTotal > 0) && (thisGlider->mode == kGliderNormal)) { #ifdef CREATEDEMODATA diff --git a/GpApp/InterfaceInit.cpp b/GpApp/InterfaceInit.cpp index 50d44d2..ad0ed24 100644 --- a/GpApp/InterfaceInit.cpp +++ b/GpApp/InterfaceInit.cpp @@ -140,6 +140,10 @@ void VariableInit (void) theGlider2.rightKey = PL_KEY_ASCII('D'); theGlider2.battKey = PL_KEY_ASCII('S'); theGlider2.bandKey = PL_KEY_ASCII('W'); + theGlider2.gamepadLeftKey = PL_KEY_GAMEPAD_BUTTON(kDPadLeft, 1); + theGlider2.gamepadRightKey = PL_KEY_GAMEPAD_BUTTON(kDPadRight, 1); + theGlider2.gamepadBandKey = PL_KEY_GAMEPAD_BUTTON(kFaceDown, 1); + theGlider2.gamepadBattKey = PL_KEY_GAMEPAD_BUTTON(kFaceLeft, 1); theGlider2.which = kPlayer2; theMode = kSplashMode; diff --git a/GpApp/Main.cpp b/GpApp/Main.cpp index 01fa2ef..f139aae 100644 --- a/GpApp/Main.cpp +++ b/GpApp/Main.cpp @@ -14,7 +14,7 @@ #include "House.h" -#define kPrefsVersion 0x0034 +#define kPrefsVersion 0x0035 void ReadInPrefs (void); @@ -72,6 +72,13 @@ void ReadInPrefs (void) theGlider.rightKey = thePrefs.wasRightMap; theGlider.battKey = thePrefs.wasBattMap; theGlider.bandKey = thePrefs.wasBandMap; + theGlider.gamepadLeftKey = thePrefs.wasGPLeftMap; + theGlider.gamepadRightKey = thePrefs.wasGPRightMap; + theGlider.gamepadBandKey = thePrefs.wasGPBandMap; + theGlider.gamepadBattKey = thePrefs.wasGPBattMap; + theGlider.gamepadFlipKey = thePrefs.wasGPFlipMap; + theGlider.gamepadFaceRightKey = thePrefs.wasGPFaceRightMap; + theGlider.gamepadFaceLeftKey = thePrefs.wasGPFaceLeftMap; #ifndef COMPILEDEMO #ifndef COMPILENOCP encryptedNumber = thePrefs.encrypted; @@ -138,7 +145,14 @@ void ReadInPrefs (void) theGlider.rightKey = PL_KEY_SPECIAL(kRightArrow); theGlider.battKey = PL_KEY_SPECIAL(kDownArrow); theGlider.bandKey = PL_KEY_SPECIAL(kUpArrow); - + theGlider.gamepadLeftKey = PL_KEY_GAMEPAD_BUTTON(kDPadLeft, 0); + theGlider.gamepadRightKey = PL_KEY_GAMEPAD_BUTTON(kDPadRight, 0); + theGlider.gamepadBandKey = PL_KEY_GAMEPAD_BUTTON(kFaceDown, 0); + theGlider.gamepadBattKey = PL_KEY_GAMEPAD_BUTTON(kFaceLeft, 0); + theGlider.gamepadFlipKey = PL_KEY_GAMEPAD_BUTTON(kFaceUp, 0); + theGlider.gamepadFaceRightKey = PL_KEY_GAMEPAD_BUTTON(kRightBumper, 0); + theGlider.gamepadFaceLeftKey = PL_KEY_GAMEPAD_BUTTON(kLeftBumper, 0); + UnivGetSoundVolume(&isVolume, thisMac.hasSM3); if (isVolume < 1) isVolume = 1; @@ -228,6 +242,13 @@ void WriteOutPrefs (void) thePrefs.wasRightMap = theGlider.rightKey; thePrefs.wasBattMap = theGlider.battKey; thePrefs.wasBandMap = theGlider.bandKey; + thePrefs.wasGPLeftMap = theGlider.gamepadLeftKey; + thePrefs.wasGPRightMap = theGlider.gamepadRightKey; + thePrefs.wasGPBattMap = theGlider.gamepadBattKey; + thePrefs.wasGPBandMap = theGlider.gamepadBandKey; + thePrefs.wasGPFlipMap = theGlider.gamepadFlipKey; + thePrefs.wasGPFaceLeftMap = theGlider.gamepadFaceLeftKey; + thePrefs.wasGPFaceRightMap = theGlider.gamepadFaceRightKey; #ifndef COMPILEDEMO #ifndef COMPILENOCP thePrefs.encrypted = encryptedNumber; diff --git a/GpApp/Settings.cpp b/GpApp/Settings.cpp index 194af68..defff8b 100644 --- a/GpApp/Settings.cpp +++ b/GpApp/Settings.cpp @@ -1225,6 +1225,13 @@ void SetAllDefaults (void) theGlider.rightKey = PL_KEY_SPECIAL(kRightArrow); theGlider.battKey = PL_KEY_SPECIAL(kDownArrow); theGlider.bandKey = PL_KEY_SPECIAL(kUpArrow); + theGlider.gamepadLeftKey = PL_KEY_GAMEPAD_BUTTON(kDPadLeft, 0); + theGlider.gamepadRightKey = PL_KEY_GAMEPAD_BUTTON(kDPadRight, 0); + theGlider.gamepadBandKey = PL_KEY_GAMEPAD_BUTTON(kFaceDown, 0); + theGlider.gamepadBattKey = PL_KEY_GAMEPAD_BUTTON(kFaceLeft, 0); + theGlider.gamepadFlipKey = PL_KEY_GAMEPAD_BUTTON(kFaceUp, 0); + theGlider.gamepadFaceRightKey = PL_KEY_GAMEPAD_BUTTON(kRightBumper, 0); + theGlider.gamepadFaceLeftKey = PL_KEY_GAMEPAD_BUTTON(kLeftBumper, 0); isEscPauseKey = false; // Default sound settings isPlayMusicIdle = true; diff --git a/GpCommon/EGpInputDriverType.h b/GpCommon/EGpInputDriverType.h new file mode 100644 index 0000000..d9f9099 --- /dev/null +++ b/GpCommon/EGpInputDriverType.h @@ -0,0 +1,8 @@ +#pragma once + +enum EGpInputDriverType +{ + EGpInputDriverType_XInput, + + EGpInputDriverType_Count, +}; diff --git a/GpCommon/GpInputDriverProperties.h b/GpCommon/GpInputDriverProperties.h new file mode 100644 index 0000000..0e13548 --- /dev/null +++ b/GpCommon/GpInputDriverProperties.h @@ -0,0 +1,13 @@ +#pragma once + +#include "EGpInputDriverType.h" + +struct IGpAudioDriver; +struct IGpVOSEventQueue; + +struct GpInputDriverProperties +{ + EGpInputDriverType m_type; + + IGpVOSEventQueue *m_eventQueue; +}; diff --git a/GpCommon/GpVOSEvent.h b/GpCommon/GpVOSEvent.h index 89df554..7c7ac4c 100644 --- a/GpCommon/GpVOSEvent.h +++ b/GpCommon/GpVOSEvent.h @@ -21,11 +21,62 @@ namespace GpKeyIDSubsets kNumPadNumber, kNumPadSpecial, kFKey, // Key value is a raw F number + kGamepadButton, + + kCount, }; } typedef GpKeyIDSubsets::GpKeyIDSubset GpKeyIDSubset_t; +namespace GpGamepadButtons +{ + enum GpGamepadButton + { + kDPadUp, + kDPadDown, + kDPadLeft, + kDPadRight, + + kFaceUp, + kFaceDown, + kFaceLeft, + kFaceRight, + + kLeftStick, + kRightStick, + + kLeftBumper, + kRightBumper, + + kMisc1, + kMisc2, + + kCount, + }; +} + +typedef GpGamepadButtons::GpGamepadButton GpGamepadButton_t; + +namespace GpGamepadAxes +{ + enum GpGamepadAxis + { + kLeftStickX, + kLeftStickY, + + kRightStickX, + kRightStickY, + + kLeftTrigger, + kRightTrigger, + + kCount, + }; +} + +typedef GpGamepadAxes::GpGamepadAxis GpGamepadAxis_t; + namespace GpKeySpecials { enum GpKeySpecial @@ -90,6 +141,22 @@ namespace GpKeyboardInputEventTypes typedef GpKeyboardInputEventTypes::GpKeyboardInputEventType GpKeyboardInputEventType_t; +namespace GpGamepadInputEventTypes +{ + enum GpGamepadInputEventType + { + kAnalogAxisChanged, + }; +} + +typedef GpGamepadInputEventTypes::GpGamepadInputEventType GpGamepadInputEventTypes_t; + +struct GpGamepadButtonAndPlayer +{ + GpGamepadButton_t m_button; + uint8_t m_player; +}; + struct GpKeyboardInputEvent { union KeyUnion @@ -100,6 +167,7 @@ struct GpKeyboardInputEvent char m_asciiChar; uint32_t m_unicodeChar; unsigned char m_fKey; + GpGamepadButtonAndPlayer m_gamepadKey; }; GpKeyboardInputEventType_t m_eventType; @@ -107,6 +175,24 @@ struct GpKeyboardInputEvent KeyUnion m_key; }; +struct GpGamepadAnalogAxisEvent +{ + GpGamepadAxis_t m_axis; + int16_t m_state; // Ranges from -32767 to 32767, is never -32768 + uint8_t m_player; +}; + +struct GpGamepadInputEvent +{ + union EventUnion + { + GpGamepadAnalogAxisEvent m_analogAxisEvent; + }; + + GpGamepadInputEventTypes_t m_eventType; + EventUnion m_event; +}; + namespace GpMouseEventTypes { enum GpMouseEventType @@ -149,6 +235,7 @@ namespace GpVOSEventTypes { kKeyboardInput, kMouseInput, + kGamepadInput, }; } @@ -160,6 +247,7 @@ struct GpVOSEvent { GpKeyboardInputEvent m_keyboardInputEvent; GpMouseInputEvent m_mouseInputEvent; + GpGamepadInputEvent m_gamepadInputEvent; }; EventUnion m_event; diff --git a/GpCommon/IGpInputDriver.h b/GpCommon/IGpInputDriver.h index cc97dc1..6480331 100644 --- a/GpCommon/IGpInputDriver.h +++ b/GpCommon/IGpInputDriver.h @@ -2,4 +2,6 @@ struct IGpInputDriver { + virtual void ProcessInput() = 0; + virtual void Shutdown() = 0; }; diff --git a/GpD3D/GpAppEnvironment.cpp b/GpD3D/GpAppEnvironment.cpp index cebd152..c5f225d 100644 --- a/GpD3D/GpAppEnvironment.cpp +++ b/GpD3D/GpAppEnvironment.cpp @@ -6,6 +6,7 @@ #include "GpPLGlueDisplayDriver.h" #include "HostSuspendCallArgument.h" #include "IGpFiber.h" +#include "IGpInputDriver.h" #include @@ -13,6 +14,8 @@ GpAppEnvironment::GpAppEnvironment() : m_applicationState(ApplicationState_NotStarted) , m_displayDriver(nullptr) , m_audioDriver(nullptr) + , m_inputDrivers(nullptr) + , m_numInputDrivers(0) , m_fontHandler(nullptr) , m_vosEventQueue(nullptr) , m_applicationFiber(nullptr) @@ -53,6 +56,7 @@ void GpAppEnvironment::Tick(IGpFiber *vosFiber) case ApplicationState_WaitingForEvents: return; case ApplicationState_Running: + SynchronizeState(); m_applicationFiber->YieldTo(); break; case ApplicationState_SystemCall: @@ -96,6 +100,12 @@ void GpAppEnvironment::SetAudioDriver(IGpAudioDriver *audioDriver) m_audioDriver = audioDriver; } +void GpAppEnvironment::SetInputDrivers(IGpInputDriver *const* inputDrivers, size_t numDrivers) +{ + m_inputDrivers = inputDrivers; + m_numInputDrivers = numDrivers; +} + void GpAppEnvironment::SetFontHandler(PortabilityLayer::HostFontHandler *fontHandler) { m_fontHandler = fontHandler; @@ -125,13 +135,15 @@ void GpAppEnvironment::InitializeApplicationState() GpAppInterface_Get()->PL_HostFontHandler_SetInstance(m_fontHandler); GpAppInterface_Get()->PL_HostVOSEventQueue_SetInstance(m_vosEventQueue); - SynchronizeState(); + GpPLGlueDisplayDriver::GetInstance()->SetGpDisplayDriver(m_displayDriver); + GpPLGlueAudioDriver::GetInstance()->SetGpAudioDriver(m_audioDriver); } void GpAppEnvironment::SynchronizeState() { - GpPLGlueDisplayDriver::GetInstance()->SetGpDisplayDriver(m_displayDriver); - GpPLGlueAudioDriver::GetInstance()->SetGpAudioDriver(m_audioDriver); + const size_t numInputDrivers = m_numInputDrivers; + for (size_t i = 0; i < numInputDrivers; i++) + m_inputDrivers[i]->ProcessInput(); } void GpAppEnvironment::StaticSuspendHookFunc(void *context, PortabilityLayer::HostSuspendCallID callID, const PortabilityLayer::HostSuspendCallArgument *args, PortabilityLayer::HostSuspendCallArgument *returnValue) diff --git a/GpD3D/GpAppEnvironment.h b/GpD3D/GpAppEnvironment.h index 417927f..5444336 100644 --- a/GpD3D/GpAppEnvironment.h +++ b/GpD3D/GpAppEnvironment.h @@ -14,6 +14,7 @@ namespace PortabilityLayer struct IGpDisplayDriver; struct IGpAudioDriver; +struct IGpInputDriver; struct IGpFiber; class GpAppEnvironment @@ -29,6 +30,7 @@ public: void SetDisplayDriver(IGpDisplayDriver *displayDriver); void SetAudioDriver(IGpAudioDriver *audioDriver); + void SetInputDrivers(IGpInputDriver *const* inputDrivers, size_t numDrivers); void SetFontHandler(PortabilityLayer::HostFontHandler *fontHandler); void SetVOSEventQueue(GpVOSEventQueue *eventQueue); @@ -54,12 +56,14 @@ private: ApplicationState m_applicationState; IGpDisplayDriver *m_displayDriver; IGpAudioDriver *m_audioDriver; + IGpInputDriver *const* m_inputDrivers; PortabilityLayer::HostFontHandler *m_fontHandler; GpVOSEventQueue *m_vosEventQueue; IGpFiber *m_applicationFiber; IGpFiber *m_vosFiber; uint32_t m_delaySuspendTicks; + size_t m_numInputDrivers; PortabilityLayer::HostSuspendCallID m_suspendCallID; const PortabilityLayer::HostSuspendCallArgument *m_suspendArgs; diff --git a/GpD3D/GpD3D.vcxproj b/GpD3D/GpD3D.vcxproj index b154c77..a0b56eb 100644 --- a/GpD3D/GpD3D.vcxproj +++ b/GpD3D/GpD3D.vcxproj @@ -153,6 +153,7 @@ + @@ -166,20 +167,18 @@ + + - - - - @@ -187,6 +186,7 @@ + @@ -217,6 +217,9 @@ {ffc961ac-55b4-4a38-a83e-06ae98f59acc} + + {17b96f07-ef92-47cd-95a5-8e6ee38ab564} + diff --git a/GpD3D/GpD3D.vcxproj.filters b/GpD3D/GpD3D.vcxproj.filters index f647b7a..77920f3 100644 --- a/GpD3D/GpD3D.vcxproj.filters +++ b/GpD3D/GpD3D.vcxproj.filters @@ -78,6 +78,9 @@ Source Files + + Source Files + @@ -92,12 +95,6 @@ Header Files - - Header Files - - - Header Files - Header Files @@ -140,12 +137,6 @@ Header Files - - Header Files - - - Header Files - Header Files @@ -191,6 +182,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + diff --git a/GpD3D/GpDisplayDriverFactory.cpp b/GpD3D/GpDisplayDriverFactory.cpp index f196225..b3ed350 100644 --- a/GpD3D/GpDisplayDriverFactory.cpp +++ b/GpD3D/GpDisplayDriverFactory.cpp @@ -7,8 +7,8 @@ IGpDisplayDriver *GpDisplayDriverFactory::CreateDisplayDriver(const GpDisplayDri { assert(properties.m_type < EGpDisplayDriverType_Count); - if (ms_Registry[properties.m_type]) - return ms_Registry[properties.m_type](properties); + if (ms_registry[properties.m_type]) + return ms_registry[properties.m_type](properties); else return nullptr; } @@ -17,7 +17,7 @@ void GpDisplayDriverFactory::RegisterDisplayDriverFactory(EGpDisplayDriverType t { assert(type < EGpDisplayDriverType_Count); - ms_Registry[type] = func; + ms_registry[type] = func; } -GpDisplayDriverFactory::FactoryFunc_t GpDisplayDriverFactory::ms_Registry[EGpDisplayDriverType_Count]; +GpDisplayDriverFactory::FactoryFunc_t GpDisplayDriverFactory::ms_registry[EGpDisplayDriverType_Count]; diff --git a/GpD3D/GpDisplayDriverFactory.h b/GpD3D/GpDisplayDriverFactory.h index 09e6c2d..ceb37b1 100644 --- a/GpD3D/GpDisplayDriverFactory.h +++ b/GpD3D/GpDisplayDriverFactory.h @@ -14,5 +14,5 @@ public: static void RegisterDisplayDriverFactory(EGpDisplayDriverType type, FactoryFunc_t func); private: - static FactoryFunc_t ms_Registry[EGpDisplayDriverType_Count]; + static FactoryFunc_t ms_registry[EGpDisplayDriverType_Count]; }; diff --git a/GpD3D/GpGlobalConfig.h b/GpD3D/GpGlobalConfig.h index bc9a990..7df0ff6 100644 --- a/GpD3D/GpGlobalConfig.h +++ b/GpD3D/GpGlobalConfig.h @@ -1,10 +1,16 @@ #pragma once -#include "EGpDisplayDriverType.h" +#include "EGpDisplayDriverType.h" +#include "EGpAudioDriverType.h" +#include "EGpInputDriverType.h" struct GpGlobalConfig { EGpDisplayDriverType m_displayDriverType; + EGpAudioDriverType m_audioDriverType; + const EGpInputDriverType *m_inputDriverTypes; + size_t m_numInputDrivers; + void *m_osGlobals; }; diff --git a/GpD3D/GpInputDriverFactory.cpp b/GpD3D/GpInputDriverFactory.cpp new file mode 100644 index 0000000..c173974 --- /dev/null +++ b/GpD3D/GpInputDriverFactory.cpp @@ -0,0 +1,23 @@ +#include "GpInputDriverFactory.h" +#include "GpInputDriverProperties.h" + +#include + +IGpInputDriver *GpInputDriverFactory::CreateInputDriver(const GpInputDriverProperties &properties) +{ + assert(properties.m_type < EGpInputDriverType_Count); + + if (ms_registry[properties.m_type]) + return ms_registry[properties.m_type](properties); + else + return nullptr; +} + +void GpInputDriverFactory::RegisterInputDriverFactory(EGpInputDriverType type, FactoryFunc_t func) +{ + assert(type < EGpInputDriverType_Count); + + ms_registry[type] = func; +} + +GpInputDriverFactory::FactoryFunc_t GpInputDriverFactory::ms_registry[EGpInputDriverType_Count]; diff --git a/GpD3D/GpInputDriverFactory.h b/GpD3D/GpInputDriverFactory.h new file mode 100644 index 0000000..53fb10d --- /dev/null +++ b/GpD3D/GpInputDriverFactory.h @@ -0,0 +1,18 @@ +#pragma once + +#include "EGpInputDriverType.h" + +struct IGpInputDriver; +struct GpInputDriverProperties; + +class GpInputDriverFactory +{ +public: + typedef IGpInputDriver *(*FactoryFunc_t)(const GpInputDriverProperties &properties); + + static IGpInputDriver *CreateInputDriver(const GpInputDriverProperties &properties); + static void RegisterInputDriverFactory(EGpInputDriverType type, FactoryFunc_t func); + +private: + static FactoryFunc_t ms_registry[EGpInputDriverType_Count]; +}; diff --git a/GpD3D/GpMain.cpp b/GpD3D/GpMain.cpp index f8b1342..3557e8b 100644 --- a/GpD3D/GpMain.cpp +++ b/GpD3D/GpMain.cpp @@ -4,12 +4,16 @@ #include "GpFontHandlerFactory.h" #include "GpDisplayDriverFactory.h" #include "GpDisplayDriverProperties.h" +#include "GpInputDriverFactory.h" +#include "GpInputDriverProperties.h" #include "GpGlobalConfig.h" #include "GpAppEnvironment.h" #include "IGpAudioDriver.h" #include "IGpDisplayDriver.h" +#include "IGpInputDriver.h" #include +#include namespace { @@ -32,8 +36,6 @@ int GpMain::Run() GpDisplayDriverProperties ddProps; memset(&ddProps, 0, sizeof(ddProps)); - ddProps.m_type = EGpDisplayDriverType_D3D11; - ddProps.m_frameTimeLockNumerator = 1; ddProps.m_frameTimeLockDenominator = 60; @@ -58,10 +60,28 @@ int GpMain::Run() // The sample rate used in all of Glider PRO's sound is 0x56ee8ba3 // This appears to be the "standard" Mac sample rate, probably rounded from 244800/11. - adProps.m_type = EGpAudioDriverType_XAudio2; + adProps.m_type = g_gpGlobalConfig.m_audioDriverType; adProps.m_sampleRate = (244800 * 2 + 11) / (11 * 2); adProps.m_debug = true; + IGpInputDriver **inputDrivers = static_cast(malloc(sizeof(IGpInputDriver*) * g_gpGlobalConfig.m_numInputDrivers)); + + size_t numCreatedInputDrivers = 0; + if (inputDrivers) + { + for (size_t i = 0; i < g_gpGlobalConfig.m_numInputDrivers; i++) + { + GpInputDriverProperties inputProps; + memset(&inputProps, 0, sizeof(inputProps)); + + inputProps.m_type = g_gpGlobalConfig.m_inputDriverTypes[i]; + inputProps.m_eventQueue = eventQueue; + + if (IGpInputDriver *driver = GpInputDriverFactory::CreateInputDriver(inputProps)) + inputDrivers[numCreatedInputDrivers++] = driver; + } + } + IGpDisplayDriver *displayDriver = GpDisplayDriverFactory::CreateDisplayDriver(ddProps); IGpAudioDriver *audioDriver = GpAudioDriverFactory::CreateAudioDriver(adProps); PortabilityLayer::HostFontHandler *fontHandler = GpFontHandlerFactory::Create(); @@ -70,11 +90,23 @@ int GpMain::Run() appEnvironment->SetDisplayDriver(displayDriver); appEnvironment->SetAudioDriver(audioDriver); + appEnvironment->SetInputDrivers(inputDrivers, numCreatedInputDrivers); appEnvironment->SetFontHandler(fontHandler); appEnvironment->SetVOSEventQueue(eventQueue); // Start the display loop displayDriver->Run(); + // Clean up + if (inputDrivers) + { + for (size_t i = 0; i < numCreatedInputDrivers; i++) + inputDrivers[i]->Shutdown(); + + free(inputDrivers); + } + + // GP TODO: Cleanup + return 0; } diff --git a/GpD3D/GpMain_Win32.cpp b/GpD3D/GpMain_Win32.cpp index 8358f76..c6dc6ed 100644 --- a/GpD3D/GpMain_Win32.cpp +++ b/GpD3D/GpMain_Win32.cpp @@ -5,6 +5,7 @@ #include "GpGlobalConfig.h" #include "GpFiber_Win32.h" #include "GpFileSystem_Win32.h" +#include "GpInputDriverFactory.h" #include "GpAppInterface.h" #include "GpSystemServices_Win32.h" #include "GpVOSEvent.h" @@ -21,6 +22,7 @@ GpWindowsGlobals g_gpWindowsGlobals; extern "C" __declspec(dllimport) IGpAudioDriver *GpDriver_CreateAudioDriver_XAudio2(const GpAudioDriverProperties &properties); extern "C" __declspec(dllimport) IGpDisplayDriver *GpDriver_CreateDisplayDriver_D3D11(const GpDisplayDriverProperties &properties); +extern "C" __declspec(dllimport) IGpInputDriver *GpDriver_CreateInputDriver_XInput(const GpInputDriverProperties &properties); static void PostMouseEvent(IGpVOSEventQueue *eventQueue, GpMouseEventType_t eventType, GpMouseButton_t button, int32_t x, int32_t y) { @@ -372,10 +374,21 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine g_gpWindowsGlobals.m_translateWindowsMessageFunc = TranslateWindowsMessage; g_gpGlobalConfig.m_displayDriverType = EGpDisplayDriverType_D3D11; + g_gpGlobalConfig.m_audioDriverType = EGpAudioDriverType_XAudio2; + + EGpInputDriverType inputDrivers[] = + { + EGpInputDriverType_XInput + }; + + g_gpGlobalConfig.m_inputDriverTypes = inputDrivers; + g_gpGlobalConfig.m_numInputDrivers = sizeof(inputDrivers) / sizeof(inputDrivers[0]); + g_gpGlobalConfig.m_osGlobals = &g_gpWindowsGlobals; GpDisplayDriverFactory::RegisterDisplayDriverFactory(EGpDisplayDriverType_D3D11, GpDriver_CreateDisplayDriver_D3D11); GpAudioDriverFactory::RegisterAudioDriverFactory(EGpAudioDriverType_XAudio2, GpDriver_CreateAudioDriver_XAudio2); + GpInputDriverFactory::RegisterInputDriverFactory(EGpInputDriverType_XInput, GpDriver_CreateInputDriver_XInput); return GpMain::Run(); } diff --git a/GpInputDriver_XInput/GpInputDriverXInput.cpp b/GpInputDriver_XInput/GpInputDriverXInput.cpp new file mode 100644 index 0000000..7b2d2b8 --- /dev/null +++ b/GpInputDriver_XInput/GpInputDriverXInput.cpp @@ -0,0 +1,183 @@ +#include "GpInputDriverXInput.h" +#include "GpVOSEvent.h" +#include "GpWindows.h" +#include "IGpVOSEventQueue.h" + +#include +#include + +#pragma comment(lib, "xinput.lib") + +void GpInputDriverXInput::ProcessInput() +{ + for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) + { + XINPUT_STATE newState; + memset(&newState, 0, sizeof(newState)); + + DWORD result = XInputGetState(i, &newState); + + if (result == ERROR_SUCCESS) + { + bool isNewState = false; + unsigned int playerNumber = 0; + if (m_xUserToPlayerNumber[i] < 0) + { + // Newly-connected player + + for (int i = 0; i < XUSER_MAX_COUNT; i++) + { + if (!m_playerNumberIsConnected[i]) + { + playerNumber = i; + break; + } + } + + m_xUserToPlayerNumber[i] = playerNumber; + m_playerNumberIsConnected[playerNumber] = true; + + isNewState = true; + } + else + { + playerNumber = m_xUserToPlayerNumber[i]; + isNewState = (newState.dwPacketNumber != m_controllerStates[i].dwPacketNumber); + } + + if (isNewState) + { + this->ProcessControllerStateChange(playerNumber, m_controllerStates[i], newState); + m_controllerStates[i] = newState; + } + } + else + { + if (m_xUserToPlayerNumber[i] >= 0) + { + // Was connected last frame, process as a blank state and then free the player slot + memset(&newState, 0, sizeof(newState)); + + const unsigned int playerNumber = m_xUserToPlayerNumber[i]; + + this->ProcessControllerStateChange(playerNumber, m_controllerStates[i], newState); + + m_controllerStates[i] = newState; + m_playerNumberIsConnected[playerNumber] = false; + m_xUserToPlayerNumber[i] = -1; + } + } + } +} + +void GpInputDriverXInput::Shutdown() +{ + this->~GpInputDriverXInput(); + free(this); +} + +GpInputDriverXInput *GpInputDriverXInput::Create(const GpInputDriverProperties &props) +{ + void *storage = malloc(sizeof(GpInputDriverXInput)); + if (!storage) + return nullptr; + + return new (storage) GpInputDriverXInput(props); +} + +GpInputDriverXInput::GpInputDriverXInput(const GpInputDriverProperties &props) + : m_properties(props) +{ + for (int i = 0; i < XUSER_MAX_COUNT; i++) + m_xUserToPlayerNumber[i] = -1; + + memset(m_controllerStates, 0, sizeof(m_controllerStates)); + memset(m_playerNumberIsConnected, 0, sizeof(m_playerNumberIsConnected)); +} + +GpInputDriverXInput::~GpInputDriverXInput() +{ +} + +void GpInputDriverXInput::ProcessControllerStateChange(unsigned int playerNumber, const XINPUT_STATE &prevState, const XINPUT_STATE &newState) +{ + const XINPUT_GAMEPAD &prevGamepad = prevState.Gamepad; + const XINPUT_GAMEPAD &newGamepad = newState.Gamepad; + + DWORD prevButtons = prevGamepad.wButtons; + DWORD newButtons = newGamepad.wButtons; + ProcessButtonStateChange(prevButtons, newButtons, XINPUT_GAMEPAD_START, playerNumber, GpGamepadButtons::kMisc1); + ProcessButtonStateChange(prevButtons, newButtons, XINPUT_GAMEPAD_BACK, playerNumber, GpGamepadButtons::kMisc2); + + ProcessButtonStateChange(prevButtons, newButtons, XINPUT_GAMEPAD_DPAD_UP, playerNumber, GpGamepadButtons::kDPadUp); + ProcessButtonStateChange(prevButtons, newButtons, XINPUT_GAMEPAD_DPAD_DOWN, playerNumber, GpGamepadButtons::kDPadDown); + ProcessButtonStateChange(prevButtons, newButtons, XINPUT_GAMEPAD_DPAD_LEFT, playerNumber, GpGamepadButtons::kDPadLeft); + ProcessButtonStateChange(prevButtons, newButtons, XINPUT_GAMEPAD_DPAD_RIGHT, playerNumber, GpGamepadButtons::kDPadRight); + + ProcessButtonStateChange(prevButtons, newButtons, XINPUT_GAMEPAD_LEFT_THUMB, playerNumber, GpGamepadButtons::kLeftStick); + ProcessButtonStateChange(prevButtons, newButtons, XINPUT_GAMEPAD_RIGHT_THUMB, playerNumber, GpGamepadButtons::kRightStick); + + ProcessButtonStateChange(prevButtons, newButtons, XINPUT_GAMEPAD_LEFT_SHOULDER, playerNumber, GpGamepadButtons::kLeftBumper); + ProcessButtonStateChange(prevButtons, newButtons, XINPUT_GAMEPAD_RIGHT_SHOULDER, playerNumber, GpGamepadButtons::kRightBumper); + + ProcessButtonStateChange(prevButtons, newButtons, XINPUT_GAMEPAD_Y, playerNumber, GpGamepadButtons::kFaceUp); + ProcessButtonStateChange(prevButtons, newButtons, XINPUT_GAMEPAD_A, playerNumber, GpGamepadButtons::kFaceDown); + ProcessButtonStateChange(prevButtons, newButtons, XINPUT_GAMEPAD_X, playerNumber, GpGamepadButtons::kFaceLeft); + ProcessButtonStateChange(prevButtons, newButtons, XINPUT_GAMEPAD_B, playerNumber, GpGamepadButtons::kFaceRight); + + ProcessAxisStateChange(ConvertTriggerValue(prevState.Gamepad.bLeftTrigger), ConvertTriggerValue(newState.Gamepad.bLeftTrigger), playerNumber, GpGamepadAxes::kLeftTrigger); + ProcessAxisStateChange(ConvertTriggerValue(prevState.Gamepad.bRightTrigger), ConvertTriggerValue(newState.Gamepad.bRightTrigger), playerNumber, GpGamepadAxes::kRightTrigger); + ProcessAxisStateChange(prevState.Gamepad.sThumbLX, newState.Gamepad.sThumbLX, playerNumber, GpGamepadAxes::kLeftStickX); + ProcessAxisStateChange(prevState.Gamepad.sThumbLY, newState.Gamepad.sThumbLY, playerNumber, GpGamepadAxes::kLeftStickY); + ProcessAxisStateChange(prevState.Gamepad.sThumbRX, newState.Gamepad.sThumbRX, playerNumber, GpGamepadAxes::kRightStickX); + ProcessAxisStateChange(prevState.Gamepad.sThumbRY, newState.Gamepad.sThumbRY, playerNumber, GpGamepadAxes::kRightStickY); +} + +void GpInputDriverXInput::ProcessButtonStateChange(DWORD prevState, DWORD newState, DWORD deltaBit, unsigned int playerNum, GpGamepadButton_t gamepadButton) +{ + DWORD deltaState = prevState ^ newState; + + if ((deltaState & deltaBit) == 0) + return; + + const GpKeyboardInputEventType_t eventType = ((prevState & deltaBit) == 0) ? GpKeyboardInputEventTypes::kDown : GpKeyboardInputEventTypes::kUp; + + if (GpVOSEvent *evt = m_properties.m_eventQueue->QueueEvent()) + { + evt->m_eventType = GpVOSEventTypes::kKeyboardInput; + evt->m_event.m_keyboardInputEvent.m_eventType = eventType; + evt->m_event.m_keyboardInputEvent.m_keyIDSubset = GpKeyIDSubsets::kGamepadButton; + evt->m_event.m_keyboardInputEvent.m_key.m_gamepadKey.m_button = gamepadButton; + evt->m_event.m_keyboardInputEvent.m_key.m_gamepadKey.m_player = playerNum; + } +} + +int16_t GpInputDriverXInput::ConvertTriggerValue(uint8_t v) +{ + return static_cast((v * 257) >> 1); +} + +void GpInputDriverXInput::ProcessAxisStateChange(int16_t prevState, int16_t newState, unsigned int playerNum, GpGamepadAxis_t gamepadAxis) +{ + if (prevState != newState) + { + if (prevState == -32768) + prevState = -32767; + if (newState == -32768) + newState = -32767; + + if (GpVOSEvent *evt = m_properties.m_eventQueue->QueueEvent()) + { + evt->m_eventType = GpVOSEventTypes::kGamepadInput; + evt->m_event.m_gamepadInputEvent.m_eventType = GpGamepadInputEventTypes::kAnalogAxisChanged; + evt->m_event.m_gamepadInputEvent.m_event.m_analogAxisEvent.m_axis = gamepadAxis; + evt->m_event.m_gamepadInputEvent.m_event.m_analogAxisEvent.m_state = newState; + evt->m_event.m_gamepadInputEvent.m_event.m_analogAxisEvent.m_player = playerNum; + } + } +} + +extern "C" __declspec(dllexport) IGpInputDriver *GpDriver_CreateInputDriver_XInput(const GpInputDriverProperties &properties) +{ + return GpInputDriverXInput::Create(properties); +} diff --git a/GpInputDriver_XInput/GpInputDriverXInput.h b/GpInputDriver_XInput/GpInputDriverXInput.h new file mode 100644 index 0000000..c0981cd --- /dev/null +++ b/GpInputDriver_XInput/GpInputDriverXInput.h @@ -0,0 +1,32 @@ +#pragma once + +#include "IGpInputDriver.h" +#include "GpInputDriverProperties.h" +#include "GpVOSEvent.h" +#include "GpWindows.h" + +#include + +class GpInputDriverXInput final : public IGpInputDriver +{ +public: + void ProcessInput() override; + void Shutdown() override; + + static GpInputDriverXInput *Create(const GpInputDriverProperties &props); + +private: + GpInputDriverXInput(const GpInputDriverProperties &props); + ~GpInputDriverXInput(); + + void ProcessControllerStateChange(unsigned int playerNumber, const XINPUT_STATE &prevState, const XINPUT_STATE &newState); + void ProcessButtonStateChange(DWORD prevState, DWORD newState, DWORD deltaBit, unsigned int playerNum, GpGamepadButton_t gamepadButton); + void ProcessAxisStateChange(int16_t prevState, int16_t newState, unsigned int playerNum, GpGamepadAxis_t gamepadAxis); + + static int16_t ConvertTriggerValue(uint8_t v); + + GpInputDriverProperties m_properties; + int m_xUserToPlayerNumber[XUSER_MAX_COUNT]; + bool m_playerNumberIsConnected[XUSER_MAX_COUNT]; + XINPUT_STATE m_controllerStates[XUSER_MAX_COUNT]; +}; diff --git a/GpInputDriver_XInput/GpInputDriver_XInput.vcxproj b/GpInputDriver_XInput/GpInputDriver_XInput.vcxproj new file mode 100644 index 0000000..60eee3c --- /dev/null +++ b/GpInputDriver_XInput/GpInputDriver_XInput.vcxproj @@ -0,0 +1,130 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {17B96F07-EF92-47CD-95A5-8E6EE38AB564} + GpInputDriverXInput + 10.0.17763.0 + + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + DynamicLibrary + true + v141 + MultiByte + + + DynamicLibrary + false + v141 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + true + true + + + + + Level3 + Disabled + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + + + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + + + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/GpInputDriver_XInput/GpInputDriver_XInput.vcxproj.filters b/GpInputDriver_XInput/GpInputDriver_XInput.vcxproj.filters new file mode 100644 index 0000000..5c73590 --- /dev/null +++ b/GpInputDriver_XInput/GpInputDriver_XInput.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/PortabilityLayer/InputManager.cpp b/PortabilityLayer/InputManager.cpp index 2780c18..694110f 100644 --- a/PortabilityLayer/InputManager.cpp +++ b/PortabilityLayer/InputManager.cpp @@ -13,13 +13,18 @@ namespace PortabilityLayer InputManagerImpl(); void GetKeys(KeyMap &keyMap) const override; - void ApplyEvent(const GpKeyboardInputEvent &vosEvent) override; + void ApplyKeyboardEvent(const GpKeyboardInputEvent &vosEvent) override; + void ApplyGamepadEvent(const GpGamepadInputEvent &vosEvent) override; + int16_t GetGamepadAxis(unsigned int playerNum, GpGamepadAxis_t gamepadAxis) override; static InputManagerImpl *GetInstance(); private: void ApplyEventAsKey(const GpKeyboardInputEvent &vosEvent, bool bit); + void ApplyAnalogAxisEvent(const GpGamepadAnalogAxisEvent &axisEvent); + KeyMap m_keyMap; + int16_t m_axisStates[PL_INPUT_MAX_PLAYERS][GpGamepadAxes::kCount]; static InputManagerImpl ms_instance; }; @@ -29,7 +34,7 @@ namespace PortabilityLayer keyMap = m_keyMap; } - void InputManagerImpl::ApplyEvent(const GpKeyboardInputEvent &vosEvent) + void InputManagerImpl::ApplyKeyboardEvent(const GpKeyboardInputEvent &vosEvent) { if (vosEvent.m_eventType == GpKeyboardInputEventTypes::kDown) ApplyEventAsKey(vosEvent, true); @@ -37,6 +42,19 @@ namespace PortabilityLayer ApplyEventAsKey(vosEvent, false); } + void InputManagerImpl::ApplyGamepadEvent(const GpGamepadInputEvent &vosEvent) + { + if (vosEvent.m_eventType == GpGamepadInputEventTypes::kAnalogAxisChanged) + ApplyAnalogAxisEvent(vosEvent.m_event.m_analogAxisEvent); + } + + int16_t InputManagerImpl::GetGamepadAxis(unsigned int playerNum, GpGamepadAxis_t gamepadAxis) + { + assert(playerNum < PL_INPUT_MAX_PLAYERS); + + return m_axisStates[playerNum][gamepadAxis]; + } + void InputManagerImpl::ApplyEventAsKey(const GpKeyboardInputEvent &vosEvent, bool bit) { switch (vosEvent.m_keyIDSubset) @@ -70,12 +88,22 @@ namespace PortabilityLayer case GpKeyIDSubsets::kFKey: m_keyMap.m_fKey.Set(vosEvent.m_key.m_fKey - 1, bit); break; + case GpKeyIDSubsets::kGamepadButton: + if (vosEvent.m_key.m_gamepadKey.m_player < PL_INPUT_MAX_PLAYERS) + m_keyMap.m_gamepadButtons[vosEvent.m_key.m_gamepadKey.m_player].Set(vosEvent.m_key.m_gamepadKey.m_button, bit); + break; default: assert(false); break; } } + void InputManagerImpl::ApplyAnalogAxisEvent(const GpGamepadAnalogAxisEvent &axisEvent) + { + if (axisEvent.m_player < PL_INPUT_MAX_PLAYERS) + m_axisStates[axisEvent.m_player][axisEvent.m_axis] = axisEvent.m_state; + } + InputManagerImpl *InputManagerImpl::GetInstance() { return &ms_instance; @@ -83,6 +111,7 @@ namespace PortabilityLayer InputManagerImpl::InputManagerImpl() { + memset(m_axisStates, 0, sizeof(m_axisStates)); } InputManagerImpl InputManagerImpl::ms_instance; diff --git a/PortabilityLayer/InputManager.h b/PortabilityLayer/InputManager.h index 09e07a8..00664bb 100644 --- a/PortabilityLayer/InputManager.h +++ b/PortabilityLayer/InputManager.h @@ -1,6 +1,9 @@ #pragma once +#include "GpVOSEvent.h" + struct GpKeyboardInputEvent; +struct GpGamepadInputEvent; struct KeyMap; namespace PortabilityLayer @@ -9,7 +12,9 @@ namespace PortabilityLayer { public: virtual void GetKeys(KeyMap &keys16) const = 0; - virtual void ApplyEvent(const GpKeyboardInputEvent &vosEvent) = 0; + virtual void ApplyKeyboardEvent(const GpKeyboardInputEvent &vosEvent) = 0; + virtual void ApplyGamepadEvent(const GpGamepadInputEvent &vosEvent) = 0; + virtual int16_t GetGamepadAxis(unsigned int playerNum, GpGamepadAxis_t gamepadAxis) = 0; static InputManager *GetInstance(); }; diff --git a/PortabilityLayer/PLCore.cpp b/PortabilityLayer/PLCore.cpp index 27ca57b..49784dc 100644 --- a/PortabilityLayer/PLCore.cpp +++ b/PortabilityLayer/PLCore.cpp @@ -98,12 +98,24 @@ static void TranslateMouseInputEvent(const GpMouseInputEvent &vosEvent, Portabil } } -static void TranslateKeyboardInputEvent(const GpKeyboardInputEvent &vosEvent, PortabilityLayer::EventQueue *queue) +static void TranslateGamepadInputEvent(const GpGamepadInputEvent &vosEvent, PortabilityLayer::EventQueue *queue) { PortabilityLayer::InputManager *inputManager = PortabilityLayer::InputManager::GetInstance(); + inputManager->ApplyGamepadEvent(vosEvent); + + PL_DEAD(queue); +} + +static void TranslateKeyboardInputEvent(const GpKeyboardInputEvent &vosEvent, PortabilityLayer::EventQueue *queue) +{ + PL_STATIC_ASSERT((1 << PL_INPUT_PLAYER_INDEX_BITS) >= PL_INPUT_MAX_PLAYERS); + PL_STATIC_ASSERT((1 << PL_INPUT_TYPE_CODE_BITS) >= KeyEventType_Count); + + PortabilityLayer::InputManager *inputManager = PortabilityLayer::InputManager::GetInstance(); + if (vosEvent.m_eventType == GpKeyboardInputEventTypes::kUp || vosEvent.m_eventType == GpKeyboardInputEventTypes::kDown) - inputManager->ApplyEvent(vosEvent); + inputManager->ApplyKeyboardEvent(vosEvent); intptr_t msg = 0; @@ -134,6 +146,9 @@ static void TranslateKeyboardInputEvent(const GpKeyboardInputEvent &vosEvent, Po } } break; + case GpKeyIDSubsets::kGamepadButton: + msg = PL_KEY_GAMEPAD_BUTTON_ENCODE(vosEvent.m_key.m_gamepadKey.m_button, vosEvent.m_key.m_gamepadKey.m_player); + break; default: PL_NotYetImplemented(); } @@ -171,6 +186,9 @@ static void TranslateVOSEvent(const GpVOSEvent *vosEvent, PortabilityLayer::Even case GpVOSEventTypes::kKeyboardInput: TranslateKeyboardInputEvent(vosEvent->m_event.m_keyboardInputEvent, queue); break; + case GpVOSEventTypes::kGamepadInput: + TranslateGamepadInputEvent(vosEvent->m_event.m_gamepadInputEvent, queue); + break; } } @@ -521,6 +539,15 @@ bool BitTst(const KeyMap &keyMap, int encodedKey) return keyMap.m_fKey.Get(evtValue - 1); case KeyEventType_EitherSpecial: return BitTestEitherSpecial(keyMap, evtValue); + case KeyEventType_GamepadButton: + { + unsigned int playerNum = evtValue & ((1 << PL_INPUT_PLAYER_INDEX_BITS) - 1); + assert(playerNum < PL_INPUT_MAX_PLAYERS); + unsigned int button = evtValue >> PL_INPUT_PLAYER_INDEX_BITS; + + return keyMap.m_gamepadButtons[playerNum].Get(button); + } + break; default: assert(false); return false; diff --git a/PortabilityLayer/PLKeyEncoding.h b/PortabilityLayer/PLKeyEncoding.h index ab50de7..fcfafda 100644 --- a/PortabilityLayer/PLKeyEncoding.h +++ b/PortabilityLayer/PLKeyEncoding.h @@ -11,8 +11,10 @@ enum KeyEventType KeyEventType_NumPadNumber, KeyEventType_NumPadSpecial, KeyEventType_FKey, - KeyEventType_EitherSpecial, + KeyEventType_GamepadButton, + + KeyEventType_Count, }; namespace KeyEventEitherSpecialCategories @@ -25,18 +27,25 @@ namespace KeyEventEitherSpecialCategories }; } -#define PL_KEY_SPECIAL(k) ((KeyEventType_Special) | (GpKeySpecials::k) << 3) -#define PL_KEY_SPECIAL_ENCODE(k) ((KeyEventType_Special) | (k) << 3) -#define PL_KEY_ASCII(k) ((KeyEventType_ASCII) | (k) << 3) -#define PL_KEY_MACROMAN(k) ((KeyEventType_MacRoman) | (k) << 3) -#define PL_KEY_NUMPAD_NUMBER(k) ((KeyEventType_NumPadNumber) | (k) << 3) -#define PL_KEY_NUMPAD_SPECIAL(k) ((KeyEventType_NumPadSpecial) | (GpKeySpecials::k) << 3) -#define PL_KEY_NUMPAD_SPECIAL_ENCODE(k) ((KeyEventType_NumPadSpecial) | (k) << 3) -#define PL_KEY_FKEY(k) ((KeyEventType_FKey) | (k) << 3) -#define PL_KEY_EITHER_SPECIAL(k) ((KeyEventType_EitherSpecial) | (KeyEventEitherSpecialCategories::k) << 3) +#define PL_INPUT_MAX_PLAYERS 2 +#define PL_INPUT_PLAYER_INDEX_BITS 1 -#define PL_KEY_GET_EVENT_TYPE(k) (static_cast(k & 7)) -#define PL_KEY_GET_VALUE(k) ((k) >> 3) +#define PL_INPUT_TYPE_CODE_BITS 3 + +#define PL_KEY_SPECIAL(k) ((KeyEventType_Special) | ((GpKeySpecials::k) << PL_INPUT_TYPE_CODE_BITS)) +#define PL_KEY_SPECIAL_ENCODE(k) ((KeyEventType_Special) | ((k) << PL_INPUT_TYPE_CODE_BITS)) +#define PL_KEY_ASCII(k) ((KeyEventType_ASCII) | ((k) << PL_INPUT_TYPE_CODE_BITS)) +#define PL_KEY_MACROMAN(k) ((KeyEventType_MacRoman) | ((k) << PL_INPUT_TYPE_CODE_BITS)) +#define PL_KEY_NUMPAD_NUMBER(k) ((KeyEventType_NumPadNumber) | ((k) << PL_INPUT_TYPE_CODE_BITS)) +#define PL_KEY_NUMPAD_SPECIAL(k) ((KeyEventType_NumPadSpecial) | ((GpKeySpecials::k) << PL_INPUT_TYPE_CODE_BITS)) +#define PL_KEY_NUMPAD_SPECIAL_ENCODE(k) ((KeyEventType_NumPadSpecial) | ((k) << PL_INPUT_TYPE_CODE_BITS)) +#define PL_KEY_FKEY(k) ((KeyEventType_FKey) | ((k) << PL_INPUT_TYPE_CODE_BITS)) +#define PL_KEY_EITHER_SPECIAL(k) ((KeyEventType_EitherSpecial) | ((KeyEventEitherSpecialCategories::k) << PL_INPUT_TYPE_CODE_BITS)) +#define PL_KEY_GAMEPAD_BUTTON(k, pl) ((KeyEventType_GamepadButton) | (pl << PL_INPUT_TYPE_CODE_BITS) | ((GpGamepadButtons::k) << (PL_INPUT_TYPE_CODE_BITS + PL_INPUT_PLAYER_INDEX_BITS))) +#define PL_KEY_GAMEPAD_BUTTON_ENCODE(k, pl) ((KeyEventType_GamepadButton) | (pl << PL_INPUT_TYPE_CODE_BITS) | ((k) << (PL_INPUT_TYPE_CODE_BITS + PL_INPUT_PLAYER_INDEX_BITS))) + +#define PL_KEY_GET_EVENT_TYPE(k) (static_cast(k & ((1 << PL_INPUT_TYPE_CODE_BITS) - 1))) +#define PL_KEY_GET_VALUE(k) ((k) >> PL_INPUT_TYPE_CODE_BITS) struct KeyMap { @@ -45,5 +54,6 @@ struct KeyMap GpBitfield<128> m_macRoman; GpBitfield<10> m_numPadNumber; GpBitfield m_numPadSpecial; - GpBitfield m_fKey; + GpBitfield m_fKey; + GpBitfield m_gamepadButtons[PL_INPUT_MAX_PLAYERS]; };