Compare commits
20 Commits
458a466c15
...
master
Author | SHA1 | Date | |
---|---|---|---|
15bee9bf62 | |||
32758cf062 | |||
f4524161ac | |||
12ac48aa76 | |||
62f92708c2 | |||
88005c2125 | |||
df936e187d | |||
833355cd60 | |||
0b7aaa2f99 | |||
274a75b93d | |||
3b038b0fc9 | |||
69fd02e331 | |||
87bd2132e5 | |||
1cdfba0b14 | |||
0e3f2005d1 | |||
c4e9007f2b | |||
1f314d5c4b | |||
f234279135 | |||
baeadba638 | |||
bad2313c18 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@
|
||||
obj
|
||||
bin
|
||||
.vs
|
||||
packages
|
||||
|
@@ -1,6 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
|
@@ -37,8 +37,39 @@
|
||||
<Prefer32bit>false</Prefer32bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.9.0.8\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.IO.Pipelines, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Pipelines.9.0.8\lib\net462\System.IO.Pipelines.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Text.Encodings.Web, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Text.Encodings.Web.9.0.8\lib\net462\System.Text.Encodings.Web.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Text.Json, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Text.Json.9.0.8\lib\net462\System.Text.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
@@ -56,6 +87,15 @@
|
||||
<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" />
|
||||
@@ -69,6 +109,13 @@
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="SettingsForm.resx">
|
||||
<DependentUpon>SettingsForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="WindowPanelForm.resx">
|
||||
<DependentUpon>WindowPanelForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
@@ -84,6 +131,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="beep.wav" />
|
||||
<Content Include="app.ico">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
58
DD2Switcher/Form1.Designer.cs
generated
58
DD2Switcher/Form1.Designer.cs
generated
@@ -26,11 +26,67 @@
|
||||
/// </summary>
|
||||
private void InitializeComponent() {
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components);
|
||||
this.trayMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.settingsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.separatorMenuItem = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.exitMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.trayMenu.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// notifyIcon
|
||||
//
|
||||
this.notifyIcon.ContextMenuStrip = this.trayMenu;
|
||||
this.notifyIcon.Text = "DD2Switcher";
|
||||
this.notifyIcon.Visible = true;
|
||||
this.notifyIcon.MouseDoubleClick +=
|
||||
new System.Windows.Forms.MouseEventHandler(this.notifyIcon_MouseDoubleClick);
|
||||
//
|
||||
// trayMenu
|
||||
//
|
||||
this.trayMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.settingsMenuItem, this.separatorMenuItem, this.exitMenuItem
|
||||
});
|
||||
this.trayMenu.Name = "trayMenu";
|
||||
this.trayMenu.Size = new System.Drawing.Size(120, 54);
|
||||
//
|
||||
// settingsMenuItem
|
||||
//
|
||||
this.settingsMenuItem.Name = "settingsMenuItem";
|
||||
this.settingsMenuItem.Size = new System.Drawing.Size(119, 22);
|
||||
this.settingsMenuItem.Text = "Settings";
|
||||
this.settingsMenuItem.Click += new System.EventHandler(this.settingsMenuItem_Click);
|
||||
//
|
||||
// separatorMenuItem
|
||||
//
|
||||
this.separatorMenuItem.Name = "separatorMenuItem";
|
||||
this.separatorMenuItem.Size = new System.Drawing.Size(116, 6);
|
||||
//
|
||||
// exitMenuItem
|
||||
//
|
||||
this.exitMenuItem.Name = "exitMenuItem";
|
||||
this.exitMenuItem.Size = new System.Drawing.Size(119, 22);
|
||||
this.exitMenuItem.Text = "Exit";
|
||||
this.exitMenuItem.Click += new System.EventHandler(this.exitMenuItem_Click);
|
||||
//
|
||||
// Form1
|
||||
//
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(800, 450);
|
||||
this.Text = "Form1";
|
||||
this.Text = "DD2Switcher";
|
||||
this.WindowState = System.Windows.Forms.FormWindowState.Minimized;
|
||||
this.ShowInTaskbar = false;
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
|
||||
this.trayMenu.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
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 {
|
||||
public partial class Form1 : Form {
|
||||
private SettingsForm settingsForm;
|
||||
|
||||
public Form1() {
|
||||
InitializeComponent();
|
||||
LoadIcons();
|
||||
this.Load += Form1_Load;
|
||||
}
|
||||
|
||||
private void Form1_Load(object sender, EventArgs e) {
|
||||
// Hide the form initially since we're running in system tray
|
||||
this.Hide();
|
||||
}
|
||||
|
||||
private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e) {
|
||||
ShowSettings();
|
||||
}
|
||||
|
||||
private void settingsMenuItem_Click(object sender, EventArgs e) {
|
||||
ShowSettings();
|
||||
}
|
||||
|
||||
private void exitMenuItem_Click(object sender, EventArgs e) {
|
||||
Application.Exit();
|
||||
}
|
||||
|
||||
private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
|
||||
// Prevent the form from closing, just hide it
|
||||
if (e.CloseReason == CloseReason.UserClosing) {
|
||||
e.Cancel = true;
|
||||
this.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowSettings() {
|
||||
if (settingsForm == null || settingsForm.IsDisposed) {
|
||||
settingsForm = new SettingsForm();
|
||||
}
|
||||
|
||||
settingsForm.Show();
|
||||
settingsForm.BringToFront();
|
||||
}
|
||||
|
||||
private void LoadIcons() {
|
||||
try {
|
||||
string iconPath = System.IO.Path.Combine(
|
||||
System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
|
||||
"app.ico");
|
||||
this.Icon = new System.Drawing.Icon(iconPath);
|
||||
this.notifyIcon.Icon = new System.Drawing.Icon(iconPath);
|
||||
} catch {
|
||||
// Use default icon if custom icon not found
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -37,13 +37,15 @@ class KeyboardHook {
|
||||
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("Same event");
|
||||
Console.WriteLine($"KeyboardHook: Same event filtered out - vkCode: {vkCode}, wParam: {wParam}");
|
||||
}
|
||||
}
|
||||
return CallNextHookEx(_hookID, nCode, wParam, lParam);
|
||||
|
@@ -1,18 +1,265 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using System.Threading;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DD2Switcher {
|
||||
public class Settings {
|
||||
public Keys SequenceKeybind { get; set; } = Keys.F1;
|
||||
public int SequenceTimerDelay { get; set; } = 100;
|
||||
}
|
||||
|
||||
internal static class Program {
|
||||
private static int NumProc = 19;
|
||||
private static Process[] windows = new Process[NumProc];
|
||||
private static string settingsPath =
|
||||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "DD2Switcher.json");
|
||||
|
||||
// Public access to tracked windows for the settings form
|
||||
public static Process[] GetTrackedWindows() {
|
||||
return windows;
|
||||
}
|
||||
|
||||
public static void UntrackWindow(int index) {
|
||||
if (index >= 0 && index < NumProc) {
|
||||
windows[index] = null;
|
||||
|
||||
// Update ActiveIndex if needed
|
||||
if (ActiveIndex == index) {
|
||||
ActiveIndex = -1;
|
||||
}
|
||||
|
||||
// Update first/last indices if needed
|
||||
if (FirstIndex == index) {
|
||||
FirstIndex = -1;
|
||||
}
|
||||
if (LastIndex == index) {
|
||||
LastIndex = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void StartSequenceMode() {
|
||||
Console.WriteLine($"StartSequenceMode called. FirstIndex: {FirstIndex}, LastIndex: {LastIndex}");
|
||||
|
||||
// Compute indices only when sequence starts, not stored permanently
|
||||
int sequenceFirstIndex = FirstIndex;
|
||||
int sequenceLastIndex = LastIndex;
|
||||
|
||||
// If no user indices, use absolute first and last windows
|
||||
if (sequenceFirstIndex == -1 || sequenceLastIndex == -1) {
|
||||
sequenceFirstIndex = FindFirstNonNullWindow();
|
||||
sequenceLastIndex = FindLastNonNullWindow();
|
||||
Console.WriteLine(
|
||||
$"Computed sequence indices: FirstIndex={sequenceFirstIndex}, LastIndex={sequenceLastIndex}");
|
||||
}
|
||||
|
||||
if (sequenceFirstIndex >= 0 && sequenceLastIndex >= 0 && sequenceFirstIndex <= sequenceLastIndex) {
|
||||
CurrentSequenceIndex = sequenceFirstIndex;
|
||||
Console.WriteLine($"Starting sequence mode, tabbing to index {CurrentSequenceIndex + 1}");
|
||||
TabTo(CurrentSequenceIndex + 1); // Tab to first window
|
||||
CurrentState = SequenceState.WAITING_FOR_EVENT;
|
||||
Console.WriteLine($"State changed to: {CurrentState}");
|
||||
} else {
|
||||
Console.WriteLine("Cannot start sequence mode - invalid first/last indices");
|
||||
}
|
||||
}
|
||||
|
||||
public static void ExitSequenceMode() {
|
||||
CurrentState = SequenceState.INACTIVE;
|
||||
CurrentSequenceIndex = -1;
|
||||
Console.WriteLine($"State changed to: {CurrentState}");
|
||||
}
|
||||
|
||||
public static bool IsInSequenceMode() {
|
||||
return CurrentState != SequenceState.INACTIVE;
|
||||
}
|
||||
|
||||
private static void LoadSettings() {
|
||||
Console.WriteLine($"Attempting to load settings from: {settingsPath}");
|
||||
try {
|
||||
if (File.Exists(settingsPath)) {
|
||||
Console.WriteLine("Settings file exists, reading...");
|
||||
string json = File.ReadAllText(settingsPath);
|
||||
Console.WriteLine($"Read JSON: {json}");
|
||||
var settings = JsonSerializer.Deserialize<Settings>(json);
|
||||
SequenceKeybind = settings.SequenceKeybind;
|
||||
SequenceTimerDelay = settings.SequenceTimerDelay;
|
||||
Console.WriteLine(
|
||||
$"Loaded settings: Keybind={SequenceKeybind}, TimerDelay={SequenceTimerDelay} (First/Last indices NOT loaded)");
|
||||
} else {
|
||||
Console.WriteLine($"Settings file does not exist at: {settingsPath}");
|
||||
Console.WriteLine("Using default settings");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Console.WriteLine($"Error loading settings: {ex.Message}");
|
||||
Console.WriteLine($"Stack trace: {ex.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void SaveSettings() {
|
||||
try {
|
||||
var settings =
|
||||
new Settings { SequenceKeybind = SequenceKeybind, SequenceTimerDelay = SequenceTimerDelay };
|
||||
string json = JsonSerializer.Serialize(settings, new JsonSerializerOptions { WriteIndented = true });
|
||||
File.WriteAllText(settingsPath, json);
|
||||
Console.WriteLine($"Saved settings: Keybind={SequenceKeybind}, TimerDelay={SequenceTimerDelay}");
|
||||
} catch (Exception ex) {
|
||||
Console.WriteLine($"Error saving settings: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static int FindFirstNonNullWindow() {
|
||||
for (int i = 0; i < NumProc; i++) {
|
||||
if (windows[i] != null && windows[i].MainWindowHandle != IntPtr.Zero) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static int FindLastNonNullWindow() {
|
||||
for (int i = NumProc - 1; i >= 0; i--) {
|
||||
if (windows[i] != null && windows[i].MainWindowHandle != IntPtr.Zero) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static int FindNextNonNullWindow(int startIndex) {
|
||||
for (int i = startIndex; i < NumProc; i++) {
|
||||
if (windows[i] != null && windows[i].MainWindowHandle != IntPtr.Zero) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static void SetDefaultFirstLastIndices() {
|
||||
if (FirstIndex == -1) {
|
||||
FirstIndex = FindFirstNonNullWindow();
|
||||
Console.WriteLine($"Set default FirstIndex to: {FirstIndex}");
|
||||
}
|
||||
if (LastIndex == -1) {
|
||||
LastIndex = FindLastNonNullWindow();
|
||||
Console.WriteLine($"Set default LastIndex to: {LastIndex}");
|
||||
}
|
||||
|
||||
// Ensure LastIndex is different from FirstIndex if there are multiple windows
|
||||
if (FirstIndex != -1 && LastIndex != -1 && FirstIndex == LastIndex) {
|
||||
// Find the next non-null window after FirstIndex
|
||||
int nextWindow = FindNextNonNullWindow(FirstIndex + 1);
|
||||
if (nextWindow != -1) {
|
||||
LastIndex = nextWindow;
|
||||
Console.WriteLine($"Adjusted LastIndex to: {LastIndex} (different from FirstIndex)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateSequenceHotkey(Keys newKey) {
|
||||
Console.WriteLine($"UpdateSequenceHotkey called with new key: {newKey} (code: {(int)newKey})");
|
||||
Console.WriteLine($"Old SequenceKeybind before update: {SequenceKeybind} (code: {(int)SequenceKeybind})");
|
||||
|
||||
// Unregister old hotkey
|
||||
if (sequenceHotkeyId != -1) {
|
||||
Console.WriteLine($"Unregistering old hotkey ID: {sequenceHotkeyId}");
|
||||
HotKeyManager.UnregisterHotKey(sequenceHotkeyId);
|
||||
}
|
||||
|
||||
// Register new hotkey
|
||||
sequenceHotkeyId = HotKeyManager.RegisterHotKey(newKey, KeyModifiers.NoRepeat);
|
||||
Console.WriteLine($"Registered new hotkey ID: {sequenceHotkeyId} for key: {newKey}");
|
||||
SequenceKeybind = newKey;
|
||||
Console.WriteLine($"New SequenceKeybind after update: {SequenceKeybind} (code: {(int)SequenceKeybind})");
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
public static void SaveFirstLastIndices() {
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
// Static properties for first/last selection persistence
|
||||
public static int FirstIndex { get; set; } = -1;
|
||||
public static int LastIndex { get; set; } = -1;
|
||||
|
||||
// Sequence mode state engine
|
||||
public enum SequenceState { INACTIVE, WAITING_FOR_EVENT, WAITING_TO_ADVANCE, ADVANCE }
|
||||
|
||||
public static SequenceState CurrentState { get; set; } = SequenceState.INACTIVE;
|
||||
public static int CurrentSequenceIndex { get; set; } = -1;
|
||||
public static Keys SequenceKeybind { get; set; } = Keys.F1;
|
||||
public static int SequenceTimerDelay { get; set; } = 100;
|
||||
private static int sequenceHotkeyId = -1;
|
||||
private static int ActiveIndex = -1;
|
||||
private static bool AltPressed = false;
|
||||
|
||||
// State handlers
|
||||
private static readonly Dictionary<SequenceState, Action> stateHandlers =
|
||||
new Dictionary<SequenceState, Action> { { SequenceState.INACTIVE, HandleInactive },
|
||||
{ SequenceState.WAITING_FOR_EVENT, HandleWaitingForEvent },
|
||||
{ SequenceState.WAITING_TO_ADVANCE, HandleWaitingToAdvance },
|
||||
{ SequenceState.ADVANCE, HandleAdvance } };
|
||||
|
||||
private static void HandleInactive() {
|
||||
// Inactive state - do nothing
|
||||
}
|
||||
|
||||
private static void HandleWaitingForEvent() {
|
||||
// Event happened, transition to waiting to advance
|
||||
Console.WriteLine($"Event detected in state: {CurrentState}, transitioning to WAITING_TO_ADVANCE");
|
||||
CurrentState = SequenceState.WAITING_TO_ADVANCE;
|
||||
Console.WriteLine($"State changed to: {CurrentState}");
|
||||
HandleWaitingToAdvance();
|
||||
}
|
||||
|
||||
private static void HandleWaitingToAdvance() {
|
||||
// Start timer to advance after N milliseconds
|
||||
Console.WriteLine($"Starting {SequenceTimerDelay}ms timer in WAITING_TO_ADVANCE state");
|
||||
Task.Delay(SequenceTimerDelay)
|
||||
.ContinueWith(
|
||||
_ => {
|
||||
if (CurrentState == SequenceState.WAITING_TO_ADVANCE) {
|
||||
CurrentState = SequenceState.ADVANCE;
|
||||
Console.WriteLine($"Timer expired, transitioning to ADVANCE state");
|
||||
HandleSequenceEvent();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void HandleAdvance() {
|
||||
Console.WriteLine($"Advancing sequence from ADVANCE state");
|
||||
|
||||
CurrentSequenceIndex++;
|
||||
Console.WriteLine($"Advanced to index {CurrentSequenceIndex}");
|
||||
|
||||
// Get the actual last index for this sequence (computed or user-set)
|
||||
int sequenceLastIndex = (LastIndex != -1) ? LastIndex : FindLastNonNullWindow();
|
||||
|
||||
if (CurrentSequenceIndex > sequenceLastIndex) {
|
||||
// End of sequence - tab back to first
|
||||
int sequenceFirstIndex = (FirstIndex != -1) ? FirstIndex : FindFirstNonNullWindow();
|
||||
Console.WriteLine("End of sequence reached, tabbing back to first window");
|
||||
TabTo(sequenceFirstIndex + 1);
|
||||
ExitSequenceMode();
|
||||
} else {
|
||||
Console.WriteLine($"Tabbing to index {CurrentSequenceIndex + 1}");
|
||||
TabTo(CurrentSequenceIndex + 1);
|
||||
CurrentState = SequenceState.WAITING_FOR_EVENT;
|
||||
Console.WriteLine($"State changed to: {CurrentState}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleSequenceEvent() {
|
||||
stateHandlers[CurrentState]?.Invoke();
|
||||
}
|
||||
|
||||
// Simple list to track last 5 windows
|
||||
private static List<int> lastWindows = new List<int>();
|
||||
|
||||
@@ -26,9 +273,20 @@ namespace DD2Switcher {
|
||||
[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();
|
||||
@@ -36,6 +294,42 @@ namespace DD2Switcher {
|
||||
[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];
|
||||
@@ -222,6 +516,7 @@ namespace DD2Switcher {
|
||||
}
|
||||
|
||||
private static void TabTo(int index) {
|
||||
Console.WriteLine($"TabTo called with index: {index}");
|
||||
index = (index - 1) % NumProc;
|
||||
if (index < 0)
|
||||
index = NumProc - 1;
|
||||
@@ -230,7 +525,29 @@ namespace DD2Switcher {
|
||||
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;
|
||||
@@ -238,19 +555,30 @@ namespace DD2Switcher {
|
||||
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");
|
||||
@@ -284,7 +612,12 @@ namespace DD2Switcher {
|
||||
|
||||
[STAThread]
|
||||
private static void Main() {
|
||||
// AllocConsole();
|
||||
// AllocConsole(); // Enable console for debug output
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
|
||||
// Load settings
|
||||
LoadSettings();
|
||||
|
||||
var processes = Process.GetProcesses();
|
||||
var currentProcess = Process.GetCurrentProcess();
|
||||
@@ -297,6 +630,12 @@ namespace DD2Switcher {
|
||||
|
||||
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) {
|
||||
@@ -314,6 +653,20 @@ namespace DD2Switcher {
|
||||
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);
|
||||
@@ -324,15 +677,48 @@ namespace DD2Switcher {
|
||||
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;
|
||||
@@ -352,9 +738,14 @@ namespace DD2Switcher {
|
||||
}
|
||||
}
|
||||
|
||||
// Console.CancelKeyPress += (sender, e) => { Process.GetCurrentProcess().Kill(); };
|
||||
Application.Run();
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
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