' Push to Talk Button Inline-Function for VoiceAttack - Get/Set any Keyboard/Mouse/Joystick Button as a PTT Button ' by SemlerPDX Jan2021/Oct2021 ' VETERANS-GAMING.COM Imports Microsoft.VisualBasic Imports System Imports System.Collections Imports System.Collections.Generic Imports System.Threading Imports System.Threading.Tasks Imports System.Windows.Forms Public Class VAInline dim mouseButtons() as string = { "STATE_LEFTMOUSEBUTTON", "STATE_RIGHTMOUSEBUTTON", "STATE_MIDDLEMOUSEBUTTON", "STATE_FORWARDMOUSEBUTTON", "STATE_BACKMOUSEBUTTON" } dim gamepadTriggers() as string = {"LEFTTRIGGER","RIGHTTRIGGER"} dim buttonsAlreadySetList as New List(Of String) dim buttonsAlwaysDownList as New List(Of String) dim buttonsAlwaysDown as boolean = False dim buttonDown as string = "" dim buttonCheck as string = "" dim checkPOV as string = "" dim buttonSet as boolean = False dim userReady as boolean = False dim counter as integer = 0 dim keyCheck as string = "" dim keyString as string = "" dim keyCode() as string dim kc as KeysConverter = new KeysConverter() dim activeProfile as string = "CORE" dim debugCheck as boolean dim debugCount as integer = 0 Private Function SendDebugMessage(ByVal debugText as string, ByVal debugColor as integer) '1=Blue - 2=Green - 3=Yellow - 4=Red - 5=Purple - 6=Blank - 7=Orange - 8=Black - 9=Gray - 10=Pink if ((VA.GetText("AVCS_Debug_QMSG")) isNot nothing) debugCount = VA.GetInt("AVCS_Debug_QMSG") end if debugCount += 1 VA.SetText("AVCS_Debug_TMSG_" + debugCount.ToString(), debugText) VA.SetInt("AVCS_Debug_WCLR_" + debugCount.ToString(), debugColor) VA.SetInt("AVCS_Debug_QMSG", debugCount) try vaProxy.Command.Execute("f_core_debug -log", true) catch VA.WriteToLog("AVCS ERROR: PTTGET02 - f_core_debug null - restart VoiceAttack or create bug report", "red") end try debugCount = 0 end function Private Function BuildPTTkeysList() for keyIndex as integer = 1 to 6 'Check for PTT buttons already set if ((VA.GetText("AVCS_" + activeProfile + "_PTTBUTTON_" + keyIndex.ToString())) isNot nothing) buttonCheck = VA.GetText("AVCS_" + activeProfile + "_PTTBUTTON_" + keyIndex.ToString()) buttonsAlreadySetList.Add(buttonCheck) end if next end function Private Function BuildAlwaysDownList() 'Mouse Buttons Baseline State Loop if ((vaProxy.Utility.ParseTokens("{STATE_ANYMOUSEDOWN}")) <> "0") for m as integer = 0 to 4 if ((vaProxy.Utility.ParseTokens("{"+ mouseButtons(m) +"}")) <> "0") buttonsAlwaysDownList.Add(mouseButtons(m)) buttonsAlwaysDown = true if (debugCheck) SendDebugMessage("MOUSE BUTTON ("+ mouseButtons(m) +") DISREGARED AS ALWAYS DOWN", 4) end if end if next end if 'Keyboard Key Baseline State Loop for k as integer = 1 to 254 if ((vaProxy.Utility.ParseTokens("{STATE_ANYKEYDOWN}")) <> "0") if ((vaProxy.Utility.ParseTokens("{STATE_KEYSTATE:" + k.ToString() + "}")) = "1") buttonsAlwaysDownList.Add("STATE_KEYSTATE:" + k.ToString()) buttonsAlwaysDown = true if (debugCheck) SendDebugMessage("KEYBOARD KEY (virtual-key code " + k.ToString() + ") DISREGARED AS ALWAYS DOWN", 4) end if end if end if next 'Joystick Button Baseline State Loop for d as integer = 1 to 4 if ((vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "ENABLED}")) = "1") 'Joystick Buttons Baseline "Pressed" States if ((vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "ANYBUTTON}")) <> "0") for i as integer = 1 to 128 if ((vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "BUTTON:" + i.ToString() + "}")) = "1") buttonsAlwaysDownList.Add("STATE_JOYSTICK" + d.ToString() + "BUTTON:" + i.ToString()) buttonsAlwaysDown = true if (debugCheck) SendDebugMessage("JOYSTICK " + d.ToString() + " BUTTON " + i.ToString() + " DISREGARED - POSSIBLE DUAL STAGE TRIGGER", 4) end if end if next 'Joystick POV Buttons Baseline States (4-way only) if ((vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "POVENABLED}")) = "1") for i as integer = 1 to 4 if ((vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "POV" + i.ToString() + "TYPE}")) = "4") 'Loop though this Joystick POV 1-4 if ((vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "POV" + i.ToString() + "}")) <> "CENTER") checkPOV = vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "POV" + i.ToString() + "}") buttonsAlwaysDownList.Add("STATE_JOYSTICK" + d.ToString() + "POV" + i.ToString() + ":" + checkPOV) buttonsAlwaysDown = true if (debugCheck) SendDebugMessage("JOYSTICK " + d.ToString() + " POV " + i.ToString() + ":" + checkPOV + " DISREGARED", 4) end if end if end if next end if end if 'Joystick as Gamepad Baseline Trigger States (with 20 of 255 as 'deadzone') if ((vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "ISGAMEPAD}")) <> "0") for t as integer = 0 to 1 if (IsNumeric(vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + gamepadTriggers(t) + "}"))) if ((Convert.ToInt32(vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + gamepadTriggers(t) + "}"))) > 20) buttonsAlwaysDownList.Add("STATE_JOYSTICK" + d.ToString() + gamepadTriggers(t)) buttonsAlwaysDown = true if (debugCheck) SendDebugMessage("Always Down " + gamepadTriggers(t), 3) end if end if end if next end if end if next End function Private Function GetReverseMouseButton(ByRef buttonSet as boolean) 'Check Always Down Mouse Button for "Unpressed" state if ((buttonsAlwaysDown) and (buttonsAlwaysDownList isNot nothing)) for each buttonAlwaysDown as string in buttonsAlwaysDownList if (buttonAlwaysDown.EndsWith("MOUSEBUTTON")) if ((vaProxy.Utility.ParseTokens("{" + buttonAlwaysDown + "}")) = "0") buttonSet = true buttonDown = buttonAlwaysDown 'changed from buttonCheck Sept2021 VA.SetBoolean("~avcs_ptt_reverse", true) if (debugCheck) SendDebugMessage("(DST)- REVERSE MOUSE BUTTON (" + buttonDown + ") SET", 2) end if end if end if next end if End Function Private Function GetMouseButton(ByRef buttonSet as boolean) 'Mouse Button Current States if ((vaProxy.Utility.ParseTokens("{STATE_ANYMOUSEDOWN}")) <> "0") for m as integer = 0 to 4 if (buttonSet = false) if ((vaProxy.Utility.ParseTokens("{"+ mouseButtons(m) +"}")) <> "0") buttonCheck = mouseButtons(m) if ((buttonsAlwaysDown) and (buttonsAlwaysDownList isNot nothing)) if (not(buttonsAlwaysDownList.Contains(buttonCheck))) buttonSet = true buttonDown = buttonCheck if (debugCheck) SendDebugMessage("(DST)- MOUSE BUTTON (" + mouseButtons(m) + ") SET", 2) end if else if (debugCheck) SendDebugMessage("MOUSE BUTTON (" + mouseButtons(m) + ") DISREGARED - DISCOVERED ON LIST", 4) end if end if else buttonSet = true buttonDown = buttonCheck if (debugCheck) SendDebugMessage("MOUSE BUTTON (" + mouseButtons(m) + ") SET", 2) end if end if end if end if next end if End Function Private Function GetReverseKeyboardKey(ByRef buttonSet as boolean) 'Check Always Down Keyboard Key for "Unpressed" state if ((buttonsAlwaysDown) and (buttonsAlwaysDownList isNot nothing)) for each buttonAlwaysDown as string in buttonsAlwaysDownList if (buttonSet = false) if (buttonAlwaysDown.StartsWith("STATE_KEYSTATE")) if ((vaProxy.Utility.ParseTokens("{" + buttonAlwaysDown + "}")) <> "1") buttonSet = true buttonDown = buttonAlwaysDown VA.SetBoolean("~avcs_ptt_reverse", true) if (debugCheck) SendDebugMessage("(DST)- REVERSE KEYBOARD KEY (" + buttonAlwaysDown + ") SET", 2) end if end if end if end if next end if End Function Private Function GetKeyboardKey(ByRef buttonSet as boolean) 'Keyboard Keys Current State Loop if ((vaProxy.Utility.ParseTokens("{STATE_ANYKEYDOWN}")) <> "0") for k as integer = 1 to 254 if (buttonSet = false) if ((vaProxy.Utility.ParseTokens("{STATE_KEYSTATE:" + k.ToString() + "}")) = "1") buttonCheck = "STATE_KEYSTATE:" + k.ToString() if ((buttonsAlwaysDown) and (buttonsAlwaysDownList isNot nothing)) if (not(buttonsAlwaysDownList.Contains(buttonCheck))) buttonSet = true buttonDown = buttonCheck if (debugCheck) SendDebugMessage("(DST)- KEYBOARD KEY (virtual-key code " + k.ToString() + ") SET", 2) end if else if (debugCheck) SendDebugMessage("KEYBOARD KEY (virtual-key code " + k.ToString() + ") DISREGARED - DISCOVERED ON LIST", 4) end if end if else buttonSet = true buttonDown = buttonCheck if (debugCheck) SendDebugMessage("KEYBOARD KEY (virtual-key code " + k.ToString() + ") SET", 2) end if end if end if end if next end if End Function 'Check Always Down Style Joystick Buttons for "Unpressed" state Private Function GetReverseJoystickButton(ByRef buttonSet as boolean) for d as integer = 1 to 4 if ((vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "ENABLED}")) = "1") if ((buttonsAlwaysDown) and (buttonsAlwaysDownList isNot nothing)) for each buttonAlwaysDown as string in buttonsAlwaysDownList if (buttonSet = false) if (buttonAlwaysDown.StartsWith("STATE_JOYSTICK" + d.ToString())) if ((vaProxy.Utility.ParseTokens("{" + buttonAlwaysDown + "}")) = "0") buttonSet = true buttonDown = buttonAlwaysDown 'changed from buttonCheck Sept2021 VA.SetBoolean("~avcs_ptt_reverse", true) if (debugCheck) SendDebugMessage("(DST)- REVERSE JOYSTICK " + d.ToString() + " BUTTON (" + buttonAlwaysDown + ") HAS BEEN SET", 2) end if end if end if end if next end if end if next End Function 'Standard Button Current "Pressed" state Private Function GetJoystickButton(ByRef buttonSet as boolean) for d as integer = 1 to 4 if ((vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "ENABLED}")) = "1") if ((vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "ANYBUTTON}")) = "1") for i as integer = 1 to 128 if (buttonSet = false) if ((vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "BUTTON:" + i.ToString() + "}")) = "1") buttonCheck = "STATE_JOYSTICK" + d.ToString() + "BUTTON:" + i.ToString() if ((buttonsAlwaysDown) and (buttonsAlwaysDownList isNot nothing)) if (not(buttonsAlwaysDownList.Contains(buttonCheck))) buttonSet = true buttonDown = buttonCheck if (debugCheck) SendDebugMessage("(DST)- JOYSTICK " + d.ToString() + " BUTTON " + i.ToString() + " SET", 2) end if else if (debugCheck) SendDebugMessage("JOYSTICK " + d.ToString() + " BUTTON " + i.ToString() + " DISREGARED - DISCOVERED ON LIST", 4) end if end if else buttonSet = true buttonDown = buttonCheck if (debugCheck) SendDebugMessage("JOYSTICK " + d.ToString() + " BUTTON " + i.ToString() + " SET", 2) end if end if end if end if next end if end if next End Function 'Check Always Down POV for "Unpressed" state Private Function GetReverseJoystickPOV(ByRef buttonSet as boolean) for d as integer = 1 to 4 if ((vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "POVENABLED}")) = "1") for i as integer = 1 to 4 checkPOV = "STATE_JOYSTICK" + d.ToString() + "POV" + i.toString() if ((buttonsAlwaysDown) and (buttonsAlwaysDownList isNot nothing)) if (buttonsAlwaysDownList.Contains(checkPOV)) for each buttonAlwaysDown as string in buttonsAlwaysDownList if (buttonSet = false) and (buttonAlwaysDown.StartsWith(checkPOV)) if ((vaProxy.Utility.ParseTokens("{" + checkPOV + "}")) = "CENTER") buttonSet = true buttonDown = buttonAlwaysDown VA.SetBoolean("~avcs_ptt_reverse", true) if (debugCheck) SendDebugMessage("(DST)- REVERSE JOYSTICK " + d.ToString() + " POV (" + buttonAlwaysDown + ") HAS BEEN SET", 2) end if end if end if next end if end if next end if next End Function 'Check Joystick POV for "Pressed" state Private Function GetJoystickPOV(ByRef buttonSet as boolean) for d as integer = 1 to 4 if ((vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "POVENABLED}")) = "1") for i as integer = 1 to 4 if (buttonSet = false) if ((vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "POV" + i.toString() + "TYPE}")) = "4") checkPOV = vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "POV" + i.toString() + "}") if (checkPOV <> "CENTER") buttonCheck = "STATE_JOYSTICK" + d.ToString() + "POV" + i.toString() + ":" + checkPOV if ((buttonsAlwaysDown) and (buttonsAlwaysDownList isNot nothing)) if (not(buttonsAlwaysDownList.Contains(buttonCheck))) buttonSet = true buttonDown = buttonCheck if (debugCheck) SendDebugMessage("JOYSTICK " + d.ToString() + "POV" + i.ToString() + ":" + checkPOV + " SET", 2) end if else if (debugCheck) SendDebugMessage("JOYSTICK " + d.ToString() + "POV" + i.ToString() + ":" + checkPOV + " DISREGARED - DISCOVERED ON LIST", 4) end if end if else buttonSet = true buttonDown = buttonCheck if (debugCheck) SendDebugMessage("JOYSTICK " + d.ToString() + "POV" + i.ToString() + ":" + checkPOV + " SET", 2) end if end if end if end if end if next end if next End Function '--------------------------------------------------------------------------- '--------------------------------------------------------------------------- 'Check Always Down Triggers for "Unpressed" state Private Function GetReverseJoystickTrigger(ByRef buttonSet as boolean) for d as integer = 1 to 4 if (((vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "ENABLED}")) = "1") and ((vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "ISGAMEPAD}")) = "1")) if ((buttonsAlwaysDown) and (buttonsAlwaysDownList isNot nothing)) for each buttonAlwaysDown as string in buttonsAlwaysDownList if (buttonSet = false) if (buttonAlwaysDown.EndsWith("TRIGGER")) if (IsNumeric(vaProxy.Utility.ParseTokens("{" + buttonAlwaysDown + "}"))) if ((Convert.ToInt32(vaProxy.Utility.ParseTokens("{" + buttonAlwaysDown + "}"))) < 20) buttonSet = true buttonDown = buttonCheck VA.SetBoolean("~avcs_ptt_reverse", true) if (debugCheck) SendDebugMessage("(DST)- REVERSE JOYSTICK GAMEPAD " + d.ToString() + " TRIGGER (" + buttonAlwaysDown + ") HAS BEEN SET", 2) end if end if end if end if end if next end if end if next End Function 'Check Triggers for "Pressed" state Private Function GetJoystickTrigger(ByRef buttonSet as boolean) for d as integer = 1 to 4 if (((vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "ENABLED}")) = "1") and ((vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + "ISGAMEPAD}")) = "1")) 'Gamepad Triggers Current State (with 20 of 255 as 'deadzone') for t as integer = 0 to 1 if (buttonSet = false) if (IsNumeric(vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + gamepadTriggers(t) + "}"))) if ((Convert.ToInt32(vaProxy.Utility.ParseTokens("{STATE_JOYSTICK" + d.ToString() + gamepadTriggers(t) + "}"))) > 20) buttonCheck = "STATE_JOYSTICK" + d.ToString() + gamepadTriggers(t) if ((buttonsAlwaysDown) and (buttonsAlwaysDownList isNot nothing)) if (not(buttonsAlwaysDownList.Contains(buttonCheck))) buttonSet = true buttonDown = buttonCheck else if (debugCheck) SendDebugMessage("JOYSTICK GAMEPAD " + d.ToString() + gamepadTriggers(t) + " DISREGARED - DISCOVERED ON LIST", 4) end if end if else buttonSet = true buttonDown = buttonCheck if (debugCheck) SendDebugMessage("JOYSTICK GAMEPAD " + d.ToString() + gamepadTriggers(t) + " SET", 2) end if end if end if end if end if next end if next End Function Public Sub Main() if (VA.GetBoolean("AVCS_Debug_ON") IsNot nothing) debugCheck = VA.GetBoolean("AVCS_Debug_ON") end if if ((VA.GetText("AVCS_ACTIVE_PROFILE")) isNot nothing) activeProfile = VA.GetText("AVCS_ACTIVE_PROFILE") end if if (debugCheck) VA.ClearLog() SendDebugMessage("inline begin....", 3) end if 'Get Button/Key Baseline States BuildPTTkeysList() BuildAlwaysDownList() VA.SetBoolean("~avcs_getting_input", true) if (debugCheck) SendDebugMessage("Always Down Array Complete", 3) end if 'Begin a pause loop to wait for timeout or user input (key/button press or voice 'cancel' phrase) while (not(userReady)) Thread.CurrentThread.Sleep(1000) counter += 1 'Check for Timeout or TTS User Prompt Instructions complete if ((VA.GetBoolean("~avcs_user_ready")) isNot nothing) userReady = VA.GetBoolean("~avcs_user_ready") end if if ((counter >= 15) or (userReady)) if (userReady) VA.WriteToLog("== PLEASE PRESS ANY KEY OR BUTTON NOW ==","green") else VA.WriteToLog("cancelled - command timed out... TTS or primary function error","red") if (debugCheck) SendDebugMessage("AVCS PTT SET cancelled - command timed out", 3) end if VA.SetBoolean("~avcs_getting_input", false) Exit sub end if end if end while 'Reset counter for Keypress/Button monitor counter = 0 userReady = false VA.SetBoolean("~avcs_user_ready", false) 'Begin a pause loop to wait for Joystick/Gamepad Input or spoken 'cancel/done' speech while (not(userReady)) Thread.CurrentThread.Sleep(75) counter += 1 if (buttonSet = false) GetReverseMouseButton(buttonSet) GetMouseButton(buttonSet) GetReverseKeyboardKey(buttonSet) GetKeyboardKey(buttonSet) GetReverseJoystickButton(buttonSet) GetJoystickButton(buttonSet) GetReverseJoystickPOV(buttonSet) GetJoystickPOV(buttonSet) GetReverseJoystickTrigger(buttonSet) GetJoystickTrigger(buttonSet) end if 'Check for Input, Timeout or TTS User Prompt Instructions complete if ((VA.GetBoolean("~avcs_user_ready")) isNot nothing) userReady = VA.GetBoolean("~avcs_user_ready") end if if ((counter >= 200) or ((buttonSet) and (buttonDown <> "")) or (userReady)) if ((buttonSet) and (buttonDown <> "")) if (buttonsAlreadySetList isNot nothing) if (buttonsAlreadySetList.Contains(buttonDown)) VA.SetBoolean("~avcs_getting_input", false) VA.SetText("~avcs_button_choice", "alreadyset") if (debugCheck) SendDebugMessage("ERROR - Existing PTT button has already been set to " + buttonDown, 4) end if Exit While end if end if VA.SetBoolean("~avcs_getting_input", false) VA.SetText("~avcs_button_choice", buttonDown) if (debugCheck) SendDebugMessage("PTT button has been set " + buttonDown, 2) end if Exit While elseif (userReady) VA.SetBoolean("~avcs_getting_input", false) VA.WriteToLog("command cancelled - user input not detected","red") if (debugCheck) SendDebugMessage("AVCS PTT SET user input not detected", 4) end if Exit While elseif (counter >= 200) VA.SetBoolean("~avcs_getting_input", false) VA.WriteToLog("command timed out... user input not detected","red") if (debugCheck) SendDebugMessage("AVCS PTT SET command timed out", 4) end if Exit While end if end if end while if ((buttonSet) and (buttonDown <> "")) if (buttonDown.StartsWith("STATE_KEYSTATE:")) keyCode = buttonDown.Split(":") if (IsNumeric(keyCode(1))) try keyString = kc.ConvertToString(Convert.ToInt32(keyCode(1))) keyString = keyString.Replace("Oem","") VA.WriteToLog("PTT Button Set to " + buttonDown + " == " + keyString, "green") catch VA.WriteToLog("PTT Button Set to " + buttonDown, "green") end try end if else VA.WriteToLog("PTT Button Set to " + buttonDown, "green") end if end if End Sub End Class