So basically here is a working solution, with the following caveats:
- You need to know the max amount of mouse units that a given mech can twist.
- You need to know the max mouse units / ms that a given mech can twist at.
So, as long as one can find these values (Through either trial and error, or through a yet-to-be-written calibration system), then this implementation seems to perfectly map joystick input to mouse output.
Ideally, you want the highest values as possible, but I have found some that are pretty darned close for my test mech and it never, seems to go out of synch, although I did not play a match as I found it unusable for the following reasons:
The "coordinate space" (ie the range of coordinates that can be acheived for both axes) for a joystick is square.
The coordinate space for the mech is a wide rectangle.
This means that if you map the joystick directly to the mouse, your X and Y sensitivities can be quite different, making it difficult to aim.
Also, the only flightstick I have is the Hotas X, and it is very low resolution, so it is quite unsuitable for stick aiming in MWO.
I think the X/Y ratio thing could be sorted out - you could make the Y axis match the X axis sensitivity, and "clip" it. It would mean that only the middle part of your Y axis would do anything, but at least it would be even.
Could anyone with a high accuracy stick try this out and see what they think?
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
#SingleInstance force
; User configurables
; For all [arrays], the first value is X, the second is Y
MOUSE_UNITS_RANGE := [5000, 1000] ; The total range of movement, in mouse units, for each axis.
MAX_TWIST_RATE := 25 ; The max twist rate, in mouse units
STICK_ID := 2 ; The ID of the stick to take input from
STICK_AXES := ["X", "Y"] ; The axes on the stick to take input from
; Internal vars
MAX_JOYSTICK_RANGE := 100
JOYSTICK_OFFSET := MAX_JOYSTICK_RANGE / 2
JOYSTICK_MOUSE_RATIOS := [MOUSE_UNITS_RANGE[1] / MAX_JOYSTICK_RANGE, MOUSE_UNITS_RANGE[2] / MAX_JOYSTICK_RANGE]
AXIS_NAMES := [STICK_ID "Joy" STICK_AXES[1], STICK_ID "Joy" STICK_AXES[2]]
current_values := [0,0]
Loop {
; Reset the move amount
delta_move := [0, 0]
; Work out how much we want to move in X and Y
Loop 2 {
; Get state of axis
axis_in := GetKeyState(AXIS_NAMES[A_Index])
; Work out at what mouse "coordinate" that the stick position equates to
desired_value := round((axis_in - JOYSTICK_OFFSET) * JOYSTICK_MOUSE_RATIOS[A_Index])
; Do we need to generate mouse input?
if (desired_value != current_values[A_Index]){
; Find out how much we want to move the mouse by
delta_move[A_Index] := desired_value - current_values[A_Index]
; Limit the amount of movement for this tick to the MAX_TWIST_RATE
delta_move[A_Index] := abs(delta_move[A_Index]) > MAX_TWIST_RATE ? MAX_TWIST_RATE * sgn(delta_move[A_Index]) : delta_move[A_Index]
; Update current value
current_values[A_Index] += delta_move[A_Index]
}
}
; Generate mouse input for both axes at once
DllCall("user32.dll\mouse_event", "UInt", 0x0001, "Int", delta_move[1], "Int", delta_move[2], "UInt", 0, "UPtr", 0)
Sleep 10
}
; Returns -1 if value is negative, or +1 if 0 or positive
sgn(val){
if (val >= 0)
return 1
else
return -1
}