Improve shuffle logic to ignore games which have exited. Add next game hotkey to manually jump to a new game after exiting.

This commit is contained in:
sesouthall
2024-05-16 21:08:35 -07:00
parent 064b70f1de
commit bc30c471f1
3 changed files with 232 additions and 126 deletions

View File

@@ -36,151 +36,161 @@ namespace GameShuffler
/// </summary>
private void InitializeComponent()
{
this.runningProcessesSelectionList = new System.Windows.Forms.CheckedListBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.startButton = new System.Windows.Forms.Button();
this.label3 = new System.Windows.Forms.Label();
this.minTimeTextBox = new System.Windows.Forms.TextBox();
this.maxTimeTextBox = new System.Windows.Forms.TextBox();
this.label4 = new System.Windows.Forms.Label();
this.label5 = new System.Windows.Forms.Label();
this.label6 = new System.Windows.Forms.Label();
this.refreshButton = new System.Windows.Forms.Button();
this.stopButton = new System.Windows.Forms.Button();
this.SuspendLayout();
runningProcessesSelectionList = new CheckedListBox();
label1 = new Label();
label2 = new Label();
startButton = new Button();
label3 = new Label();
minTimeTextBox = new TextBox();
maxTimeTextBox = new TextBox();
label4 = new Label();
label5 = new Label();
label6 = new Label();
refreshButton = new Button();
stopButton = new Button();
label7 = new Label();
SuspendLayout();
//
// runningProcessesSelectionList
//
this.runningProcessesSelectionList.FormattingEnabled = true;
this.runningProcessesSelectionList.Location = new System.Drawing.Point(40, 40);
this.runningProcessesSelectionList.Name = "runningProcessesSelectionList";
this.runningProcessesSelectionList.Size = new System.Drawing.Size(720, 340);
this.runningProcessesSelectionList.TabIndex = 0;
runningProcessesSelectionList.FormattingEnabled = true;
runningProcessesSelectionList.Location = new Point(40, 40);
runningProcessesSelectionList.Name = "runningProcessesSelectionList";
runningProcessesSelectionList.Size = new Size(720, 340);
runningProcessesSelectionList.TabIndex = 0;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(40, 9);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(200, 25);
this.label1.TabIndex = 1;
this.label1.Text = "Select games to shuffle:";
label1.AutoSize = true;
label1.Location = new Point(40, 9);
label1.Name = "label1";
label1.Size = new Size(200, 25);
label1.TabIndex = 1;
label1.Text = "Select games to shuffle:";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(40, 502);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(426, 25);
this.label2.TabIndex = 2;
this.label2.Text = "Press PageDown to remove a game from the shuffle";
label2.AutoSize = true;
label2.Location = new Point(40, 502);
label2.Name = "label2";
label2.Size = new Size(426, 25);
label2.TabIndex = 2;
label2.Text = "Press PageDown to remove a game from the shuffle";
//
// startButton
//
this.startButton.Location = new System.Drawing.Point(472, 497);
this.startButton.Name = "startButton";
this.startButton.Size = new System.Drawing.Size(133, 34);
this.startButton.TabIndex = 3;
this.startButton.Text = "Start Shuffling";
this.startButton.UseVisualStyleBackColor = true;
this.startButton.Click += new System.EventHandler(this.StartButton_Clicked);
startButton.Location = new Point(472, 497);
startButton.Name = "startButton";
startButton.Size = new Size(133, 34);
startButton.TabIndex = 3;
startButton.Text = "Start Shuffling";
startButton.UseVisualStyleBackColor = true;
startButton.Click += StartButton_Clicked;
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(40, 389);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(263, 25);
this.label3.TabIndex = 4;
this.label3.Text = "Minimum time before shuffling:";
label3.AutoSize = true;
label3.Location = new Point(40, 389);
label3.Name = "label3";
label3.Size = new Size(263, 25);
label3.TabIndex = 4;
label3.Text = "Minimum time before shuffling:";
//
// minTimeTextBox
//
this.minTimeTextBox.Location = new System.Drawing.Point(309, 386);
this.minTimeTextBox.Name = "minTimeTextBox";
this.minTimeTextBox.Size = new System.Drawing.Size(150, 31);
this.minTimeTextBox.TabIndex = 5;
this.minTimeTextBox.Text = "60";
minTimeTextBox.Location = new Point(309, 386);
minTimeTextBox.Name = "minTimeTextBox";
minTimeTextBox.Size = new Size(150, 31);
minTimeTextBox.TabIndex = 5;
minTimeTextBox.Text = "60";
//
// maxTimeTextBox
//
this.maxTimeTextBox.Location = new System.Drawing.Point(309, 423);
this.maxTimeTextBox.Name = "maxTimeTextBox";
this.maxTimeTextBox.Size = new System.Drawing.Size(150, 31);
this.maxTimeTextBox.TabIndex = 6;
this.maxTimeTextBox.Text = "120";
maxTimeTextBox.Location = new Point(309, 423);
maxTimeTextBox.Name = "maxTimeTextBox";
maxTimeTextBox.Size = new Size(150, 31);
maxTimeTextBox.TabIndex = 6;
maxTimeTextBox.Text = "120";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(40, 426);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(266, 25);
this.label4.TabIndex = 7;
this.label4.Text = "Maximum time before shuffling:";
label4.AutoSize = true;
label4.Location = new Point(40, 426);
label4.Name = "label4";
label4.Size = new Size(266, 25);
label4.TabIndex = 7;
label4.Text = "Maximum time before shuffling:";
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(465, 389);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(77, 25);
this.label5.TabIndex = 8;
this.label5.Text = "seconds";
label5.AutoSize = true;
label5.Location = new Point(465, 389);
label5.Name = "label5";
label5.Size = new Size(77, 25);
label5.TabIndex = 8;
label5.Text = "seconds";
//
// label6
//
this.label6.AutoSize = true;
this.label6.Location = new System.Drawing.Point(465, 426);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(77, 25);
this.label6.TabIndex = 9;
this.label6.Text = "seconds";
label6.AutoSize = true;
label6.Location = new Point(465, 426);
label6.Name = "label6";
label6.Size = new Size(77, 25);
label6.TabIndex = 9;
label6.Text = "seconds";
//
// refreshButton
//
this.refreshButton.Location = new System.Drawing.Point(648, 4);
this.refreshButton.Name = "refreshButton";
this.refreshButton.Size = new System.Drawing.Size(112, 34);
this.refreshButton.TabIndex = 10;
this.refreshButton.Text = "Refresh";
this.refreshButton.UseVisualStyleBackColor = true;
this.refreshButton.Click += new System.EventHandler(this.Refresh_Clicked);
refreshButton.Location = new Point(648, 4);
refreshButton.Name = "refreshButton";
refreshButton.Size = new Size(112, 34);
refreshButton.TabIndex = 10;
refreshButton.Text = "Refresh";
refreshButton.UseVisualStyleBackColor = true;
refreshButton.Click += Refresh_Clicked;
//
// stopButton
//
this.stopButton.Enabled = false;
this.stopButton.Location = new System.Drawing.Point(611, 497);
this.stopButton.Name = "stopButton";
this.stopButton.Size = new System.Drawing.Size(149, 34);
this.stopButton.TabIndex = 11;
this.stopButton.Text = "Stop Shuffling";
this.stopButton.UseVisualStyleBackColor = true;
this.stopButton.Click += new System.EventHandler(this.StopButton_Clicked);
stopButton.Enabled = false;
stopButton.Location = new Point(611, 497);
stopButton.Name = "stopButton";
stopButton.Size = new Size(149, 34);
stopButton.TabIndex = 11;
stopButton.Text = "Stop Shuffling";
stopButton.UseVisualStyleBackColor = true;
stopButton.Click += StopButton_Clicked;
//
// label7
//
label7.AutoSize = true;
label7.Location = new Point(40, 531);
label7.Name = "label7";
label7.Size = new Size(331, 25);
label7.TabIndex = 12;
label7.Text = "Press PageUp to move to the next game";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 593);
this.Controls.Add(this.stopButton);
this.Controls.Add(this.refreshButton);
this.Controls.Add(this.label6);
this.Controls.Add(this.label5);
this.Controls.Add(this.label4);
this.Controls.Add(this.maxTimeTextBox);
this.Controls.Add(this.minTimeTextBox);
this.Controls.Add(this.label3);
this.Controls.Add(this.startButton);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.runningProcessesSelectionList);
this.Name = "Form1";
this.Text = "Game Shuffler";
this.ResumeLayout(false);
this.PerformLayout();
AutoScaleDimensions = new SizeF(10F, 25F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 593);
Controls.Add(label7);
Controls.Add(stopButton);
Controls.Add(refreshButton);
Controls.Add(label6);
Controls.Add(label5);
Controls.Add(label4);
Controls.Add(maxTimeTextBox);
Controls.Add(minTimeTextBox);
Controls.Add(label3);
Controls.Add(startButton);
Controls.Add(label2);
Controls.Add(label1);
Controls.Add(runningProcessesSelectionList);
Name = "Form1";
Text = "Game Shuffler";
ResumeLayout(false);
PerformLayout();
}
#endregion
@@ -197,5 +207,6 @@ namespace GameShuffler
private Label label6;
private Button refreshButton;
private Button stopButton;
private Label label7;
}
}

View File

@@ -39,9 +39,11 @@ namespace GameShuffler
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
int RemoveGameKeyId = 1;
int RemoveGameKey = (int)Keys.PageDown;
int NextGameKeyId = 2;
int NextGameKey = (int)Keys.PageUp;
Thread? shuffleThread = null;
bool stopShuffle = false;
@@ -89,13 +91,21 @@ namespace GameShuffler
if (!RegisterHotKey(this.Handle, RemoveGameKeyId, 0x0000, RemoveGameKey))
{
MessageBox.Show("Failed to initialize shuffle start key");
MessageBox.Show("Failed to initialize remove game key");
}
if (!RegisterHotKey(this.Handle, NextGameKeyId, 0x0000, NextGameKey))
{
MessageBox.Show("Failed to initialize next game key");
}
foreach (var processString in runningProcessesSelectionList.CheckedItems)
{
var process = Process.GetProcessById(int.Parse(((string)processString).Split("\t")[1]));
gamesToShuffle.Add(process);
if (process != null)
{
gamesToShuffle.Add(process);
}
}
shuffleThread = new Thread(ShuffleLoop);
@@ -118,18 +128,31 @@ namespace GameShuffler
}
UnregisterHotKey(this.Handle, RemoveGameKeyId);
UnregisterHotKey(this.Handle, NextGameKeyId);
foreach (var process in gamesToShuffle)
{
if (process != currentGame)
{
ResumeProcess(process);
ShowWindow(process.MainWindowHandle, 3);
}
process.Dispose();
}
gamesToShuffle = new List<Process>();
currentGame = null;
}
private void ShuffleLoop()
{
foreach (var process in gamesToShuffle)
{
foreach (var process in gamesToShuffle)
{
SuspendProcess(process);
}
while (gamesToShuffle.Any() && !stopShuffle)
{
if (currentGame != null)
if (currentGame != null && gamesToShuffle.Count > 1)
{
ShowWindow(currentGame.MainWindowHandle, 0);
SuspendProcess(currentGame);
@@ -140,26 +163,32 @@ namespace GameShuffler
Thread.Sleep(rand.Next(minShuffleTime, maxShuffleTime)*1000);
}
foreach (var process in gamesToShuffle)
{
if (process != currentGame)
{
ResumeProcess(process);
}
}
stopShuffle = false;
}
private void StartNewGame()
{
var currentGameIndex = currentGame == null ? 0 : gamesToShuffle.IndexOf(currentGame);
var newGameIndex = currentGameIndex;
while (newGameIndex == currentGameIndex)
var newGame = currentGame;
while (newGame == currentGame)
{
newGameIndex = rand.Next(gamesToShuffle.Count);
var newGameIndex = rand.Next(gamesToShuffle.Count);
newGame = gamesToShuffle[newGameIndex];
if (gamesToShuffle.Count <= 1)
{
break;
}
if (newGame.HasExited)
{
gamesToShuffle.RemoveAt(newGameIndex);
newGame = currentGame;
}
}
var newGame = gamesToShuffle[newGameIndex];
if (newGame == null)
{
return;
}
ResumeProcess(newGame);
ShowWindow(newGame.MainWindowHandle, 3);
SetForegroundWindow(newGame.MainWindowHandle);
@@ -217,11 +246,17 @@ namespace GameShuffler
{
gamesToShuffle.Remove(currentGame);
currentGame.Kill();
currentGame.Dispose();
if (gamesToShuffle.Any())
{
StartNewGame();
}
}
if (id == NextGameKeyId && gamesToShuffle.Any())
{
StartNewGame();
}
}
base.WndProc(ref m);

View File

@@ -1,4 +1,64 @@
<root>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">