#NoTrayIcon ; Original program by Ejoc ; Improved by Adam1213 ; Extended by a guest #include #include ; Global variables (DLL and control handles) Global $Memo, $WinMMDLL = -1, $KernelDll = -1 ; Variables for program flow and error handling Local $DLLRetValArray, $OK = True, $V, $i, $NextPoll ; Variables for DLL access Local $JoyStruct, $JoyStructPtr, $JoyStructSize Local $JCapStruct, $JCapStructPtr, $JCapStructSize ; Variables for detection of the joystick to use Local $MaxJoyNum, $JCount = 0, $JIDSelected = -1, $JIDFirst = -1, $JoyNum ; Variables for information about detected joysicks Local $Mid, $Pid, $Pname, $NumAxes, $NumButtons, $Caps Local $XMin, $XMax, $YMin, $YMax, $TMin, $TMax, $RMin, $RMax ; Variables for settings Local $KeyUp, $KeyDown, $KeyLeft, $KeyRight Local $KeyTUp, $KeyTDown, $KeyRLeft, $KeyRRight Local $KeyB1, $KeyB2, $KeyB3, $KeyB4, $KeyB5, $KeyB6, $KeyB7, $KeyB8 Local $KeyB9, $KeyB10, $KeyB11, $KeyB12, $KeyB13, $KeyB14, $KeyB15, $KeyB16 Local $KeyP1, $KeyP2, $KeyP3, $KeyP4 Local $JPreset, $PollTime, $DeadZoneX, $DeadZoneY, $DeadZoneT, $DeadZoneR ; Variables for thresholds for movement detection Local $Ax1Low, $Ax1High, $Ax2Low, $Ax2High Local $Ax3Low, $Ax3High, $Ax4Low, $Ax4High ; Variables for old button/axis status needed to detect changes Local $OldUp = 0, $OldDown = 0, $OldLeft = 0, $OldRight = 0 Local $OldTUp = 0, $OldTDown = 0, $OldRLeft = 0, $OldRRight = 0 Local $OldB1 = 0, $OldB2 = 0, $OldB3 = 0, $OldB4 = 0 Local $OldB5 = 0, $OldB6 = 0, $OldB7 = 0, $OldB8 = 0 Local $OldB9 = 0, $OldB10 = 0, $OldB11 = 0, $OldB12 = 0 Local $OldB13 = 0, $OldB14 = 0, $OldB15 = 0, $OldB16 = 0 Local $OldP1 = 0, $OldP2 = 0, $OldP3 = 0, $OldP4 = 0 ; Precalculated variables to speed up processing inside loop Local $CheckX, $CheckY, $CheckT, $CheckR, $CheckButtons, $CheckPOV ; Variables for timer to compensate running time Local $TimeLeft, $Timer ; Functions Func CloseButton(); Releases resources and terminates the program GUIDelete() If $WinMMDLL <> -1 Then DllCall($WinMMDLL, "ULONG", "timeEndPeriod", "UINT", 1) DllClose($WinMMDLL) EndIf If $KernelDll <> -1 Then DllClose($KernelDll) Exit EndFunc Func MemoWrite($Message = ""); Writes a line of text to the trace window GUICtrlSetData($Memo, $Message & @CRLF, 1) EndFunc Func GetFromEnv($Env, $Def = ""); Reads a setting from environment/the default Local $Val = EnvGet("SJP_" & $Env) If $Val Then If $Val = "---" Then $Val = "" Else If $Def Then $Val = $Def EndIf If $Val Then MemoWrite($Env & ": " & $Val) Return $Val EndFunc Func GetFromEnvNum($Env, $Def = ""); Reads a numeric setting Local $Val = GetFromEnv($Env, $Def) If $Val = "" Then $Val = 0 Else $Val = Number($Val) EndIf Return $Val EndFunc ; Send a keypress/release on change ; Workaround for odd behavior of not fully releasing CTRL, SHIFT and ALT ; Note that switch is case insensitive, so we don't need to address this Func SendOnChange(ByRef $Old, $New, $Key) If $Old <> $New Then If $New Then Send("{" & $Key & " down}") Else Send("{" & $Key & " up}") Switch $Key Case "LALT", "RALT" Send("{ALTDOWN}") Send("{ALTUP}") Case "LSHIFT", "RSHIFT" Send("{SHIFTDOWN}") Send("{SHIFTUP}") Case "LCTRL", "RCTRL" Send("{CTRLDOWN}") Send("{CTRLUP}") EndSwitch EndIf $Old = $New EndIf EndFunc ; Detects status changes of stick/slider movement and triggers keypress/release Func SendOnAxChange($Val, $Low, $High, ByRef $OldLow, ByRef $OldHigh, $LowKey, $HighKey) Local $L, $H If $Val > $High Then $L = 0 $H = 1 ElseIf $Val < $Low Then $L = 1 $H = 0 Else $L = 0 $H = 0 EndIf If $LowKey Then SendOnChange($OldLow, $L, $LowKey) If $HighKey Then SendOnChange($OldHigh, $H, $HighKey) EndFunc ; Set the threshold values for the different axes/sliders Func SetAxisDeadZone(ByRef $AxLow, ByRef $AxHigh, $Min, $Max, $DeadZonePercent) Local $Diff = $Max - $Min, $Center = $Diff / 2 + $Min Local $DeadZone = $Diff * $DeadZonePercent / 100 $AxLow = $Center - $DeadZone $AxHigh = $Center + $DeadZone EndFunc ; Main program starting here ; Don't use send delay because they consume CPU time AutoItSetOption("SendKeyDelay", 0) AutoItSetOption("SendKeyDownDelay", 0) ; Create the trace window If $OK Then If GUICreate("Joystick tool trace window", 600, 400) = 0 Then MsgBox($MB_SYSTEMMODAL, "", "Couldn't create the GUI.") Exit 1 EndIf EndIf ; Create text control for the trace output If $OK Then $Memo = GUICtrlCreateEdit("", 2, 2, 596, 396, _ BitOr($WS_VSCROLL,$WS_HSCROLL,$ES_MULTILINE,$ES_READONLY)) If $Memo = 0 Then MsgBox($MB_SYSTEMMODAL, "", "Couldn't create the trace output control.") Exit 2 EndIf EndIf ; Display the window If $OK Then If GUISetState(@SW_SHOW) = 0 Then MsgBox($MB_SYSTEMMODAL, "", "Couldn't open the trace window for display.") Exit 3 EndIf EndIf ; From now on it is possible to display something in th trace window. If $OK Then MemoWrite("Program startup.") MemoWrite() EndIf ; Change font for better readability If $OK Then If GUICtrlSetFont($Memo, 9, 400, 0, "Courier New") = 0 Then MemoWrite("Couldn't change font for better readability. Using the default.") MemoWrite() EndIf EndIf ; Register close event (ensure the program releases resources at termination) If $OK Then Opt("GUIOnEventMode", 1) GUISetOnEvent($GUI_EVENT_CLOSE, "CloseButton") EndIf ; Create and initialize memory stucture for joystick axis/slider/button states If $OK Then MemoWrite("Create joystick memory structure.") $JoyStruct = DllStructCreate("struct;DWORD Size;DWORD Flags;DWORD Xpos;" & _ "DWORD Ypos;DWORD Zpos;DWORD Rpos;DWORD Upos;DWORD Vpos;DWORD Buttons;" & _ "DWORD ButtonNumber;DWORD POV;DWORD Reserved1;DWORD Reserved2;endstruct") If @error Then $OK = False MemoWrite("Error creating structure.") EndIf EndIf If $OK Then $JoyStructPtr = DllStructGetPtr($JoyStruct) If $JoyStructPtr = 0 Then $OK = False MemoWrite("Error creating pointer to stucture.") EndIf EndIf If $OK Then $JoyStructSize = DllStructGetSize($JoyStruct) If @error Then $OK = False MemoWrite("Error calculating structure size.") EndIf EndIf If $OK Then DllStructSetData($JoyStruct, "Size", $JoyStructSize) If @error Then $OK = False MemoWrite("Error setting structure size.") EndIf EndIf ;X = 1 ;Y = 2 ;Z = 4 ;R = 8 ;U = 16 ;V = 32 ;POV = 64 ;BUTTONS = 128 ;RAWDATA = 256 ;POVCTS = 512 ;CENTERED = 1024 If $OK Then DllStructSetData($JoyStruct, "Flags", 207); X + Y + Z + R + POV + BUTTONS If @error Then $OK = False MemoWrite("Error setting return all flag.") EndIf EndIf ; Create and initialize memory stucture for joystick capabilities If $OK Then MemoWrite("OK") MemoWrite() MemoWrite("Create joystick capabilities structure.") $JCapStruct = DllStructCreate("struct;word Mid;word Pid;char Pname[32];" & _ "ulong Xmin;ulong Xmax;ulong Ymin;ulong Ymax;ulong Zmin;ulong Zmax;" & _ "ulong NumButtons;ulong PeriodMin;ulong PeriodMax;ulong Rmin;ulong Rmax;" & _ "ulong Umin;ulong Umax;ulong Vmin;ulong Vmax;ulong Caps;ulong MaxAxes;" & _ "ulong NumAxes;ulong MaxButtons;char RegKey[32];char OEMVxD[260];endstruct") If @error Then $OK = False MemoWrite("Error creating structure.") EndIf EndIf If $OK Then $JCapStructPtr = DllStructGetPtr($JCapStruct) If $JCapStructPtr = 0 Then $OK = False MemoWrite("Error creating pointer to stucture.") EndIf EndIf If $OK Then $JCapStructSize = DllStructGetSize($JCapStruct) If @error Then $OK = False MemoWrite("Error calculating structure size.") EndIf EndIf ; Initialize Windows Multimedia DLL If $OK Then MemoWrite("OK") MemoWrite() MemoWrite("Open windows multimedia DLL.") $WinMMDLL = DllOpen("winmm.dll") If $WinMMDLL = -1 Then $OK = False MemoWrite("Error opening DLL.") EndIf EndIf ; Switch timer to higher precision for better sleep accuracy If $OK Then DllCall($WinMMDLL, "ULONG", "timeBeginPeriod", "UINT", 1) EndIf ; Initialize Windows Kernel DLL (only used for a more accurate sleep function) If $OK Then MemoWrite("OK") MemoWrite() MemoWrite("Open kernel DLL.") $KernelDll = DllOpen("kernel32.dll") If $KernelDll = -1 Then $OK = False MemoWrite("Error opening DLL.") EndIf EndIf ; Read maximum number of supported joysticks If $OK Then MemoWrite("OK") MemoWrite() MemoWrite("Read maximum number of supported joysticks.") $DLLRetValArray = DllCall($WinMMDLL, "uint", "joyGetNumDevs") If @error Then $OK = False MemoWrite("Error reading maximum number of joysicks.") EndIf EndIf If $OK Then MemoWrite("OK") $MaxJoyNum = $DLLRetValArray[0] MemoWrite("Maximum number of supported joysticks: " & $MaxJoyNum) MemoWrite() EndIf ; Initialize variables from envirnonment if set and from default otherwise If $OK Then MemoWrite("Read settings:") $KeyUp = GetFromEnv("KeyUp", "w") $KeyDown = GetFromEnv("KeyDown", "s") $KeyLeft = GetFromEnv("KeyLeft", "a") $KeyRight = GetFromEnv("KeyRight", "d") $KeyTUp = GetFromEnv("KeyTUp") $KeyTDown = GetFromEnv("KeyTDown") $KeyRLeft = GetFromEnv("KeyRLeft") $KeyRRight = GetFromEnv("KeyRRight") $KeyB1 = GetFromEnv("KeyB1", "SPACE") $KeyB2 = GetFromEnv("KeyB2", "e") $KeyB3 = GetFromEnv("KeyB3", "LCTRL") $KeyB4 = GetFromEnv("KeyB4") $KeyB5 = GetFromEnv("KeyB5") $KeyB6 = GetFromEnv("KeyB6") $KeyB7 = GetFromEnv("KeyB7") $KeyB8 = GetFromEnv("KeyB8") $KeyB9 = GetFromEnv("KeyB9") $KeyB10 = GetFromEnv("KeyB10") $KeyB11 = GetFromEnv("KeyB11") $KeyB12 = GetFromEnv("KeyB12") $KeyB13 = GetFromEnv("KeyB13") $KeyB14 = GetFromEnv("KeyB14") $KeyB15 = GetFromEnv("KeyB15") $KeyB16 = GetFromEnv("KeyB16") $KeyP1 = GetFromEnv("KeyPovUp") $KeyP3 = GetFromEnv("KeyPovDown") $KeyP4 = GetFromEnv("KeyPovLeft") $KeyP2 = GetFromEnv("KeyPovRight") $JPreset = GetFromEnv("JPreset") $PollTime = GetFromEnvNum("PollTime", "10") $DeadZoneX = GetFromEnvNum("DeadZoneX", "20") $DeadZoneY = GetFromEnvNum("DeadZoneY", "20") $DeadZoneT = GetFromEnvNum("DeadZoneT", "40") $DeadZoneR = GetFromEnvNum("DeadZoneR", "20") MemoWrite() EndIf If $OK Then If $KeyLeft Or $KeyRight Then $CheckX = True Else $CheckX = False EndIf If $KeyUp Or $KeyDown Then $CheckY = True Else $CheckY = False EndIf If $KeyTUp Or $KeyTDown Then $CheckT = True Else $CheckT = False EndIf If $KeyRLeft Or $KeyRRight Then $CheckR = True Else $CheckR = False EndIf If $KeyB1 Or $KeyB2 Or $KeyB3 Or $KeyB4 Or $KeyB5 Or $KeyB6 Or $KeyB7 _ Or $KeyB8 Or $KeyB9 Or $KeyB10 Or $KeyB11 Or $KeyB12 Or $KeyB13 Or $KeyB14 _ Or $KeyB15 Or $KeyB16 Then $CheckButtons = True Else $CheckButtons = False EndIf If $KeyP1 Or $KeyP2 Or $KeyP3 Or $KeyP4 Then $CheckPOV = True Else $CheckPOV = False EndIf EndIf ; List detected joysticks and try to select the intended one If $OK Then MemoWrite("Listing of detected joysticks:") MemoWrite() For $i = 0 To $MaxJoyNum - 1 $DLLRetValArray = DllCall($WinMMDLL, "int", "joyGetDevCapsA", "uint", $i, _ "ptr", $JCapStructPtr, "uint", $JCapStructSize) If @error Then $OK = False MemoWrite("Error reading joystick capabilities: " & @error) ExitLoop EndIf If $DLLRetValArray[0] = 0 Then $Mid = DllStructGetData($JCapStruct, "Mid") If $Mid Then $Pid = DllStructGetData($JCapStruct, "Pid") $Pname = DllStructGetData($JCapStruct, "Pname") $NumAxes = DllStructGetData($JCapStruct, "NumAxes") $NumButtons = DllStructGetData($JCapStruct, "NumButtons") $Caps = DllStructGetData($JCapStruct, "Caps") $XMin = DllStructGetData($JCapStruct, "Xmin") $XMax = DllStructGetData($JCapStruct, "Xmax") $YMin = DllStructGetData($JCapStruct, "Ymin") $YMax = DllStructGetData($JCapStruct, "Ymax") $TMin = DllStructGetData($JCapStruct, "Zmin") $TMax = DllStructGetData($JCapStruct, "Zmax") $RMin = DllStructGetData($JCapStruct, "Rmin") $RMax = DllStructGetData($JCapStruct, "Rmax") $JCount += 1 MemoWrite("" & $JCount & ". ManProdID: " & $Mid & "/" & $Pid & _ ", Axes: " & $NumAxes & _ ", Buttons: " & $NumButtons & ", Capabilities: " & $Caps) $V = False If $JIDFirst = -1 Then $JIDFirst = $i $V = True EndIf If $JIDSelected = -1 And $JPreset = $Mid & "/" & $Pid Then $JIDSelected = $i $V = True EndIf ; Set axis thresholds for the selected joystick If $V Then SetAxisDeadZone( $Ax1Low, $Ax1High, $XMin, $XMax, $DeadZoneX) SetAxisDeadZone( $Ax2Low, $Ax2High, $YMin, $YMax, $DeadZoneY) SetAxisDeadZone( $Ax3Low, $Ax3High, $TMin, $TMax, $DeadZoneT) SetAxisDeadZone( $Ax4Low, $Ax4High, $RMin, $RMax, $DeadZoneR) EndIf EndIf EndIf Next EndIf ; Output information which joystick is selected If $OK Then MemoWrite() If $JIDSelected <> -1 Then $JoyNum = $JIDSelected MemoWrite("Preset joystick " & $JPreset & " found.") Else $JoyNum = $JIDFirst If $JoyNum = -1 Then MemoWrite("No joystick detected.") MemoWrite("Please check it is correctly plugged and try again.") $OK = False Else If $JPreset Then MemoWrite("Preset joystick " & $JPreset & " not found.") If $JCount = 1 Then MemoWrite("Using found joystick.") Else MemoWrite("Using first found joystick.") MemoWrite("To use a specific joystick set an environment variable.") MemoWrite("See readme.txt for more information.") EndIf EndIf EndIf EndIf ; Bump up process priority for more accurate timing If $OK Then ProcessSetPriority(@AutoItPID, 5) EndIf ; Startup finished, getting to work now If $OK Then MemoWrite() MemoWrite("Startup finished, now polling for joystick input.") MemoWrite("Close this window to stop polling and end program.") ; Initialize timer and start polling $NextPoll = $PollTime $Timer = TimerInit() EndIf While $OK ; Read current values of interest for the selected joystick $DLLRetValArray = DllCall($WinMMDLL, "int", "joyGetPosEx", "uint", $JoyNum, _ "ptr", $JoyStructPtr) ; Process X axis If $CheckX Then SendOnAxChange(DllStructGetData($JoyStruct, "XPos"), $Ax1Low, $Ax1High, _ $OldLeft, $OldRight, $KeyLeft, $KeyRight) EndIf ; Process Y axis If $CheckY Then SendOnAxChange(DllStructGetData($JoyStruct, "YPos"), $Ax2Low, $Ax2High, _ $OldUp, $OldDown, $KeyUp, $KeyDown) EndIf ; Process thrust slider If $CheckT Then SendOnAxChange(DllStructGetData($JoyStruct, "ZPos"), $Ax3Low, $Ax3High, _ $OldTUp, $OldTDown, $KeyTUp, $KeyTDown) EndIf ; Process rudder If $CheckR Then SendOnAxChange(DllStructGetData($JoyStruct, "RPos"), $Ax4Low, $Ax4High, _ $OldRLeft, $OldRRight, $KeyRLeft, $KeyRRight) EndIf ; Process Buttons If $CheckButtons Then $V = DllStructGetData($JoyStruct, "Buttons") If $KeyB1 Then SendOnChange($OldB1, BitAND($V, 1), $KeyB1) If $KeyB2 Then SendOnChange($OldB2, BitAND($V, 2), $KeyB2) If $KeyB3 Then SendOnChange($OldB3, BitAND($V, 4), $KeyB3) If $KeyB4 Then SendOnChange($OldB4, BitAND($V, 8), $KeyB4) If $KeyB5 Then SendOnChange($OldB5, BitAND($V, 16), $KeyB5) If $KeyB6 Then SendOnChange($OldB6, BitAND($V, 32), $KeyB6) If $KeyB7 Then SendOnChange($OldB7, BitAND($V, 64), $KeyB7) If $KeyB8 Then SendOnChange($OldB8, BitAND($V, 128), $KeyB8) If $KeyB9 Then SendOnChange($OldB9, BitAND($V, 256), $KeyB9) If $KeyB10 Then SendOnChange($OldB10, BitAND($V, 512), $KeyB10) If $KeyB11 Then SendOnChange($OldB11, BitAND($V, 1024), $KeyB11) If $KeyB12 Then SendOnChange($OldB12, BitAND($V, 2048), $KeyB12) If $KeyB13 Then SendOnChange($OldB13, BitAND($V, 4096), $KeyB13) If $KeyB14 Then SendOnChange($OldB14, BitAND($V, 8192), $KeyB14) If $KeyB15 Then SendOnChange($OldB15, BitAND($V, 16384), $KeyB15) If $KeyB16 Then SendOnChange($OldB16, BitAND($V, 32768), $KeyB16) EndIf ; Process POV If $CheckPOV Then Switch Round(DllStructGetData($JoyStruct, "POV") / 4500) Case 0, 8 $V = 1 Case 1 $V = 3 Case 2 $V = 2 Case 3 $V = 6 Case 4 $V = 4 Case 5 $V = 12 Case 6 $V = 8 Case 7 $V = 9 Case Else $V = 0 EndSwitch If $KeyP1 Then SendOnChange($OldP1, BitAND($V, 1), $KeyP1) If $KeyP2 Then SendOnChange($OldP2, BitAND($V, 2), $KeyP2) If $KeyP3 Then SendOnChange($OldP3, BitAND($V, 4), $KeyP3) If $KeyP4 Then SendOnChange($OldP4, BitAND($V, 8), $KeyP4) EndIf If $PollTime Then $TimeLeft = $NextPoll - TimerDiff($Timer) $NextPoll += $PollTime If $TimeLeft >= 1 Then DllCall($KernelDll, "DWORD", "Sleep", "int", Floor($TimeLeft)) EndIf WEnd ; Keep trace window open While True Sleep(3600000) WEnd