通过 Python 从罗技方向盘获取轴信息

Get axis info from Logitech racing wheel via Python

最近一直在玩公交车驾驶模拟器。我有一个没有离合器踏板的赛车方向盘,所以我想方设法让鼠标充当带有离合器、刹车和油门的操纵杆。我找到了 vJoy 和 FreePIE - 可编程输入模拟器的解决方案。我找到了一个非常适合鼠标的示例:

#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)

我是 Python 的新手,所以我开始在谷歌上搜索有关如何将两踏板罗技车轮转换为三踏板车轮的解决方案。我想出了使用 vJoy 作为我的 "final" 游戏杆的想法。我计划用轮子的所有轴和鼠标的 Y 轴来喂它,这将充当离合器。所以,在寻找解决方案后,我添加了这段 Python 代码:

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)

我的想法来自 this documentation and this documentation。他们说,joyNum 应该在 0 到 15 之间。我尝试了 0 到 15 之间的每个数字,甚至尝试了 16 和 17。每次,isHere 都是 0,尽管我已经将轮子连接到我的三个 USB 端口之一笔记本电脑。我试图将它附加到所有这三个结果相同。 _glfw.glfwGetJoystickName(joyNum) 也每次都给我 0。有人可以帮我调试吗?我不明白为什么它找不到轮子。这不是驱动程序的问题,因为我现在可以毫无问题地玩游戏 - 方向盘工作正常。

当我尝试调用 _glfw.glfwGetJoystickAxes(0)_glfw.glfwGetJoystickButtons(0) - FreePIE 崩溃并且当我使用 VS2010 调试它时,异常消息是:"Attempted to read or write protected memory. This is often an indication that another memory is corrupt."

编辑:

我仔细查看了 another documentation 并将我添加的代码替换为以下代码:

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)

现在脚本根本不是 运行,我在 FreePIE 的控制台中看到以下错误:

预期

range() 整数结束参数,得到 c_long。 错误发生在这一行: axes = [joy[i].value for i in range(cnt)]

我很困惑。 Here 他们展示了如何获取轴值的示例。这是他们网站上的片段:

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)]

正如您在这里看到的,计数是 c_int 类型,他们将其提供给 range(),他们说它应该可以工作。或者我的代码片段中的 joy[i].value 是 c_long 类型,是这样吗?

任何帮助将不胜感激!谢谢!

编辑2:

对于可能陷入这种情况的任何人。这是为我完成工作的代码:

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

不是您问题的解决方案,但是:

  1. 一个 python 模块可用于 GLFW : glfw 1.4.0

  2. documentation 中所述,GLFW 应在使用 glfwJoystickPresent 之前通过调用 glfwInit 进行初始化。也许会有帮助