Here's my FreePIE + vJoy script for mouse steering. It was initially made to mimic the LFS style of mouse steering in other racing games, and the axes are therefor mapped to the axes which the default G27 profile had in the games I tested.
It isn't very elegant because I ran into scoping problems as soon as I tried to solve this using functions and classes/objects.
The script features:
- Easy axis inversion controls
- LFS style sensitivity center reduction for mouse steering
- Timer based ignition cut so you don't manually cut the ignition for longer than necessary by holding down the shift up key
- Throttle blip that can be controlled by how long you hold down the shift down key
- Independent rate controls for increasing and decreasing throttle, brakes and clutch
- Addition rate controls for increasing and decreasing throttle and clutch during ignition cut and throttle blip events
if starting:
system.setThreadTiming(TimingTypes.HighresSystemTimer)
system.threadExecutionInterval = 5
def set_button(button, key):
if keyboard.getKeyDown(key):
v.setButton(button, True)
else:
v.setButton(button, False)
def calculate_rate(max, time):
if time > 0:
return max / (time / system.threadExecutionInterval)
else:
return max
int32_max = (2 ** 14) - 1
int32_min = (( 2** 14) * -1) + 1
v = vJoy[0]
v.x, v.y, v.z, v.rx, v.ry, v.rz, v.slider, v.dial = (int32_min,) * 8
# =============================================================================================
# Axis inversion settings (multiplier): normal = 1; inverted = -1
# =============================================================================================
global throttle_inversion, braking_inversion, clutch_inversion
throttle_inversion = 1
braking_inversion = 1
clutch_inversion = 1
# =============================================================================================
# Mouse settings
# =============================================================================================
global mouse_sensitivity, sensitivity_center_reduction
mouse_sensitivity = 25.0
sensitivity_center_reduction = 5.0
# =============================================================================================
# Ignition cut settings
# =============================================================================================
global ignition_cut_time, ignition_cut_elapsed_time
ignition_cut_enabled = True
ignition_cut_time = 100
ignition_cut_elapsed_time = 0
global ignition_cut, ignition_cut_released
# Init values, do not change
ignition_cut = False
ignition_cut_released = True
# =============================================================================================
# Steering settings
# =============================================================================================
global steering, steering_max, steering_min, steering_center_reduction
# Init values, do not change
steering = 0.0
steering_max = float(int32_max)
steering_min = float(int32_min)
steering_center_reduction = 1.0
# =============================================================================================
# Throttle settings
# =============================================================================================
global throttle_blip_enabled
throttle_blip_enabled = True
# In milliseconds
throttle_increase_time = 100
throttle_increase_time_after_ignition_cut = 0
throttle_increase_time_blip = 50
throttle_decrease_time = 100
global throttle, throttle_max, throttle_min
# Init values, do not change
throttle_max = int32_max * throttle_inversion
throttle_min = int32_min * throttle_inversion
throttle = throttle_min
global throttle_increase_rate, throttle_decrease_rate
# Set throttle behaviour with the increase and decrease time,
# the actual increase and decrease rates are calculated automatically
throttle_increase_rate = calculate_rate(throttle_max, throttle_increase_time)
throttle_increase_rate_after_ignition_cut = calculate_rate(throttle_max, throttle_increase_time_after_ignition_cut)
throttle_increase_rate_blip = calculate_rate(throttle_max, throttle_increase_time_blip)
throttle_decrease_rate = calculate_rate(throttle_max, throttle_decrease_time) * -1
# =============================================================================================
# Braking settings
# =============================================================================================
# In milliseconds
braking_increase_time = 100
braking_decrease_time = 100
global braking, braking_max, braking_min
# Init values, do not change
braking_max = int32_max * braking_inversion
braking_min = int32_min * braking_inversion
braking = braking_min
global braking_increase_rate, braking_decrease_rate
# Set braking behaviour with the increase and decrease time,
# the actual increase and decrease rates are calculated automatically
braking_increase_rate = calculate_rate(braking_max, braking_increase_time)
braking_decrease_rate = calculate_rate(braking_max, braking_decrease_time) * -1
# =============================================================================================
# Clutch settings
# =============================================================================================
# In milliseconds
clutch_increase_time = 0
clutch_decrease_time = 50
global clutch, clutch_max, clutch_min
# Init values, do not change
clutch_max = int32_max * clutch_inversion
clutch_min = int32_min * clutch_inversion
clutch = clutch_min
global clutch_increase_rate, clutch_decrease_rate
# Set clutch behaviour with the increase and decrease time,
# the actual increase and decrease rates are calculated automatically
clutch_increase_rate = calculate_rate(clutch_max, clutch_increase_time)
clutch_decrease_rate = calculate_rate(clutch_max, clutch_decrease_time) * -1
# =============================================================================================
# Button and key assignments
# =============================================================================================
global clutch_key
clutch_key = Key.C
global shift_up_key, shift_up_button
shift_up_key = Key.W
shift_up_button = 1
global shift_down_key, shift_down_button
shift_down_key = Key.S
shift_down_button = 2
global look_left_key, look_left_button
look_left_key = Key.A
look_left_button = 3
global look_right_key, look_right_button
look_right_key = Key.D
look_right_button = 4
global look_back_key, look_back_button
look_back_key = Key.X
look_back_button = 5
global change_view_key, change_view_button
change_view_key = Key.V
change_view_button = 6
global indicator_left_key, indicator_left_button
indicator_left_key = Key.Q
indicator_left_button = 7
global indicator_right_key, indicator_right_button
indicator_right_key = Key.E
indicator_right_button = 8
# =================================================================================================
# LOOP START
# =================================================================================================
# =================================================================================================
# Steering logic
# =================================================================================================
if steering > 0:
steering_center_reduction = sensitivity_center_reduction ** (1 - (steering / steering_max))
elif steering < 0:
steering_center_reduction = sensitivity_center_reduction ** (1 - (steering / steering_min))
steering = steering + ((float(mouse.deltaX) * mouse_sensitivity) / steering_center_reduction)
if steering > steering_max:
steering = steering_max
elif steering < steering_min:
steering = steering_min
v.x = int(round(steering))
# =================================================================================================
# Clutch logic
# =================================================================================================
if (throttle_blip_enabled and keyboard.getKeyDown(shift_down_key)) or (ignition_cut_enabled and ignition_cut_released and keyboard.getKeyDown(shift_up_key)) or keyboard.getKeyDown(clutch_key):
clutch = clutch_max
else:
clutch = clutch + clutch_decrease_rate
if clutch > clutch_max * clutch_inversion:
clutch = clutch_max * clutch_inversion
elif clutch < clutch_min * clutch_inversion:
clutch = clutch_min * clutch_inversion
v.slider = clutch
# =================================================================================================
# Throttle logic
# =================================================================================================
if ignition_cut_enabled and ignition_cut and ignition_cut_elapsed_time < ignition_cut_time:
ignition_cut_elapsed_time = ignition_cut_elapsed_time + system.threadExecutionInterval
if ignition_cut_enabled and not ignition_cut_released and keyboard.getKeyUp(shift_up_key):
ignition_cut_released = True
if throttle_blip_enabled and ((ignition_cut_enabled and not ignition_cut) or (not ignition_cut_enabled)) and keyboard.getKeyDown(shift_down_key):
# Throttle blip
throttle = throttle + throttle_increase_rate_blip
elif ignition_cut_enabled and ignition_cut_released and keyboard.getKeyDown(shift_up_key):
# Ignition cut
throttle = throttle_min
ignition_cut = True
ignition_cut_released = False
ignition_cut_elapsed_time = 0
elif mouse.leftButton:
if ignition_cut_enabled and ignition_cut and ignition_cut_elapsed_time >= ignition_cut_time:
throttle = throttle_max
else:
throttle = throttle + throttle_increase_rate
else:
throttle = throttle + throttle_decrease_rate
if ignition_cut_enabled and ignition_cut and ignition_cut_elapsed_time >= ignition_cut_time:
ignition_cut = False
ignition_cut_elapsed_time = 0
if throttle > throttle_max * throttle_inversion:
throttle = throttle_max * throttle_inversion
elif throttle < throttle_min * throttle_inversion:
throttle = throttle_min * throttle_inversion
v.y = throttle
# =================================================================================================
# Braking logic
# =================================================================================================
if mouse.rightButton:
braking = braking + braking_increase_rate
else:
braking = braking + braking_decrease_rate
if braking > braking_max * braking_inversion:
braking = braking_max * braking_inversion
elif braking < braking_min * braking_inversion:
braking = braking_min * braking_inversion
v.rz = braking
# =================================================================================================
# Buttons post-throttle logic
# =================================================================================================
set_button(look_left_button, look_left_key)
set_button(look_right_button, look_right_key)
set_button(look_back_button, look_back_key)
set_button(change_view_button, change_view_key)
set_button(indicator_left_button, indicator_left_key)
set_button(indicator_right_button, indicator_right_key)
# =================================================================================================
# PIE diagnostics logic
# =================================================================================================
diagnostics.watch(v.x)
diagnostics.watch(v.y)
diagnostics.watch(v.rz)
diagnostics.watch(v.slider)
diagnostics.watch(steering_center_reduction)
diagnostics.watch(throttle_blip_enabled)
diagnostics.watch(ignition_cut_enabled)