Skip to content

Instantly share code, notes, and snippets.

@cyberluke
Created October 13, 2024 11:33
Show Gist options
  • Save cyberluke/5ad828d52a3726dc9bf8fcc36ca17c17 to your computer and use it in GitHub Desktop.
Save cyberluke/5ad828d52a3726dc9bf8fcc36ca17c17 to your computer and use it in GitHub Desktop.
FreePIE for my fork with fixed FFB Force Feedback: https://github.com/cyberluke/FreePIE
if starting:
import time
import math
system.setThreadTiming(TimingTypes.HighresSystemTimer)
system.threadExecutionInterval = 30
#system.setThreadTiming(TimingTypes.SystemTimer)
#system.threadExecutionInterval = 1
G940_JoystickID="Logitech G940 Joystick";
G940_PedalsID="Logitech G940 Pedals";
G940_ThrottleID="Logitech G940 Throttle";
#G940_JoystickID=1;
#G940_PedalsID=1;
#G940_ThrottleID=1;
buttonsState = {}
for i in xrange(vJoy[0].buttonsMax):
buttonsState[i] = False
joystick[G940_ThrottleID].printSupportedEffects();
diagnostics.debug("starting")
joystick[G940_ThrottleID].setAllG940LED(LogiColor.LOGI_AMBER);
time.sleep(1);
joystick[G940_ThrottleID].setAllG940LED(LogiColor.LOGI_OFF);
# ENABLE FFB
vJoy[0].registerFfbDevice(joystick[G940_JoystickID])
#diagnostics.disable();
#The following is the tweakaxis function. Don't change this unless you know how to program. Call on this function in the Axis Rebinds section.
def tweakaxis(input, input_range_min, adjusted_center, input_range_max, dband):
if input >= adjusted_center:
return filters.ensureMapRange(input, adjusted_center + dband, input_range_max, 0, 1000)
elif input <= adjusted_center:
return filters.ensureMapRange(input, input_range_min, adjusted_center - dband, -1000, 0)
else:
return 0
#The tweakaxis function's variables explained:
#input:-------------This specifies the input (usually a real joystick axis) to be modified.
#input_range_min:---The value of the input to map to the tweaked output's full minimum. Use -1000 for an unchanged endpoint on conventional joysticks.
#adjusted_center:---The value of the input to map to the tweaked output's center. Assign a new center point to your joystick's axis with this value.
#input_range_max:---The value of the input to map to the tweaked output's full maximum. Use 1000 for an unchanged endpoint on conventional joysticks.
#dband:-------------Deadband. The distance that you must move the input away from adjusted_center before the smallest value is output.
#Tips:
#input_range_min and _max can be changed to alter the effective range of an axis on a physical device.
#For example, it can be used to halve the stick travel distance for the full range of outputs by using a _min of -500 and a _max of 500.
#If making asymmetrical changes to the input_range values, remember to consider whether adjusted_center needs to bisect those values.
#Using values for these vars with absolute value greater than 1000 (again, for most sticks) will result in more precision by sacrificing access to the output values at the extremities.
#tweakaxis() is meant to be composed, including with itself. The order matters greatly. The true power of the script lies here.
#Enclose every set of functions in this before setting a vJoy axis equal to it:
def vJR(input):
return filters.ensureMapRange(input, -1000, 1000, -vJoy[0].axisMax, vJoy[0].axisMax)
#Curve functions:
#Basic x^n curve:
def powcv(input, curvepower, min = -1000, max = 1000):
if input >= 0:
return filters.ensureMapRange(math.pow(input, curvepower), 0, math.pow(max, curvepower), 0, max)
else:
return filters.ensureMapRange(-math.pow(-input, curvepower), -math.pow(-min, curvepower), 0, min, 0)
#Fancy -((1-x)^n)+1 curve, made origin-symmetric:
#Use 0 << n << 1 for best results, with small f''(x) for small x and large f''(x) for large x.
def revrootcv(input, curvepower, min = -1000, max = 1000):
if input >= 0:
return filters.ensureMapRange(1-math.pow(1-filters.ensureMapRange(input, 0, max, 0, 1), curvepower), 0, 1, 0, max)
else:
return filters.ensureMapRange(-1+math.pow(1-filters.ensureMapRange(-input, 0, -min, 0, 1), curvepower), -1, 0, min, 0)
#Master-controlled scaling for inputs:
#The variable limits created converge on the center of whichever function is directly inside it.
#"master" switch made to easily determine which control to use.
def mscale(input, master = 0):
if master == 0: #Positional master
scalevalue = filters.ensureMapRange(-joystick[2].x, 0, 1000, 0.15, 1)
if joystick[2].x > 990:
scalevalue = 0
return input * scalevalue
elif master == 1: #Rotational master
scalevalue = filters.ensureMapRange(joystick[2].zRotation, -990, 990, 0, 1)
return input * scalevalue
else:
return 0
#Change axis_mult if 'Windows output: vJoy' axes have the wrong range of motion.
# (They should match the correspondingly bound values of
# 'Windows output: Physical' 1 and 2 exactly.)
axis_mult = (vJoy[0].axisMax / 1000)
t0 = time.clock()
#Joystick button to keyboard button variable function
def jkey(j_index, j_button, keybind):
if joystick[j_index].getDown(j_button):
keyboard.setKeyDown(keybind)
else:
keyboard.setKeyUp(keybind)
#Joystick button to keyboard button variable function
def keyj(Key, j_button):
if keyboard.getKeyDown(Key):
vJoy[0].setButton(j_button, 1)
else:
vJoy[0].setButton(j_button, 0)
def keyCodeToNumber(key):
if (key == Key.D1):
return -16535
if (key == Key.D2):
return -12258
if (key == Key.D3):
return -8192
if (key == Key.D4):
return -4096
if (key == Key.D5):
return 0
if (key == Key.D6):
return 4096
if (key == Key.D7):
return 8192
if (key == Key.D8):
return 12258
if (key == Key.D9):
return 16535
#Joystick button to keyboard button variable function
def keyaxis(key):
if keyboard.getKeyDown(key):
vJoy[0].z = keyCodeToNumber(key)
#Joystick button to vJoy button variable function
def jvjb(j_index, j_button, vjoy_button):
if joystick[j_index].getDown(j_button):
vJoy[0].setButton(vjoy_button, 1)
else:
vJoy[0].setButton(vjoy_button, 0)
#Joystick button to vJoy button variable function (G940 LED)
def jvjbled(j_index, j_button, vjoy_button):
if joystick[j_index].getDown(j_button):
vJoy[0].setButton(vjoy_button, 1)
buttonsState[j_button]=True
if joystick[G940_ThrottleID].isG940LED(j_button+1-4, LogiColor.LOGI_AMBER):
joystick[G940_ThrottleID].setG940LED(j_button+1-4, LogiColor.LOGI_GREEN)
else:
joystick[G940_ThrottleID].setG940LED(j_button+1-4, LogiColor.LOGI_AMBER)
elif buttonsState[j_button] == True:
buttonsState[j_button]=False
vJoy[0].setButton(vjoy_button, 0)
#Invert all LEDs (G940 LED)
def jvjbledinv(j_index, j_button):
if joystick[j_index].getDown(j_button):
for b in range(0, 7):
if joystick[G940_ThrottleID].isG940LED(b+1, LogiColor.LOGI_OFF):
continue
if joystick[G940_ThrottleID].isG940LED(b+1, LogiColor.LOGI_AMBER):
joystick[G940_ThrottleID].setG940LED(b+1, LogiColor.LOGI_GREEN)
else:
joystick[G940_ThrottleID].setG940LED(b+1, LogiColor.LOGI_AMBER)
#Axis rebinds
#Adding 1 before multiplying by axis_mult seems to compensate for
# a one step offset in the vJoy driver itself.
jvjb(G940_JoystickID, 0, 0)
jvjb(G940_JoystickID, 1, 1)
jvjb(G940_JoystickID, 2, 2)
jvjb(G940_JoystickID, 3, 3)
jvjb(G940_JoystickID, 4, 4)
jvjb(G940_JoystickID, 5, 5)
jvjb(G940_JoystickID, 6, 6)
jvjb(G940_JoystickID, 7, 7)
jvjbled(G940_ThrottleID, 4+0, 8)
jvjbled(G940_ThrottleID, 4+1, 9)
jvjbled(G940_ThrottleID, 4+2, 10)
jvjbled(G940_ThrottleID, 4+3, 11)
jvjbled(G940_ThrottleID, 4+4, 12)
jvjbled(G940_ThrottleID, 4+5, 13)
jvjbled(G940_ThrottleID, 4+6, 14)
#jvjbled(G940_ThrottleID, 4+7, 15)
jvjbledinv(G940_ThrottleID, 4+7)
vJoy[0].setAnalogPov(0, joystick[G940_JoystickID].pov[0])
vJoy[0].rx = joystick[G940_JoystickID].sliders[1];
vJoy[0].ry = joystick[G940_JoystickID].sliders[0];
vJoy[0].rz = joystick[G940_PedalsID].zRotation;
vJoy[0].x = joystick[G940_JoystickID].x;
vJoy[0].y = joystick[G940_JoystickID].y;
vJoy[0].z = joystick[G940_ThrottleID].x;
#diagnostics.watch(joystick[G940_JoystickID].sliders[0])
#diagnostics.watch(joystick[G940_JoystickID].sliders[1])
#Script execution time tracker
#totaltime = time.clock() - t0
#diagnostics.watch(totaltime)
""""""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment