Compare commits
	
		
			33 Commits
		
	
	
		
			be2c6f7829
			...
			master
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 15bee9bf62 | |||
| 32758cf062 | |||
| f4524161ac | |||
| 12ac48aa76 | |||
| 62f92708c2 | |||
| 88005c2125 | |||
| df936e187d | |||
| 833355cd60 | |||
| 0b7aaa2f99 | |||
| 274a75b93d | |||
| 3b038b0fc9 | |||
| 69fd02e331 | |||
| 87bd2132e5 | |||
| 1cdfba0b14 | |||
| 0e3f2005d1 | |||
| c4e9007f2b | |||
| 1f314d5c4b | |||
| f234279135 | |||
| baeadba638 | |||
| bad2313c18 | |||
| 458a466c15 | |||
| 5e95937ae9 | |||
| 48d3af7c94 | |||
| 603bc488e8 | |||
| cf804a6c8b | |||
| 9de3ae43d5 | |||
| 886258e4c3 | |||
| b5446516e4 | |||
| c28bc4ac69 | |||
| 04cb6c1e38 | |||
| 50f7c777b3 | |||
| 740d3d8b01 | |||
| 6a766a5441 | 
							
								
								
									
										3
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
BasedOnStyle: Google
 | 
			
		||||
IndentWidth: 4
 | 
			
		||||
ColumnLimit: 120
 | 
			
		||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,5 @@
 | 
			
		||||
.idea
 | 
			
		||||
obj
 | 
			
		||||
bin
 | 
			
		||||
.vs
 | 
			
		||||
packages
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,14 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8" ?>
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<configuration>
 | 
			
		||||
    <startup>
 | 
			
		||||
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
 | 
			
		||||
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
 | 
			
		||||
    </startup>
 | 
			
		||||
  <runtime>
 | 
			
		||||
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
 | 
			
		||||
      <dependentAssembly>
 | 
			
		||||
        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
 | 
			
		||||
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
 | 
			
		||||
      </dependentAssembly>
 | 
			
		||||
    </assemblyBinding>
 | 
			
		||||
  </runtime>
 | 
			
		||||
</configuration>
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 | 
			
		||||
    <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')"/>
 | 
			
		||||
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
 | 
			
		||||
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
 | 
			
		||||
@@ -8,11 +8,12 @@
 | 
			
		||||
    <OutputType>WinExe</OutputType>
 | 
			
		||||
    <RootNamespace>DD2Switcher</RootNamespace>
 | 
			
		||||
    <AssemblyName>DD2Switcher</AssemblyName>
 | 
			
		||||
        <TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
 | 
			
		||||
    <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
 | 
			
		||||
    <FileAlignment>512</FileAlignment>
 | 
			
		||||
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
 | 
			
		||||
    <Deterministic>true</Deterministic>
 | 
			
		||||
        <LangVersion>10</LangVersion>
 | 
			
		||||
    <LangVersion>9.0</LangVersion>
 | 
			
		||||
    <TargetFrameworkProfile />
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
 | 
			
		||||
    <PlatformTarget>x64</PlatformTarget>
 | 
			
		||||
@@ -36,17 +37,48 @@
 | 
			
		||||
    <Prefer32bit>false</Prefer32bit>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
        <Reference Include="System"/>
 | 
			
		||||
        <Reference Include="System.Core"/>
 | 
			
		||||
        <Reference Include="System.Xml.Linq"/>
 | 
			
		||||
        <Reference Include="System.Data.DataSetExtensions"/>
 | 
			
		||||
        <Reference Include="Microsoft.CSharp"/>
 | 
			
		||||
        <Reference Include="System.Data"/>
 | 
			
		||||
        <Reference Include="System.Deployment"/>
 | 
			
		||||
        <Reference Include="System.Drawing"/>
 | 
			
		||||
        <Reference Include="System.Net.Http"/>
 | 
			
		||||
        <Reference Include="System.Windows.Forms"/>
 | 
			
		||||
        <Reference Include="System.Xml"/>
 | 
			
		||||
    <Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
 | 
			
		||||
      <HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.9.0.8\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
 | 
			
		||||
    </Reference>
 | 
			
		||||
    <Reference Include="System" />
 | 
			
		||||
    <Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
 | 
			
		||||
      <HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
 | 
			
		||||
    </Reference>
 | 
			
		||||
    <Reference Include="System.Core" />
 | 
			
		||||
    <Reference Include="System.IO.Pipelines, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
 | 
			
		||||
      <HintPath>..\packages\System.IO.Pipelines.9.0.8\lib\net462\System.IO.Pipelines.dll</HintPath>
 | 
			
		||||
    </Reference>
 | 
			
		||||
    <Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
 | 
			
		||||
      <HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
 | 
			
		||||
    </Reference>
 | 
			
		||||
    <Reference Include="System.Numerics" />
 | 
			
		||||
    <Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
 | 
			
		||||
      <HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
 | 
			
		||||
    </Reference>
 | 
			
		||||
    <Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
 | 
			
		||||
      <HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
 | 
			
		||||
    </Reference>
 | 
			
		||||
    <Reference Include="System.Text.Encodings.Web, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
 | 
			
		||||
      <HintPath>..\packages\System.Text.Encodings.Web.9.0.8\lib\net462\System.Text.Encodings.Web.dll</HintPath>
 | 
			
		||||
    </Reference>
 | 
			
		||||
    <Reference Include="System.Text.Json, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
 | 
			
		||||
      <HintPath>..\packages\System.Text.Json.9.0.8\lib\net462\System.Text.Json.dll</HintPath>
 | 
			
		||||
    </Reference>
 | 
			
		||||
    <Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
 | 
			
		||||
      <HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
 | 
			
		||||
    </Reference>
 | 
			
		||||
    <Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
 | 
			
		||||
      <HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
 | 
			
		||||
    </Reference>
 | 
			
		||||
    <Reference Include="System.Xml.Linq" />
 | 
			
		||||
    <Reference Include="System.Data.DataSetExtensions" />
 | 
			
		||||
    <Reference Include="Microsoft.CSharp" />
 | 
			
		||||
    <Reference Include="System.Data" />
 | 
			
		||||
    <Reference Include="System.Deployment" />
 | 
			
		||||
    <Reference Include="System.Drawing" />
 | 
			
		||||
    <Reference Include="System.Net.Http" />
 | 
			
		||||
    <Reference Include="System.Windows.Forms" />
 | 
			
		||||
    <Reference Include="System.Xml" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Compile Include="Form1.cs">
 | 
			
		||||
@@ -55,9 +87,19 @@
 | 
			
		||||
    <Compile Include="Form1.Designer.cs">
 | 
			
		||||
      <DependentUpon>Form1.cs</DependentUpon>
 | 
			
		||||
    </Compile>
 | 
			
		||||
        <Compile Include="HotKeyManager.cs"/>
 | 
			
		||||
        <Compile Include="Program.cs"/>
 | 
			
		||||
        <Compile Include="Properties\AssemblyInfo.cs"/>
 | 
			
		||||
    <Compile Include="SettingsForm.cs">
 | 
			
		||||
      <SubType>Form</SubType>
 | 
			
		||||
    </Compile>
 | 
			
		||||
    <Compile Include="WindowPanelForm.cs">
 | 
			
		||||
      <SubType>UserControl</SubType>
 | 
			
		||||
    </Compile>
 | 
			
		||||
    <Compile Include="WindowPanelForm.Designer.cs">
 | 
			
		||||
      <DependentUpon>WindowPanelForm.cs</DependentUpon>
 | 
			
		||||
    </Compile>
 | 
			
		||||
    <Compile Include="HotKeyManager.cs" />
 | 
			
		||||
    <Compile Include="KeyboardHook.cs" />
 | 
			
		||||
    <Compile Include="Program.cs" />
 | 
			
		||||
    <Compile Include="Properties\AssemblyInfo.cs" />
 | 
			
		||||
    <EmbeddedResource Include="Properties\Resources.resx">
 | 
			
		||||
      <Generator>ResXFileCodeGenerator</Generator>
 | 
			
		||||
      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
 | 
			
		||||
@@ -67,6 +109,13 @@
 | 
			
		||||
      <AutoGen>True</AutoGen>
 | 
			
		||||
      <DependentUpon>Resources.resx</DependentUpon>
 | 
			
		||||
    </Compile>
 | 
			
		||||
    <EmbeddedResource Include="SettingsForm.resx">
 | 
			
		||||
      <DependentUpon>SettingsForm.cs</DependentUpon>
 | 
			
		||||
    </EmbeddedResource>
 | 
			
		||||
    <EmbeddedResource Include="WindowPanelForm.resx">
 | 
			
		||||
      <DependentUpon>WindowPanelForm.cs</DependentUpon>
 | 
			
		||||
    </EmbeddedResource>
 | 
			
		||||
    <None Include="packages.config" />
 | 
			
		||||
    <None Include="Properties\Settings.settings">
 | 
			
		||||
      <Generator>SettingsSingleFileGenerator</Generator>
 | 
			
		||||
      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
 | 
			
		||||
@@ -78,10 +127,13 @@
 | 
			
		||||
    </Compile>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
        <None Include="App.config"/>
 | 
			
		||||
    <None Include="App.config" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
        <Content Include="beep.wav"/>
 | 
			
		||||
    <Content Include="beep.wav" />
 | 
			
		||||
    <Content Include="app.ico">
 | 
			
		||||
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 | 
			
		||||
    </Content>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
    <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets"/>
 | 
			
		||||
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 | 
			
		||||
</Project>
 | 
			
		||||
							
								
								
									
										80
									
								
								DD2Switcher/Form1.Designer.cs
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										80
									
								
								DD2Switcher/Form1.Designer.cs
									
									
									
										generated
									
									
									
								
							@@ -1,7 +1,5 @@
 | 
			
		||||
namespace DD2Switcher
 | 
			
		||||
{
 | 
			
		||||
    partial class Form1
 | 
			
		||||
    {
 | 
			
		||||
namespace DD2Switcher {
 | 
			
		||||
    partial class Form1 {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Required designer variable.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@@ -10,31 +8,85 @@
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Clean up any resources being used.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
 | 
			
		||||
        protected override void Dispose(bool disposing)
 | 
			
		||||
        {
 | 
			
		||||
            if (disposing && (components != null))
 | 
			
		||||
            {
 | 
			
		||||
        /// <param name="disposing">true if managed resources should be disposed;
 | 
			
		||||
        /// otherwise, false.</param>
 | 
			
		||||
        protected override void Dispose(bool disposing) {
 | 
			
		||||
            if (disposing && (components != null)) {
 | 
			
		||||
                components.Dispose();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            base.Dispose(disposing);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #region Windows Form Designer generated code
 | 
			
		||||
#region Windows Form Designer generated code
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Required method for Designer support - do not modify
 | 
			
		||||
        /// the contents of this method with the code editor.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private void InitializeComponent()
 | 
			
		||||
        {
 | 
			
		||||
        private void InitializeComponent() {
 | 
			
		||||
            this.components = new System.ComponentModel.Container();
 | 
			
		||||
            this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components);
 | 
			
		||||
            this.trayMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
 | 
			
		||||
            this.settingsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
 | 
			
		||||
            this.separatorMenuItem = new System.Windows.Forms.ToolStripSeparator();
 | 
			
		||||
            this.exitMenuItem = new System.Windows.Forms.ToolStripMenuItem();
 | 
			
		||||
            this.trayMenu.SuspendLayout();
 | 
			
		||||
            this.SuspendLayout();
 | 
			
		||||
            //
 | 
			
		||||
            // notifyIcon
 | 
			
		||||
            //
 | 
			
		||||
            this.notifyIcon.ContextMenuStrip = this.trayMenu;
 | 
			
		||||
            this.notifyIcon.Text = "DD2Switcher";
 | 
			
		||||
            this.notifyIcon.Visible = true;
 | 
			
		||||
            this.notifyIcon.MouseDoubleClick +=
 | 
			
		||||
                new System.Windows.Forms.MouseEventHandler(this.notifyIcon_MouseDoubleClick);
 | 
			
		||||
            //
 | 
			
		||||
            // trayMenu
 | 
			
		||||
            //
 | 
			
		||||
            this.trayMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
 | 
			
		||||
                this.settingsMenuItem, this.separatorMenuItem, this.exitMenuItem
 | 
			
		||||
            });
 | 
			
		||||
            this.trayMenu.Name = "trayMenu";
 | 
			
		||||
            this.trayMenu.Size = new System.Drawing.Size(120, 54);
 | 
			
		||||
            //
 | 
			
		||||
            // settingsMenuItem
 | 
			
		||||
            //
 | 
			
		||||
            this.settingsMenuItem.Name = "settingsMenuItem";
 | 
			
		||||
            this.settingsMenuItem.Size = new System.Drawing.Size(119, 22);
 | 
			
		||||
            this.settingsMenuItem.Text = "Settings";
 | 
			
		||||
            this.settingsMenuItem.Click += new System.EventHandler(this.settingsMenuItem_Click);
 | 
			
		||||
            //
 | 
			
		||||
            // separatorMenuItem
 | 
			
		||||
            //
 | 
			
		||||
            this.separatorMenuItem.Name = "separatorMenuItem";
 | 
			
		||||
            this.separatorMenuItem.Size = new System.Drawing.Size(116, 6);
 | 
			
		||||
            //
 | 
			
		||||
            // exitMenuItem
 | 
			
		||||
            //
 | 
			
		||||
            this.exitMenuItem.Name = "exitMenuItem";
 | 
			
		||||
            this.exitMenuItem.Size = new System.Drawing.Size(119, 22);
 | 
			
		||||
            this.exitMenuItem.Text = "Exit";
 | 
			
		||||
            this.exitMenuItem.Click += new System.EventHandler(this.exitMenuItem_Click);
 | 
			
		||||
            //
 | 
			
		||||
            // Form1
 | 
			
		||||
            //
 | 
			
		||||
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
 | 
			
		||||
            this.ClientSize = new System.Drawing.Size(800, 450);
 | 
			
		||||
            this.Text = "Form1";
 | 
			
		||||
            this.Text = "DD2Switcher";
 | 
			
		||||
            this.WindowState = System.Windows.Forms.FormWindowState.Minimized;
 | 
			
		||||
            this.ShowInTaskbar = false;
 | 
			
		||||
            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
 | 
			
		||||
            this.trayMenu.ResumeLayout(false);
 | 
			
		||||
            this.ResumeLayout(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #endregion
 | 
			
		||||
#endregion
 | 
			
		||||
 | 
			
		||||
        private System.Windows.Forms.NotifyIcon notifyIcon;
 | 
			
		||||
        private System.Windows.Forms.ContextMenuStrip trayMenu;
 | 
			
		||||
        private System.Windows.Forms.ToolStripMenuItem settingsMenuItem;
 | 
			
		||||
        private System.Windows.Forms.ToolStripSeparator separatorMenuItem;
 | 
			
		||||
        private System.Windows.Forms.ToolStripMenuItem exitMenuItem;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,9 +1,60 @@
 | 
			
		||||
using System.Windows.Forms;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Windows.Forms;
 | 
			
		||||
 | 
			
		||||
namespace DD2Switcher; 
 | 
			
		||||
namespace DD2Switcher {
 | 
			
		||||
    public partial class Form1 : Form {
 | 
			
		||||
        private SettingsForm settingsForm;
 | 
			
		||||
 | 
			
		||||
public partial class Form1 : Form {
 | 
			
		||||
        public Form1() {
 | 
			
		||||
            InitializeComponent();
 | 
			
		||||
            LoadIcons();
 | 
			
		||||
            this.Load += Form1_Load;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void Form1_Load(object sender, EventArgs e) {
 | 
			
		||||
            // Hide the form initially since we're running in system tray
 | 
			
		||||
            this.Hide();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e) {
 | 
			
		||||
            ShowSettings();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void settingsMenuItem_Click(object sender, EventArgs e) {
 | 
			
		||||
            ShowSettings();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void exitMenuItem_Click(object sender, EventArgs e) {
 | 
			
		||||
            Application.Exit();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
 | 
			
		||||
            // Prevent the form from closing, just hide it
 | 
			
		||||
            if (e.CloseReason == CloseReason.UserClosing) {
 | 
			
		||||
                e.Cancel = true;
 | 
			
		||||
                this.Hide();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ShowSettings() {
 | 
			
		||||
            if (settingsForm == null || settingsForm.IsDisposed) {
 | 
			
		||||
                settingsForm = new SettingsForm();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            settingsForm.Show();
 | 
			
		||||
            settingsForm.BringToFront();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void LoadIcons() {
 | 
			
		||||
            try {
 | 
			
		||||
                string iconPath = System.IO.Path.Combine(
 | 
			
		||||
                    System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
 | 
			
		||||
                    "app.ico");
 | 
			
		||||
                this.Icon = new System.Drawing.Icon(iconPath);
 | 
			
		||||
                this.notifyIcon.Icon = new System.Drawing.Icon(iconPath);
 | 
			
		||||
            } catch {
 | 
			
		||||
                // Use default icon if custom icon not found
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -3,9 +3,8 @@ using System.Runtime.InteropServices;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Windows.Forms;
 | 
			
		||||
 | 
			
		||||
namespace DD2Switcher; 
 | 
			
		||||
 | 
			
		||||
public static class HotKeyManager {
 | 
			
		||||
namespace DD2Switcher {
 | 
			
		||||
    public static class HotKeyManager {
 | 
			
		||||
        private static volatile MessageWindow _wnd;
 | 
			
		||||
        private static volatile IntPtr _hwnd;
 | 
			
		||||
        private static readonly ManualResetEvent _windowReadyEvent = new(false);
 | 
			
		||||
@@ -41,7 +40,8 @@ public static class HotKeyManager {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void OnHotKeyPressed(HotKeyEventArgs e) {
 | 
			
		||||
        if (HotKeyPressed != null) HotKeyPressed(null, e);
 | 
			
		||||
            if (HotKeyPressed != null)
 | 
			
		||||
                HotKeyPressed(null, e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [DllImport("user32", SetLastError = true)]
 | 
			
		||||
@@ -77,9 +77,9 @@ public static class HotKeyManager {
 | 
			
		||||
                base.SetVisibleCore(false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
public class HotKeyEventArgs : EventArgs {
 | 
			
		||||
    public class HotKeyEventArgs : EventArgs {
 | 
			
		||||
        public readonly Keys Key;
 | 
			
		||||
        public readonly KeyModifiers Modifiers;
 | 
			
		||||
 | 
			
		||||
@@ -93,13 +93,8 @@ public class HotKeyEventArgs : EventArgs {
 | 
			
		||||
            Key = (Keys)((param & 0xffff0000) >> 16);
 | 
			
		||||
            Modifiers = (KeyModifiers)(param & 0x0000ffff);
 | 
			
		||||
        }
 | 
			
		||||
}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
[Flags]
 | 
			
		||||
public enum KeyModifiers {
 | 
			
		||||
    Alt = 1,
 | 
			
		||||
    Control = 2,
 | 
			
		||||
    Shift = 4,
 | 
			
		||||
    Windows = 8,
 | 
			
		||||
    NoRepeat = 0x4000
 | 
			
		||||
    [Flags]
 | 
			
		||||
    public enum KeyModifiers { Alt = 1, Control = 2, Shift = 4, Windows = 8, NoRepeat = 0x4000 }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								DD2Switcher/KeyboardHook.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								DD2Switcher/KeyboardHook.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Windows.Forms;
 | 
			
		||||
using System.Runtime.InteropServices;
 | 
			
		||||
 | 
			
		||||
class KeyboardHook {
 | 
			
		||||
    private const int WH_KEYBOARD_LL = 13;
 | 
			
		||||
    private const int WM_KEYDOWN = 0x0104;
 | 
			
		||||
    private const int WM_KEYUP = 0x0101;
 | 
			
		||||
    private static LowLevelKeyboardProc _proc = HookCallback;
 | 
			
		||||
    private static IntPtr _hookID = IntPtr.Zero;
 | 
			
		||||
 | 
			
		||||
    public static int previousEvent = 0;
 | 
			
		||||
    public static event EventHandler<int> KeyDown;
 | 
			
		||||
    public static event EventHandler<int> KeyUp;
 | 
			
		||||
 | 
			
		||||
    public static void Start() {
 | 
			
		||||
        _hookID = SetHook(_proc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void Stop() {
 | 
			
		||||
        UnhookWindowsHookEx(_hookID);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static IntPtr SetHook(LowLevelKeyboardProc proc) {
 | 
			
		||||
        using (Process curProcess = Process.GetCurrentProcess()) using (ProcessModule curModule =
 | 
			
		||||
                                                                            curProcess.MainModule) {
 | 
			
		||||
            return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
 | 
			
		||||
 | 
			
		||||
    private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
 | 
			
		||||
        if (nCode >= 0) {
 | 
			
		||||
            int vkCode = Marshal.ReadInt32(lParam);
 | 
			
		||||
            int pero = (int)wParam * 1000 + vkCode;
 | 
			
		||||
            if (pero != previousEvent) {
 | 
			
		||||
                if (wParam == (IntPtr)WM_KEYDOWN) {
 | 
			
		||||
                    Console.WriteLine($"KeyboardHook: KeyDown event for key {vkCode}");
 | 
			
		||||
                    KeyDown?.Invoke(null, vkCode);
 | 
			
		||||
                } else if (wParam == (IntPtr)WM_KEYUP) {
 | 
			
		||||
                    Console.WriteLine($"KeyboardHook: KeyUp event for key {vkCode}");
 | 
			
		||||
                    KeyUp?.Invoke(null, vkCode);
 | 
			
		||||
                }
 | 
			
		||||
                previousEvent = pero;
 | 
			
		||||
            } else {
 | 
			
		||||
                Console.WriteLine($"KeyboardHook: Same event filtered out - vkCode: {vkCode}, wParam: {wParam}");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return CallNextHookEx(_hookID, nCode, wParam, lParam);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
 | 
			
		||||
    private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
 | 
			
		||||
 | 
			
		||||
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
 | 
			
		||||
    [return:MarshalAs(UnmanagedType.Bool)]
 | 
			
		||||
    private static extern bool UnhookWindowsHookEx(IntPtr hhk);
 | 
			
		||||
 | 
			
		||||
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
 | 
			
		||||
    private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
 | 
			
		||||
 | 
			
		||||
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
 | 
			
		||||
    private static extern IntPtr GetModuleHandle(string lpModuleName);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,18 +1,271 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Runtime.InteropServices;
 | 
			
		||||
using System.Windows.Forms;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Text.Json;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace DD2Switcher;
 | 
			
		||||
namespace DD2Switcher {
 | 
			
		||||
    public class Settings {
 | 
			
		||||
        public Keys SequenceKeybind { get; set; } = Keys.F1;
 | 
			
		||||
        public int SequenceTimerDelay { get; set; } = 100;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
internal static class Program {
 | 
			
		||||
    internal static class Program {
 | 
			
		||||
        private static int NumProc = 19;
 | 
			
		||||
        private static Process[] windows = new Process[NumProc];
 | 
			
		||||
        private static string settingsPath =
 | 
			
		||||
            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "DD2Switcher.json");
 | 
			
		||||
 | 
			
		||||
        // Public access to tracked windows for the settings form
 | 
			
		||||
        public static Process[] GetTrackedWindows() {
 | 
			
		||||
            return windows;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void UntrackWindow(int index) {
 | 
			
		||||
            if (index >= 0 && index < NumProc) {
 | 
			
		||||
                windows[index] = null;
 | 
			
		||||
 | 
			
		||||
                // Update ActiveIndex if needed
 | 
			
		||||
                if (ActiveIndex == index) {
 | 
			
		||||
                    ActiveIndex = -1;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Update first/last indices if needed
 | 
			
		||||
                if (FirstIndex == index) {
 | 
			
		||||
                    FirstIndex = -1;
 | 
			
		||||
                }
 | 
			
		||||
                if (LastIndex == index) {
 | 
			
		||||
                    LastIndex = -1;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void StartSequenceMode() {
 | 
			
		||||
            Console.WriteLine($"StartSequenceMode called. FirstIndex: {FirstIndex}, LastIndex: {LastIndex}");
 | 
			
		||||
 | 
			
		||||
            // Compute indices only when sequence starts, not stored permanently
 | 
			
		||||
            int sequenceFirstIndex = FirstIndex;
 | 
			
		||||
            int sequenceLastIndex = LastIndex;
 | 
			
		||||
 | 
			
		||||
            // If no user indices, use absolute first and last windows
 | 
			
		||||
            if (sequenceFirstIndex == -1 || sequenceLastIndex == -1) {
 | 
			
		||||
                sequenceFirstIndex = FindFirstNonNullWindow();
 | 
			
		||||
                sequenceLastIndex = FindLastNonNullWindow();
 | 
			
		||||
                Console.WriteLine(
 | 
			
		||||
                    $"Computed sequence indices: FirstIndex={sequenceFirstIndex}, LastIndex={sequenceLastIndex}");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (sequenceFirstIndex >= 0 && sequenceLastIndex >= 0 && sequenceFirstIndex <= sequenceLastIndex) {
 | 
			
		||||
                CurrentSequenceIndex = sequenceFirstIndex;
 | 
			
		||||
                Console.WriteLine($"Starting sequence mode, tabbing to index {CurrentSequenceIndex + 1}");
 | 
			
		||||
                TabTo(CurrentSequenceIndex + 1);  // Tab to first window
 | 
			
		||||
                CurrentState = SequenceState.WAITING_FOR_EVENT;
 | 
			
		||||
                Console.WriteLine($"State changed to: {CurrentState}");
 | 
			
		||||
            } else {
 | 
			
		||||
                Console.WriteLine("Cannot start sequence mode - invalid first/last indices");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void ExitSequenceMode() {
 | 
			
		||||
            CurrentState = SequenceState.INACTIVE;
 | 
			
		||||
            CurrentSequenceIndex = -1;
 | 
			
		||||
            Console.WriteLine($"State changed to: {CurrentState}");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static bool IsInSequenceMode() {
 | 
			
		||||
            return CurrentState != SequenceState.INACTIVE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void LoadSettings() {
 | 
			
		||||
            Console.WriteLine($"Attempting to load settings from: {settingsPath}");
 | 
			
		||||
            try {
 | 
			
		||||
                if (File.Exists(settingsPath)) {
 | 
			
		||||
                    Console.WriteLine("Settings file exists, reading...");
 | 
			
		||||
                    string json = File.ReadAllText(settingsPath);
 | 
			
		||||
                    Console.WriteLine($"Read JSON: {json}");
 | 
			
		||||
                    var settings = JsonSerializer.Deserialize<Settings>(json);
 | 
			
		||||
                    SequenceKeybind = settings.SequenceKeybind;
 | 
			
		||||
                    SequenceTimerDelay = settings.SequenceTimerDelay;
 | 
			
		||||
                    Console.WriteLine(
 | 
			
		||||
                        $"Loaded settings: Keybind={SequenceKeybind}, TimerDelay={SequenceTimerDelay} (First/Last indices NOT loaded)");
 | 
			
		||||
                } else {
 | 
			
		||||
                    Console.WriteLine($"Settings file does not exist at: {settingsPath}");
 | 
			
		||||
                    Console.WriteLine("Using default settings");
 | 
			
		||||
                }
 | 
			
		||||
            } catch (Exception ex) {
 | 
			
		||||
                Console.WriteLine($"Error loading settings: {ex.Message}");
 | 
			
		||||
                Console.WriteLine($"Stack trace: {ex.StackTrace}");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void SaveSettings() {
 | 
			
		||||
            try {
 | 
			
		||||
                var settings =
 | 
			
		||||
                    new Settings { SequenceKeybind = SequenceKeybind, SequenceTimerDelay = SequenceTimerDelay };
 | 
			
		||||
                string json = JsonSerializer.Serialize(settings, new JsonSerializerOptions { WriteIndented = true });
 | 
			
		||||
                File.WriteAllText(settingsPath, json);
 | 
			
		||||
                Console.WriteLine($"Saved settings: Keybind={SequenceKeybind}, TimerDelay={SequenceTimerDelay}");
 | 
			
		||||
            } catch (Exception ex) {
 | 
			
		||||
                Console.WriteLine($"Error saving settings: {ex.Message}");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static int FindFirstNonNullWindow() {
 | 
			
		||||
            for (int i = 0; i < NumProc; i++) {
 | 
			
		||||
                if (windows[i] != null && windows[i].MainWindowHandle != IntPtr.Zero) {
 | 
			
		||||
                    return i;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static int FindLastNonNullWindow() {
 | 
			
		||||
            for (int i = NumProc - 1; i >= 0; i--) {
 | 
			
		||||
                if (windows[i] != null && windows[i].MainWindowHandle != IntPtr.Zero) {
 | 
			
		||||
                    return i;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static int FindNextNonNullWindow(int startIndex) {
 | 
			
		||||
            for (int i = startIndex; i < NumProc; i++) {
 | 
			
		||||
                if (windows[i] != null && windows[i].MainWindowHandle != IntPtr.Zero) {
 | 
			
		||||
                    return i;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void SetDefaultFirstLastIndices() {
 | 
			
		||||
            if (FirstIndex == -1) {
 | 
			
		||||
                FirstIndex = FindFirstNonNullWindow();
 | 
			
		||||
                Console.WriteLine($"Set default FirstIndex to: {FirstIndex}");
 | 
			
		||||
            }
 | 
			
		||||
            if (LastIndex == -1) {
 | 
			
		||||
                LastIndex = FindLastNonNullWindow();
 | 
			
		||||
                Console.WriteLine($"Set default LastIndex to: {LastIndex}");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Ensure LastIndex is different from FirstIndex if there are multiple windows
 | 
			
		||||
            if (FirstIndex != -1 && LastIndex != -1 && FirstIndex == LastIndex) {
 | 
			
		||||
                // Find the next non-null window after FirstIndex
 | 
			
		||||
                int nextWindow = FindNextNonNullWindow(FirstIndex + 1);
 | 
			
		||||
                if (nextWindow != -1) {
 | 
			
		||||
                    LastIndex = nextWindow;
 | 
			
		||||
                    Console.WriteLine($"Adjusted LastIndex to: {LastIndex} (different from FirstIndex)");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void UpdateSequenceHotkey(Keys newKey) {
 | 
			
		||||
            Console.WriteLine($"UpdateSequenceHotkey called with new key: {newKey} (code: {(int)newKey})");
 | 
			
		||||
            Console.WriteLine($"Old SequenceKeybind before update: {SequenceKeybind} (code: {(int)SequenceKeybind})");
 | 
			
		||||
 | 
			
		||||
            // Unregister old hotkey
 | 
			
		||||
            if (sequenceHotkeyId != -1) {
 | 
			
		||||
                Console.WriteLine($"Unregistering old hotkey ID: {sequenceHotkeyId}");
 | 
			
		||||
                HotKeyManager.UnregisterHotKey(sequenceHotkeyId);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Register new hotkey
 | 
			
		||||
            sequenceHotkeyId = HotKeyManager.RegisterHotKey(newKey, KeyModifiers.NoRepeat);
 | 
			
		||||
            Console.WriteLine($"Registered new hotkey ID: {sequenceHotkeyId} for key: {newKey}");
 | 
			
		||||
            SequenceKeybind = newKey;
 | 
			
		||||
            Console.WriteLine($"New SequenceKeybind after update: {SequenceKeybind} (code: {(int)SequenceKeybind})");
 | 
			
		||||
            SaveSettings();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void SaveFirstLastIndices() {
 | 
			
		||||
            SaveSettings();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Static properties for first/last selection persistence
 | 
			
		||||
        public static int FirstIndex { get; set; } = -1;
 | 
			
		||||
        public static int LastIndex { get; set; } = -1;
 | 
			
		||||
 | 
			
		||||
        // Sequence mode state engine
 | 
			
		||||
        public enum SequenceState { INACTIVE, WAITING_FOR_EVENT, WAITING_TO_ADVANCE, ADVANCE }
 | 
			
		||||
 | 
			
		||||
        public static SequenceState CurrentState { get; set; } = SequenceState.INACTIVE;
 | 
			
		||||
        public static int CurrentSequenceIndex { get; set; } = -1;
 | 
			
		||||
        public static Keys SequenceKeybind { get; set; } = Keys.F1;
 | 
			
		||||
        public static int SequenceTimerDelay { get; set; } = 100;
 | 
			
		||||
        private static int sequenceHotkeyId = -1;
 | 
			
		||||
        private static int ActiveIndex = -1;
 | 
			
		||||
        private static bool AltPressed = false;
 | 
			
		||||
 | 
			
		||||
        // State handlers
 | 
			
		||||
        private static readonly Dictionary<SequenceState, Action> stateHandlers =
 | 
			
		||||
            new Dictionary<SequenceState, Action> { { SequenceState.INACTIVE, HandleInactive },
 | 
			
		||||
                                                    { SequenceState.WAITING_FOR_EVENT, HandleWaitingForEvent },
 | 
			
		||||
                                                    { SequenceState.WAITING_TO_ADVANCE, HandleWaitingToAdvance },
 | 
			
		||||
                                                    { SequenceState.ADVANCE, HandleAdvance } };
 | 
			
		||||
 | 
			
		||||
        private static void HandleInactive() {
 | 
			
		||||
            // Inactive state - do nothing
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void HandleWaitingForEvent() {
 | 
			
		||||
            // Event happened, transition to waiting to advance
 | 
			
		||||
            Console.WriteLine($"Event detected in state: {CurrentState}, transitioning to WAITING_TO_ADVANCE");
 | 
			
		||||
            CurrentState = SequenceState.WAITING_TO_ADVANCE;
 | 
			
		||||
            Console.WriteLine($"State changed to: {CurrentState}");
 | 
			
		||||
            HandleWaitingToAdvance();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void HandleWaitingToAdvance() {
 | 
			
		||||
            // Start timer to advance after N milliseconds
 | 
			
		||||
            Console.WriteLine($"Starting {SequenceTimerDelay}ms timer in WAITING_TO_ADVANCE state");
 | 
			
		||||
            Task.Delay(SequenceTimerDelay)
 | 
			
		||||
                .ContinueWith(
 | 
			
		||||
                    _ => {
 | 
			
		||||
                        if (CurrentState == SequenceState.WAITING_TO_ADVANCE) {
 | 
			
		||||
                            CurrentState = SequenceState.ADVANCE;
 | 
			
		||||
                            Console.WriteLine($"Timer expired, transitioning to ADVANCE state");
 | 
			
		||||
                            HandleSequenceEvent();
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void HandleAdvance() {
 | 
			
		||||
            Console.WriteLine($"Advancing sequence from ADVANCE state");
 | 
			
		||||
 | 
			
		||||
            CurrentSequenceIndex++;
 | 
			
		||||
            Console.WriteLine($"Advanced to index {CurrentSequenceIndex}");
 | 
			
		||||
 | 
			
		||||
            // Get the actual last index for this sequence (computed or user-set)
 | 
			
		||||
            int sequenceLastIndex = (LastIndex != -1) ? LastIndex : FindLastNonNullWindow();
 | 
			
		||||
 | 
			
		||||
            if (CurrentSequenceIndex > sequenceLastIndex) {
 | 
			
		||||
                // End of sequence - tab back to first
 | 
			
		||||
                int sequenceFirstIndex = (FirstIndex != -1) ? FirstIndex : FindFirstNonNullWindow();
 | 
			
		||||
                Console.WriteLine("End of sequence reached, tabbing back to first window");
 | 
			
		||||
                TabTo(sequenceFirstIndex + 1);
 | 
			
		||||
                ExitSequenceMode();
 | 
			
		||||
            } else {
 | 
			
		||||
                Console.WriteLine($"Tabbing to index {CurrentSequenceIndex + 1}");
 | 
			
		||||
                TabTo(CurrentSequenceIndex + 1);
 | 
			
		||||
                CurrentState = SequenceState.WAITING_FOR_EVENT;
 | 
			
		||||
                Console.WriteLine($"State changed to: {CurrentState}");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void HandleSequenceEvent() {
 | 
			
		||||
            stateHandlers[CurrentState]?.Invoke();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Simple list to track last 5 windows
 | 
			
		||||
        private static List<int> lastWindows = new List<int>();
 | 
			
		||||
 | 
			
		||||
        private static readonly IntPtr defaultAffinity = new(0xFF000000);
 | 
			
		||||
        private static readonly IntPtr fullAffinity = new(0xFFFFFFFF);
 | 
			
		||||
        private static readonly KeyboardHook keyboardHook = new();
 | 
			
		||||
 | 
			
		||||
        [DllImport("user32.dll")]
 | 
			
		||||
        public static extern IntPtr GetForegroundWindow();
 | 
			
		||||
@@ -20,14 +273,68 @@ internal static class Program {
 | 
			
		||||
        [DllImport("user32.dll")]
 | 
			
		||||
        public static extern bool SetForegroundWindow(IntPtr hWnd);
 | 
			
		||||
 | 
			
		||||
        [DllImport("user32.dll")]
 | 
			
		||||
        private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
 | 
			
		||||
 | 
			
		||||
        [DllImport("user32.dll")]
 | 
			
		||||
        private static extern bool BringWindowToTop(IntPtr hWnd);
 | 
			
		||||
 | 
			
		||||
        [DllImport("user32.dll")]
 | 
			
		||||
        private static extern IntPtr SetActiveWindow(IntPtr hWnd);
 | 
			
		||||
 | 
			
		||||
        [DllImport("user32.dll")]
 | 
			
		||||
        private static extern short GetKeyState(int nVirtKey);
 | 
			
		||||
 | 
			
		||||
        private const int SW_RESTORE = 9;
 | 
			
		||||
 | 
			
		||||
        [DllImport("kernel32.dll", SetLastError = true)]
 | 
			
		||||
	[return: MarshalAs(UnmanagedType.Bool)]
 | 
			
		||||
        [return:MarshalAs(UnmanagedType.Bool)]
 | 
			
		||||
        static extern bool AllocConsole();
 | 
			
		||||
 | 
			
		||||
        [DllImport("user32.dll")]
 | 
			
		||||
        private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
 | 
			
		||||
 | 
			
		||||
        [DllImport("user32.dll")]
 | 
			
		||||
        private static extern IntPtr SetWindowsHookEx(int idHook, IntPtr lpfn, IntPtr hMod, uint dwThreadId);
 | 
			
		||||
 | 
			
		||||
        [DllImport("user32.dll")]
 | 
			
		||||
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);
 | 
			
		||||
 | 
			
		||||
        [DllImport("user32.dll")]
 | 
			
		||||
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
 | 
			
		||||
 | 
			
		||||
        [DllImport("kernel32.dll")]
 | 
			
		||||
        private static extern IntPtr GetModuleHandle(string lpModuleName);
 | 
			
		||||
 | 
			
		||||
        private const int WH_MOUSE_LL = 14;
 | 
			
		||||
        private const int WM_LBUTTONDOWN = 0x0201;
 | 
			
		||||
        private const int WM_RBUTTONDOWN = 0x0204;
 | 
			
		||||
        private const int WM_MBUTTONDOWN = 0x0207;
 | 
			
		||||
        private static IntPtr mouseHookId = IntPtr.Zero;
 | 
			
		||||
        private static IntPtr mouseHookProc = IntPtr.Zero;
 | 
			
		||||
        private static MouseHookProc mouseHookDelegate;  // Keep reference to prevent GC
 | 
			
		||||
 | 
			
		||||
        private delegate IntPtr MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam);
 | 
			
		||||
 | 
			
		||||
        private static IntPtr MouseHookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
 | 
			
		||||
            if (nCode >= 0) {
 | 
			
		||||
                int wParamInt = (int)wParam;
 | 
			
		||||
                if (wParamInt == WM_LBUTTONDOWN || wParamInt == WM_RBUTTONDOWN || wParamInt == WM_MBUTTONDOWN) {
 | 
			
		||||
                    if (CurrentState == SequenceState.WAITING_FOR_EVENT) {
 | 
			
		||||
                        Console.WriteLine($"Mouse click detected in state: {CurrentState}");
 | 
			
		||||
                        // Handle sequence event asynchronously to avoid interfering with mouse event processing
 | 
			
		||||
                        Task.Run(() => HandleSequenceEvent());
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return CallNextHookEx(mouseHookId, nCode, wParam, lParam);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void CleanWindows() {
 | 
			
		||||
            for (int i = 0; i < NumProc; i++) {
 | 
			
		||||
                var window = windows[i];
 | 
			
		||||
			if (window == null) continue;
 | 
			
		||||
                if (window == null)
 | 
			
		||||
                    continue;
 | 
			
		||||
                if (window.MainWindowHandle == IntPtr.Zero) {
 | 
			
		||||
                    Console.WriteLine($"Window at index {i} has no main window, removing from tracked windows");
 | 
			
		||||
                    windows[i] = null;
 | 
			
		||||
@@ -39,12 +346,12 @@ internal static class Program {
 | 
			
		||||
            CleanWindows();
 | 
			
		||||
            for (int i = 0; i < NumProc; i++) {
 | 
			
		||||
                var window = windows[i];
 | 
			
		||||
			if (window == null) continue;
 | 
			
		||||
                if (window == null)
 | 
			
		||||
                    continue;
 | 
			
		||||
                if (i != ActiveIndex) {
 | 
			
		||||
                    try {
 | 
			
		||||
                        window.ProcessorAffinity = defaultAffinity;
 | 
			
		||||
				}
 | 
			
		||||
				catch (Exception e) {
 | 
			
		||||
                    } catch (Exception e) {
 | 
			
		||||
                        windows[i] = null;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
@@ -54,8 +361,7 @@ internal static class Program {
 | 
			
		||||
            if (active != null) {
 | 
			
		||||
                try {
 | 
			
		||||
                    active.ProcessorAffinity = fullAffinity;
 | 
			
		||||
			}
 | 
			
		||||
			catch (Exception e) {
 | 
			
		||||
                } catch (Exception e) {
 | 
			
		||||
                    windows[ActiveIndex] = null;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -65,13 +371,13 @@ internal static class Program {
 | 
			
		||||
            CleanWindows();
 | 
			
		||||
            for (int i = 0; i < NumProc; i++) {
 | 
			
		||||
                var window = windows[i];
 | 
			
		||||
			if (window == null) continue;
 | 
			
		||||
                if (window == null)
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                if (i != ActiveIndex) {
 | 
			
		||||
                    try {
 | 
			
		||||
                        window.PriorityClass = ProcessPriorityClass.Idle;
 | 
			
		||||
				}
 | 
			
		||||
				catch (Exception e) {
 | 
			
		||||
                    } catch (Exception e) {
 | 
			
		||||
                        windows[i] = null;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
@@ -81,8 +387,7 @@ internal static class Program {
 | 
			
		||||
            if (active != null) {
 | 
			
		||||
                try {
 | 
			
		||||
                    active.PriorityClass = ProcessPriorityClass.High;
 | 
			
		||||
			}
 | 
			
		||||
			catch (Exception e) {
 | 
			
		||||
                } catch (Exception e) {
 | 
			
		||||
                    windows[ActiveIndex] = null;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -98,7 +403,8 @@ internal static class Program {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
		if (foregroundProcess == null) return null;
 | 
			
		||||
            if (foregroundProcess == null)
 | 
			
		||||
                return null;
 | 
			
		||||
            return foregroundProcess;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -113,21 +419,51 @@ internal static class Program {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void Track(Process process) {
 | 
			
		||||
            // First find the first null slot
 | 
			
		||||
            int firstNullIndex = -1;
 | 
			
		||||
            for (int i = 0; i < NumProc; i++) {
 | 
			
		||||
                if (windows[i] == null) {
 | 
			
		||||
				windows[i] = process;
 | 
			
		||||
				Console.WriteLine($"Added {process.ProcessName} to tracked windows at index {i}");
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
                    firstNullIndex = i;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
	private static void TrackWows() {
 | 
			
		||||
            if (firstNullIndex == -1) {
 | 
			
		||||
                Console.WriteLine("No slots available for tracking");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Compact the array by shifting non-null elements to the left
 | 
			
		||||
            for (int i = firstNullIndex + 1; i < NumProc; i++) {
 | 
			
		||||
                if (windows[i] != null) {
 | 
			
		||||
                    windows[firstNullIndex] = windows[i];
 | 
			
		||||
                    windows[i] = null;
 | 
			
		||||
                    firstNullIndex++;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Add the new process at the first null slot
 | 
			
		||||
            windows[firstNullIndex] = process;
 | 
			
		||||
            PushHistory(firstNullIndex);
 | 
			
		||||
            ActiveIndex = firstNullIndex;
 | 
			
		||||
            Console.WriteLine($"Added {process.ProcessName} to tracked windows at index {firstNullIndex}");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void TrackProcess() {
 | 
			
		||||
            CleanWindows();
 | 
			
		||||
		var processes = Process.GetProcesses();
 | 
			
		||||
            var foregroundWindow = GetForegroundWindow();
 | 
			
		||||
            var foregroundProcess = Process.GetProcesses().FirstOrDefault(p => p.MainWindowHandle == foregroundWindow);
 | 
			
		||||
            if (foregroundProcess == null) {
 | 
			
		||||
                Console.WriteLine("No foreground process found");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            Console.WriteLine($"Foreground process: {foregroundProcess.ProcessName} PID: {foregroundProcess.Id}");
 | 
			
		||||
 | 
			
		||||
            var processes = Process.GetProcesses().OrderBy(p => p.Id).ToList();
 | 
			
		||||
            foreach (var process in processes) {
 | 
			
		||||
			if (process.ProcessName == "UWow-64") {
 | 
			
		||||
				Console.WriteLine($"Found UWow-64 at pid {process.Id}");
 | 
			
		||||
                // Console.WriteLine($"Checking {process.ProcessName} at pid {process.Id}");
 | 
			
		||||
                if (process.ProcessName == foregroundProcess.ProcessName) {
 | 
			
		||||
                    Console.WriteLine($"Found {foregroundProcess.ProcessName} at pid {process.Id}");
 | 
			
		||||
                    if (ProcessTracked(process.Id))
 | 
			
		||||
                        continue;
 | 
			
		||||
                    Track(process);
 | 
			
		||||
@@ -137,12 +473,15 @@ internal static class Program {
 | 
			
		||||
 | 
			
		||||
        private static void Swap(int index) {
 | 
			
		||||
            index = (index - 1) % NumProc;
 | 
			
		||||
		if (index < 0) index = NumProc - 1;
 | 
			
		||||
		if (index >= NumProc) return;
 | 
			
		||||
            if (index < 0)
 | 
			
		||||
                index = NumProc - 1;
 | 
			
		||||
            if (index >= NumProc)
 | 
			
		||||
                return;
 | 
			
		||||
            CleanWindows();
 | 
			
		||||
            Console.WriteLine($"Swapping window at index {index}");
 | 
			
		||||
            var process = GetForegroundProcess();
 | 
			
		||||
		if (process == null) return;
 | 
			
		||||
            if (process == null)
 | 
			
		||||
                return;
 | 
			
		||||
            Console.WriteLine($"Foreground process: {process}");
 | 
			
		||||
            bool found = false;
 | 
			
		||||
 | 
			
		||||
@@ -160,6 +499,7 @@ internal static class Program {
 | 
			
		||||
                    if (window == null) {
 | 
			
		||||
                        Console.WriteLine($"Adding foreground window to tracked at index {i}...");
 | 
			
		||||
                        windows[i] = process;
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -176,28 +516,108 @@ internal static class Program {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void TabTo(int index) {
 | 
			
		||||
            Console.WriteLine($"TabTo called with index: {index}");
 | 
			
		||||
            index = (index - 1) % NumProc;
 | 
			
		||||
		if (index < 0) index = NumProc - 1;
 | 
			
		||||
		if (index >= NumProc) return;
 | 
			
		||||
            if (index < 0)
 | 
			
		||||
                index = NumProc - 1;
 | 
			
		||||
            if (index >= NumProc)
 | 
			
		||||
                return;
 | 
			
		||||
            CleanWindows();
 | 
			
		||||
            Console.WriteLine($"Tab to window at index {index}");
 | 
			
		||||
 | 
			
		||||
            // Find the next non-null window if the target is null
 | 
			
		||||
            int originalIndex = index;
 | 
			
		||||
            while (index < NumProc && (windows[index] == null || windows[index].MainWindowHandle == IntPtr.Zero)) {
 | 
			
		||||
                index++;
 | 
			
		||||
            }
 | 
			
		||||
            if (index >= NumProc) {
 | 
			
		||||
                // Try from the beginning
 | 
			
		||||
                index = 0;
 | 
			
		||||
                while (index < originalIndex &&
 | 
			
		||||
                       (windows[index] == null || windows[index].MainWindowHandle == IntPtr.Zero)) {
 | 
			
		||||
                    index++;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (index >= NumProc || windows[index] == null || windows[index].MainWindowHandle == IntPtr.Zero) {
 | 
			
		||||
                Console.WriteLine("No valid windows found to tab to");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var window = windows[index];
 | 
			
		||||
            Console.WriteLine(
 | 
			
		||||
                $"Window at index {index}: {(window == null ? "NULL" : window.ProcessName + " PID:" + window.Id)}");
 | 
			
		||||
 | 
			
		||||
            if (window == null || window.MainWindowHandle == IntPtr.Zero) {
 | 
			
		||||
                Console.WriteLine($"Window at index {index} does not exist, removing from tracked windows");
 | 
			
		||||
                windows[index] = null;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
            } else {
 | 
			
		||||
                if (ActiveIndex != -1)
 | 
			
		||||
                    PushHistory(ActiveIndex);
 | 
			
		||||
 | 
			
		||||
                Console.WriteLine($"Setting foreground window to: {window.ProcessName} PID:{window.Id}");
 | 
			
		||||
                SetForegroundWindow(window.MainWindowHandle);
 | 
			
		||||
                ShowWindow(window.MainWindowHandle, SW_RESTORE);
 | 
			
		||||
                BringWindowToTop(window.MainWindowHandle);
 | 
			
		||||
                SetActiveWindow(window.MainWindowHandle);
 | 
			
		||||
 | 
			
		||||
                ActiveIndex = index;
 | 
			
		||||
                AdjustAffinities();
 | 
			
		||||
                AdjustPriorities();
 | 
			
		||||
                Console.WriteLine($"Successfully switched to window at index {index}");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void TabToPrevious() {
 | 
			
		||||
            return;
 | 
			
		||||
            try {
 | 
			
		||||
                var foreground = GetForegroundProcess();
 | 
			
		||||
                if (!ProcessTracked(foreground.Id)) {
 | 
			
		||||
                    Console.WriteLine("Foreground process not tracked, skipping");
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            } catch (Exception e) {
 | 
			
		||||
                Console.WriteLine($"Error setting foreground window: {e}");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (lastWindows.Count == 0) {
 | 
			
		||||
                Console.WriteLine("No previous window to switch to");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            CleanWindows();
 | 
			
		||||
 | 
			
		||||
            for (int i = lastWindows.Count - 1; i >= 0; i--) {
 | 
			
		||||
                int index = lastWindows[i];
 | 
			
		||||
                if (index != ActiveIndex) {
 | 
			
		||||
                    TabTo(index + 1);  // Our windows are 1-indexed because... I don't remember why
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static bool IsCapsLockOn() {
 | 
			
		||||
            return (GetKeyState(0x14) & 1) == 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void ToggleCapsLock() {
 | 
			
		||||
            keybd_event(0x14, 0, 0, 0);       // KEYEVENTF_KEYDOWN
 | 
			
		||||
            keybd_event(0x14, 0, 0x0002, 0);  // KEYEVENTF_KEYUP
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void PushHistory(int index) {
 | 
			
		||||
            lastWindows.Add(index);
 | 
			
		||||
            if (lastWindows.Count > 50)
 | 
			
		||||
                lastWindows.RemoveAt(0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [STAThread]
 | 
			
		||||
        private static void Main() {
 | 
			
		||||
		//AllocConsole();
 | 
			
		||||
            // AllocConsole();  // Enable console for debug output
 | 
			
		||||
            Application.EnableVisualStyles();
 | 
			
		||||
            Application.SetCompatibleTextRenderingDefault(false);
 | 
			
		||||
 | 
			
		||||
            // Load settings
 | 
			
		||||
            LoadSettings();
 | 
			
		||||
 | 
			
		||||
            var processes = Process.GetProcesses();
 | 
			
		||||
            var currentProcess = Process.GetCurrentProcess();
 | 
			
		||||
@@ -208,48 +628,124 @@ internal static class Program {
 | 
			
		||||
                    Process.GetCurrentProcess().Kill();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
		// Register main number keys (0-9)
 | 
			
		||||
		for (int i = 0; i < 10; i++) {
 | 
			
		||||
			HotKeyManager.RegisterHotKey(Keys.D0 + i, KeyModifiers.Alt);
 | 
			
		||||
			HotKeyManager.RegisterHotKey(Keys.D0 + i, KeyModifiers.Alt | KeyModifiers.Shift);
 | 
			
		||||
            bool onlyAlt = false;
 | 
			
		||||
            KeyboardHook.Start();
 | 
			
		||||
 | 
			
		||||
            // Set up mouse hook for sequence mode
 | 
			
		||||
            mouseHookDelegate = new MouseHookProc(MouseHookCallback);
 | 
			
		||||
            mouseHookProc = Marshal.GetFunctionPointerForDelegate(mouseHookDelegate);
 | 
			
		||||
            mouseHookId = SetWindowsHookEx(WH_MOUSE_LL, mouseHookProc,
 | 
			
		||||
                                           GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
 | 
			
		||||
            KeyboardHook.KeyDown += (sender, e) => {
 | 
			
		||||
                Console.WriteLine($"Key down: {e}");
 | 
			
		||||
                if (e == 164 && !onlyAlt) {
 | 
			
		||||
                    Console.WriteLine("Only alt");
 | 
			
		||||
                    onlyAlt = true;
 | 
			
		||||
                } else {
 | 
			
		||||
                    Console.WriteLine("Not only alt");
 | 
			
		||||
                    onlyAlt = false;
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            KeyboardHook.KeyUp += (sender, e) => {
 | 
			
		||||
                Console.WriteLine($"Key up: {e}");
 | 
			
		||||
                if (e == 164 && onlyAlt) {  // Left alt
 | 
			
		||||
                    Console.WriteLine("Tab to previous");
 | 
			
		||||
                    onlyAlt = false;
 | 
			
		||||
                    TabToPrevious();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Handle sequence mode event detection with KeyUp
 | 
			
		||||
                if (CurrentState == SequenceState.WAITING_FOR_EVENT) {
 | 
			
		||||
                    // Ignore the sequence keybind itself
 | 
			
		||||
                    if (e != (int)SequenceKeybind) {
 | 
			
		||||
                        Console.WriteLine($"Key up detected in state: {CurrentState} - Key: {e}");
 | 
			
		||||
                        HandleSequenceEvent();
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Console.WriteLine($"Ignoring sequence keybind release: {e}");
 | 
			
		||||
                    }
 | 
			
		||||
                } else if (CurrentState == SequenceState.WAITING_TO_ADVANCE) {
 | 
			
		||||
                    // Ignore key events while waiting to advance
 | 
			
		||||
                    Console.WriteLine($"Ignoring key event in WAITING_TO_ADVANCE state: {e}");
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            HotKeyManager.RegisterHotKey(Keys.Capital, KeyModifiers.NoRepeat);
 | 
			
		||||
            // Register main number keys (0-9)
 | 
			
		||||
            for (int i = 0; i < 10; i++) HotKeyManager.RegisterHotKey(Keys.D0 + i, KeyModifiers.Alt);
 | 
			
		||||
 | 
			
		||||
            // Register numpad keys (1-9)
 | 
			
		||||
		for (int i = 0; i < 9; i++) {
 | 
			
		||||
			HotKeyManager.RegisterHotKey(Keys.NumPad1 + i, KeyModifiers.Alt);
 | 
			
		||||
			HotKeyManager.RegisterHotKey(Keys.NumPad1 + i, KeyModifiers.Alt | KeyModifiers.Shift);
 | 
			
		||||
		}
 | 
			
		||||
            for (int i = 0; i < 9; i++) HotKeyManager.RegisterHotKey(Keys.NumPad1 + i, KeyModifiers.Alt);
 | 
			
		||||
 | 
			
		||||
            HotKeyManager.RegisterHotKey(Keys.Oemtilde, KeyModifiers.Alt);
 | 
			
		||||
            sequenceHotkeyId = HotKeyManager.RegisterHotKey(SequenceKeybind, KeyModifiers.NoRepeat);
 | 
			
		||||
            Console.WriteLine(
 | 
			
		||||
                $"Initial sequence hotkey registration - ID: {sequenceHotkeyId}, Key: {SequenceKeybind} (code: {(int)SequenceKeybind})");
 | 
			
		||||
            HotKeyManager.HotKeyPressed += HotKeyManager_HotKeyPressed;
 | 
			
		||||
 | 
			
		||||
		static void HotKeyManager_HotKeyPressed(object sender, HotKeyEventArgs e) {
 | 
			
		||||
			if (e.Key == Keys.Oemtilde && e.Modifiers == KeyModifiers.Alt) {
 | 
			
		||||
				TrackWows();
 | 
			
		||||
            void HotKeyManager_HotKeyPressed(object sender, HotKeyEventArgs e) {
 | 
			
		||||
                Console.WriteLine($"Hotkey pressed: {e.Key} with modifiers {e.Modifiers}");
 | 
			
		||||
                Console.WriteLine($"Current sequence keybind: {SequenceKeybind}");
 | 
			
		||||
                Console.WriteLine($"Key codes - Pressed: {(int)e.Key}, Expected: {(int)SequenceKeybind}");
 | 
			
		||||
 | 
			
		||||
                // Cancel sequence mode on any manual window switching
 | 
			
		||||
                if (CurrentState != SequenceState.INACTIVE && e.Modifiers == KeyModifiers.Alt) {
 | 
			
		||||
                    Console.WriteLine("Manual window switching detected, cancelling sequence mode");
 | 
			
		||||
                    ExitSequenceMode();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (e.Key == Keys.Oemtilde && e.Modifiers == KeyModifiers.Alt && IsCapsLockOn()) {
 | 
			
		||||
                    TrackProcess();
 | 
			
		||||
                    ToggleCapsLock();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Check for sequence mode keybind
 | 
			
		||||
                Console.WriteLine(
 | 
			
		||||
                    $"Checking sequence keybind - Key: {e.Key} == {SequenceKeybind} = {e.Key == SequenceKeybind}");
 | 
			
		||||
                Console.WriteLine($"Checking modifiers - Received: {e.Modifiers}, Expected: {KeyModifiers.NoRepeat}");
 | 
			
		||||
                if (e.Key == SequenceKeybind) {
 | 
			
		||||
                    Console.WriteLine("Sequence keybind detected!");
 | 
			
		||||
                    if (CurrentState != SequenceState.INACTIVE) {
 | 
			
		||||
                        Console.WriteLine("Advancing sequence step");
 | 
			
		||||
                        HandleSequenceEvent();
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Console.WriteLine("Starting sequence mode");
 | 
			
		||||
                        StartSequenceMode();
 | 
			
		||||
                    }
 | 
			
		||||
                    return;
 | 
			
		||||
                } else {
 | 
			
		||||
                    Console.WriteLine(
 | 
			
		||||
                        $"Sequence keybind check failed - Key match: {e.Key == SequenceKeybind}, Modifiers match: {e.Modifiers == KeyModifiers.NoRepeat}");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                int index;
 | 
			
		||||
                if (e.Key >= Keys.D0 && e.Key <= Keys.D9) {
 | 
			
		||||
                    index = e.Key - Keys.D0;
 | 
			
		||||
			}
 | 
			
		||||
			else if (e.Key >= Keys.NumPad1 && e.Key <= Keys.NumPad9) {
 | 
			
		||||
                } else if (e.Key >= Keys.NumPad1 && e.Key <= Keys.NumPad9) {
 | 
			
		||||
                    index = 10 + (e.Key - Keys.NumPad1);
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
                } else {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (e.Modifiers == KeyModifiers.Alt) {
 | 
			
		||||
                    if (IsCapsLockOn()) {
 | 
			
		||||
                        Swap(index);
 | 
			
		||||
                        ToggleCapsLock();
 | 
			
		||||
                    } else {
 | 
			
		||||
                        TabTo(index);
 | 
			
		||||
                    }
 | 
			
		||||
			else if (e.Modifiers == (KeyModifiers.Alt | KeyModifiers.Shift)) {
 | 
			
		||||
				Swap(index);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
		Console.CancelKeyPress += (sender, e) => { Process.GetCurrentProcess().Kill(); };
 | 
			
		||||
		while (true)
 | 
			
		||||
			System.Threading.Thread.Sleep(100000);
 | 
			
		||||
            // Run the WinForms application with Form1 as the main form
 | 
			
		||||
            Application.Run(new Form1());
 | 
			
		||||
            KeyboardHook.Stop();
 | 
			
		||||
 | 
			
		||||
            // Clean up mouse hook
 | 
			
		||||
            if (mouseHookId != IntPtr.Zero) {
 | 
			
		||||
                UnhookWindowsHookEx(mouseHookId);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,22 +4,23 @@ using System.Runtime.InteropServices;
 | 
			
		||||
// General Information about an assembly is controlled through the following
 | 
			
		||||
// set of attributes. Change these attribute values to modify the information
 | 
			
		||||
// associated with an assembly.
 | 
			
		||||
[assembly: AssemblyTitle("DD2Switcher")]
 | 
			
		||||
[assembly: AssemblyDescription("")]
 | 
			
		||||
[assembly: AssemblyConfiguration("")]
 | 
			
		||||
[assembly: AssemblyCompany("")]
 | 
			
		||||
[assembly: AssemblyProduct("DD2Switcher")]
 | 
			
		||||
[assembly: AssemblyCopyright("Copyright ©  2022")]
 | 
			
		||||
[assembly: AssemblyTrademark("")]
 | 
			
		||||
[assembly: AssemblyCulture("")]
 | 
			
		||||
[assembly:AssemblyTitle("DD2Switcher")]
 | 
			
		||||
[assembly:AssemblyDescription("")]
 | 
			
		||||
[assembly:AssemblyConfiguration("")]
 | 
			
		||||
[assembly:AssemblyCompany("")]
 | 
			
		||||
[assembly:AssemblyProduct("DD2Switcher")]
 | 
			
		||||
[assembly:AssemblyCopyright("Copyright ©  2022")]
 | 
			
		||||
[assembly:AssemblyTrademark("")]
 | 
			
		||||
[assembly:AssemblyCulture("")]
 | 
			
		||||
 | 
			
		||||
// Setting ComVisible to false makes the types in this assembly not visible
 | 
			
		||||
// to COM components.  If you need to access a type in this assembly from
 | 
			
		||||
// COM, set the ComVisible attribute to true on that type.
 | 
			
		||||
[assembly: ComVisible(false)]
 | 
			
		||||
[assembly:ComVisible(false)]
 | 
			
		||||
 | 
			
		||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
 | 
			
		||||
[assembly: Guid("2AC26899-8E27-4B96-85A9-C387186EAD27")]
 | 
			
		||||
// The following GUID is for the ID of the typelib if this project is exposed to
 | 
			
		||||
// COM
 | 
			
		||||
[assembly:Guid("2AC26899-8E27-4B96-85A9-C387186EAD27")]
 | 
			
		||||
 | 
			
		||||
// Version information for an assembly consists of the following four values:
 | 
			
		||||
//
 | 
			
		||||
@@ -28,8 +29,7 @@ using System.Runtime.InteropServices;
 | 
			
		||||
//      Build Number
 | 
			
		||||
//      Revision
 | 
			
		||||
//
 | 
			
		||||
// You can specify all the values or you can default the Build and Revision Numbers
 | 
			
		||||
// by using the '*' as shown below:
 | 
			
		||||
// [assembly: AssemblyVersion("1.0.*")]
 | 
			
		||||
[assembly: AssemblyVersion("1.0.0.0")]
 | 
			
		||||
[assembly: AssemblyFileVersion("1.0.0.0")]
 | 
			
		||||
// You can specify all the values or you can default the Build and Revision
 | 
			
		||||
// Numbers by using the '*' as shown below: [assembly: AssemblyVersion("1.0.*")]
 | 
			
		||||
[assembly:AssemblyVersion("1.0.0.0")]
 | 
			
		||||
[assembly:AssemblyFileVersion("1.0.0.0")]
 | 
			
		||||
							
								
								
									
										28
									
								
								DD2Switcher/Properties/Resources.Designer.cs
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										28
									
								
								DD2Switcher/Properties/Resources.Designer.cs
									
									
									
										generated
									
									
									
								
							@@ -11,7 +11,6 @@
 | 
			
		||||
namespace DD2Switcher.Properties {
 | 
			
		||||
    using System;
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    ///   A strongly-typed resource class, for looking up localized strings, etc.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
@@ -19,27 +18,29 @@ namespace DD2Switcher.Properties {
 | 
			
		||||
    // class via a tool like ResGen or Visual Studio.
 | 
			
		||||
    // To add or remove a member, edit your .ResX file then rerun ResGen
 | 
			
		||||
    // with the /str option, or rebuild your VS project.
 | 
			
		||||
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
 | 
			
		||||
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder",
 | 
			
		||||
                                                            "17.0.0.0")]
 | 
			
		||||
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
 | 
			
		||||
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
 | 
			
		||||
    internal class Resources {
 | 
			
		||||
        
 | 
			
		||||
        private static global::System.Resources.ResourceManager resourceMan;
 | 
			
		||||
 | 
			
		||||
        private static global::System.Globalization.CultureInfo resourceCulture;
 | 
			
		||||
 | 
			
		||||
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
 | 
			
		||||
        internal Resources() {
 | 
			
		||||
        }
 | 
			
		||||
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance",
 | 
			
		||||
                                                                          "CA1811:AvoidUncalledPrivateCode")]
 | 
			
		||||
        internal Resources() {}
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        ///   Returns the cached ResourceManager instance used by this class.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
 | 
			
		||||
        [global::System.ComponentModel.EditorBrowsableAttribute(
 | 
			
		||||
            global::System.ComponentModel.EditorBrowsableState.Advanced)]
 | 
			
		||||
        internal static global::System.Resources.ResourceManager ResourceManager {
 | 
			
		||||
            get {
 | 
			
		||||
                if (object.ReferenceEquals(resourceMan, null)) {
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DD2Switcher.Properties.Resources", typeof(Resources).Assembly);
 | 
			
		||||
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(
 | 
			
		||||
                        "DD2Switcher.Properties.Resources", typeof(Resources).Assembly);
 | 
			
		||||
                    resourceMan = temp;
 | 
			
		||||
                }
 | 
			
		||||
                return resourceMan;
 | 
			
		||||
@@ -50,14 +51,11 @@ namespace DD2Switcher.Properties {
 | 
			
		||||
        ///   Overrides the current thread's CurrentUICulture property for all
 | 
			
		||||
        ///   resource lookups using this strongly typed resource class.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
 | 
			
		||||
        [global::System.ComponentModel.EditorBrowsableAttribute(
 | 
			
		||||
            global::System.ComponentModel.EditorBrowsableState.Advanced)]
 | 
			
		||||
        internal static global::System.Globalization.CultureInfo Culture {
 | 
			
		||||
            get {
 | 
			
		||||
                return resourceCulture;
 | 
			
		||||
            }
 | 
			
		||||
            set {
 | 
			
		||||
                resourceCulture = value;
 | 
			
		||||
            }
 | 
			
		||||
            get { return resourceCulture; }
 | 
			
		||||
            set { resourceCulture = value; }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								DD2Switcher/Properties/Settings.Designer.cs
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										12
									
								
								DD2Switcher/Properties/Settings.Designer.cs
									
									
									
										generated
									
									
									
								
							@@ -8,18 +8,16 @@
 | 
			
		||||
// </auto-generated>
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
namespace DD2Switcher.Properties
 | 
			
		||||
{
 | 
			
		||||
namespace DD2Switcher.Properties {
 | 
			
		||||
 | 
			
		||||
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
 | 
			
		||||
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(
 | 
			
		||||
        "Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
 | 
			
		||||
    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
 | 
			
		||||
    {
 | 
			
		||||
        "Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.14.0.0")]
 | 
			
		||||
    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
 | 
			
		||||
        private static Settings defaultInstance =
 | 
			
		||||
            ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
 | 
			
		||||
 | 
			
		||||
        public static Settings Default
 | 
			
		||||
        {
 | 
			
		||||
        public static Settings Default {
 | 
			
		||||
            get { return defaultInstance; }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										316
									
								
								DD2Switcher/SettingsForm.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										316
									
								
								DD2Switcher/SettingsForm.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,316 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Drawing;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Windows.Forms;
 | 
			
		||||
 | 
			
		||||
namespace DD2Switcher {
 | 
			
		||||
    public partial class SettingsForm : Form {
 | 
			
		||||
        private TabControl tabControl;
 | 
			
		||||
        private TabPage windowsTab;
 | 
			
		||||
        private TabPage sequenceTab;
 | 
			
		||||
        private FlowLayoutPanel windowsPanel;
 | 
			
		||||
        private Label sequenceKeybindLabel;
 | 
			
		||||
        private TextBox sequenceKeybindTextBox;
 | 
			
		||||
        private Label sequenceTimerDelayLabel;
 | 
			
		||||
        private NumericUpDown sequenceTimerDelayNumericUpDown;
 | 
			
		||||
 | 
			
		||||
        public SettingsForm() {
 | 
			
		||||
            InitializeComponent();
 | 
			
		||||
            LoadIcon();
 | 
			
		||||
            RefreshWindowsList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void InitializeComponent() {
 | 
			
		||||
            this.tabControl = new System.Windows.Forms.TabControl();
 | 
			
		||||
            this.windowsTab = new System.Windows.Forms.TabPage();
 | 
			
		||||
            this.windowsPanel = new System.Windows.Forms.FlowLayoutPanel();
 | 
			
		||||
            this.sequenceTab = new System.Windows.Forms.TabPage();
 | 
			
		||||
            this.sequenceKeybindTextBox = new System.Windows.Forms.TextBox();
 | 
			
		||||
            this.sequenceKeybindLabel = new System.Windows.Forms.Label();
 | 
			
		||||
            this.sequenceTimerDelayNumericUpDown = new System.Windows.Forms.NumericUpDown();
 | 
			
		||||
            this.sequenceTimerDelayLabel = new System.Windows.Forms.Label();
 | 
			
		||||
            this.tabControl.SuspendLayout();
 | 
			
		||||
            this.windowsTab.SuspendLayout();
 | 
			
		||||
            this.sequenceTab.SuspendLayout();
 | 
			
		||||
            ((System.ComponentModel.ISupportInitialize)(this.sequenceTimerDelayNumericUpDown)).BeginInit();
 | 
			
		||||
            this.SuspendLayout();
 | 
			
		||||
            //
 | 
			
		||||
            // tabControl
 | 
			
		||||
            //
 | 
			
		||||
            this.tabControl.Controls.Add(this.windowsTab);
 | 
			
		||||
            this.tabControl.Controls.Add(this.sequenceTab);
 | 
			
		||||
            this.tabControl.Location = new System.Drawing.Point(12, 12);
 | 
			
		||||
            this.tabControl.Name = "tabControl";
 | 
			
		||||
            this.tabControl.SelectedIndex = 0;
 | 
			
		||||
            this.tabControl.Size = new System.Drawing.Size(576, 396);
 | 
			
		||||
            this.tabControl.TabIndex = 0;
 | 
			
		||||
            //
 | 
			
		||||
            // windowsTab
 | 
			
		||||
            //
 | 
			
		||||
            this.windowsTab.Controls.Add(this.windowsPanel);
 | 
			
		||||
            this.windowsTab.Location = new System.Drawing.Point(4, 22);
 | 
			
		||||
            this.windowsTab.Name = "windowsTab";
 | 
			
		||||
            this.windowsTab.Padding = new System.Windows.Forms.Padding(3);
 | 
			
		||||
            this.windowsTab.Size = new System.Drawing.Size(568, 370);
 | 
			
		||||
            this.windowsTab.TabIndex = 0;
 | 
			
		||||
            this.windowsTab.Text = "Windows";
 | 
			
		||||
            this.windowsTab.UseVisualStyleBackColor = true;
 | 
			
		||||
            //
 | 
			
		||||
            // windowsPanel
 | 
			
		||||
            //
 | 
			
		||||
            this.windowsPanel.AutoScroll = true;
 | 
			
		||||
            this.windowsPanel.BackColor = System.Drawing.Color.White;
 | 
			
		||||
            this.windowsPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
 | 
			
		||||
            this.windowsPanel.Location = new System.Drawing.Point(6, 6);
 | 
			
		||||
            this.windowsPanel.Name = "windowsPanel";
 | 
			
		||||
            this.windowsPanel.Padding = new System.Windows.Forms.Padding(10);
 | 
			
		||||
            this.windowsPanel.Size = new System.Drawing.Size(556, 358);
 | 
			
		||||
            this.windowsPanel.TabIndex = 0;
 | 
			
		||||
            //
 | 
			
		||||
            // sequenceTab
 | 
			
		||||
            //
 | 
			
		||||
            this.sequenceTab.Controls.Add(this.sequenceTimerDelayNumericUpDown);
 | 
			
		||||
            this.sequenceTab.Controls.Add(this.sequenceTimerDelayLabel);
 | 
			
		||||
            this.sequenceTab.Controls.Add(this.sequenceKeybindTextBox);
 | 
			
		||||
            this.sequenceTab.Controls.Add(this.sequenceKeybindLabel);
 | 
			
		||||
            this.sequenceTab.Location = new System.Drawing.Point(4, 22);
 | 
			
		||||
            this.sequenceTab.Name = "sequenceTab";
 | 
			
		||||
            this.sequenceTab.Padding = new System.Windows.Forms.Padding(3);
 | 
			
		||||
            this.sequenceTab.Size = new System.Drawing.Size(568, 370);
 | 
			
		||||
            this.sequenceTab.TabIndex = 1;
 | 
			
		||||
            this.sequenceTab.Text = "Sequence";
 | 
			
		||||
            this.sequenceTab.UseVisualStyleBackColor = true;
 | 
			
		||||
            //
 | 
			
		||||
            // sequenceKeybindTextBox
 | 
			
		||||
            //
 | 
			
		||||
            this.sequenceKeybindTextBox.Location = new System.Drawing.Point(126, 17);
 | 
			
		||||
            this.sequenceKeybindTextBox.Name = "sequenceKeybindTextBox";
 | 
			
		||||
            this.sequenceKeybindTextBox.Size = new System.Drawing.Size(111, 20);
 | 
			
		||||
            this.sequenceKeybindTextBox.TabIndex = 1;
 | 
			
		||||
            this.sequenceKeybindTextBox.Text = Program.SequenceKeybind.ToString();
 | 
			
		||||
            this.sequenceKeybindTextBox.Leave += new System.EventHandler(this.sequenceKeybindTextBox_Leave);
 | 
			
		||||
            //
 | 
			
		||||
            // sequenceKeybindLabel
 | 
			
		||||
            //
 | 
			
		||||
            this.sequenceKeybindLabel.AutoSize = true;
 | 
			
		||||
            this.sequenceKeybindLabel.Location = new System.Drawing.Point(20, 20);
 | 
			
		||||
            this.sequenceKeybindLabel.Name = "sequenceKeybindLabel";
 | 
			
		||||
            this.sequenceKeybindLabel.Size = new System.Drawing.Size(100, 13);
 | 
			
		||||
            this.sequenceKeybindLabel.TabIndex = 0;
 | 
			
		||||
            this.sequenceKeybindLabel.Text = "Sequence Keybind:";
 | 
			
		||||
            //
 | 
			
		||||
            // sequenceTimerDelayLabel
 | 
			
		||||
            //
 | 
			
		||||
            this.sequenceTimerDelayLabel.AutoSize = true;
 | 
			
		||||
            this.sequenceTimerDelayLabel.Location = new System.Drawing.Point(20, 50);
 | 
			
		||||
            this.sequenceTimerDelayLabel.Name = "sequenceTimerDelayLabel";
 | 
			
		||||
            this.sequenceTimerDelayLabel.Size = new System.Drawing.Size(100, 13);
 | 
			
		||||
            this.sequenceTimerDelayLabel.TabIndex = 2;
 | 
			
		||||
            this.sequenceTimerDelayLabel.Text = "Timer Delay (ms):";
 | 
			
		||||
            //
 | 
			
		||||
            // sequenceTimerDelayNumericUpDown
 | 
			
		||||
            //
 | 
			
		||||
            this.sequenceTimerDelayNumericUpDown.Location = new System.Drawing.Point(126, 47);
 | 
			
		||||
            this.sequenceTimerDelayNumericUpDown.Name = "sequenceTimerDelayNumericUpDown";
 | 
			
		||||
            this.sequenceTimerDelayNumericUpDown.Size = new System.Drawing.Size(111, 20);
 | 
			
		||||
            this.sequenceTimerDelayNumericUpDown.TabIndex = 3;
 | 
			
		||||
            this.sequenceTimerDelayNumericUpDown.Minimum = 10;
 | 
			
		||||
            this.sequenceTimerDelayNumericUpDown.Maximum = 10000;
 | 
			
		||||
            this.sequenceTimerDelayNumericUpDown.Value = Program.SequenceTimerDelay;
 | 
			
		||||
            this.sequenceTimerDelayNumericUpDown.ValueChanged +=
 | 
			
		||||
                new System.EventHandler(this.sequenceTimerDelayNumericUpDown_ValueChanged);
 | 
			
		||||
            //
 | 
			
		||||
            // SettingsForm
 | 
			
		||||
            //
 | 
			
		||||
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
 | 
			
		||||
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
 | 
			
		||||
            this.ClientSize = new System.Drawing.Size(600, 420);
 | 
			
		||||
            this.Controls.Add(this.tabControl);
 | 
			
		||||
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
 | 
			
		||||
            this.MaximizeBox = false;
 | 
			
		||||
            this.MinimizeBox = false;
 | 
			
		||||
            this.Name = "SettingsForm";
 | 
			
		||||
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
 | 
			
		||||
            this.Text = "DD2Switcher Settings";
 | 
			
		||||
            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SettingsForm_FormClosing);
 | 
			
		||||
            this.tabControl.ResumeLayout(false);
 | 
			
		||||
            this.windowsTab.ResumeLayout(false);
 | 
			
		||||
            this.sequenceTab.ResumeLayout(false);
 | 
			
		||||
            this.sequenceTab.PerformLayout();
 | 
			
		||||
            ((System.ComponentModel.ISupportInitialize)(this.sequenceTimerDelayNumericUpDown)).EndInit();
 | 
			
		||||
            this.ResumeLayout(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void closeButton_Click(object sender, EventArgs e) {
 | 
			
		||||
            this.Close();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void refreshButton_Click(object sender, EventArgs e) {
 | 
			
		||||
            RefreshWindowsList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void RefreshWindowsList() {
 | 
			
		||||
            windowsPanel.Controls.Clear();
 | 
			
		||||
 | 
			
		||||
            // Get tracked windows from Program
 | 
			
		||||
            var trackedWindows = GetTrackedWindows();
 | 
			
		||||
 | 
			
		||||
            if (trackedWindows.Count == 0) {
 | 
			
		||||
                var noWindowsLabel = new Label();
 | 
			
		||||
                noWindowsLabel.Text = "No windows currently tracked";
 | 
			
		||||
                noWindowsLabel.AutoSize = true;
 | 
			
		||||
                noWindowsLabel.ForeColor = Color.Gray;
 | 
			
		||||
                noWindowsLabel.Font = new Font("Segoe UI", 10F);
 | 
			
		||||
                windowsPanel.Controls.Add(noWindowsLabel);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < trackedWindows.Count; i++) {
 | 
			
		||||
                var window = trackedWindows[i];
 | 
			
		||||
                if (window == null)
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                var windowPanelForm = new WindowPanelForm();
 | 
			
		||||
                windowPanelForm.WindowIndex = i;
 | 
			
		||||
                windowPanelForm.WindowProcess = window;
 | 
			
		||||
                windowPanelForm.IsFirst = (i == Program.FirstIndex);
 | 
			
		||||
                windowPanelForm.IsLast = (i == Program.LastIndex);
 | 
			
		||||
                windowPanelForm.UpdateDisplay();
 | 
			
		||||
 | 
			
		||||
                windowPanelForm.PickClicked += (sender, index) => {
 | 
			
		||||
                    // If clicking on a window that's already first or last, remove that setting
 | 
			
		||||
                    if (index == Program.FirstIndex) {
 | 
			
		||||
                        Program.FirstIndex = -1;
 | 
			
		||||
                        Console.WriteLine($"Removed first index: {index}");
 | 
			
		||||
                    } else if (index == Program.LastIndex) {
 | 
			
		||||
                        Program.LastIndex = -1;
 | 
			
		||||
                        Console.WriteLine($"Removed last index: {index}");
 | 
			
		||||
                    } else if (Program.FirstIndex == -1) {
 | 
			
		||||
                        // First pick - set both first and last
 | 
			
		||||
                        Program.FirstIndex = index;
 | 
			
		||||
                        Program.LastIndex = index;
 | 
			
		||||
                        Console.WriteLine($"Set first and last index: {index}");
 | 
			
		||||
                    } else if (Program.LastIndex == -1) {
 | 
			
		||||
                        // Second pick - set last (must be >= first)
 | 
			
		||||
                        if (index >= Program.FirstIndex) {
 | 
			
		||||
                            Program.LastIndex = index;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            Program.LastIndex = Program.FirstIndex;
 | 
			
		||||
                            Program.FirstIndex = index;
 | 
			
		||||
                        }
 | 
			
		||||
                        Console.WriteLine($"Set last index: {Program.LastIndex}");
 | 
			
		||||
                    } else {
 | 
			
		||||
                        // Subsequent picks - determine which becomes first
 | 
			
		||||
                        int distanceToFirst = Math.Abs(index - Program.FirstIndex);
 | 
			
		||||
                        int distanceToLast = Math.Abs(index - Program.LastIndex);
 | 
			
		||||
 | 
			
		||||
                        if (distanceToFirst <= distanceToLast) {
 | 
			
		||||
                            // New index is closer to first, so first moves
 | 
			
		||||
                            if (index <= Program.LastIndex) {
 | 
			
		||||
                                Program.FirstIndex = index;
 | 
			
		||||
                            } else {
 | 
			
		||||
                                Program.LastIndex = Program.FirstIndex;
 | 
			
		||||
                                Program.FirstIndex = index;
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            // New index is closer to last, so last moves
 | 
			
		||||
                            if (index >= Program.FirstIndex) {
 | 
			
		||||
                                Program.LastIndex = index;
 | 
			
		||||
                            } else {
 | 
			
		||||
                                Program.FirstIndex = Program.LastIndex;
 | 
			
		||||
                                Program.LastIndex = index;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        Console.WriteLine($"Updated indices: First={Program.FirstIndex}, Last={Program.LastIndex}");
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Ensure last >= first
 | 
			
		||||
                    if (Program.LastIndex < Program.FirstIndex) {
 | 
			
		||||
                        int tmp = Program.LastIndex;
 | 
			
		||||
                        Program.LastIndex = Program.FirstIndex;
 | 
			
		||||
                        Program.FirstIndex = tmp;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    RefreshWindowsList();
 | 
			
		||||
                };
 | 
			
		||||
                windowPanelForm.UntrackClicked += (sender, index) => {
 | 
			
		||||
                    UntrackWindow(index);
 | 
			
		||||
                    RefreshWindowsList();
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                windowsPanel.Controls.Add(windowPanelForm);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string GetFirstLastText(int index) {
 | 
			
		||||
            if (index == Program.FirstIndex && index == Program.LastIndex) {
 | 
			
		||||
                return "First & Last";
 | 
			
		||||
            } else if (index == Program.FirstIndex) {
 | 
			
		||||
                return "First";
 | 
			
		||||
            } else if (index == Program.LastIndex) {
 | 
			
		||||
                return "Last";
 | 
			
		||||
            }
 | 
			
		||||
            return "";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private List<Process> GetTrackedWindows() {
 | 
			
		||||
            var windows = Program.GetTrackedWindows();
 | 
			
		||||
            return windows.ToList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void UntrackWindow(int index) {
 | 
			
		||||
            Program.UntrackWindow(index);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void LoadIcon() {
 | 
			
		||||
            try {
 | 
			
		||||
                this.Icon = new Icon(System.IO.Path.Combine(
 | 
			
		||||
                    System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
 | 
			
		||||
                    "app.ico"));
 | 
			
		||||
            } catch {
 | 
			
		||||
                // Use default icon if custom icon not found
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void sequenceKeybindTextBox_Leave(object sender, EventArgs e) {
 | 
			
		||||
            Console.WriteLine($"sequenceKeybindTextBox_Leave called with text: {sequenceKeybindTextBox.Text}");
 | 
			
		||||
            try {
 | 
			
		||||
                KeysConverter converter = new KeysConverter();
 | 
			
		||||
                Keys newKey = (Keys)converter.ConvertFromString(sequenceKeybindTextBox.Text);
 | 
			
		||||
                Console.WriteLine($"Converted key: {newKey} (code: {(int)newKey})");
 | 
			
		||||
                Program.UpdateSequenceHotkey(newKey);
 | 
			
		||||
                Console.WriteLine("Keybind updated successfully!");
 | 
			
		||||
            } catch (Exception ex) {
 | 
			
		||||
                Console.WriteLine($"Error converting key: {ex.Message}");
 | 
			
		||||
                sequenceKeybindTextBox.Text = Program.SequenceKeybind.ToString();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void sequenceTimerDelayNumericUpDown_ValueChanged(object sender, EventArgs e) {
 | 
			
		||||
            Console.WriteLine(
 | 
			
		||||
                $"sequenceTimerDelayNumericUpDown_ValueChanged called with value: {sequenceTimerDelayNumericUpDown.Value}");
 | 
			
		||||
            try {
 | 
			
		||||
                int newDelay = (int)sequenceTimerDelayNumericUpDown.Value;
 | 
			
		||||
                Program.SequenceTimerDelay = newDelay;
 | 
			
		||||
                Program.SaveSettings();
 | 
			
		||||
                Console.WriteLine($"Timer delay updated to: {newDelay}ms");
 | 
			
		||||
            } catch (Exception ex) {
 | 
			
		||||
                Console.WriteLine($"Error updating timer delay: {ex.Message}");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void SettingsForm_FormClosing(object sender, FormClosingEventArgs e) {
 | 
			
		||||
            Console.WriteLine("SettingsForm closing - saving keybind");
 | 
			
		||||
            try {
 | 
			
		||||
                KeysConverter converter = new KeysConverter();
 | 
			
		||||
                Keys newKey = (Keys)converter.ConvertFromString(sequenceKeybindTextBox.Text);
 | 
			
		||||
                Console.WriteLine($"Saving keybind on close: {newKey}");
 | 
			
		||||
                Program.UpdateSequenceHotkey(newKey);
 | 
			
		||||
            } catch (Exception ex) {
 | 
			
		||||
                Console.WriteLine($"Error saving keybind on close: {ex.Message}");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										120
									
								
								DD2Switcher/SettingsForm.resx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								DD2Switcher/SettingsForm.resx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,120 @@
 | 
			
		||||
<?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">
 | 
			
		||||
      <xsd:complexType>
 | 
			
		||||
        <xsd:choice maxOccurs="unbounded">
 | 
			
		||||
          <xsd:element name="metadata">
 | 
			
		||||
            <xsd:complexType>
 | 
			
		||||
              <xsd:sequence>
 | 
			
		||||
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
 | 
			
		||||
              </xsd:sequence>
 | 
			
		||||
              <xsd:attribute name="name" use="required" type="xsd:string" />
 | 
			
		||||
              <xsd:attribute name="type" type="xsd:string" />
 | 
			
		||||
              <xsd:attribute name="mimetype" type="xsd:string" />
 | 
			
		||||
              <xsd:attribute ref="xml:space" />
 | 
			
		||||
            </xsd:complexType>
 | 
			
		||||
          </xsd:element>
 | 
			
		||||
          <xsd:element name="assembly">
 | 
			
		||||
            <xsd:complexType>
 | 
			
		||||
              <xsd:attribute name="alias" type="xsd:string" />
 | 
			
		||||
              <xsd:attribute name="name" type="xsd:string" />
 | 
			
		||||
            </xsd:complexType>
 | 
			
		||||
          </xsd:element>
 | 
			
		||||
          <xsd:element name="data">
 | 
			
		||||
            <xsd:complexType>
 | 
			
		||||
              <xsd:sequence>
 | 
			
		||||
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
 | 
			
		||||
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
 | 
			
		||||
              </xsd:sequence>
 | 
			
		||||
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
 | 
			
		||||
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
 | 
			
		||||
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
 | 
			
		||||
              <xsd:attribute ref="xml:space" />
 | 
			
		||||
            </xsd:complexType>
 | 
			
		||||
          </xsd:element>
 | 
			
		||||
          <xsd:element name="resheader">
 | 
			
		||||
            <xsd:complexType>
 | 
			
		||||
              <xsd:sequence>
 | 
			
		||||
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
 | 
			
		||||
              </xsd:sequence>
 | 
			
		||||
              <xsd:attribute name="name" type="xsd:string" use="required" />
 | 
			
		||||
            </xsd:complexType>
 | 
			
		||||
          </xsd:element>
 | 
			
		||||
        </xsd:choice>
 | 
			
		||||
      </xsd:complexType>
 | 
			
		||||
    </xsd:element>
 | 
			
		||||
  </xsd:schema>
 | 
			
		||||
  <resheader name="resmimetype">
 | 
			
		||||
    <value>text/microsoft-resx</value>
 | 
			
		||||
  </resheader>
 | 
			
		||||
  <resheader name="version">
 | 
			
		||||
    <value>2.0</value>
 | 
			
		||||
  </resheader>
 | 
			
		||||
  <resheader name="reader">
 | 
			
		||||
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
 | 
			
		||||
  </resheader>
 | 
			
		||||
  <resheader name="writer">
 | 
			
		||||
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
 | 
			
		||||
  </resheader>
 | 
			
		||||
</root>
 | 
			
		||||
							
								
								
									
										133
									
								
								DD2Switcher/WindowPanelForm.Designer.cs
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								DD2Switcher/WindowPanelForm.Designer.cs
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,133 @@
 | 
			
		||||
namespace DD2Switcher {
 | 
			
		||||
    partial class WindowPanelForm {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Required designer variable.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private System.ComponentModel.IContainer components = null;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Clean up any resources being used.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
 | 
			
		||||
        protected override void Dispose(bool disposing) {
 | 
			
		||||
            if (disposing && (components != null)) {
 | 
			
		||||
                components.Dispose();
 | 
			
		||||
            }
 | 
			
		||||
            base.Dispose(disposing);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#region Windows Form Designer generated code
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Required method for Designer support - do not modify
 | 
			
		||||
        /// the contents of this method with the code editor.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private void InitializeComponent() {
 | 
			
		||||
            this.indexLabel = new System.Windows.Forms.Label();
 | 
			
		||||
            this.nameLabel = new System.Windows.Forms.Label();
 | 
			
		||||
            this.pidLabel = new System.Windows.Forms.Label();
 | 
			
		||||
            this.titleLabel = new System.Windows.Forms.Label();
 | 
			
		||||
            this.firstLastLabel = new System.Windows.Forms.Label();
 | 
			
		||||
            this.pickButton = new System.Windows.Forms.Button();
 | 
			
		||||
            this.untrackButton = new System.Windows.Forms.Button();
 | 
			
		||||
            this.SuspendLayout();
 | 
			
		||||
            //
 | 
			
		||||
            // indexLabel
 | 
			
		||||
            //
 | 
			
		||||
            this.indexLabel.AutoSize = true;
 | 
			
		||||
            this.indexLabel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
 | 
			
		||||
            this.indexLabel.Location = new System.Drawing.Point(10, 5);
 | 
			
		||||
            this.indexLabel.Name = "indexLabel";
 | 
			
		||||
            this.indexLabel.Size = new System.Drawing.Size(52, 15);
 | 
			
		||||
            this.indexLabel.TabIndex = 0;
 | 
			
		||||
            this.indexLabel.Text = "Index: 0";
 | 
			
		||||
            //
 | 
			
		||||
            // nameLabel
 | 
			
		||||
            //
 | 
			
		||||
            this.nameLabel.AutoSize = true;
 | 
			
		||||
            this.nameLabel.Font = new System.Drawing.Font("Segoe UI", 9F);
 | 
			
		||||
            this.nameLabel.Location = new System.Drawing.Point(12, 35);
 | 
			
		||||
            this.nameLabel.Name = "nameLabel";
 | 
			
		||||
            this.nameLabel.Size = new System.Drawing.Size(45, 15);
 | 
			
		||||
            this.nameLabel.TabIndex = 1;
 | 
			
		||||
            this.nameLabel.Text = "Name: ";
 | 
			
		||||
            //
 | 
			
		||||
            // pidLabel
 | 
			
		||||
            //
 | 
			
		||||
            this.pidLabel.AutoSize = true;
 | 
			
		||||
            this.pidLabel.Font = new System.Drawing.Font("Segoe UI", 9F);
 | 
			
		||||
            this.pidLabel.Location = new System.Drawing.Point(12, 50);
 | 
			
		||||
            this.pidLabel.Name = "pidLabel";
 | 
			
		||||
            this.pidLabel.Size = new System.Drawing.Size(28, 15);
 | 
			
		||||
            this.pidLabel.TabIndex = 2;
 | 
			
		||||
            this.pidLabel.Text = "PID:";
 | 
			
		||||
            //
 | 
			
		||||
            // titleLabel
 | 
			
		||||
            //
 | 
			
		||||
            this.titleLabel.AutoSize = true;
 | 
			
		||||
            this.titleLabel.Font = new System.Drawing.Font("Segoe UI", 9F);
 | 
			
		||||
            this.titleLabel.Location = new System.Drawing.Point(12, 20);
 | 
			
		||||
            this.titleLabel.MaximumSize = new System.Drawing.Size(200, 0);
 | 
			
		||||
            this.titleLabel.Name = "titleLabel";
 | 
			
		||||
            this.titleLabel.Size = new System.Drawing.Size(36, 15);
 | 
			
		||||
            this.titleLabel.TabIndex = 3;
 | 
			
		||||
            this.titleLabel.Text = "Title: ";
 | 
			
		||||
            //
 | 
			
		||||
            // firstLastLabel
 | 
			
		||||
            //
 | 
			
		||||
            this.firstLastLabel.AutoSize = true;
 | 
			
		||||
            this.firstLastLabel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
 | 
			
		||||
            this.firstLastLabel.ForeColor = System.Drawing.Color.DarkBlue;
 | 
			
		||||
            this.firstLastLabel.Location = new System.Drawing.Point(200, 45);
 | 
			
		||||
            this.firstLastLabel.Name = "firstLastLabel";
 | 
			
		||||
            this.firstLastLabel.Size = new System.Drawing.Size(0, 15);
 | 
			
		||||
            this.firstLastLabel.TabIndex = 4;
 | 
			
		||||
            //
 | 
			
		||||
            // pickButton
 | 
			
		||||
            //
 | 
			
		||||
            this.pickButton.Location = new System.Drawing.Point(420, 10);
 | 
			
		||||
            this.pickButton.Name = "pickButton";
 | 
			
		||||
            this.pickButton.Size = new System.Drawing.Size(88, 25);
 | 
			
		||||
            this.pickButton.TabIndex = 5;
 | 
			
		||||
            this.pickButton.Text = "Pick";
 | 
			
		||||
            this.pickButton.UseVisualStyleBackColor = true;
 | 
			
		||||
            this.pickButton.Click += new System.EventHandler(this.pickButton_Click);
 | 
			
		||||
            //
 | 
			
		||||
            // untrackButton
 | 
			
		||||
            //
 | 
			
		||||
            this.untrackButton.Location = new System.Drawing.Point(420, 45);
 | 
			
		||||
            this.untrackButton.Name = "untrackButton";
 | 
			
		||||
            this.untrackButton.Size = new System.Drawing.Size(88, 25);
 | 
			
		||||
            this.untrackButton.TabIndex = 6;
 | 
			
		||||
            this.untrackButton.Text = "Untrack";
 | 
			
		||||
            this.untrackButton.UseVisualStyleBackColor = true;
 | 
			
		||||
            this.untrackButton.Click += new System.EventHandler(this.untrackButton_Click);
 | 
			
		||||
            //
 | 
			
		||||
            // WindowPanelForm
 | 
			
		||||
            //
 | 
			
		||||
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
 | 
			
		||||
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
 | 
			
		||||
            this.Controls.Add(this.indexLabel);
 | 
			
		||||
            this.Controls.Add(this.nameLabel);
 | 
			
		||||
            this.Controls.Add(this.pidLabel);
 | 
			
		||||
            this.Controls.Add(this.titleLabel);
 | 
			
		||||
            this.Controls.Add(this.firstLastLabel);
 | 
			
		||||
            this.Controls.Add(this.pickButton);
 | 
			
		||||
            this.Controls.Add(this.untrackButton);
 | 
			
		||||
            this.Name = "WindowPanelForm";
 | 
			
		||||
            this.Size = new System.Drawing.Size(520, 80);
 | 
			
		||||
            this.ResumeLayout(false);
 | 
			
		||||
            this.PerformLayout();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#endregion
 | 
			
		||||
 | 
			
		||||
        private System.Windows.Forms.Label indexLabel;
 | 
			
		||||
        private System.Windows.Forms.Label nameLabel;
 | 
			
		||||
        private System.Windows.Forms.Label pidLabel;
 | 
			
		||||
        private System.Windows.Forms.Label titleLabel;
 | 
			
		||||
        private System.Windows.Forms.Label firstLastLabel;
 | 
			
		||||
        private System.Windows.Forms.Button pickButton;
 | 
			
		||||
        private System.Windows.Forms.Button untrackButton;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										47
									
								
								DD2Switcher/WindowPanelForm.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								DD2Switcher/WindowPanelForm.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Drawing;
 | 
			
		||||
using System.Windows.Forms;
 | 
			
		||||
 | 
			
		||||
namespace DD2Switcher {
 | 
			
		||||
    public partial class WindowPanelForm : UserControl {
 | 
			
		||||
        public event EventHandler<int> PickClicked;
 | 
			
		||||
        public event EventHandler<int> UntrackClicked;
 | 
			
		||||
 | 
			
		||||
        public int WindowIndex { get; set; }
 | 
			
		||||
        public Process WindowProcess { get; set; }
 | 
			
		||||
        public bool IsFirst { get; set; }
 | 
			
		||||
        public bool IsLast { get; set; }
 | 
			
		||||
 | 
			
		||||
        public WindowPanelForm() {
 | 
			
		||||
            InitializeComponent();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void UpdateDisplay() {
 | 
			
		||||
            if (WindowProcess != null) {
 | 
			
		||||
                indexLabel.Text = $"Index: {WindowIndex}";
 | 
			
		||||
                nameLabel.Text = $"Name: {WindowProcess.ProcessName}";
 | 
			
		||||
                pidLabel.Text = $"PID: {WindowProcess.Id}";
 | 
			
		||||
                titleLabel.Text = $"Title: {WindowProcess.MainWindowTitle}";
 | 
			
		||||
 | 
			
		||||
                if (IsFirst && IsLast) {
 | 
			
		||||
                    firstLastLabel.Text = "First & Last";
 | 
			
		||||
                } else if (IsFirst) {
 | 
			
		||||
                    firstLastLabel.Text = "First";
 | 
			
		||||
                } else if (IsLast) {
 | 
			
		||||
                    firstLastLabel.Text = "Last";
 | 
			
		||||
                } else {
 | 
			
		||||
                    firstLastLabel.Text = "";
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void pickButton_Click(object sender, EventArgs e) {
 | 
			
		||||
            PickClicked?.Invoke(this, WindowIndex);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void untrackButton_Click(object sender, EventArgs e) {
 | 
			
		||||
            UntrackClicked?.Invoke(this, WindowIndex);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										120
									
								
								DD2Switcher/WindowPanelForm.resx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								DD2Switcher/WindowPanelForm.resx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,120 @@
 | 
			
		||||
<?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">
 | 
			
		||||
      <xsd:complexType>
 | 
			
		||||
        <xsd:choice maxOccurs="unbounded">
 | 
			
		||||
          <xsd:element name="metadata">
 | 
			
		||||
            <xsd:complexType>
 | 
			
		||||
              <xsd:sequence>
 | 
			
		||||
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
 | 
			
		||||
              </xsd:sequence>
 | 
			
		||||
              <xsd:attribute name="name" use="required" type="xsd:string" />
 | 
			
		||||
              <xsd:attribute name="type" type="xsd:string" />
 | 
			
		||||
              <xsd:attribute name="mimetype" type="xsd:string" />
 | 
			
		||||
              <xsd:attribute ref="xml:space" />
 | 
			
		||||
            </xsd:complexType>
 | 
			
		||||
          </xsd:element>
 | 
			
		||||
          <xsd:element name="assembly">
 | 
			
		||||
            <xsd:complexType>
 | 
			
		||||
              <xsd:attribute name="alias" type="xsd:string" />
 | 
			
		||||
              <xsd:attribute name="name" type="xsd:string" />
 | 
			
		||||
            </xsd:complexType>
 | 
			
		||||
          </xsd:element>
 | 
			
		||||
          <xsd:element name="data">
 | 
			
		||||
            <xsd:complexType>
 | 
			
		||||
              <xsd:sequence>
 | 
			
		||||
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
 | 
			
		||||
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
 | 
			
		||||
              </xsd:sequence>
 | 
			
		||||
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
 | 
			
		||||
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
 | 
			
		||||
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
 | 
			
		||||
              <xsd:attribute ref="xml:space" />
 | 
			
		||||
            </xsd:complexType>
 | 
			
		||||
          </xsd:element>
 | 
			
		||||
          <xsd:element name="resheader">
 | 
			
		||||
            <xsd:complexType>
 | 
			
		||||
              <xsd:sequence>
 | 
			
		||||
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
 | 
			
		||||
              </xsd:sequence>
 | 
			
		||||
              <xsd:attribute name="name" type="xsd:string" use="required" />
 | 
			
		||||
            </xsd:complexType>
 | 
			
		||||
          </xsd:element>
 | 
			
		||||
        </xsd:choice>
 | 
			
		||||
      </xsd:complexType>
 | 
			
		||||
    </xsd:element>
 | 
			
		||||
  </xsd:schema>
 | 
			
		||||
  <resheader name="resmimetype">
 | 
			
		||||
    <value>text/microsoft-resx</value>
 | 
			
		||||
  </resheader>
 | 
			
		||||
  <resheader name="version">
 | 
			
		||||
    <value>2.0</value>
 | 
			
		||||
  </resheader>
 | 
			
		||||
  <resheader name="reader">
 | 
			
		||||
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
 | 
			
		||||
  </resheader>
 | 
			
		||||
  <resheader name="writer">
 | 
			
		||||
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
 | 
			
		||||
  </resheader>
 | 
			
		||||
</root>
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								DD2Switcher/app.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								DD2Switcher/app.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 106 KiB  | 
							
								
								
									
										13
									
								
								DD2Switcher/packages.config
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								DD2Switcher/packages.config
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<packages>
 | 
			
		||||
  <package id="Microsoft.Bcl.AsyncInterfaces" version="9.0.8" targetFramework="net48" />
 | 
			
		||||
  <package id="System.Buffers" version="4.5.1" targetFramework="net48" />
 | 
			
		||||
  <package id="System.IO.Pipelines" version="9.0.8" targetFramework="net48" />
 | 
			
		||||
  <package id="System.Memory" version="4.5.5" targetFramework="net48" />
 | 
			
		||||
  <package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" />
 | 
			
		||||
  <package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net48" />
 | 
			
		||||
  <package id="System.Text.Encodings.Web" version="9.0.8" targetFramework="net48" />
 | 
			
		||||
  <package id="System.Text.Json" version="9.0.8" targetFramework="net48" />
 | 
			
		||||
  <package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net48" />
 | 
			
		||||
  <package id="System.ValueTuple" version="4.5.0" targetFramework="net48" />
 | 
			
		||||
</packages>
 | 
			
		||||
		Reference in New Issue
	
	Block a user