Author Topic: Wait for process window to activate  (Read 96 times)

Exergist

  • Moderator
  • Full Member
  • *****
  • Posts: 227
  • Can you dig it?
Wait for process window to activate
« on: January 22, 2018, 02:03:29 pm »
VoiceAttack currently provides functionality to automatically switch between profiles depending on the activated window's title. This title check does not consider the actual Windows process associated with the activate window. Unfortunately under certain circumstances this can lead to "false positive" profile switching. In other words, if you have two windows with the same title VoiceAttack will perform the switch if either is activated, though most likely only one of those windows is tied to the actual process (an application or game) that you want associated with the profile. The way I see it this only becomes an actual problem if:
  • You have separate profiles for each of the same-titled windows.
  • You need to execute a command automatically after profile load and you want the triggering active window to be the desired app or game.
I've already submitted this feature request to allow tokens to be used in the "enable profile switching" field (which would lead to options for eliminating false positive profile switching). In the mean time I came up with the following command actions as a workaround (Calculator app example):

Code: [Select]
Begin Text Compare : [{CMDACTION}] Equals 'Profile'
    Set Text [ProcessName] to 'calculator'
    Begin Text Compare : [ProcessName] Does Not Contain '{ACTIVEWINDOWPROCESSNAME}'
        Write '[Blue] Waiting for "{TXT:ProcessName}" process window to be activated...' to log
        Start Loop While : [ProcessName] Does Not Contain '{ACTIVEWINDOWPROCESSNAME}'
            Pause 1 second
        End Loop
        Write '[Blue] "{TXT:ProcessName}" process window activated' to log
    End Condition
End Condition
// Remainder of command goes here

So basically the above code block will execute if the command is launched due to a profile change (automatic or manual), and the code waits for the active window's process name to match a user-defined process name before continuing.

However if we implement some of the above steps in an inline function we can clean up the action sequence:

Code: [Select]
Begin Text Compare : [{CMDACTION}] Equals 'Profile'
    Set Text [ProcessName] to 'calculator'
    Inline C# Function: Wait for Process Window Activation, wait until execution finishes
End Condition
// Remainder of command goes here

Referenced Assemblies: none required
Code: [Select]
using System;
using System.Threading;

public class VAInline
{
    public void main()
    {
        string ProcessName = VA.GetText("ProcessName"); // Retrieve desired ProcessName from VoiceAttack text variable
        string ActiveProcessName; // Initialize string for storing the ActiveProcessName
        if (ProcessName.IndexOf(VA.ParseTokens("{ACTIVEWINDOWPROCESSNAME}"), StringComparison.OrdinalIgnoreCase) < 0) // Check if the text from VA token {ACTIVEWINDOWPROCESSNAME} is NOT found in ProcessName (case-insensitive)
        {
            VA.WriteToLog(@"Waiting for """ + ProcessName + @""" process window to be activated...", "blue"); // Output information to VoiceAttack event log
            while (ProcessName.IndexOf((ActiveProcessName = VA.ParseTokens("{ACTIVEWINDOWPROCESSNAME}")), StringComparison.OrdinalIgnoreCase) < 0) // Loop while the text from VA token {ACTIVEWINDOWPROCESSNAME} is NOT found in ProcessName (case-insensitive)
            {
                Thread.Sleep(1000); // Pause code execution for 1000 ms
            }
            VA.WriteToLog(@"""" + ProcessName + @""" process window activated", "blue"); // Output information to VoiceAttack event log
        }
    }
}

For both cases the looping runs indefinitely in the background until the window tied to the desired process name is activated or the command is stopped (pressing the "stop commands" button, switching to a different profile, etc). The looping does not prevent VA from going into "sleep mode."

Yes the command action and inline function methods produce the same end result, but I like to simplify my command action sequences whenever possible. I figured I'd share this in case others might also have use for it.
« Last Edit: January 22, 2018, 02:47:51 pm by Exergist »