JoystickGremlin icon indicating copy to clipboard operation
JoystickGremlin copied to clipboard

Altering virtual axis input via plugins

Open Ryuk47 opened this issue 3 years ago • 2 comments

I am trying to create a plugin that works as a kind of moving deadzone to counter the at times unstable output of my X56 rotaries. I based this on a previous edit of yours being a moving average, however I cannot seem to find a way about "catching" the unwanted signals before they are already put out. From my very limited understanding of Python (C# guy), I can hook onto the callback of an axis input and spawn a thread that regularly updates the value. Even with an update rate of 10 milliseconds the unwanted signal gets through still. Is there any way to alter a physical axis input before it reaches the virtual output axis?

Ryuk47 avatar Feb 10 '22 21:02 Ryuk47

I'm not really clear what you actually want to do, but some information.

  • physical events are only forwarded if you instruct Gremlin to do so
  • spawning a thread in response to axis input seems like a horrible idea that likely results in tons of threads fighting each other
  • if you attempt to "overwrite" values cause by noise then this will never work, you will have to have a single callback that receives all physical input and decides what to do, trying to suppress, outpace, or similar ideas will not work

WhiteMagic avatar Feb 12 '22 13:02 WhiteMagic

So my problem is that I have a physical input that occasionally starts to jitter within a very small margin of +- 0.02, which is extremely annoying when binding it to e.g. the in-game zoom. What I would like to achieve is to have a plugin detect and smooth out this jittering before the physical input is processed to the virtual axis.

Upon another inspection of my setup I think I have identified the issue: While using the attached script to filter the physical Z axis to the virtual one, I still had the physical z axis set up to remap to the virtual z axis, so I assume my moving deadzone plugin was fighting with the remapped input. The code below now seems to do as I wished for.

from gremlin.user_plugin import *


mode = ModeVariable("Mode", "The mode in which to use this mapping")

virtual_axis = VirtualInputVariable(
        "Virtual output axis",
        "The vJoy axis to send the filtered output to.",
        [gremlin.common.InputType.JoystickAxis]
)

physical_axis = PhysicalInputVariable(
        "Physical input axis",
        "The physical input axis being filtered.",
        [gremlin.common.InputType.JoystickAxis]
)

deadzone = IntegerVariable(
        "Deadzone size",
        "Size of the deadzone around the cached value.",
        5,
        0,
        100
)

# Decorator for the physical axis 
dec_physical_axis = physical_axis.create_decorator(mode.value)

# Global variables
# The cached physical input
g_cached_value = 0.0
# The current input
g_current_value = 0.0
g_vjoy = gremlin.joystick_handling.VJoyProxy()

def apply_deadzone():
    global g_current_value, g_cached_value
    if(abs(g_current_value - g_cached_value) > deadzone.value/100):
        g_cached_value = g_current_value
    return g_cached_value

def update_vjoy():
    global g_vjoy
    g_vjoy[virtual_axis.vjoy_id].axis(virtual_axis.input_id).value = apply_deadzone()

@dec_physical_axis.axis(physical_axis.input_id)
def axis_cb(event):
    global g_current_value
    g_current_value = event.value
    update_vjoy()

Ryuk47 avatar Feb 12 '22 14:02 Ryuk47