Skip to content

Conversation

@Nintorch
Copy link
Contributor

@Nintorch Nintorch commented Jan 6, 2026

Closes godotengine/godot-proposals#8309

TODO:

  • What is an offset parameter mentioned in the original proposal exactly?
  • Is this approach good enough or should we expose the entirety of the haptic subsystem? (With InputHapticEffect classes, constants and such, which sounds quite tedious to both use and implement 😅)
  • Other effect types?
  • Finish class boilerplate
  • Replace M_PI with Math::PI
  • Input.create_joy_haptic_effect()
  • Input.start_joy_haptic_effect()
  • Input.update_joy_haptic_effect()
  • Input.stop_joy_haptic_effect()
  • Input.remove_joy_haptic_effect()
  • Documentation
  • Mark as experimental

@berarma
Copy link
Contributor

berarma commented Jan 6, 2026

What is an offset parameter mentioned in the original proposal exactly?

It's used in conditional effects (named center in SDL3) together with the deadband parameter to set a dead zone for this kind of effects. Wheels in real vehicles have a dead zone where the wheel is resting when driving straight. These parameters can simulate that dead zone, and when changing the offset it can also simulate a broken steering that has its center off.

It's also used in periodic effects to the set the mean value.

Is this approach good enough or should we expose the entirety of the haptic subsystem? Other effect types?

The periodic effects should be included, they can be used to simulate vibrations on the wheel without having to update the effects periodically.

We're missing parameters like direction, saturation, deadband, envelope, repetition, etc.

I like better the SDL3 approach with generic functions for all effect types, and passing the effect as a parameter. It makes it easier to add many effects without duplicating code. It also has structs with all parameters that are standard nowadays for force-feedback.

It's probably tedious to use, but it gives way more control over the effects, kinda professional versus a hobbyist implementation. I appreciate its simplicity but it would turn fast into excessive rigidity when using it seriously.

It might be a bit tedious to implement but not much work since it's just mirroring what SDL3 (and all APIs) already does.

We should have functions to handle this flow:

  • Create effect.
  • Start effect.
  • Update effect.
  • Stop effect.
  • Remove effect.

The reason to do it separately like this is because effects are uploaded into device slots. Creating an effect can have a performance cost depending on the device, so we want to create the effect once and maybe play it many times, update it many times, then remove it when it will be no longer used for a while to free the slot.

Start and Stop can actually be handled in the same call by setting repetition to zero, or just updating the effect with length zero.

We have to also make sure we're handling infinite duration and infinite repetition correctly.

@Nintorch Nintorch force-pushed the steering-wheels-force-feedback branch from 0360006 to 16377ae Compare January 6, 2026 12:16
@Nintorch Nintorch changed the title Add support for SDL haptics Add support for joypad haptics (force feedback) Jan 6, 2026
@Nintorch Nintorch force-pushed the steering-wheels-force-feedback branch from 16377ae to 9621efe Compare January 7, 2026 12:50
@GNSS-Stylist
Copy link
Contributor

Although this PR is draft, I played a bit with this (using only constant_force_feedback). Seems that the force is likely set to 0 for a while every time it is set, at least when the previous value is still in use.

Video (with sound):
https://github.com/user-attachments/assets/55689ffd-5865-4653-82f3-3549d2eb30c0

First tested this with another project, but then made this tiny test-project (as seen in the video) to understand the behavior better:
ffb-test.zip

In https://github.com/Dechode/Godot-FFB-SDL (that I originally used in the "another project" mentioned) there are no these kind of glitches.

Steering wheel used: Logitech Driving Force GT (yes, it's old and noisy, but at least the glitches can be easily heard ;) ), OS: Linux (Mint)

BTW: Compiling this seemed to fail due to some undefined references. Commented these lines out from core/register_core_types.cpp to make it compilable (don't know if worth mentioning as this is draft, though...):

GDREGISTER_CLASS(InputHapticEffectPeriodic);
GDREGISTER_CLASS(InputHapticEffectCondition);
GDREGISTER_CLASS(InputHapticEffectLeftRight);
GDREGISTER_CLASS(InputHapticEffectCustom);

@Dechode
Copy link

Dechode commented Jan 24, 2026

Looking at the code, the behaviour (the wheel rattling) GNSS-Stylist said is because calling constant_force_feedback() starts and plays a new ffb effect, always. When the code is updated to work as Berarma said (and the description of the commit now), we can start, update, stop and remove the effect as we please. Then it should work as intended, as long as the process()/physics_process() only updates the already uploaded effect.

@Spiltdestructor
Copy link

What about GameInput API?

Idk much about APIs
Nor know a lot about the current-used API to help
So sorry if this seems like a stupid question
But maybe that one can help?
Seems to support many Devices out-of-the-box
Technically, supports Linux and can be implemented in Godot
Idk much more
Just wanted to help as I need this too

@Nintorch
Copy link
Contributor Author

Nintorch commented Feb 1, 2026

What about GameInput API?

Idk much about APIs Nor know a lot about the current-used API to help So sorry if this seems like a stupid question But maybe that one can help? Seems to support many Devices out-of-the-box Technically, supports Linux and can be implemented in Godot Idk much more Just wanted to help as I need this too

We thought about using GameInput for SDL, but the license looks incompatible with Godot's MIT license: #107967 (comment)

@Spiltdestructor
Copy link

I see, thx!

@Nintorch Nintorch force-pushed the steering-wheels-force-feedback branch 2 times, most recently from 72b01e1 to f125636 Compare February 4, 2026 17:43
@Nintorch Nintorch force-pushed the steering-wheels-force-feedback branch from f125636 to 49de134 Compare February 4, 2026 18:07
@Nintorch
Copy link
Contributor Author

Nintorch commented Feb 4, 2026

I have just overcome my biggest problem with this PR: my laziness to write the boilerplate code.

This evening (for me) I wrote a Python script that would read a file in a special format I came up with and it would transform this simple file into a .h and a .cpp files with the generated boilerplate, the resulting files are used here in this PR for core\input\input_haptic_effect.h and core\input\input_haptic_effect.cpp files.
Which means I can continue working on this PR later :D

This script will be useful later when I decide to add InputEvents for joypad motion sensors and touchpads too.

I open-sourced this script in case anyone would find it useful too :D
https://github.com/Nintorch/GodotBoilerplateGenerator

}

void InputHapticEffect::set_direction_radians(float p_direction_radians) {
direction_radians = Math::fmod(p_direction_radians, (float)Math::PI);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
direction_radians = Math::fmod(p_direction_radians, (float)Math::PI);
direction_radians = Math::fmod(p_direction_radians, (float)Math::PI*2);

For other places too

class InputHapticEffectCondition : public InputHapticEffect {
GDCLASS(InputHapticEffectCondition, InputHapticEffect);

Type type;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Type type;
Type type = HAPTIC_EFFECT_SPRING;

void set_period(int p_period);
int get_period() const;

void set_samples(int p_samples);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in SDL samples is the amount of bytes in the data, so I should remove this property.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for force feedback in steering wheels

7 participants