So, you want a Relative Mouse toggle? Here it is... ### DIY GUIDE ###

Great script. I made two additions of my own that I find useful:
Glad you like it. I made a similar functionality a while back. I'm using mouse look on mouse 4, it will disable the whole mouse routine when it is toggled.

This is what I got so far now:
Python:
##

##
from System import Int16
global mouse_wheel, boost_compensation_enabled, cached_pip_setting, block_button_timer, configured_pip_setting, mouse_ctrl_enabled, pip_management_enabled, time_lapse, timer_duration, button_timer, relative_x_sens, relative_y_sens, relative_x_range, relative_y_range, rel_x_speed, rel_y_speed,rel_x_speed_curve, rel_y_speed_curve, absolute_curve, controller, absolute_sens, selected_pip_setting, pip_settings, current_pip_setting, current_weapons_setting, current_engine_setting, current_system_setting, cycle, max_cycle_count, weapon_focus, init_pip_management, engine_focus, system_focus

class PipSetting(object):
    def __init__(self, system, engine, weapons, keys):
        self.keys = keys
        self.current_key = 0
        self.system = system
        self.engine = engine
        self.weapons = weapons

#############################################################################################################################
# User adjustable parameters                                                                                                 #
#############################################################################################################################
                                                                                                                            #
controller = vJoy[0]                                        # the reference to the installed vJoy device                    #
absolute_curve = 3                                            # exponential factor for the ablsolute axises curve                #
absolute_sens = 20                                            # absolute mouse mode sensitivity                                #
relative_x_sens = 15                                        # relative mouse mode x sensitivity                                #
relative_y_sens = 15                                        # relative mouse mode y sensitivity                                #
relative_x_range = 300                                        # relative mouse range for x auto centering                        #
relative_y_range = 300                                        # relative mouse range for y auto centering                        #
rel_x_speed_curve = 1.7                                        # exponential factor for tweeking the x auto centering curve    #
rel_y_speed_curve = 2.2                                        # exponential factor for tweeking the y auto centering curve    #
max_cycle_count = 5                                            # determines how fast the keyboard is signaled to cycle pips    #
timer_duration = 100                                        # determines the length of the fire button timer                  #
                                                                                                                            #
#############################################################################################################################

if starting:
    # Init
    system.setThreadTiming(TimingTypes.HighresSystemTimer)
    system.threadExecutionInterval = 5 # loop delay

    #Pip configurations
    pip_settings = []
    pip_settings.append(PipSetting(4,4,4,["D"]))                            #0
    pip_settings.append(PipSetting(2,2,8,["D","R","R"]))                    #1
    pip_settings.append(PipSetting(2,4,6,["D","L","R","R","R","U","U"]))    #2
    pip_settings.append(PipSetting(1,4,7,["D","U","R","R"]))                #3
    pip_settings.append(PipSetting(3,3,6,["D","R","R","U","L"]))            #4
    pip_settings.append(PipSetting(2,5,5,["D","U","R"]))                    #5
    pip_settings.append(PipSetting(4,8,0,["D","L","U","L","L"]))            #6
    pip_settings.append(PipSetting(3,6,3,["D","U","U","R","L"]))            #7
    pip_settings.append(PipSetting(5,5,2,["D","U","L"]))                    #8
    pip_settings.append(PipSetting(6,3,3,["D","L","L","U","R"]))            #9
    pip_settings.append(PipSetting(7,4,1,["D","U","L","L"]))                #10
    pip_settings.append(PipSetting(8,2,2,["D","L","L"]))                    #11
    pip_settings.append(PipSetting(4,4,4,["D"]))                            #12

    #Setting max ranges
    max =  Int16.MaxValue*0.5+0.5   #  16384
    min = -Int16.MaxValue*0.5-0.5   # -16384
    mouse_rx = 0; mouse_ry = 0; mouse_x = 0; mouse_y = 0; mouse_x_curved = 0; mouse_y_curved = 0; selected_pip_setting = 0; button_timer = 0; time_lapse = 5; pip_management_enabled = False; configured_pip_setting = 5; block_button_timer = False; cached_pip_setting = 0

    #Coordinates for self centering
    a = 0; b = 0; c = 0; d = 0

    #pip settings
    current_pip_setting = 0;
    current_weapons_setting = 4
    current_engine_setting = 4
    current_system_setting = 4
    cycle = 0
    mouse_ctrl_enabled = True
    init_pip_management = False
    boost_compensation_enabled = False
    system_focus = True
    weapon_focus = False
    engine_focus = True

#Configure pip setting
if(keyboard.getPressed(Key.NumberPad1)):
    configured_pip_setting = 3
elif(keyboard.getPressed(Key.NumberPad2)):
    configured_pip_setting = 5
elif(keyboard.getPressed(Key.NumberPad3)):
    configured_pip_setting = 2

#Toggle mouse control
if(mouse.getPressed(4)):
    if(mouse_ctrl_enabled == False): mouse_ctrl_enabled = True
    else: mouse_ctrl_enabled = False

if(mouse_ctrl_enabled):
    #Toggle pip management
    if(keyboard.getPressed(Key.Delete)):
        if(pip_management_enabled == False): pip_management_enabled = True
        else: pip_management_enabled = False
   
    #Toggle boost compensation
    if(keyboard.getPressed(Key.PrintScreen)):
        if(boost_compensation_enabled == False): boost_compensation_enabled = True
        else: boost_compensation_enabled = False

    #Listen for mouse.wheel
    if(pip_management_enabled and mouse.wheelDown):
        keyboard.setPressed(Key.LeftBracket)
    if(pip_management_enabled and mouse.wheelUp):
        keyboard.setPressed(Key.RightBracket)

    #Adjusting pip_settings cycle.
    if(pip_management_enabled and (mouse.leftButton or mouse.rightButton)):
        # fire was pressed, focus on weapons.
        weapon_focus = True
        engine_focus = False
        system_focus = False
        button_timer = timer_duration * time_lapse
        init_pip_management = True
   
    if(pip_management_enabled and keyboard.getPressed(Key.Tab) and boost_compensation_enabled):
        # TAB was pressed, focus on engines.
        weapon_focus = False
        engine_focus = True
        system_focus = False
        button_timer = timer_duration * 4
        init_pip_management = True
   
    if(pip_management_enabled and keyboard.getPressed(Key.F15)):
        # shield block was clicked
        block_button_timer = True
        cached_pip_setting = selected_pip_setting
        selected_pip_setting = 11
    elif(pip_management_enabled and keyboard.getKeyUp(Key.F15)):
        # shield block was released
        block_button_timer = False
        if(cached_pip_setting != 0):
            selected_pip_setting = cached_pip_setting
        cached_pip_setting = 0
        # init_pip_management = True
   
    if(weapon_focus and init_pip_management):
        # first pip cycle for weapons.
        init_pip_management = False
        selected_pip_setting = configured_pip_setting
        button_timer = button_timer - 1
    elif(engine_focus and init_pip_management):
        # first pip cycle for engines.
        init_pip_management = False
        selected_pip_setting = 7
        button_timer = button_timer - 1
    elif(block_button_timer == False and button_timer > 0):
        button_timer = button_timer - 1
    elif(block_button_timer == False and button_timer == 0):
        selected_pip_setting = 10
        weapon_focus = False
        engine_focus = False
        system_focus = True
   
    if(current_pip_setting != selected_pip_setting):
        #Selection has been changed, select the chosen pip settings.
        current_pip_setting = selected_pip_setting
        pip_settings[current_pip_setting].current_key = 0
    else:
        #The main cycle of this script runs once in every 5 milliseconds.
        #2 keystrokes within 5 milliseconds of each other simply won't register.
        #So in order to give the keyboard time to react, only enter the adjusting loop once in whatever is configured in max_cycle_count.
        if(cycle == max_cycle_count):
            while True:
                if(pip_settings[current_pip_setting].current_key != len(pip_settings[current_pip_setting].keys)):
                    if(pip_settings[current_pip_setting].keys[pip_settings[current_pip_setting].current_key] == "D"):
                        keyboard.setPressed(Key.DownArrow)
                        pip_settings[current_pip_setting].current_key = pip_settings[current_pip_setting].current_key + 1
                    elif(pip_settings[current_pip_setting].keys[pip_settings[current_pip_setting].current_key] == "U"):
                        keyboard.setPressed(Key.UpArrow)
                        pip_settings[current_pip_setting].current_key = pip_settings[current_pip_setting].current_key + 1
                    elif(pip_settings[current_pip_setting].keys[pip_settings[current_pip_setting].current_key] == "R"):
                        keyboard.setPressed(Key.RightArrow)
                        pip_settings[current_pip_setting].current_key = pip_settings[current_pip_setting].current_key + 1
                    elif(pip_settings[current_pip_setting].keys[pip_settings[current_pip_setting].current_key] == "L"):
                        keyboard.setPressed(Key.LeftArrow)
                        pip_settings[current_pip_setting].current_key = pip_settings[current_pip_setting].current_key + 1
                    break           
                break
    if(cycle > max_cycle_count): cycle = 0       
    cycle = cycle + 1

    #Mouse axis definition
    mouse_x += mouse.deltaX * absolute_sens          # absolute mouse, lateral
    mouse_y += mouse.deltaY * absolute_sens          #                 vertical
    mouse_rx += mouse.deltaX * relative_x_sens         # relative mouse, lateral
    mouse_ry += mouse.deltaY * relative_y_sens         #                 vertical

    # Constraining axises to max values
    if (mouse_x > max): mouse_x = max
    elif (mouse_x < min): mouse_x = min
    if (mouse_y > max): mouse_y = max
    elif (mouse_y < min): mouse_y = min

    if (mouse_rx > max): mouse_rx = max
    elif (mouse_rx < min): mouse_rx = min
    if (mouse_ry > max): mouse_ry = max
    elif (mouse_ry < min): mouse_ry = min

    if(pip_management_enabled and keyboard.getPressed(Key.NumberPadPlus)):
        if(time_lapse < 10): time_lapse = time_lapse + 1
    if(pip_management_enabled and keyboard.getPressed(Key.NumberPadMinus)):
        if(time_lapse > 1): time_lapse = time_lapse - 1

    # Absolute mouse; lightly exponential curved axis
    if (mouse_x > 0): mouse_x_curved = math.floor((math.sqrt(mouse_x ** absolute_curve) /2 ) / 64)
    if (mouse_x < 0): mouse_x_curved = math.floor(-abs(math.sqrt(abs(mouse_x ** absolute_curve)) / 2 ) / 64)

    if (mouse_y > 0): mouse_y_curved = math.floor((math.sqrt(mouse_y ** absolute_curve) /2 ) / 64)
    if (mouse_y < 0): mouse_y_curved = math.floor(-abs(math.sqrt(abs(mouse_y ** absolute_curve)) / 2 ) / 64)

    # Writing absolute output to controller
    controller.x = filters.deadband(mouse_x_curved, 25)
    controller.y = filters.deadband(mouse_y_curved, 25)

    # Relative mouse; self centering axis routine
    a += mouse.deltaX
    b += mouse.deltaX

    if filters.stopWatch(True,60): c = a + 0
    if filters.stopWatch(True,30): d = b + 0

    if (c - d == 0):
        if mouse_rx < -(relative_x_range): mouse_rx += math.sqrt(abs(mouse_rx)) * rel_x_speed_curve
        elif mouse_rx > relative_x_range: mouse_rx -= math.sqrt(abs(mouse_rx)) * rel_x_speed_curve
   
        if mouse_ry < -(relative_y_range): mouse_ry += math.sqrt(abs(mouse_ry)) * rel_y_speed_curve
        elif mouse_ry > relative_y_range: mouse_ry -= math.sqrt(abs(mouse_ry)) * rel_y_speed_curve

    # Writing relative output to controller
    controller.rx = filters.deadband(mouse_rx, relative_x_range)
    controller.ry = filters.deadband(mouse_ry, relative_y_range)
else:
    controller.x = 0
    controller.y = 0

##### Diagnostics
diagnostics.watch(len(pip_settings[current_pip_setting].keys))
diagnostics.watch(pip_settings[current_pip_setting].current_key)
diagnostics.watch(mouse_ctrl_enabled)
diagnostics.watch(boost_compensation_enabled)
diagnostics.watch(cycle)
diagnostics.watch(controller.rx)
diagnostics.watch(controller.ry)
diagnostics.watch(controller.x)
diagnostics.watch(controller.y)
diagnostics.watch(selected_pip_setting)
diagnostics.watch(button_timer)
diagnostics.watch(configured_pip_setting)
diagnostics.watch(time_lapse)
diagnostics.watch(cached_pip_setting)

It has automated pip settings that can be toggled with the [DEL] button, and a boost toggle using [PRTSC]. I use the [TAB] key to actually boost.
note: this will mess with your keyboard seriously, hence the toggle function. When you're typing in the chat window while this function comes along, things will look totally different :ROFLMAO:

You have to set the cursor keys to pip management in order to use this, but thats the default setting I believe.
Numpad [+] and [-] sets the length of the timer. Numpad [1] to [3] sets the target pip settings. There should be more, but you'll get the idea.
When you set '[' and ']' to previous and next sub target, you can cycle through the targets modules using the mouse wheel.
I'm using mouse 6 to instantly set the shield to 4 pips, but had to bind mouse 6 to F15 in my logitec software because FeePIE ignored my mouse 6 button.
 
Last edited:
I basically rewrote the freepie script today for myself, and noticed one serious problem with it that I fixed:

Original (incorrect) code (from: https://github.com/EliteDangerous-Stuff/RelativeMouseToggle/blob/master/FreePIE Script.py):

Code:
# Self Centering Alternate Axis
a += mouse.deltaX
b += mouse.deltaX

if filters.stopWatch(True,60): c = a + 0
if filters.stopWatch(True,30): d = b + 0

if (c - d == 0):
    if mouseRX < -(relative_range): mouseRX += rel_speed
    elif mouseRX > relative_range:  mouseRX -= rel_speed
    if mouseRY < -(relative_range): mouseRY += rel_speed
    elif mouseRY > relative_range:  mouseRY -= rel_speed


Correct code:

Code:
# Self Centering Alternate Axis
    a += mouse.deltaX
    b += mouse.deltaX
    c += mouse.deltaY
    d += mouse.deltaY

    if filters.stopWatch(True, 60):  #see EDIT below for updated code
        e = a + 0                             #see EDIT below for updated code
        g = c + 0                             #see EDIT below for updated code
    if filters.stopWatch(True, 30): #see EDIT below for updated code
        f = b + 0                             #see EDIT below for updated code
        h = d + 0                            #see EDIT below for updated code
    if (e - f == 0):      
        if mouseRX < -(relative_range): mouseRX += rel_speed
        elif mouseRX > relative_range:  mouseRX -= rel_speed
    if (g - h == 0):
        if mouseRY < -(relative_range): mouseRY += rel_speed
        elif mouseRY > relative_range:  mouseRY -= rel_speed

You also need to add the following new global variables for the above code to work: e, f, g, h
... and intitialize them to 0 in the if starting: block, just like the a, b, c, d global variables.

The original code seems to be based on freepie code that was intended to be used with something like a steering wheel, and so only looked at one axis when determining when to autocenter. However, <pause for effect> mice have two independent axis.

EDIT: After further testing, there's one last thing that needs to be corrected:

Code:
    #if (filters.stopWatch(True, 30)):  # this version does what I expect, but the one below does what I *want* by happy accident.
    #    if (flip):
    #        flip = False
    #        f = b + 0
    #        h = d + 0
    #    else:
    #        flip = True
    #        e = a + 0  
    #        g = c + 0
        
    if (filters.stopWatch(flip, 30)):    
        flip = False
        f = b + 0
        h = d + 0
    else:
        flip = True
        e = a + 0  
        g = c + 0

... with a new variable (flip = True) added to the if starting: block. The reason why is because when checking the difference between those variables every 30 and 60 ms, what you actually want is for them to alternate every 30 seconds. Otherwise, (possibly due to timer inaccuracies) they'll land at the same time or too close to each other and cause the difference to be 0 whether the mouse is moving or not. That results in inconsistent mouseRX values and the above code fixes it. There are two versions because the top one does what I expect, while the bottom one behaves the way I actually want during gameplay. Freepie documentation is terrible, so I don't actually know how the filters.stopwatch function works.

Anyways, here's my complete version of this relative mouse toggle freepie script: https://pastebin.com/83UKKnfz
 
Last edited:
Can you help me here?

I, like other users have roported too, can't recognise vJoy as an input device, wen i launch the game this appears in the log file on the bidings folder:
sadness.png

Also the mouse on the game Flickers so badly thats even difficult to navigate through the menus...

And just one more thing, were in the script can i toggle between relative and absolute?

[Edit]

Finnaly put the vjoy up and running, now the only doubt i have is where to switch between the relative and absolute...

For those who, just like me, have the STEAM VERSION, the solution for the vJoy not appearing its on this post, also from ED's Forum XD

https://forums.frontier.co.uk/threads/solved-missing-devices-thrustmastertflighthotasx.549347/

The problem is that because of the Steam Input, the vJoy do not inicialize as an "multi-vector" joystick but as an Xbox Command LOL, to resolve this simply go to the Elite's config Tab on steam, "Controller", and Disable Steam-Input.

DONE


[Porbably Last Edit]

Never mind XD,

Its all running as it should be! Thank you all for your effort ;3
 
Last edited:
In the in-game controls setup, you can choose between relative or nor-relative mouse behavior. It means: in relative mode, as soon as you stop to move your mouse, the ship stop to move (unless you are in FA-Off). In non-relative, it behave similar to FA-Off, so if you impart a slight movement at your right, the ship continuously follow the same vector, until you change this. The game does not allow you to toggle between the two, but if you like non-relative movement, when you enter FA-Off you'll find extremely - if not impossible! - to properly fly your ship. Of course, relative and non-relative apply only to the lateral and vertical direction of the mouse, so it's only effective on the movement you had configured to be modified by the mouse.

I do not agree that the non-relative mouse is a cheat, as someone suggest. It's an ergonomic need: if you use your mouse in relative mode only, you are prone to muscular fatigue and other quite annoying chronic injuries. Believe me, I'm a musician and I'm quite expert on that field...



Its 2021 why doesn't the game have a relative mouse toggle. I am going to rez this thread everyday.
 
Bump. Surely, FA-OFF is meant to be employed for a proper space flight experience, but having to grind your wrists to deal with prolonged SC or FA-ON turns or instead perform incessant option menu hopping every time you want to switch flight mode can hardly be considered 'player experience' – at least not in the desirable sense. What is this supposed to be, a slave-driven imperial galley of yore?

Why does this game seem so intent on shooting itself (or rather its players?) in the foot at every given opportunity? An option to tie relative mouse to FA-OFF could be implemented in no time, and would certainly improve the experience for many who enjoy the flight model and happen to use KB/M. Isn't a good experience what a video game should aim for, first and foremost?

Adding more and more half-baked grindy mechanics will not brush over the lack of polish in plenty of the existing ones, which to a seasoned player eventually do stick out like sore thumbs, and I can't help but suspect that the devs are no longer driven by a perfectionist passion, but rather just the galley's drums. Tragic.
 
Last edited:
Bump. Surely, FA-OFF is meant to be employed for a proper space flight experience, but having to grind your wrists to deal with prolonged SC or FA-ON turns or instead perform incessant option menu hopping every time you want to switch flight mode can hardly be considered 'player experience' – at least not in the desirable sense. What is this supposed to be, a slave-driven imperial galley of yore?

Why does this game seem so intent on shooting itself (or rather its players?) in the foot at every given opportunity? An option to tie relative mouse to FA-OFF could be implemented in no time, and would certainly improve the experience for many who enjoy the flight model and happen to use KB/M. Isn't a good experience what a video game should aim for, first and foremost?

Adding more and more half-baked grindy mechanics will not brush over the lack of polish in plenty of the existing ones, which to a seasoned player eventually do stick out like sore thumbs, and I can't help but suspect that the devs are no longer driven by a perfectionist passion, but rather just the galley's drums. Tragic.
As someone once said : "It is what it is", this is nothing but an "marketing" scheme, why give the ability to FAOFF for free with kb&mouse when you can "lock" this function behind an HOTAS purchase? Lets not cry over the spilled milk, ive recently made an guide, that im sure is going to help you, if you're really into starting an "FAOFF Carrer" in Elite Dangerous, if that's what your looking for i recommend a lookup Here.
 
Thanks for the guide, but all of this could be implemented much more readily and conveniently on the game client's side. That it isn't – and hasn't been for many years now – suggests FDev either lack awareness or ambition, both of which wouldn't reflect all too well on future prospects of it ever fulfilling its actual potential. And I wouldn't be here criticizing it if I didn't care about it becoming all it could and should be...
 
Thanks for the guide, but all of this could be implemented much more readily and conveniently on the game client's side. That it isn't – and hasn't been for many years now – suggests FDev either lack awareness or ambition, both of which wouldn't reflect all too well on future prospects of it ever fulfilling its actual potential. And I wouldn't be here criticizing it if I didn't care about it becoming all it could and should be...
You just summed up the entirety of Elite Dangerous right there.

There are so many things that could have been, or should have been, and head scratching decisions. Missing supercruise button, 10item at a time for PP (when you need hundreds), same can be said for data gathering CG, a 3-4 step process to request docking (probably the most used feature for most players) instead of 1 button to trigger it, no easy way to transfer tritium from FC cargo to fuel storage,....

The list is quite long. And that's not even touching gameplay itself.
 
Thanks for the guide, but all of this could be implemented much more readily and conveniently on the game client's side. That it isn't – and hasn't been for many years now – suggests FDev either lack awareness or ambition, both of which wouldn't reflect all too well on future prospects of it ever fulfilling its actual potential. And I wouldn't be here criticizing it if I didn't care about it becoming all it could and should be...
To be frank, I wouldn't even use a FDev implementation. Yes this method is pretty technical, but so is flying FA off. So if this is too technical, with respect, its prolly a solution to a problem you don't have, and that is fine.

With FreePIE, you have control over all axis, you can draw control curves, and use those. You can implement your own pip management, your own programming skills are the limit. If Fdev was to slap on a generic function, it would prolly be to aggressive for one, and too slow for the other (and it would stop working after update13.5, only to be fixed in 14.8 before it breaks something else again in 14.9).
 
Top Bottom