diff --git a/src/common/engine/m_haptics.cpp b/src/common/engine/m_haptics.cpp index 2d1305536..e19040d91 100644 --- a/src/common/engine/m_haptics.cpp +++ b/src/common/engine/m_haptics.cpp @@ -62,6 +62,13 @@ struct { bool dirty = false; // do we need to do something next tick ? bool enabled = true; // do we need to do anything ever ? bool active = true; // is the game currently not paused ? + struct { + double base = 1.0; // [0,1] -> number <1 turns down rumble strength + double high_frequency = 1.0; // [0,inf) + double low_frequency = 1.0; // [0,inf) + double left_trigger = 1.0; // [0,inf) + double right_trigger = 1.0; // [0,inf) + } strength; struct Haptics current = {0,0,0,0,0}; // current state of the controller TMap channels; // active rumbles (that will be mixed) } Haptics; @@ -79,6 +86,48 @@ const FName HapticIntense = "INTENSE", // PUBLIC DATA DEFINITIONS ------------------------------------------------- +// for fine-control, if user wants/needs +// added because trigger haptics are much stronger on xbone controller than expected +CUSTOM_CVARD(Float, haptics_strength_lf, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "low frequency motor fine-control") +{ + if (self < 0) self = 0; + Haptics.strength.low_frequency = self * Haptics.strength.base; +}; +CUSTOM_CVARD(Float, haptics_strength_hf, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "high frequency motor fine-control") +{ + if (self < 0) self = 0; + Haptics.strength.high_frequency = self * Haptics.strength.base; +}; +CUSTOM_CVARD(Float, haptics_strength_lt, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "left trigger motor fine-control") +{ + if (self < 0) self = 0; + Haptics.strength.left_trigger = self * Haptics.strength.base; +}; +CUSTOM_CVARD(Float, haptics_strength_rt, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "right trigger motor fine-control") +{ + if (self < 0) self = 0; + Haptics.strength.right_trigger = self * Haptics.strength.base; +}; + +CUSTOM_CVARD(Int, haptics_strength, 10, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "Translate linear haptics to audio taper") +{ + double l1 = self / 10.0; + double l2 = l1 * l1; + double l3 = l2 * l1; + double m3 = 2; // cubed portion + double m2 = -2; // squared portion + double m1 = 1 - m2 - m3; // linear portion + + Haptics.enabled = self > 0; + Haptics.strength.base = l1*m1 + l2*m2 + l3*m3; + Haptics.strength.high_frequency = haptics_strength_hf * Haptics.strength.base; + Haptics.strength.low_frequency = haptics_strength_lf * Haptics.strength.base; + Haptics.strength.left_trigger = haptics_strength_lt * Haptics.strength.base; + Haptics.strength.right_trigger = haptics_strength_rt * Haptics.strength.base; + + if (!Haptics.enabled) I_Rumble(0, 0, 0, 0); +} + CVARD(Bool, haptics_debug, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "print diagnostics for haptic feedback"); // CODE -------------------------------------------------------------------- @@ -349,10 +398,10 @@ void Joy_Rumble(const FName source, const struct Haptics data, double attenuatio // this will overwrite stuff from same source mapping (weapons/pistol not W_BULLET) Haptics.channels.Insert(source, { Haptics.tic + data.ticks + 1, - data.high_frequency * strength, - data.low_frequency * strength, - data.left_trigger * strength, - data.right_trigger * strength, + data.high_frequency * Haptics.strength.high_frequency * strength, + data.low_frequency * Haptics.strength.low_frequency * strength, + data.left_trigger * Haptics.strength.left_trigger * strength, + data.right_trigger * Haptics.strength.right_trigger * strength, }); Haptics.dirty = true; diff --git a/src/common/engine/m_joy.cpp b/src/common/engine/m_joy.cpp index b85001ef6..4e8cb932e 100644 --- a/src/common/engine/m_joy.cpp +++ b/src/common/engine/m_joy.cpp @@ -4,6 +4,7 @@ ** Cross-platform joystick/gamepad management ** **--------------------------------------------------------------------------- +** ** Copyright 2005-2016 Randy Heit ** Copyright 2017-2025 GZDoom Maintainers and Contributors ** All rights reserved. @@ -30,6 +31,7 @@ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** **--------------------------------------------------------------------------- ** */ @@ -172,6 +174,12 @@ bool M_LoadJoystickConfig(IJoystickConfig *joy) joy->SetSensitivity((float)atof(value)); } + value = GameConfig->GetValueForKey("Haptics"); + if (value) + { + joy->SetHapticsStrength((float)atof(value)); + } + numaxes = joy->GetNumAxes(); for (int i = 0; i < numaxes; ++i) { @@ -262,12 +270,19 @@ void M_SaveJoystickConfig(IJoystickConfig *joy) { GameConfig->SetValueForKey("EnabledInBackground", "1"); } - + if (!joy->IsSensitivityDefault()) { mysnprintf(value, countof(value), "%g", joy->GetSensitivity()); GameConfig->SetValueForKey("Sensitivity", value); } + + if (!joy->IsHapticsStrengthDefault()) + { + mysnprintf(value, countof(value), "%g", joy->GetHapticsStrength()); + GameConfig->SetValueForKey("Haptics", value); + } + numaxes = joy->GetNumAxes(); for (int i = 0; i < numaxes; ++i) { diff --git a/src/common/engine/m_joy.h b/src/common/engine/m_joy.h index a17c87fde..16a962db2 100644 --- a/src/common/engine/m_joy.h +++ b/src/common/engine/m_joy.h @@ -48,6 +48,10 @@ struct IJoystickConfig virtual float GetSensitivity() = 0; virtual void SetSensitivity(float scale) = 0; + virtual bool HasHaptics() = 0; + virtual float GetHapticsStrength() = 0; + virtual void SetHapticsStrength(float strength) = 0; + virtual int GetNumAxes() = 0; virtual float GetAxisDeadZone(int axis) = 0; virtual const char *GetAxisName(int axis) = 0; @@ -71,6 +75,7 @@ struct IJoystickConfig // Used by the saver to not save properties that are at their defaults. virtual bool IsSensitivityDefault() = 0; + virtual bool IsHapticsStrengthDefault() = 0; virtual bool IsAxisDeadZoneDefault(int axis) = 0; virtual bool IsAxisScaleDefault(int axis) = 0; virtual bool IsAxisDigitalThresholdDefault(int axis) = 0; diff --git a/src/common/menu/joystickmenu.cpp b/src/common/menu/joystickmenu.cpp index 1edec1e3b..d65049e47 100644 --- a/src/common/menu/joystickmenu.cpp +++ b/src/common/menu/joystickmenu.cpp @@ -4,6 +4,7 @@ ** The joystick configuration menus ** **--------------------------------------------------------------------------- +** ** Copyright 2010 Christoph Oelckers ** Copyright 2017-2025 GZDoom Maintainers and Contributors ** All rights reserved. @@ -30,6 +31,7 @@ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** **--------------------------------------------------------------------------- ** */ @@ -54,6 +56,26 @@ DEFINE_ACTION_FUNCTION(IJoystickConfig, SetSensitivity) return 0; } +DEFINE_ACTION_FUNCTION(IJoystickConfig, HasHaptics) +{ + PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig); + ACTION_RETURN_BOOL(self->HasHaptics()); +} + +DEFINE_ACTION_FUNCTION(IJoystickConfig, GetHapticsStrength) +{ + PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig); + ACTION_RETURN_FLOAT(self->GetHapticsStrength()); +} + +DEFINE_ACTION_FUNCTION(IJoystickConfig, SetHapticsStrength) +{ + PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig); + PARAM_FLOAT(strength); + self->SetHapticsStrength((float)strength); + return 0; +} + DEFINE_ACTION_FUNCTION(IJoystickConfig, GetAxisScale) { PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig); diff --git a/src/common/platform/posix/cocoa/i_joystick.cpp b/src/common/platform/posix/cocoa/i_joystick.cpp index 34d60d158..adf1daa55 100644 --- a/src/common/platform/posix/cocoa/i_joystick.cpp +++ b/src/common/platform/posix/cocoa/i_joystick.cpp @@ -2,6 +2,7 @@ ** i_joystick.cpp ** **--------------------------------------------------------------------------- +** ** Copyright 2012-2015 Alexey Lysiuk ** Copyright 2017-2025 GZDoom Maintainers and Contributors ** All rights reserved. @@ -28,6 +29,7 @@ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** **--------------------------------------------------------------------------- ** */ @@ -45,11 +47,9 @@ #include "printf.h" #include "keydef.h" - EXTERN_CVAR(Bool, joy_axespolling) EXTERN_CVAR(Bool, use_joystick) - namespace { @@ -77,10 +77,8 @@ FString ToFString(const CFStringRef string) return FString(buffer); } - // --------------------------------------------------------------------------- - class IOKitJoystick : public IJoystickConfig { public: @@ -91,6 +89,10 @@ public: virtual float GetSensitivity(); virtual void SetSensitivity(float scale); + virtual bool HasHaptics(); + virtual float GetHapticsStrength(); + virtual void SetHapticsStrength(float strength); + virtual int GetNumAxes(); virtual float GetAxisDeadZone(int axis); virtual const char* GetAxisName(int axis); @@ -106,6 +108,7 @@ public: void SetAxisResponseCurvePoint(int axis, int point, float value); virtual bool IsSensitivityDefault(); + virtual bool IsHapticsStrengthDefault(); virtual bool IsAxisDeadZoneDefault(int axis); virtual bool IsAxisScaleDefault(int axis); bool IsAxisDigitalThresholdDefault(int axis); @@ -206,7 +209,6 @@ private: void RemoveFromQueue(IOHIDElementCookie cookie); }; - IOHIDDeviceInterface** CreateDeviceInterface(const io_object_t device) { IOCFPlugInInterface** plugInInterface = NULL; @@ -285,7 +287,6 @@ IOHIDQueueInterface** CreateDeviceQueue(IOHIDDeviceInterface** const interface) return queue; } - IOKitJoystick::IOKitJoystick(const io_object_t device) : m_interface(CreateDeviceInterface(device)) , m_queue(CreateDeviceQueue(m_interface)) @@ -344,13 +345,11 @@ IOKitJoystick::~IOKitJoystick() } } - FString IOKitJoystick::GetName() { return m_name; } - float IOKitJoystick::GetSensitivity() { return m_sensitivity; @@ -361,6 +360,20 @@ void IOKitJoystick::SetSensitivity(float scale) m_sensitivity = scale; } +bool IOKitJoystick::HasHaptics() +{ + return false; +} + +float IOKitJoystick::GetHapticsStrength() +{ + return JOYHAPSTRENGTH_DEFAULT; +} + +void IOKitJoystick::SetHapticsStrength(float strength) +{ + // nope +} int IOKitJoystick::GetNumAxes() { @@ -448,6 +461,11 @@ bool IOKitJoystick::IsSensitivityDefault() return JOYSENSITIVITY_DEFAULT == m_sensitivity; } +bool IOKitJoystick::IsHapticsStrengthDefault() +{ + return true; +} + bool IOKitJoystick::IsAxisDeadZoneDefault(int axis) { return IS_AXIS_VALID @@ -548,13 +566,11 @@ void IOKitJoystick::SetDefaultConfig() } } - FString IOKitJoystick::GetIdentifier() { return m_identifier; } - void IOKitJoystick::AddAxes(float axes[NUM_AXIS_CODES]) const { for (size_t i = 0, count = m_axes.Size(); i < count; ++i) @@ -582,7 +598,6 @@ void IOKitJoystick::AddAxes(float axes[NUM_AXIS_CODES]) const } } - void IOKitJoystick::UseAxesPolling(const bool axesPolling) { m_useAxesPolling = axesPolling; @@ -602,7 +617,6 @@ void IOKitJoystick::UseAxesPolling(const bool axesPolling) } } - void IOKitJoystick::Update() { if (NULL == m_queue) @@ -630,7 +644,6 @@ void IOKitJoystick::Update() if(m_enabled) ProcessAxes(); } - void IOKitJoystick::ProcessAxes() { if (NULL == m_interface || !m_useAxesPolling) @@ -717,7 +730,6 @@ void IOKitJoystick::ProcessAxes() } } - bool IOKitJoystick::ProcessAxis(const IOHIDEventStruct& event) { if (m_useAxesPolling) @@ -809,7 +821,6 @@ bool IOKitJoystick::ProcessPOV(const IOHIDEventStruct& event) return false; } - void IOKitJoystick::GatherDeviceInfo(const io_object_t device, const CFDictionaryRef properties) { assert(NULL != properties); @@ -914,7 +925,6 @@ void IOKitJoystick::GatherDeviceInfo(const io_object_t device, const CFDictionar } } - long GetElementValue(const CFDictionaryRef element, const CFStringRef key) { const CFNumberRef number = @@ -991,7 +1001,6 @@ void IOKitJoystick::GatherCollectionElements(const CFDictionaryRef properties) CFArrayApplyFunction(topElement, range, GatherElementsHandler, this); } - IOHIDElementCookie GetElementCookie(const CFDictionaryRef element) { // Use C-style cast to avoid 32/64-bit IOHIDElementCookie type issue @@ -1039,7 +1048,6 @@ void IOKitJoystick::AddPOV(CFDictionaryRef element) AddToQueue(pov.cookie); } - void IOKitJoystick::AddToQueue(const IOHIDElementCookie cookie) { if (NULL == m_queue) @@ -1066,16 +1074,13 @@ void IOKitJoystick::RemoveFromQueue(const IOHIDElementCookie cookie) } } - io_object_t* IOKitJoystick::GetNotificationPtr() { return &m_notification; } - // --------------------------------------------------------------------------- - class IOKitJoystickManager { public: @@ -1109,10 +1114,8 @@ private: natural_t messageType, void* messageArgument); }; - IOKitJoystickManager* s_joystickManager; - IOKitJoystickManager::IOKitJoystickManager() { memset(m_notifications, 0, sizeof m_notifications); @@ -1160,7 +1163,6 @@ IOKitJoystickManager::~IOKitJoystickManager() } } - void IOKitJoystickManager::GetJoysticks(TArray& joysticks) const { const size_t joystickCount = m_joysticks.Size(); @@ -1183,7 +1185,6 @@ void IOKitJoystickManager::AddAxes(float axes[NUM_AXIS_CODES]) const } } - void IOKitJoystickManager::Update() { for (size_t i = 0, count = m_joysticks.Size(); i < count; ++i) @@ -1192,7 +1193,6 @@ void IOKitJoystickManager::Update() } } - void IOKitJoystickManager::UseAxesPolling(const bool axesPolling) { for (size_t i = 0, count = m_joysticks.Size(); i < count; ++i) @@ -1201,14 +1201,12 @@ void IOKitJoystickManager::UseAxesPolling(const bool axesPolling) } } - void PostDeviceChangeEvent() { event_t event = { EV_DeviceChange }; D_PostEvent(&event); } - void IOKitJoystickManager::Rescan(const int usagePage, const int usage, const size_t notificationPortIndex) { CFMutableDictionaryRef deviceMatching = IOServiceMatching(kIOHIDDeviceKey); @@ -1270,7 +1268,6 @@ void IOKitJoystickManager::AddDevices(const IONotificationPortRef notificationPo } } - void IOKitJoystickManager::OnDeviceAttached(void* const refcon, const io_iterator_t iterator) { assert(NULL != refcon); @@ -1309,10 +1306,8 @@ void IOKitJoystickManager::OnDeviceRemoved(void* const refcon, io_service_t, con } // unnamed namespace - // --------------------------------------------------------------------------- - void I_ShutdownInput() { delete s_joystickManager; @@ -1358,10 +1353,8 @@ IJoystickConfig* I_UpdateDeviceList() return NULL; } - // --------------------------------------------------------------------------- - void I_ProcessJoysticks() { if (NULL != s_joystickManager) @@ -1370,10 +1363,8 @@ void I_ProcessJoysticks() } } - // --------------------------------------------------------------------------- - CUSTOM_CVAR(Bool, joy_axespolling, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) { if (NULL != s_joystickManager) @@ -1388,3 +1379,4 @@ void I_Rumble(double high_freq, double low_freq, double left_trig, double right_ // stub } + diff --git a/src/common/platform/posix/sdl/i_joystick.cpp b/src/common/platform/posix/sdl/i_joystick.cpp index 63b714a06..c26d6b1ae 100644 --- a/src/common/platform/posix/sdl/i_joystick.cpp +++ b/src/common/platform/posix/sdl/i_joystick.cpp @@ -4,6 +4,7 @@ ** Handles sdl joysticks and gamepads ** **--------------------------------------------------------------------------- +** ** Copyright 2005-2016 Randy Heit ** Copyright 2017-2025 GZDoom Maintainers and Contributors ** All rights reserved. @@ -30,6 +31,7 @@ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** **--------------------------------------------------------------------------- ** */ @@ -138,6 +140,25 @@ public: Multiplier = scale; } + bool HasHaptics() + { + return Haptics != 0; + } + + float GetHapticsStrength() + { + return HasHaptics() + ? HapticsStrength + : 0; + } + + void SetHapticsStrength(float strength) + { + if (!HasHaptics()) return; + SettingsChanged = true; + HapticsStrength = clamp(strength, 0.f, 2.f); + } + int GetNumAxes() { return NumAxes + NumHats*2; @@ -207,6 +228,10 @@ public: { return Multiplier == JOYSENSITIVITY_DEFAULT; } + bool IsHapticsStrengthDefault() + { + return HapticsStrength == JOYHAPSTRENGTH_DEFAULT; + } bool IsAxisDeadZoneDefault(int axis) { if(axis >= DefaultAxesCount) diff --git a/src/common/platform/win32/i_dijoy.cpp b/src/common/platform/win32/i_dijoy.cpp index 0fcfe3a49..127955a2a 100644 --- a/src/common/platform/win32/i_dijoy.cpp +++ b/src/common/platform/win32/i_dijoy.cpp @@ -4,6 +4,7 @@ ** Handles direct input joysticks ** **--------------------------------------------------------------------------- +** ** Copyright 2005-2016 Randy Heit ** Copyright 2017-2025 GZDoom Maintainers and Contributors ** All rights reserved. @@ -30,12 +31,14 @@ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** **--------------------------------------------------------------------------- ** */ // HEADER FILES ------------------------------------------------------------ +#include "m_joy.h" #define WIN32_LEAN_AND_MEAN #define DIRECTINPUT_VERSION 0x800 #include @@ -166,6 +169,10 @@ public: float GetSensitivity(); virtual void SetSensitivity(float scale); + bool HasHaptics(); + float GetHapticsStrength(); + void SetHapticsStrength(float strength); + int GetNumAxes(); float GetAxisDeadZone(int axis); const char *GetAxisName(int axis); @@ -181,6 +188,7 @@ public: void SetAxisResponseCurvePoint(int axis, int point, float value); bool IsSensitivityDefault(); + bool IsHapticsStrengthDefault(); bool IsAxisDeadZoneDefault(int axis); bool IsAxisScaleDefault(int axis); bool IsAxisDigitalThresholdDefault(int axis); @@ -913,6 +921,50 @@ bool FDInputJoystick::IsSensitivityDefault() return Multiplier == JOYSENSITIVITY_DEFAULT; } +//=========================================================================== +// +// FDInputJoystick :: HasHaptics +// +//=========================================================================== + +bool FDInputJoystick::HasHaptics() +{ + return false; +} + +//=========================================================================== +// +// FDInputJoystick :: GetHapticsStrength +// +//=========================================================================== + +float FDInputJoystick::GetHapticsStrength() +{ + return JOYHAPSTRENGTH_DEFAULT; +} + +//=========================================================================== +// +// FDInputJoystick :: SetHapticsStrength +// +//=========================================================================== + +void FDInputJoystick::SetHapticsStrength(float strength) +{ + // nope +} + +//=========================================================================== +// +// FDInputJoystick :: IsHapticsStrengthDefault +// +//=========================================================================== + +bool FDInputJoystick::IsHapticsStrengthDefault() +{ + return true; +} + //=========================================================================== // // FDInputJoystick :: GetNumAxes diff --git a/src/common/platform/win32/i_rawps2.cpp b/src/common/platform/win32/i_rawps2.cpp index 2b06c9abf..0ca947066 100644 --- a/src/common/platform/win32/i_rawps2.cpp +++ b/src/common/platform/win32/i_rawps2.cpp @@ -2,6 +2,7 @@ ** ** **--------------------------------------------------------------------------- +** ** Copyright 2005-2016 Randy Heit ** All rights reserved. ** @@ -27,6 +28,7 @@ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** **--------------------------------------------------------------------------- ** */ @@ -98,6 +100,10 @@ public: float GetSensitivity(); virtual void SetSensitivity(float scale); + bool HasHaptics(); + float GetHapticsStrength(); + void SetHapticsStrength(float strength); + int GetNumAxes(); float GetAxisDeadZone(int axis); const char *GetAxisName(int axis); @@ -113,6 +119,7 @@ public: void SetAxisResponseCurvePoint(int axis, int point, float value); bool IsSensitivityDefault(); + bool IsHapticsStrengthDefault(); bool IsAxisDeadZoneDefault(int axis); bool IsAxisScaleDefault(int axis); bool IsAxisDigitalThresholdDefault(int axis); @@ -750,6 +757,50 @@ bool FRawPS2Controller::IsSensitivityDefault() return Multiplier == JOYSENSITIVITY_DEFAULT; } +//=========================================================================== +// +// FRawPS2Controller :: HasHaptics +// +//=========================================================================== + +bool FRawPS2Controller::HasHaptics() +{ + return false; +} + +//=========================================================================== +// +// FRawPS2Controller :: GetHapticsStrength +// +//=========================================================================== + +float FRawPS2Controller::GetHapticsStrength() +{ + return JOYHAPSTRENGTH_DEFAULT; +} + +//=========================================================================== +// +// FRawPS2Controller :: SetHapticsStrength +// +//=========================================================================== + +void FRawPS2Controller::SetHapticsStrength(float strength) +{ + // nope +} + +//=========================================================================== +// +// FRawPS2Controller :: IsHapticsStrengthDefault +// +//=========================================================================== + +bool FRawPS2Controller::IsHapticsStrengthDefault() +{ + return true; +} + //========================================================================== // // FRawPS2Controller :: GetNumAxes diff --git a/src/common/platform/win32/i_xinput.cpp b/src/common/platform/win32/i_xinput.cpp index 9bc2c2a08..e27be4022 100644 --- a/src/common/platform/win32/i_xinput.cpp +++ b/src/common/platform/win32/i_xinput.cpp @@ -4,6 +4,7 @@ ** Handles direct input gamepads ** **--------------------------------------------------------------------------- +** ** Copyright 2005-2016 Randy Heit ** Copyright 2017-2025 GZDoom Maintainers and Contributors ** All rights reserved. @@ -30,6 +31,7 @@ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** **--------------------------------------------------------------------------- ** */ @@ -95,6 +97,10 @@ public: float GetSensitivity(); virtual void SetSensitivity(float scale); + bool HasHaptics(); + float GetHapticsStrength(); + void SetHapticsStrength(float strength); + int GetNumAxes(); float GetAxisDeadZone(int axis); const char *GetAxisName(int axis); @@ -110,6 +116,7 @@ public: void SetAxisResponseCurvePoint(int axis, int point, float value); bool IsSensitivityDefault(); + bool IsHapticsStrengthDefault(); bool IsAxisDeadZoneDefault(int axis); bool IsAxisScaleDefault(int axis); bool IsAxisDigitalThresholdDefault(int axis); @@ -575,6 +582,50 @@ bool FXInputController::IsSensitivityDefault() return Multiplier == JOYSENSITIVITY_DEFAULT; } +//========================================================================== +// +// FXInputController :: HasHaptics +// +//========================================================================== + +bool FXInputController::HasHaptics() +{ + return Haptics; +} + +//========================================================================== +// +// FXInputController :: GetHapticsStrength +// +//========================================================================== + +float FXInputController::GetHapticsStrength() +{ + return HapticStrength; +} + +//========================================================================== +// +// FXInputController :: SetHapticsStrength +// +//========================================================================== + +void FXInputController::SetHapticsStrength(float strength) +{ + if (Haptics) HapticStrength = clamp(strength, 0.f, 2.f); +} + +//========================================================================== +// +// FXInputController :: IsHapticsStrengthDefault +// +//========================================================================== + +bool FXInputController::IsHapticsStrengthDefault() +{ + return true; +} + //========================================================================== // // FXInputController :: GetNumAxes diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 8985cd2e2..fc30f365d 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -365,6 +365,7 @@ OptionMenu "OptionsMenu" protected Submenu "$OPTMNU_COMPATIBILITY", "CompatibilityOptions" Submenu "$OPTMNU_AUTOMAP", "AutomapOptions" Submenu "$OPTMNU_HUD", "HUDOptions" + Submenu "$OPTMNU_HAPTICS", "HapticsOptions" Submenu "$OPTMNU_MISCELLANEOUS", "MiscOptions" Submenu "$OPTMNU_NETWORK", "NetworkOptions" Submenu "$OPTMNU_SOUND", "SoundOptions" @@ -806,7 +807,6 @@ OptionMenu "MouseOptions" protected Option "$MOUSEMNU_LOOKSTRAFE", "lookstrafe", "OnOff" } - //------------------------------------------------------------------------------------------- // // Joystick Menu @@ -818,6 +818,7 @@ OptionMenu "JoystickOptionsDefaults" protected Title "$JOYMNU_OPTIONS" Option "$JOYMNU_ENABLE", "use_joystick", "YesNo" Option "$JOYMNU_NOMENU", "m_blockcontrollers", "YesNo" + ScaleSlider "$JOYMNU_HAPTICS", "haptics_strength", 0, 10, 1, "$OPTVAL_OFF", 0, "m_simpleoptions_view", 0, 1 IfOption(Windows) { Option "$JOYMNU_DINPUT", "joy_dinput", "YesNo" @@ -873,7 +874,6 @@ OptionMenu "JoystickConfigMenu" protected // Will be filled in by joystick code. } - //------------------------------------------------------------------------------------------- // // Video Menu @@ -1020,7 +1020,6 @@ OptionMenu "VideoOptions" protected Option "$DSPLYMNU_NOMONSTERINTERPOLATION", "nomonsterinterpolation", "NoYes" } - //------------------------------------------------------------------------------------------- // // HUD menu @@ -1241,6 +1240,21 @@ OptionMenu "AltHUDOptions" protected option "$ALTHUDMNU_STATSCOLOR", "hudcolor_stats", "TextColors" } +//------------------------------------------------------------------------------------------- +// +// Haptics menu +// +//------------------------------------------------------------------------------------------- + +OptionMenu "HapticsOptions" protected +{ + Title "$HAPMNU_TITLE" + + ScaleSlider "$JOYMNU_HAPTICS", "haptics_strength", 0, 10, 1, "$OPTVAL_OFF" + StaticText "" + StaticText "$HAPMNU_OPTIONS" +} + //------------------------------------------------------------------------------------------- // // Misc menu @@ -1579,7 +1593,6 @@ OptionMenu ColorPickerMenu protected // //------------------------------------------------------------------------------------------- - OptionValue MessageLevels { 0.0, "$OPTVAL_ITEMPICKUP" @@ -1694,7 +1707,6 @@ OptionValue JumpCrouchFreeLook 2, "$OPTVAL_ON" } - OptionMenu GameplayOptions protected { Position -35 @@ -1795,7 +1807,6 @@ OptionMenu CoopOptions protected * *=======================================*/ - OptionValue CompatModes { 0, "$OPTVAL_DEFAULT" @@ -1890,7 +1901,6 @@ OptionMenu "CompatPhysicsMenu" protected Class "CompatibilityMenu" } - OptionMenu "CompatRenderMenu" protected { Position -35 @@ -1930,7 +1940,6 @@ OptionValue SampleRates 48000, "$OPTVAL_48000HZ" } - OptionValue BufferSizes { 0, "$OPTVAL_DEFAULT" @@ -1943,7 +1952,6 @@ OptionValue BufferSizes 4096, "$OPTVAL_4096SAMPLES" } - OptionValue BufferCounts { 0, "$OPTVAL_DEFAULT" @@ -1960,7 +1968,6 @@ OptionValue BufferCounts 12, "12" } - OptionString ALDevices { // filled in by the sound code @@ -1983,7 +1990,6 @@ OptionString SpeakerModes "7.1", "$OPTSTR_7POINT1" } - OptionString Resamplers { "NoInterp", "$OPTSTR_NOINTERPOLATION" @@ -1992,7 +1998,6 @@ OptionString Resamplers "Spline", "$OPTSTR_SPLINE" } - OptionMenu OpenALSoundItems protected { Title "$OPENALMNU_TITLE" @@ -2001,7 +2006,6 @@ OptionMenu OpenALSoundItems protected Option "$OPENALMNU_RESAMPLER", "snd_alresampler", "ALResamplers" } - OptionValue MidiDevices { // filled in by the sound code @@ -2051,7 +2055,6 @@ OptionValue OplCores 3, "$OPTVAL_NUKEDOPL3" } - OptionMenu AdvSoundOptions protected { Title "$ADVSNDMNU_TITLE" @@ -2109,14 +2112,12 @@ OptionMenu OPNMIDICustomBanksMenu protected Title "$ADVSNDMNU_OPNBANKFILE" } - /*======================================= * * Module Replayer Options Menu * *=======================================*/ - OptionValue ModQuality { 0.0, "$OPTVAL_ALIASING" @@ -2129,7 +2130,6 @@ OptionValue ModQuality 7.0, "$OPTVAL_SINC" } - OptionValue ModVolumeRamps { 0.0, "$OPTVAL_NONE" @@ -2143,7 +2143,6 @@ OptionValue ModReplayers 1.0, "$OPTVAL_DUMB" } - OptionMenu ModReplayerOptions protected { Title "$MODMNU_TITLE" @@ -2397,7 +2396,6 @@ OptionValue MaxFps 200, "$OPTVAL_200FPS" } - OptionMenu VideoModeMenu protected { Title "$VIDMNU_TITLE" @@ -2638,7 +2636,6 @@ OptionValue "BillboardModes" 1, "$OPTVAL_XYAXIS" } - OptionValue "Particles" { 0, "$OPTVAL_SQUARE" @@ -2731,7 +2728,6 @@ OptionValue ShadowMapFilter 3, "$OPTVAL_PCF_HIGH" } - OptionMenu "GLTextureGLOptions" protected { Title "$GLTEXMNU_TITLE" diff --git a/wadsrc/static/zscript/engine/ui/menu/joystickmenu.zs b/wadsrc/static/zscript/engine/ui/menu/joystickmenu.zs index e93b0a475..384ad30ab 100644 --- a/wadsrc/static/zscript/engine/ui/menu/joystickmenu.zs +++ b/wadsrc/static/zscript/engine/ui/menu/joystickmenu.zs @@ -3,6 +3,7 @@ ** The joystick configuration menus ** **--------------------------------------------------------------------------- +** ** Copyright 2010-2017 Christoph Oelckers ** Copyright 2017-2025 GZDoom Maintainers and Contributors ** All rights reserved. @@ -29,6 +30,7 @@ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** **--------------------------------------------------------------------------- ** */ @@ -67,6 +69,34 @@ class OptionMenuSliderJoySensitivity : OptionMenuSliderBase // //============================================================================= +class OptionMenuSliderJoyHapticsStrength : OptionMenuSliderBase +{ + JoystickConfig mJoy; + + OptionMenuSliderJoyHapticsStrength Init(String label, double min, double max, double step, int showval, JoystickConfig joy) + { + Super.Init(label, min, max, step, showval); + mJoy = joy; + return self; + } + + override double GetSliderValue() + { + return mJoy.GetHapticsStrength(); + } + + override void SetSliderValue(double val) + { + mJoy.SetHapticsStrength(val); + } +} + +//============================================================================= +// +// +// +//============================================================================= + class OptionMenuSliderJoyScale : OptionMenuSliderBase { int mAxis; @@ -492,8 +522,16 @@ class OptionMenuItemJoyConfigMenu : OptionMenuItemSubmenu it = new("OptionMenuSliderJoySensitivity").Init("$JOYMNU_OVRSENS", 0, 2, 0.1, 3, joy); opt.mItems.Push(it); + + if (joy.HasHaptics()) + { + it = new("OptionMenuSliderJoyHapticsStrength").Init("$JOYMNU_HAPTICS", 0, 2, 0.1, 3, joy); + opt.mItems.Push(it); + } + it = new("OptionMenuJoyReset").Init("$JOYMNU_RESETALL", joy); opt.mItems.Push(it); + it = new("OptionMenuItemStaticText").Init(" ", false); opt.mItems.Push(it); diff --git a/wadsrc/static/zscript/engine/ui/menu/menu.zs b/wadsrc/static/zscript/engine/ui/menu/menu.zs index 7ea6cf28c..17ad810b0 100644 --- a/wadsrc/static/zscript/engine/ui/menu/menu.zs +++ b/wadsrc/static/zscript/engine/ui/menu/menu.zs @@ -3,6 +3,7 @@ ** The menu engine core ** **--------------------------------------------------------------------------- +** ** Copyright 2010-2020 Christoph Oelckers ** Copyright 2017-2025 GZDoom Maintainers and Contributors ** All rights reserved. @@ -29,6 +30,7 @@ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** **--------------------------------------------------------------------------- ** */ @@ -81,6 +83,10 @@ struct JoystickConfig native version("2.4") native float GetSensitivity(); native void SetSensitivity(float scale); + native bool HasHaptics(); + native float GetHapticsStrength(); + native void SetHapticsStrength(float strength); + native float GetAxisScale(int axis); native void SetAxisScale(int axis, float scale);