Compare commits
41 Commits
3872c5181f
...
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 | |||
be2c6f7829 | |||
7beb55e3ce | |||
4aaedac17c | |||
6a4e25cdb8 | |||
a9024539a4 | |||
6cee7038bd | |||
197f098f67 | |||
bd24acde46 |
3
.clang-format
Normal file
3
.clang-format
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
BasedOnStyle: Google
|
||||||
|
IndentWidth: 4
|
||||||
|
ColumnLimit: 120
|
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,3 +1,5 @@
|
|||||||
.idea
|
.idea
|
||||||
obj
|
obj
|
||||||
bin
|
bin
|
||||||
|
.vs
|
||||||
|
packages
|
||||||
|
@@ -1,6 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<startup>
|
<startup>
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
|
||||||
</startup>
|
</startup>
|
||||||
</configuration>
|
<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,87 +1,139 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<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>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
<ProjectGuid>{2AC26899-8E27-4B96-85A9-C387186EAD27}</ProjectGuid>
|
<ProjectGuid>{2AC26899-8E27-4B96-85A9-C387186EAD27}</ProjectGuid>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<RootNamespace>DD2Switcher</RootNamespace>
|
<RootNamespace>DD2Switcher</RootNamespace>
|
||||||
<AssemblyName>DD2Switcher</AssemblyName>
|
<AssemblyName>DD2Switcher</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
<Deterministic>true</Deterministic>
|
<Deterministic>true</Deterministic>
|
||||||
<LangVersion>10</LangVersion>
|
<LangVersion>9.0</LangVersion>
|
||||||
</PropertyGroup>
|
<TargetFrameworkProfile />
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
</PropertyGroup>
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
<DebugType>full</DebugType>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
<Optimize>false</Optimize>
|
<DebugType>full</DebugType>
|
||||||
<OutputPath>bin\Debug\</OutputPath>
|
<Optimize>false</Optimize>
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
<WarningLevel>4</WarningLevel>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<Prefer32bit>false</Prefer32bit>
|
<WarningLevel>4</WarningLevel>
|
||||||
</PropertyGroup>
|
<Prefer32bit>false</Prefer32bit>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
</PropertyGroup>
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<DebugType>pdbonly</DebugType>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
<Optimize>true</Optimize>
|
<DebugType>pdbonly</DebugType>
|
||||||
<OutputPath>bin\Release\</OutputPath>
|
<Optimize>true</Optimize>
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
<WarningLevel>4</WarningLevel>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<Prefer32bit>false</Prefer32bit>
|
<WarningLevel>4</WarningLevel>
|
||||||
</PropertyGroup>
|
<Prefer32bit>false</Prefer32bit>
|
||||||
<ItemGroup>
|
</PropertyGroup>
|
||||||
<Reference Include="System"/>
|
<ItemGroup>
|
||||||
<Reference Include="System.Core"/>
|
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
<Reference Include="System.Xml.Linq"/>
|
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.9.0.8\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
||||||
<Reference Include="System.Data.DataSetExtensions"/>
|
</Reference>
|
||||||
<Reference Include="Microsoft.CSharp"/>
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Data"/>
|
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
<Reference Include="System.Deployment"/>
|
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
||||||
<Reference Include="System.Drawing"/>
|
</Reference>
|
||||||
<Reference Include="System.Net.Http"/>
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Windows.Forms"/>
|
<Reference Include="System.IO.Pipelines, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
<Reference Include="System.Xml"/>
|
<HintPath>..\packages\System.IO.Pipelines.9.0.8\lib\net462\System.IO.Pipelines.dll</HintPath>
|
||||||
</ItemGroup>
|
</Reference>
|
||||||
<ItemGroup>
|
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
<Compile Include="Form1.cs">
|
<HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
|
||||||
<SubType>Form</SubType>
|
</Reference>
|
||||||
</Compile>
|
<Reference Include="System.Numerics" />
|
||||||
<Compile Include="Form1.Designer.cs">
|
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
<DependentUpon>Form1.cs</DependentUpon>
|
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
||||||
</Compile>
|
</Reference>
|
||||||
<Compile Include="HotKeyManager.cs"/>
|
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
<Compile Include="Program.cs"/>
|
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||||
<Compile Include="Properties\AssemblyInfo.cs"/>
|
</Reference>
|
||||||
<EmbeddedResource Include="Properties\Resources.resx">
|
<Reference Include="System.Text.Encodings.Web, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
<HintPath>..\packages\System.Text.Encodings.Web.9.0.8\lib\net462\System.Text.Encodings.Web.dll</HintPath>
|
||||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
</Reference>
|
||||||
<SubType>Designer</SubType>
|
<Reference Include="System.Text.Json, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
</EmbeddedResource>
|
<HintPath>..\packages\System.Text.Json.9.0.8\lib\net462\System.Text.Json.dll</HintPath>
|
||||||
<Compile Include="Properties\Resources.Designer.cs">
|
</Reference>
|
||||||
<AutoGen>True</AutoGen>
|
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
<DependentUpon>Resources.resx</DependentUpon>
|
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||||
</Compile>
|
</Reference>
|
||||||
<None Include="Properties\Settings.settings">
|
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
<Generator>SettingsSingleFileGenerator</Generator>
|
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
|
||||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
</Reference>
|
||||||
</None>
|
<Reference Include="System.Xml.Linq" />
|
||||||
<Compile Include="Properties\Settings.Designer.cs">
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
<AutoGen>True</AutoGen>
|
<Reference Include="Microsoft.CSharp" />
|
||||||
<DependentUpon>Settings.settings</DependentUpon>
|
<Reference Include="System.Data" />
|
||||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
<Reference Include="System.Deployment" />
|
||||||
</Compile>
|
<Reference Include="System.Drawing" />
|
||||||
</ItemGroup>
|
<Reference Include="System.Net.Http" />
|
||||||
<ItemGroup>
|
<Reference Include="System.Windows.Forms" />
|
||||||
<None Include="App.config"/>
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="beep.wav"/>
|
<Compile Include="Form1.cs">
|
||||||
</ItemGroup>
|
<SubType>Form</SubType>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets"/>
|
</Compile>
|
||||||
|
<Compile Include="Form1.Designer.cs">
|
||||||
|
<DependentUpon>Form1.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<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>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<Compile Include="Properties\Resources.Designer.cs">
|
||||||
|
<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>
|
||||||
|
</None>
|
||||||
|
<Compile Include="Properties\Settings.Designer.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Settings.settings</DependentUpon>
|
||||||
|
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="beep.wav" />
|
||||||
|
<Content Include="app.ico">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
80
DD2Switcher/Form1.Designer.cs
generated
80
DD2Switcher/Form1.Designer.cs
generated
@@ -1,7 +1,5 @@
|
|||||||
namespace DD2Switcher
|
namespace DD2Switcher {
|
||||||
{
|
partial class Form1 {
|
||||||
partial class Form1
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required designer variable.
|
/// Required designer variable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -10,31 +8,85 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clean up any resources being used.
|
/// Clean up any resources being used.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
/// <param name="disposing">true if managed resources should be disposed;
|
||||||
protected override void Dispose(bool disposing)
|
/// otherwise, false.</param>
|
||||||
{
|
protected override void Dispose(bool disposing) {
|
||||||
if (disposing && (components != null))
|
if (disposing && (components != null)) {
|
||||||
{
|
|
||||||
components.Dispose();
|
components.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Windows Form Designer generated code
|
#region Windows Form Designer generated code
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required method for Designer support - do not modify
|
/// Required method for Designer support - do not modify
|
||||||
/// the contents of this method with the code editor.
|
/// the contents of this method with the code editor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeComponent()
|
private void InitializeComponent() {
|
||||||
{
|
|
||||||
this.components = new System.ComponentModel.Container();
|
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.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
this.ClientSize = new System.Drawing.Size(800, 450);
|
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() {
|
||||||
public Form1() {
|
InitializeComponent();
|
||||||
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,103 +3,98 @@ using System.Runtime.InteropServices;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace DD2Switcher;
|
namespace DD2Switcher {
|
||||||
|
public static class HotKeyManager {
|
||||||
|
private static volatile MessageWindow _wnd;
|
||||||
|
private static volatile IntPtr _hwnd;
|
||||||
|
private static readonly ManualResetEvent _windowReadyEvent = new(false);
|
||||||
|
|
||||||
public static class HotKeyManager {
|
private static int _id;
|
||||||
private static volatile MessageWindow _wnd;
|
|
||||||
private static volatile IntPtr _hwnd;
|
|
||||||
private static readonly ManualResetEvent _windowReadyEvent = new(false);
|
|
||||||
|
|
||||||
private static int _id;
|
static HotKeyManager() {
|
||||||
|
var messageLoop = new Thread(delegate() { Application.Run(new MessageWindow()); });
|
||||||
static HotKeyManager() {
|
messageLoop.Name = "MessageLoopThread";
|
||||||
var messageLoop = new Thread(delegate() { Application.Run(new MessageWindow()); });
|
messageLoop.IsBackground = true;
|
||||||
messageLoop.Name = "MessageLoopThread";
|
messageLoop.Start();
|
||||||
messageLoop.IsBackground = true;
|
|
||||||
messageLoop.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static event EventHandler<HotKeyEventArgs> HotKeyPressed;
|
|
||||||
|
|
||||||
public static int RegisterHotKey(Keys key, KeyModifiers modifiers) {
|
|
||||||
_windowReadyEvent.WaitOne();
|
|
||||||
var id = Interlocked.Increment(ref _id);
|
|
||||||
_wnd.Invoke(new RegisterHotKeyDelegate(RegisterHotKeyInternal), _hwnd, id, (uint)modifiers, (uint)key);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void UnregisterHotKey(int id) {
|
|
||||||
_wnd.Invoke(new UnRegisterHotKeyDelegate(UnRegisterHotKeyInternal), _hwnd, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void RegisterHotKeyInternal(IntPtr hwnd, int id, uint modifiers, uint key) {
|
|
||||||
RegisterHotKey(hwnd, id, modifiers, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void UnRegisterHotKeyInternal(IntPtr hwnd, int id) {
|
|
||||||
UnregisterHotKey(_hwnd, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void OnHotKeyPressed(HotKeyEventArgs e) {
|
|
||||||
if (HotKeyPressed != null) HotKeyPressed(null, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport("user32", SetLastError = true)]
|
|
||||||
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
|
|
||||||
|
|
||||||
[DllImport("user32", SetLastError = true)]
|
|
||||||
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
|
|
||||||
|
|
||||||
private delegate void RegisterHotKeyDelegate(IntPtr hwnd, int id, uint modifiers, uint key);
|
|
||||||
|
|
||||||
private delegate void UnRegisterHotKeyDelegate(IntPtr hwnd, int id);
|
|
||||||
|
|
||||||
private class MessageWindow : Form {
|
|
||||||
private const int WM_HOTKEY = 0x312;
|
|
||||||
|
|
||||||
public MessageWindow() {
|
|
||||||
_wnd = this;
|
|
||||||
_hwnd = Handle;
|
|
||||||
_windowReadyEvent.Set();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void WndProc(ref Message m) {
|
public static event EventHandler<HotKeyEventArgs> HotKeyPressed;
|
||||||
if (m.Msg == WM_HOTKEY) {
|
|
||||||
var e = new HotKeyEventArgs(m.LParam);
|
public static int RegisterHotKey(Keys key, KeyModifiers modifiers) {
|
||||||
OnHotKeyPressed(e);
|
_windowReadyEvent.WaitOne();
|
||||||
|
var id = Interlocked.Increment(ref _id);
|
||||||
|
_wnd.Invoke(new RegisterHotKeyDelegate(RegisterHotKeyInternal), _hwnd, id, (uint)modifiers, (uint)key);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UnregisterHotKey(int id) {
|
||||||
|
_wnd.Invoke(new UnRegisterHotKeyDelegate(UnRegisterHotKeyInternal), _hwnd, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RegisterHotKeyInternal(IntPtr hwnd, int id, uint modifiers, uint key) {
|
||||||
|
RegisterHotKey(hwnd, id, modifiers, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void UnRegisterHotKeyInternal(IntPtr hwnd, int id) {
|
||||||
|
UnregisterHotKey(_hwnd, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnHotKeyPressed(HotKeyEventArgs e) {
|
||||||
|
if (HotKeyPressed != null)
|
||||||
|
HotKeyPressed(null, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("user32", SetLastError = true)]
|
||||||
|
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
|
||||||
|
|
||||||
|
[DllImport("user32", SetLastError = true)]
|
||||||
|
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
|
||||||
|
|
||||||
|
private delegate void RegisterHotKeyDelegate(IntPtr hwnd, int id, uint modifiers, uint key);
|
||||||
|
|
||||||
|
private delegate void UnRegisterHotKeyDelegate(IntPtr hwnd, int id);
|
||||||
|
|
||||||
|
private class MessageWindow : Form {
|
||||||
|
private const int WM_HOTKEY = 0x312;
|
||||||
|
|
||||||
|
public MessageWindow() {
|
||||||
|
_wnd = this;
|
||||||
|
_hwnd = Handle;
|
||||||
|
_windowReadyEvent.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
base.WndProc(ref m);
|
protected override void WndProc(ref Message m) {
|
||||||
}
|
if (m.Msg == WM_HOTKEY) {
|
||||||
|
var e = new HotKeyEventArgs(m.LParam);
|
||||||
|
OnHotKeyPressed(e);
|
||||||
|
}
|
||||||
|
|
||||||
protected override void SetVisibleCore(bool value) {
|
base.WndProc(ref m);
|
||||||
// Ensure the window never becomes visible
|
}
|
||||||
base.SetVisibleCore(false);
|
|
||||||
|
protected override void SetVisibleCore(bool value) {
|
||||||
|
// Ensure the window never becomes visible
|
||||||
|
base.SetVisibleCore(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public class HotKeyEventArgs : EventArgs {
|
public class HotKeyEventArgs : EventArgs {
|
||||||
public readonly Keys Key;
|
public readonly Keys Key;
|
||||||
public readonly KeyModifiers Modifiers;
|
public readonly KeyModifiers Modifiers;
|
||||||
|
|
||||||
public HotKeyEventArgs(Keys key, KeyModifiers modifiers) {
|
public HotKeyEventArgs(Keys key, KeyModifiers modifiers) {
|
||||||
Key = key;
|
Key = key;
|
||||||
Modifiers = modifiers;
|
Modifiers = modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HotKeyEventArgs(IntPtr hotKeyParam) {
|
||||||
|
var param = (uint)hotKeyParam.ToInt64();
|
||||||
|
Key = (Keys)((param & 0xffff0000) >> 16);
|
||||||
|
Modifiers = (KeyModifiers)(param & 0x0000ffff);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public HotKeyEventArgs(IntPtr hotKeyParam) {
|
[Flags]
|
||||||
var param = (uint)hotKeyParam.ToInt64();
|
public enum KeyModifiers { Alt = 1, Control = 2, Shift = 4, Windows = 8, NoRepeat = 0x4000 }
|
||||||
Key = (Keys)((param & 0xffff0000) >> 16);
|
|
||||||
Modifiers = (KeyModifiers)(param & 0x0000ffff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[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,219 +1,751 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.IO;
|
||||||
using System.Windows.Forms;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
namespace DD2Switcher;
|
using System.Windows.Forms;
|
||||||
|
using System.Threading;
|
||||||
internal static class Program {
|
using System.Text.Json;
|
||||||
private static List<Process> processes = new();
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
private static Process activeProcess;
|
namespace DD2Switcher {
|
||||||
private static readonly IntPtr defaultAffinity = new(0xFF000000);
|
public class Settings {
|
||||||
private static readonly IntPtr fullAffinity = new(0xFFFFFFFF);
|
public Keys SequenceKeybind { get; set; } = Keys.F1;
|
||||||
|
public int SequenceTimerDelay { get; set; } = 100;
|
||||||
[DllImport("user32.dll")]
|
}
|
||||||
public static extern IntPtr GetForegroundWindow();
|
|
||||||
|
internal static class Program {
|
||||||
[DllImport("user32.dll")]
|
private static int NumProc = 19;
|
||||||
public static extern bool SetForegroundWindow(IntPtr hWnd);
|
private static Process[] windows = new Process[NumProc];
|
||||||
|
private static string settingsPath =
|
||||||
[DllImport("kernel32.dll", SetLastError = true)]
|
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "DD2Switcher.json");
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
|
||||||
static extern bool AllocConsole();
|
// Public access to tracked windows for the settings form
|
||||||
|
public static Process[] GetTrackedWindows() {
|
||||||
private static void AdjustAffinities() {
|
return windows;
|
||||||
List<Process> fuckedProcesses = new();
|
}
|
||||||
|
|
||||||
foreach (var process in processes)
|
public static void UntrackWindow(int index) {
|
||||||
if (process != activeProcess) {
|
if (index >= 0 && index < NumProc) {
|
||||||
try {
|
windows[index] = null;
|
||||||
process.ProcessorAffinity = defaultAffinity;
|
|
||||||
}
|
// Update ActiveIndex if needed
|
||||||
catch (Exception e) {
|
if (ActiveIndex == index) {
|
||||||
fuckedProcesses.Add(process);
|
ActiveIndex = -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Update first/last indices if needed
|
||||||
try {
|
if (FirstIndex == index) {
|
||||||
activeProcess.ProcessorAffinity = fullAffinity;
|
FirstIndex = -1;
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
if (LastIndex == index) {
|
||||||
fuckedProcesses.Add(activeProcess);
|
LastIndex = -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
foreach (var fucked in fuckedProcesses)
|
}
|
||||||
processes.Remove(fucked);
|
|
||||||
}
|
public static void StartSequenceMode() {
|
||||||
|
Console.WriteLine($"StartSequenceMode called. FirstIndex: {FirstIndex}, LastIndex: {LastIndex}");
|
||||||
private static void AdjustPriorities() {
|
|
||||||
List<Process> fuckedProcesses = new();
|
// Compute indices only when sequence starts, not stored permanently
|
||||||
|
int sequenceFirstIndex = FirstIndex;
|
||||||
foreach (var process in processes) {
|
int sequenceLastIndex = LastIndex;
|
||||||
try {
|
|
||||||
process.PriorityClass = ProcessPriorityClass.Idle;
|
// If no user indices, use absolute first and last windows
|
||||||
}
|
if (sequenceFirstIndex == -1 || sequenceLastIndex == -1) {
|
||||||
catch (Exception e) {
|
sequenceFirstIndex = FindFirstNonNullWindow();
|
||||||
fuckedProcesses.Add(process);
|
sequenceLastIndex = FindLastNonNullWindow();
|
||||||
}
|
Console.WriteLine(
|
||||||
}
|
$"Computed sequence indices: FirstIndex={sequenceFirstIndex}, LastIndex={sequenceLastIndex}");
|
||||||
|
}
|
||||||
try {
|
|
||||||
activeProcess.PriorityClass = ProcessPriorityClass.High;
|
if (sequenceFirstIndex >= 0 && sequenceLastIndex >= 0 && sequenceFirstIndex <= sequenceLastIndex) {
|
||||||
}
|
CurrentSequenceIndex = sequenceFirstIndex;
|
||||||
catch (Exception e) {
|
Console.WriteLine($"Starting sequence mode, tabbing to index {CurrentSequenceIndex + 1}");
|
||||||
fuckedProcesses.Add(activeProcess);
|
TabTo(CurrentSequenceIndex + 1); // Tab to first window
|
||||||
}
|
CurrentState = SequenceState.WAITING_FOR_EVENT;
|
||||||
|
Console.WriteLine($"State changed to: {CurrentState}");
|
||||||
foreach (var fucked in fuckedProcesses)
|
} else {
|
||||||
processes.Remove(fucked);
|
Console.WriteLine("Cannot start sequence mode - invalid first/last indices");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private static void SwitchToProcess(int index) {
|
|
||||||
Console.WriteLine("Switching to process at index " + index);
|
public static void ExitSequenceMode() {
|
||||||
if (index >= processes.Count) return;
|
CurrentState = SequenceState.INACTIVE;
|
||||||
var targetWindowHandle = processes[processes.Count - 1 - index].MainWindowHandle;
|
CurrentSequenceIndex = -1;
|
||||||
if (targetWindowHandle == IntPtr.Zero) {
|
Console.WriteLine($"State changed to: {CurrentState}");
|
||||||
processes.RemoveAt(processes.Count - 1 - index);
|
}
|
||||||
return;
|
|
||||||
}
|
public static bool IsInSequenceMode() {
|
||||||
|
return CurrentState != SequenceState.INACTIVE;
|
||||||
SetForegroundWindow(targetWindowHandle);
|
}
|
||||||
activeProcess = processes[processes.Count - 1 - index];
|
|
||||||
AdjustAffinities();
|
private static void LoadSettings() {
|
||||||
AdjustPriorities();
|
Console.WriteLine($"Attempting to load settings from: {settingsPath}");
|
||||||
}
|
try {
|
||||||
|
if (File.Exists(settingsPath)) {
|
||||||
private static void SwitchMainGame() {
|
Console.WriteLine("Settings file exists, reading...");
|
||||||
var foregroundWindow = GetForegroundWindow();
|
string json = File.ReadAllText(settingsPath);
|
||||||
Process foregroundGame = null;
|
Console.WriteLine($"Read JSON: {json}");
|
||||||
var foregroundGameIndex = -1;
|
var settings = JsonSerializer.Deserialize<Settings>(json);
|
||||||
var exists = false;
|
SequenceKeybind = settings.SequenceKeybind;
|
||||||
|
SequenceTimerDelay = settings.SequenceTimerDelay;
|
||||||
foreach (var process in processes)
|
Console.WriteLine(
|
||||||
if (foregroundWindow == process.MainWindowHandle) {
|
$"Loaded settings: Keybind={SequenceKeybind}, TimerDelay={SequenceTimerDelay} (First/Last indices NOT loaded)");
|
||||||
exists = true;
|
} else {
|
||||||
foregroundGame = process;
|
Console.WriteLine($"Settings file does not exist at: {settingsPath}");
|
||||||
foregroundGameIndex = processes.IndexOf(process);
|
Console.WriteLine("Using default settings");
|
||||||
break;
|
}
|
||||||
}
|
} catch (Exception ex) {
|
||||||
|
Console.WriteLine($"Error loading settings: {ex.Message}");
|
||||||
if (exists) {
|
Console.WriteLine($"Stack trace: {ex.StackTrace}");
|
||||||
var tempGame = processes[0];
|
}
|
||||||
processes[0] = foregroundGame;
|
}
|
||||||
processes[foregroundGameIndex] = tempGame;
|
|
||||||
}
|
public static void SaveSettings() {
|
||||||
}
|
try {
|
||||||
|
var settings =
|
||||||
private static void ToggleGame() {
|
new Settings { SequenceKeybind = SequenceKeybind, SequenceTimerDelay = SequenceTimerDelay };
|
||||||
Console.WriteLine("Toggling foreground window as tracked...");
|
string json = JsonSerializer.Serialize(settings, new JsonSerializerOptions { WriteIndented = true });
|
||||||
var foregroundWindow = GetForegroundWindow();
|
File.WriteAllText(settingsPath, json);
|
||||||
var systemProcesses = Process.GetProcesses();
|
Console.WriteLine($"Saved settings: Keybind={SequenceKeybind}, TimerDelay={SequenceTimerDelay}");
|
||||||
Process foregroundProcess = null;
|
} catch (Exception ex) {
|
||||||
|
Console.WriteLine($"Error saving settings: {ex.Message}");
|
||||||
foreach (var process in systemProcesses)
|
}
|
||||||
if (foregroundWindow == process.MainWindowHandle) {
|
}
|
||||||
foregroundProcess = process;
|
|
||||||
break;
|
private static int FindFirstNonNullWindow() {
|
||||||
}
|
for (int i = 0; i < NumProc; i++) {
|
||||||
|
if (windows[i] != null && windows[i].MainWindowHandle != IntPtr.Zero) {
|
||||||
if (foregroundProcess == null) return;
|
return i;
|
||||||
Console.WriteLine("Foreground process: " + foregroundProcess.ProcessName);
|
}
|
||||||
var existingProcess = processes.Find(process => process.Id == foregroundProcess.Id);
|
}
|
||||||
if (existingProcess != null) {
|
return -1;
|
||||||
Console.WriteLine("Removing foreground process from tracked...");
|
}
|
||||||
processes.Remove(existingProcess);
|
|
||||||
}
|
private static int FindLastNonNullWindow() {
|
||||||
else {
|
for (int i = NumProc - 1; i >= 0; i--) {
|
||||||
Console.WriteLine("Adding foreground process to tracked...");
|
if (windows[i] != null && windows[i].MainWindowHandle != IntPtr.Zero) {
|
||||||
processes.Add(foregroundProcess);
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return -1;
|
||||||
[STAThread]
|
}
|
||||||
private static void Main() {
|
|
||||||
// AllocConsole();
|
private static int FindNextNonNullWindow(int startIndex) {
|
||||||
|
for (int i = startIndex; i < NumProc; i++) {
|
||||||
var processes = Process.GetProcesses();
|
if (windows[i] != null && windows[i].MainWindowHandle != IntPtr.Zero) {
|
||||||
var currentProcess = Process.GetCurrentProcess();
|
return i;
|
||||||
|
}
|
||||||
foreach (var process in processes)
|
}
|
||||||
if (process.Id != currentProcess.Id && process.ProcessName == currentProcess.ProcessName) {
|
return -1;
|
||||||
process.Kill();
|
}
|
||||||
Process.GetCurrentProcess().Kill();
|
|
||||||
}
|
private static void SetDefaultFirstLastIndices() {
|
||||||
|
if (FirstIndex == -1) {
|
||||||
|
FirstIndex = FindFirstNonNullWindow();
|
||||||
HotKeyManager.RegisterHotKey(Keys.D1, KeyModifiers.Alt);
|
Console.WriteLine($"Set default FirstIndex to: {FirstIndex}");
|
||||||
HotKeyManager.RegisterHotKey(Keys.D2, KeyModifiers.Alt);
|
}
|
||||||
HotKeyManager.RegisterHotKey(Keys.D3, KeyModifiers.Alt);
|
if (LastIndex == -1) {
|
||||||
HotKeyManager.RegisterHotKey(Keys.D4, KeyModifiers.Alt);
|
LastIndex = FindLastNonNullWindow();
|
||||||
HotKeyManager.RegisterHotKey(Keys.D5, KeyModifiers.Alt);
|
Console.WriteLine($"Set default LastIndex to: {LastIndex}");
|
||||||
HotKeyManager.RegisterHotKey(Keys.D6, KeyModifiers.Alt);
|
}
|
||||||
HotKeyManager.RegisterHotKey(Keys.D7, KeyModifiers.Alt);
|
|
||||||
HotKeyManager.RegisterHotKey(Keys.D8, KeyModifiers.Alt);
|
// Ensure LastIndex is different from FirstIndex if there are multiple windows
|
||||||
HotKeyManager.RegisterHotKey(Keys.D9, KeyModifiers.Alt);
|
if (FirstIndex != -1 && LastIndex != -1 && FirstIndex == LastIndex) {
|
||||||
|
// Find the next non-null window after FirstIndex
|
||||||
HotKeyManager.RegisterHotKey(Keys.D1, KeyModifiers.Alt | KeyModifiers.Shift);
|
int nextWindow = FindNextNonNullWindow(FirstIndex + 1);
|
||||||
HotKeyManager.RegisterHotKey(Keys.D2, KeyModifiers.Alt | KeyModifiers.Shift);
|
if (nextWindow != -1) {
|
||||||
HotKeyManager.RegisterHotKey(Keys.D3, KeyModifiers.Alt | KeyModifiers.Shift);
|
LastIndex = nextWindow;
|
||||||
HotKeyManager.RegisterHotKey(Keys.D4, KeyModifiers.Alt | KeyModifiers.Shift);
|
Console.WriteLine($"Adjusted LastIndex to: {LastIndex} (different from FirstIndex)");
|
||||||
HotKeyManager.RegisterHotKey(Keys.D5, KeyModifiers.Alt | KeyModifiers.Shift);
|
}
|
||||||
HotKeyManager.RegisterHotKey(Keys.D6, KeyModifiers.Alt | KeyModifiers.Shift);
|
}
|
||||||
HotKeyManager.RegisterHotKey(Keys.D7, KeyModifiers.Alt | KeyModifiers.Shift);
|
}
|
||||||
HotKeyManager.RegisterHotKey(Keys.D8, KeyModifiers.Alt | KeyModifiers.Shift);
|
|
||||||
HotKeyManager.RegisterHotKey(Keys.D9, KeyModifiers.Alt | KeyModifiers.Shift);
|
public static void UpdateSequenceHotkey(Keys newKey) {
|
||||||
|
Console.WriteLine($"UpdateSequenceHotkey called with new key: {newKey} (code: {(int)newKey})");
|
||||||
HotKeyManager.RegisterHotKey(Keys.Oemtilde, KeyModifiers.Alt);
|
Console.WriteLine($"Old SequenceKeybind before update: {SequenceKeybind} (code: {(int)SequenceKeybind})");
|
||||||
|
|
||||||
// HotKeyManager.RegisterHotKey(Keys.Q, KeyModifiers.Alt);
|
// Unregister old hotkey
|
||||||
// HotKeyManager.RegisterHotKey(Keys.W, KeyModifiers.Alt);
|
if (sequenceHotkeyId != -1) {
|
||||||
// HotKeyManager.RegisterHotKey(Keys.R, KeyModifiers.Alt);
|
Console.WriteLine($"Unregistering old hotkey ID: {sequenceHotkeyId}");
|
||||||
HotKeyManager.HotKeyPressed += HotKeyManager_HotKeyPressed;
|
HotKeyManager.UnregisterHotKey(sequenceHotkeyId);
|
||||||
|
}
|
||||||
var pixelList = new System.Collections.Generic.List<Pixel>();
|
|
||||||
// pixelList.Add(new Pixel(1401, 1234, 224, 224, 224));
|
// Register new hotkey
|
||||||
pixelList.Add(new Pixel(1359, 1235, 220, 220, 220));
|
sequenceHotkeyId = HotKeyManager.RegisterHotKey(newKey, KeyModifiers.NoRepeat);
|
||||||
|
Console.WriteLine($"Registered new hotkey ID: {sequenceHotkeyId} for key: {newKey}");
|
||||||
static void HotKeyManager_HotKeyPressed(object sender, HotKeyEventArgs e) {
|
SequenceKeybind = newKey;
|
||||||
switch (e.Key) {
|
Console.WriteLine($"New SequenceKeybind after update: {SequenceKeybind} (code: {(int)SequenceKeybind})");
|
||||||
case Keys.D1:
|
SaveSettings();
|
||||||
SwitchToProcess(0);
|
}
|
||||||
break;
|
|
||||||
case Keys.D2:
|
public static void SaveFirstLastIndices() {
|
||||||
SwitchToProcess(1);
|
SaveSettings();
|
||||||
break;
|
}
|
||||||
case Keys.D3:
|
|
||||||
SwitchToProcess(2);
|
// Static properties for first/last selection persistence
|
||||||
break;
|
public static int FirstIndex { get; set; } = -1;
|
||||||
case Keys.D4:
|
public static int LastIndex { get; set; } = -1;
|
||||||
SwitchToProcess(3);
|
|
||||||
break;
|
// Sequence mode state engine
|
||||||
case Keys.D5:
|
public enum SequenceState { INACTIVE, WAITING_FOR_EVENT, WAITING_TO_ADVANCE, ADVANCE }
|
||||||
SwitchToProcess(4);
|
|
||||||
break;
|
public static SequenceState CurrentState { get; set; } = SequenceState.INACTIVE;
|
||||||
case Keys.D6:
|
public static int CurrentSequenceIndex { get; set; } = -1;
|
||||||
SwitchToProcess(5);
|
public static Keys SequenceKeybind { get; set; } = Keys.F1;
|
||||||
break;
|
public static int SequenceTimerDelay { get; set; } = 100;
|
||||||
case Keys.D7:
|
private static int sequenceHotkeyId = -1;
|
||||||
SwitchToProcess(6);
|
private static int ActiveIndex = -1;
|
||||||
break;
|
private static bool AltPressed = false;
|
||||||
case Keys.D8:
|
|
||||||
SwitchToProcess(7);
|
// State handlers
|
||||||
break;
|
private static readonly Dictionary<SequenceState, Action> stateHandlers =
|
||||||
case Keys.D9:
|
new Dictionary<SequenceState, Action> { { SequenceState.INACTIVE, HandleInactive },
|
||||||
SwitchToProcess(8);
|
{ SequenceState.WAITING_FOR_EVENT, HandleWaitingForEvent },
|
||||||
break;
|
{ SequenceState.WAITING_TO_ADVANCE, HandleWaitingToAdvance },
|
||||||
case Keys.Oemtilde:
|
{ SequenceState.ADVANCE, HandleAdvance } };
|
||||||
ToggleGame();
|
|
||||||
break;
|
private static void HandleInactive() {
|
||||||
}
|
// Inactive state - do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void HandleWaitingForEvent() {
|
||||||
Console.CancelKeyPress += (sender, e) => { Process.GetCurrentProcess().Kill(); };
|
// Event happened, transition to waiting to advance
|
||||||
while (true)
|
Console.WriteLine($"Event detected in state: {CurrentState}, transitioning to WAITING_TO_ADVANCE");
|
||||||
System.Threading.Thread.Sleep(100000);
|
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();
|
||||||
|
|
||||||
|
[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)]
|
||||||
|
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.MainWindowHandle == IntPtr.Zero) {
|
||||||
|
Console.WriteLine($"Window at index {i} has no main window, removing from tracked windows");
|
||||||
|
windows[i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AdjustAffinities() {
|
||||||
|
CleanWindows();
|
||||||
|
for (int i = 0; i < NumProc; i++) {
|
||||||
|
var window = windows[i];
|
||||||
|
if (window == null)
|
||||||
|
continue;
|
||||||
|
if (i != ActiveIndex) {
|
||||||
|
try {
|
||||||
|
window.ProcessorAffinity = defaultAffinity;
|
||||||
|
} catch (Exception e) {
|
||||||
|
windows[i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var active = windows[ActiveIndex];
|
||||||
|
if (active != null) {
|
||||||
|
try {
|
||||||
|
active.ProcessorAffinity = fullAffinity;
|
||||||
|
} catch (Exception e) {
|
||||||
|
windows[ActiveIndex] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AdjustPriorities() {
|
||||||
|
CleanWindows();
|
||||||
|
for (int i = 0; i < NumProc; i++) {
|
||||||
|
var window = windows[i];
|
||||||
|
if (window == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (i != ActiveIndex) {
|
||||||
|
try {
|
||||||
|
window.PriorityClass = ProcessPriorityClass.Idle;
|
||||||
|
} catch (Exception e) {
|
||||||
|
windows[i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var active = windows[ActiveIndex];
|
||||||
|
if (active != null) {
|
||||||
|
try {
|
||||||
|
active.PriorityClass = ProcessPriorityClass.High;
|
||||||
|
} catch (Exception e) {
|
||||||
|
windows[ActiveIndex] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Process GetForegroundProcess() {
|
||||||
|
var foregroundWindow = GetForegroundWindow();
|
||||||
|
var process = Process.GetProcesses();
|
||||||
|
Process foregroundProcess = null;
|
||||||
|
foreach (var p in process)
|
||||||
|
if (foregroundWindow == p.MainWindowHandle) {
|
||||||
|
foregroundProcess = p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foregroundProcess == null)
|
||||||
|
return null;
|
||||||
|
return foregroundProcess;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Boolean ProcessTracked(int id) {
|
||||||
|
for (int i = 0; i < NumProc; i++) {
|
||||||
|
if (windows[i] != null && windows[i].Id == id) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
firstNullIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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) {
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Swap(int index) {
|
||||||
|
index = (index - 1) % NumProc;
|
||||||
|
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;
|
||||||
|
Console.WriteLine($"Foreground process: {process}");
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < NumProc; i++) {
|
||||||
|
var window = windows[i];
|
||||||
|
if (window != null && window.Id == process.Id) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
for (int i = 0; i < NumProc; i++) {
|
||||||
|
var window = windows[i];
|
||||||
|
if (window == null) {
|
||||||
|
Console.WriteLine($"Adding foreground window to tracked at index {i}...");
|
||||||
|
windows[i] = process;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < NumProc; i++) {
|
||||||
|
var window = windows[i];
|
||||||
|
if (window != null && window.Id == process.Id) {
|
||||||
|
windows[i] = windows[index];
|
||||||
|
windows[index] = window;
|
||||||
|
Console.WriteLine($"Swapped window at index {i} to {index}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
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 {
|
||||||
|
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(); // Enable console for debug output
|
||||||
|
Application.EnableVisualStyles();
|
||||||
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
|
|
||||||
|
// Load settings
|
||||||
|
LoadSettings();
|
||||||
|
|
||||||
|
var processes = Process.GetProcesses();
|
||||||
|
var currentProcess = Process.GetCurrentProcess();
|
||||||
|
|
||||||
|
foreach (var process in processes)
|
||||||
|
if (process.Id != currentProcess.Id && process.ProcessName == currentProcess.ProcessName) {
|
||||||
|
process.Kill();
|
||||||
|
Process.GetCurrentProcess().Kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
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.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;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
index = 10 + (e.Key - Keys.NumPad1);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.Modifiers == KeyModifiers.Alt) {
|
||||||
|
if (IsCapsLockOn()) {
|
||||||
|
Swap(index);
|
||||||
|
ToggleCapsLock();
|
||||||
|
} else {
|
||||||
|
TabTo(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
// General Information about an assembly is controlled through the following
|
||||||
// set of attributes. Change these attribute values to modify the information
|
// set of attributes. Change these attribute values to modify the information
|
||||||
// associated with an assembly.
|
// associated with an assembly.
|
||||||
[assembly: AssemblyTitle("DD2Switcher")]
|
[assembly:AssemblyTitle("DD2Switcher")]
|
||||||
[assembly: AssemblyDescription("")]
|
[assembly:AssemblyDescription("")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly:AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("")]
|
[assembly:AssemblyCompany("")]
|
||||||
[assembly: AssemblyProduct("DD2Switcher")]
|
[assembly:AssemblyProduct("DD2Switcher")]
|
||||||
[assembly: AssemblyCopyright("Copyright © 2022")]
|
[assembly:AssemblyCopyright("Copyright © 2022")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly:AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly:AssemblyCulture("")]
|
||||||
|
|
||||||
// Setting ComVisible to false makes the types in this assembly not visible
|
// 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
|
// to COM components. If you need to access a type in this assembly from
|
||||||
// COM, set the ComVisible attribute to true on that type.
|
// 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
|
// The following GUID is for the ID of the typelib if this project is exposed to
|
||||||
[assembly: Guid("2AC26899-8E27-4B96-85A9-C387186EAD27")]
|
// COM
|
||||||
|
[assembly:Guid("2AC26899-8E27-4B96-85A9-C387186EAD27")]
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
// Version information for an assembly consists of the following four values:
|
||||||
//
|
//
|
||||||
@@ -28,8 +29,7 @@ using System.Runtime.InteropServices;
|
|||||||
// Build Number
|
// Build Number
|
||||||
// Revision
|
// Revision
|
||||||
//
|
//
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision
|
||||||
// by using the '*' as shown below:
|
// Numbers by using the '*' as shown below: [assembly: AssemblyVersion("1.0.*")]
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
[assembly:AssemblyVersion("1.0.0.0")]
|
||||||
[assembly: AssemblyVersion("1.0.0.0")]
|
[assembly:AssemblyFileVersion("1.0.0.0")]
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
38
DD2Switcher/Properties/Resources.Designer.cs
generated
38
DD2Switcher/Properties/Resources.Designer.cs
generated
@@ -10,8 +10,7 @@
|
|||||||
|
|
||||||
namespace DD2Switcher.Properties {
|
namespace DD2Switcher.Properties {
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -19,45 +18,44 @@ namespace DD2Switcher.Properties {
|
|||||||
// class via a tool like ResGen or Visual Studio.
|
// class via a tool like ResGen or Visual Studio.
|
||||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
// with the /str option, or rebuild your VS project.
|
// 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.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
internal class Resources {
|
internal class Resources {
|
||||||
|
|
||||||
private static global::System.Resources.ResourceManager resourceMan;
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance",
|
||||||
internal Resources() {
|
"CA1811:AvoidUncalledPrivateCode")]
|
||||||
}
|
internal Resources() {}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the cached ResourceManager instance used by this class.
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
/// </summary>
|
/// </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 {
|
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||||
get {
|
get {
|
||||||
if (object.ReferenceEquals(resourceMan, null)) {
|
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;
|
resourceMan = temp;
|
||||||
}
|
}
|
||||||
return resourceMan;
|
return resourceMan;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Overrides the current thread's CurrentUICulture property for all
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
/// resource lookups using this strongly typed resource class.
|
/// resource lookups using this strongly typed resource class.
|
||||||
/// </summary>
|
/// </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 {
|
internal static global::System.Globalization.CultureInfo Culture {
|
||||||
get {
|
get { return resourceCulture; }
|
||||||
return resourceCulture;
|
set { resourceCulture = value; }
|
||||||
}
|
|
||||||
set {
|
|
||||||
resourceCulture = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
DD2Switcher/Properties/Settings.Designer.cs
generated
14
DD2Switcher/Properties/Settings.Designer.cs
generated
@@ -8,19 +8,17 @@
|
|||||||
// </auto-generated>
|
// </auto-generated>
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
namespace DD2Switcher.Properties
|
namespace DD2Switcher.Properties {
|
||||||
{
|
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(
|
||||||
"Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
"Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.14.0.0")]
|
||||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||||
{
|
|
||||||
private static Settings defaultInstance =
|
private static Settings defaultInstance =
|
||||||
((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|
||||||
public static Settings Default
|
public static Settings Default {
|
||||||
{
|
|
||||||
get { return defaultInstance; }
|
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