Author Topic: Multi choice selection - keep window w/ list open to choose more than one option  (Read 1312 times)

zL0ki

  • Newbie
  • *
  • Posts: 16
required function:
A game that requires selecting a corresponding alphabet letter to select an item in a trade window. Goes from a-zA-Z

I initially set it up with
Code: [Select]
When I say: [big;small][alfa,bravo..etc]

Begin Text Compare : [{EXP:'{CMDSEGMENT:0}' LIKE 'big'}] Equals '1'
    Set text [input] to '{CMDSEGMENT:1}' (Upper Case)
    Quick Input, '{TXTSUBSTR:input:0:1}'
Else If Text Compare : [{EXP:'{CMDSEGMENT:0}' LIKE 'small'}] Equals '1'
    Set text [input] to '{CMDSEGMENT:1}'
    Quick Input, '{TXTSUBSTR:input:0:1}'
End Condition

I looked for a different method due to the chance of failure and opting for something less vocal.

I have this as an alternative:

Code: [Select]
When I say: trade

Set text [myVar] to 'notnull'
Start Loop While : [myVar] Does Not Equal ''
    Get Choice Input [myVar]
    Begin Text Compare : [myVar] Does Not Equal ''
        Quick Input, '{TXT:myVar}'
    End Condition
End Loop

This is actually quite neat for very little code. It loops the window until cancel is selected.

However, I was looking at the inline function with buttons created by Exergist

https://forum.voiceattack.com/smf/index.php?topic=2395.0


I tried to use this but couldn't manage to get it so that it stayed open and sent any simulated keypresses via buttons to the game window. Any button press would immediately change the focus

I was wondering if it was easy to adopt this, or needless extra work when I have a working previous option.






Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4759
  • RTFM
To send normal keyboard input to a target application, that application needs to have focus (it's how Windows is designed), so regardless of which window method you choose, that focus change will happen.

If you're running the target game in a windowed mode (rather than exclusive fullscreen), a window set to always be on top can stay there even when it loses focus.

You can try adding
Code: [Select]
this.TopMost = true;to the form setup section


Do note, however, that inline functions are very much an advanced feature. Knowledge of C# (or VB.NET) is required.

zL0ki

  • Newbie
  • *
  • Posts: 16

I'm comfortable with tinkering with code. I already use it in other commands. Find it easier to visualise/consolidate things.

I'll look into that option, thankyou. I was also thinking that I could do something similar with the previous working code, use a jump to marker to loop.  It will at least function the same but with buttons. I like buttons!


zL0ki

  • Newbie
  • *
  • Posts: 16
I ended up with using Exergist's great program as the framework. Therefore a lot of code is borrowed from that. I created dynamic buttons to avoid having to write out 52 buttons. Below code with adaptions. See link posted in previous thread for original post located in Inline Functions section.

Code: [Select]
// C# inline function for retrieving user input & preprocessing
Marker: GotoInline
Inline C# Function: Display UI for getting input & process result, wait until execution finishes

// Check if user provided relevant input
Begin Text Compare : [~~UserInput] Has Been Set
    Begin Text Compare : [~~isCancel] Equals 'No'
        // Output retrieved information
        Write [Blue] 'Letter selected is: {TXT:~~UserInput}' to log
        Quick Input, '{TXT:~~UserInput}'
        Jump to Marker: GotoInline
    Else
        // Output info to event log
        Write [Red] 'Exited Alphabet Form' to log
    End Condition
End Condition


Code: [Select]
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

public class VAInline
{
[STAThread]
public void main()
{

// Enable (operating system) visual styles for the application
Application.EnableVisualStyles();

// Create an instance of Form1 (while passing the dynamic VA for use by the form) and an associated message loop
Application.Run(new Form1(VA));

}
}

public class Form1 : Form
{
// Initialize string variable for storing user input
public string result = null;


// Create and display Form1
public Form1(dynamic VA)
{
VA.SetText("~~isCancel", "No");

// Set up the form
this.Text = "This is a Windows Form"; // Set the caption bar text of the form
this.FormBorderStyle = FormBorderStyle.FixedDialog; // Define the border style of the form to a dialog box
this.MaximizeBox = false; // Set the MaximizeBox to false to remove the maximize box
this.MinimizeBox = false; // Set the MinimizeBox to false to remove the minimize box
this.StartPosition = FormStartPosition.CenterScreen; // Set the start position of the form to the center of the screen
this.AutoSize = true; // Set form sizing to be automatic
this.AutoSizeMode = AutoSizeMode.GrowAndShrink; // Set the form's autosizing to grow or shrink based on the text
this.MinimumSize = new Size(this.Width, this.Height); // Set the form window to be no smaller than design time size
this.MaximumSize = new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); // Set the form window to be no larger than screen size
this.Padding = new Padding(10); // Set the padding around the form's border
int FontSize = 10; // Set the font size used for buttons
this.TopMost = true;
int ControlSpacing = 5; // Set the spacing between form controls
this.FormClosing += new FormClosingEventHandler((sender, e) => Form1_FormClosing(sender, e, VA)); // Subscribe to event for the form closing and pass in dynamic VA


TableLayoutPanel Table = new TableLayoutPanel();
Table.Location = new Point(10, 40);
Table.Size = new Size(820,100);
Table.AutoSize = true;
Table.Name = "Alphabet Selector";
Table.ColumnCount = 9;
Table.RowCount = 6;
Table.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
Table.GrowStyle = System.Windows.Forms.TableLayoutPanelGrowStyle.AddRows;
this.Controls.Add(Table);


// Declare and assign number of buttons = 52
System.Windows.Forms.Button[] btnArray = new System.Windows.Forms.Button[52];


//Create (52) Buttons:
for (int i = 0; i < 52; i++)
{
// Initialize one variable
btnArray[i] = new System.Windows.Forms.Button();
}

/* *********************************************
Alternative code for button text
char[] Alphabet = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
'W', 'X', 'Y', 'Z' etc}; btnArray[n].Text = Alphabet[n].ToString();
****************************************** */

int n = 0;
int j = 0;

while(n < 52)
{
if (n>25)
{
btnArray[n].Text = ((char)(j + 65)).ToString();
j++;
}
else
{
btnArray[n].Text = ((char)(n + 65)).ToString().ToLower();
}
btnArray[n].AutoSize = true;
btnArray[n].AutoSizeMode = AutoSizeMode.GrowAndShrink;
btnArray[n].Font = new Font(btnArray[n].Font.FontFamily, FontSize);
Table.Controls.Add(btnArray[n]);
btnArray[n].Click += new EventHandler((sender, e) => ClickButton(sender, e, VA));
n++;
}

//Set up Exit/Cancel Button
Button Exit = new Button();
Exit.Text = "Exit";
Exit.Size = new Size(26, 27);
Exit.Font = new Font(Exit.Font.FontFamily, 6);
Table.Controls.Add(Exit);
Exit.Click += new EventHandler((sender, e) => Exit_Click(sender, e, VA));
this.CancelButton = Exit;

// Call function for resizing the form
Functions.ResizeForm(this, ControlSpacing);

// Call function for bringing form into focus
Functions.ShowForm(this);

}

// Result of (Click Button) event, get the text of button
public void ClickButton(Object sender, System.EventArgs e, dynamic VA)
{
Button btn = (Button) sender;
VA.SetText("~~UserInput", btn.Text);
//debug
//MessageBox.Show("You clicked character [" + btn.Text + "]");
result = "Yes";
this.Close(); // Close the form
}

//Function Exit button is clicked
private void Exit_Click(object sender, EventArgs e, dynamic VA)
{
result = null;
this.Close(); // Close the form
}


// Function run when the form is closing
private void Form1_FormClosing(object sender, FormClosingEventArgs e, dynamic VA)
{
// Do stuff
if (result != null) // Check if result string contains data
VA.SetText("~~isCancel", "No");
else
VA.SetText("~~isCancel", "Yes");
}
}

public class Functions
{
// Function for resizing the form and positioning all the controls based on their width
public static void ResizeForm(Form f, int ControlSpacing)
{
// Determine the form control with the maximum width, store this width, and set position of this control
int MaxWidth = 0; // Initialize integer variable for storing the MaxWidth
Control MaxWidthControl = null; // Initialize variable for capturing the widest form control
foreach (Control c in f.Controls) // Loop through each control on the form
{
if (c.Size.Width > MaxWidth) // Check if the current control's width is greater than MaxWidth
{
MaxWidthControl = c; // Set MaxWidthControl to current control
MaxWidth = c.Size.Width; // Redefine MaxWidth using current control's width
}
}
MaxWidthControl.Location = new Point(f.Padding.Left, 0); // Set the location of the MaxWidthControl on the form

// Set location of all other controls within the form
Control PreviousControl = null; // Initialize variable for capturing the previous form control
foreach (Control c in f.Controls) // Loop through each control on the form
{
c.Location = new Point(MaxWidth / 2 + f.Padding.Left - c.Size.Width / 2, (PreviousControl == null ? ControlSpacing : PreviousControl.Height + PreviousControl.Top + ControlSpacing)); // Set location of control c
PreviousControl = c; // Store current control as PreviousControl for future processing
}
}

// Function for brining form into focus
public static void ShowForm(Form f)
{
// Retrieve the window handle for the form and give the form focus
IntPtr myHandle = f.Handle;
SetForegroundWindow(myHandle.ToInt32());
}

// External function for bringing window into focus using its handle
[DllImport("User32.dll")]
public static extern Int32 SetForegroundWindow(int hWnd);
}


It does exactly the same thing as the previous example without using inline functions, but with buttons!