Recently, I have been playing a bus driving simulator. I have a racing wheel, which doesn't have a clutch pedal, so I searched for a way to adapt the mouse to act as a joystick with clutch, brake and gas. I found a solution with vJoy and FreePIE - Programmable Input Emulator. I found an example, which works perfectly for the mouse:
#Title :OMSI 2 Freepie Mouse (Edited Mjoy vJoy FreePIE python script)
#Version :0.1 (2016-03-22)
#Author :snp, NEMOROSUS
#Description :FreePIE python script for OMSI 2 mouse controls such as acceleration, steering and clutch control that is more accurate that the built-in one.
import time
from System import Int16
from ctypes import windll, Structure, c_ulong, byref, CDLL
class POINT(Structure):
_fields_ = [("x", c_ulong), ("y", c_ulong)]
if starting:
vJoy0_stat = 1
vJoy[0].x = 0
vJoy[0].y = 0
vJoy[0].z = 0
x = 0
y = 0
z = 0
mouse_x = 0
mouse_y = 0
mouse_z = 0
mouse_x_locked = 0
mouse_y_locked = 0
x_m = 0
y_m = 0
axis_max = 16448
screen_x = windll.user32.GetSystemMetrics(0)
screen_y = windll.user32.GetSystemMetrics(1)
pt = POINT()
sequence = 0
system.setThreadTiming(TimingTypes.HighresSystemTimer)
system.threadExecutionInterval = 1
z += mouse.wheel * 10
# X/Y axis centering
#if keyboard.getKeyDown(Key.Space):
#windll.user32.SetCursorPos((screen_x / 2),(screen_y / 2))
# Mjoy vJoy
# Turn VJoy on/off
if keyboard.getPressed(Key.K):
if sequence == 0:
vJoy0_stat = 0
elif sequence == 1:
vJoy0_stat = 1
sequence = sequence + 1
if sequence > 1:
sequence = 0
if vJoy0_stat == 1:
windll.user32.GetCursorPos(byref(pt))
mouse_x = pt.x
mouse_y = pt.y
sensitivity = 28
x_m = (mouse_x - (screen_x / 2)) * sensitivity
y_m = (mouse_y - (screen_y / 2)) * sensitivity / 0.66
x_both = x_m + x
y_both = y_m + y
x_keyb_sensitivity = 350
y_keyb_sensitivity = 350
if x_m > axis_max:
x_m = axis_max
if x_m < - axis_max:
x_m = - axis_max
if y_m > axis_max:
y_m = axis_max
if y_m < - axis_max:
y_m = - axis_max
if x > axis_max:
x = axis_max
if x < - axis_max:
x = - axis_max
if y > axis_max:
y = axis_max
if y < - axis_max:
y = - axis_max
if z > axis_max:
z = axis_max
if z < - axis_max:
z = - axis_max
if x_both > axis_max:
x_both = axis_max
if x_both < - axis_max:
x_both = - axis_max
if y_both > axis_max:
y_both = axis_max
if y_both < - axis_max:
y_both = - axis_max
vJoy[0].x = x_m + x
vJoy[0].y = y_m + y
vJoy[0].z = z
# Diag
diagnostics.watch(screen_x)
diagnostics.watch(screen_y)
diagnostics.watch(mouse_x)
diagnostics.watch(mouse_y)
diagnostics.watch(mouse_x_locked)
diagnostics.watch(mouse_y_locked)
diagnostics.watch(vJoy[0].x)
diagnostics.watch(vJoy[0].y)
diagnostics.watch(vJoy[0].z)
I am very new to Python so I started googling for a solution in terms of how to convert the two-pedal Logitech wheel into a three-pedal wheel. I came up with the idea to use vJoy as my "final" joystick. I planned to feed it up with all the axis from the wheel and the Y-axe from the mouse, which will act as the clutch. So, after searching for a solution, I added this piece of Python code:
from ctypes import CDLL
_glfw = CDLL("path_to_FreePIE_installation\\plugins\\lib-mingw-w64\\glfw3.dll")
joyNum = 0
isHere = _glfw.glfwJoystickPresent(joyNum)
diagnostics.watch(isHere)
joyName = _glfw.glfwGetJoystickName(joyNum)
diagnostics.watch(joyName)
#joy = _glfw.glfwGetJoystickAxes(0)
#joy = _glfw.glfwGetJoystickButtons(0)
#diagnostics.watch(joy)
I took the idea from this documentation and this documentation. They say, that joyNum should be between 0 and 15. I tried every single number between 0 and 15 and even with 16 and 17. Every time, isHere is 0 although I have connected the wheel to one of the three USB-ports of my laptop. I tried to attach it to all them three with the same result. _glfw.glfwGetJoystickName(joyNum)
is also giving me 0 every time. Can somebody help me to debug this? I don't understand why it can't find the wheel. It is not a problem with the driver because I can play games with no problem right now - the wheel is working normally.
When I try to call _glfw.glfwGetJoystickAxes(0)
or _glfw.glfwGetJoystickButtons(0)
- FreePIE crashes and when I debug it with VS2010, the exception message is: "Attempted to read or write protected memory. This is often an indication that another memory is corrupt."
EDIT:
I took a closer look at another documentation and replaced the code I added with this one:
from ctypes import CDLL, POINTER, c_float, c_int
glfw = CDLL("path_to_FreePIE_installation\\plugins\\lib-mingw-w64\\glfw3.dll")
joyNum = 0
isHere = _glfw.glfwJoystickPresent(joyNum)
diagnostics.watch(isHere)
joyName = _glfw.glfwGetJoystickName(joyNum)
diagnostics.watch(joyName)
cnt = c_int(0)
_glfw.glfwGetJoystickAxes.restype = POINTER(c_float)
joy = _glfw.glfwGetJoystickAxes(0, byref(cnt))
diagnostics.watch(joy)
axes = [joy[i].value for i in range(cnt)]
diagnostics.watch(cnt)
diagnostics.watch(axes)
Now the script is not run at all and I see the following error in FreePIE's console:
range() integer end argument expected, got c_long. The error occurs on this line: axes = [joy[i].value for i in range(cnt)]
I am confused. Here they have shown an example on how to get the axes values. This is the snippet from their site:
def glfwGetJoystickAxes(joy):
count = c_int(0)
_glfw.glfwGetJoystickAxes.restype = POINTER(c_float)
c_axes = _glfw.glfwGetJoystickAxes(joy, byref(count))
axes = [c_axes[i].value for i in range(count)]
As you can see here, the count is of type c_int and they give it to range()
and they say it should work. Or maybe joy[i].value in my code snippet is of type c_long and that is the case?
Any help will be greatly appreciated! Thanks!
EDIT2:
For anyone, who may fall into such a situation. This is the code, which did the job for me:
if starting:
# ...
_glfw.glfwInit() # this is VERY important!
joyNum = 1 # not 0, because the mouse appears to be joystick No 0
# ...
if vJoy0_stat == 1: # the main loop
# ...
isHere = _glfw.glfwJoystickPresent(joyNum)
diagnostics.watch(isHere)
if isHere == 1:
cnt = c_int(0) # must be of type c_int!
_glfw.glfwGetJoystickAxes.restype = POINTER(c_float) # VERY important!
joy = _glfw.glfwGetJoystickAxes(joyNum, byref(cnt))
diagnostics.watch(joy[0]) # this appears to be the steering axe
diagnostics.watch(joy[1]) # this appears to be the two pedals combined in one axe
# from here I will do sth like:
windll.user32.GetCursorPos(byref(pt))
mouse_y = pt.y
y_m = (mouse_y - (screen_y / 2)) * sensitivity / 0.66
vJoy[0].x = joy[0]
vJoy[0].y = joy[1]
vJoy[0].z = y_m
Not a solution to your problem but :
A python module is available for GLFW : glfw 1.4.0
As explained in the documentation, GLFW should be initialized by calling glfwInit
before using glfwJoystickPresent
. Maybe it would help