diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a6c2861 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea +**/Debug +**/Properties \ No newline at end of file diff --git a/DD2Switcher.sln b/DD2Switcher.sln new file mode 100644 index 0000000..34f425b --- /dev/null +++ b/DD2Switcher.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DD2Switcher", "DD2Switcher\DD2Switcher.csproj", "{2AC26899-8E27-4B96-85A9-C387186EAD27}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2AC26899-8E27-4B96-85A9-C387186EAD27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2AC26899-8E27-4B96-85A9-C387186EAD27}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2AC26899-8E27-4B96-85A9-C387186EAD27}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2AC26899-8E27-4B96-85A9-C387186EAD27}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/DD2Switcher.sln.DotSettings.user b/DD2Switcher.sln.DotSettings.user new file mode 100644 index 0000000..f591ba1 --- /dev/null +++ b/DD2Switcher.sln.DotSettings.user @@ -0,0 +1,2 @@ + + INFO \ No newline at end of file diff --git a/DD2Switcher/App.config b/DD2Switcher/App.config new file mode 100644 index 0000000..8ec5bdd --- /dev/null +++ b/DD2Switcher/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/DD2Switcher/DD2Switcher.csproj b/DD2Switcher/DD2Switcher.csproj new file mode 100644 index 0000000..03cf883 --- /dev/null +++ b/DD2Switcher/DD2Switcher.csproj @@ -0,0 +1,82 @@ + + + + + Debug + AnyCPU + {2AC26899-8E27-4B96-85A9-C387186EAD27} + WinExe + DD2Switcher + DD2Switcher + v4.0 + 512 + true + true + latest + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + Form + + + Form1.cs + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + \ No newline at end of file diff --git a/DD2Switcher/Form1.Designer.cs b/DD2Switcher/Form1.Designer.cs new file mode 100644 index 0000000..9a8be34 --- /dev/null +++ b/DD2Switcher/Form1.Designer.cs @@ -0,0 +1,40 @@ +namespace DD2Switcher +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Text = "Form1"; + } + + #endregion + } +} \ No newline at end of file diff --git a/DD2Switcher/Form1.cs b/DD2Switcher/Form1.cs new file mode 100644 index 0000000..f53ed01 --- /dev/null +++ b/DD2Switcher/Form1.cs @@ -0,0 +1,12 @@ +using System.Windows.Forms; + +namespace DD2Switcher +{ + public partial class Form1 : Form + { + public Form1() + { + InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/DD2Switcher/HotKeyManager.cs b/DD2Switcher/HotKeyManager.cs new file mode 100644 index 0000000..b56d733 --- /dev/null +++ b/DD2Switcher/HotKeyManager.cs @@ -0,0 +1,106 @@ +using System; +using System.Runtime.InteropServices; +using System.Threading; +using System.Windows.Forms; + +namespace DD2Switcher { + public static class HotKeyManager { + private static volatile MessageWindow _wnd; + private static volatile IntPtr _hwnd; + private static readonly ManualResetEvent _windowReadyEvent = new ManualResetEvent(false); + + private static int _id; + + static HotKeyManager() { + var messageLoop = new Thread(delegate() { Application.Run(new MessageWindow()); }); + messageLoop.Name = "MessageLoopThread"; + messageLoop.IsBackground = true; + messageLoop.Start(); + } + + public static event EventHandler 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) { + if (m.Msg == WM_HOTKEY) { + var e = new HotKeyEventArgs(m.LParam); + OnHotKeyPressed(e); + } + + base.WndProc(ref m); + } + + protected override void SetVisibleCore(bool value) { + // Ensure the window never becomes visible + base.SetVisibleCore(false); + } + } + } + + + public class HotKeyEventArgs : EventArgs { + public readonly Keys Key; + public readonly KeyModifiers Modifiers; + + public HotKeyEventArgs(Keys key, KeyModifiers modifiers) { + Key = key; + Modifiers = modifiers; + } + + public HotKeyEventArgs(IntPtr hotKeyParam) { + var param = (uint)hotKeyParam.ToInt64(); + Key = (Keys)((param & 0xffff0000) >> 16); + Modifiers = (KeyModifiers)(param & 0x0000ffff); + } + } + + [Flags] + public enum KeyModifiers { + Alt = 1, + Control = 2, + Shift = 4, + Windows = 8, + NoRepeat = 0x4000 + } +} \ No newline at end of file diff --git a/DD2Switcher/Program.cs b/DD2Switcher/Program.cs new file mode 100644 index 0000000..1bb0265 --- /dev/null +++ b/DD2Switcher/Program.cs @@ -0,0 +1,130 @@ +using System; +using System.Windows.Forms; +using System.Runtime.InteropServices; +using System.Diagnostics; +using System.Drawing; +using System.Threading; + +namespace DD2Switcher { + internal static class Program { + [DllImport("user32.dll")] + static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, UIntPtr dwExtraInfo); + + [DllImport("user32.dll")] + public static extern IntPtr GetForegroundWindow(); + + [DllImport("user32.dll")] + public static extern bool SetForegroundWindow(IntPtr hWnd); + + [DllImport("User32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + static extern bool PrintWindow(IntPtr hwnd, IntPtr hDC, uint nFlags); + + [DllImport("user32.dll")] + static extern bool GetWindowRect(IntPtr handle, ref Rectangle rect); + + [DllImport("user32.dll", SetLastError = true)] + static extern IntPtr FindWindow(string lpClassName, string lpWindowName); + + static Process[] games = Process.GetProcessesByName("Dundefgame"); + static Process activeGame = games[0]; + static int defaultAffinity = 0b100000000000; + + private static void AdjustAffinities() { + int fullAffinity = 0b111111111111; + int i = 0; + foreach (Process game in games) { + if (game != activeGame) { + var processAffinty = defaultAffinity >> i; + fullAffinity = fullAffinity & ~processAffinty; + game.ProcessorAffinity = new IntPtr(processAffinty); + i++; + } + } + activeGame.ProcessorAffinity = new IntPtr(fullAffinity); + } + + private static void AdjustPriorities() { + foreach (Process game in games) { + game.PriorityClass = ProcessPriorityClass.Idle; + } + activeGame.PriorityClass = ProcessPriorityClass.High; + } + + private static void NerfAll() { + int i = 0; + foreach (Process game in games) { + game.ProcessorAffinity = new IntPtr(defaultAffinity >> i); + game.PriorityClass = ProcessPriorityClass.Idle; + i++; + } + } + + private static void SwitchToGame(int index) { + SetForegroundWindow(games[index].MainWindowHandle); + activeGame = games[index]; + AdjustAffinities(); + AdjustPriorities(); + } + + private static void SwitchMainGame() { + IntPtr foregroundWindow = GetForegroundWindow(); + Process foregroundGame = null; + int foregroundGameIndex = -1; + bool exists = false; + + foreach (Process game in games) { + if (foregroundWindow == game.MainWindowHandle) { + exists = true; + foregroundGame = game; + foregroundGameIndex = Array.IndexOf(games, game); + break; + } + } + + if (exists) { + Process tempGame = games[0]; + games[0] = foregroundGame; + games[foregroundGameIndex] = tempGame; + } + } + + [STAThread] + private static void Main() { + HotKeyManager.RegisterHotKey(Keys.D1, KeyModifiers.Alt); + HotKeyManager.RegisterHotKey(Keys.D2, KeyModifiers.Alt); + HotKeyManager.RegisterHotKey(Keys.D3, KeyModifiers.Alt); + HotKeyManager.RegisterHotKey(Keys.D4, KeyModifiers.Alt); + HotKeyManager.RegisterHotKey(Keys.D5, KeyModifiers.Alt); + HotKeyManager.RegisterHotKey(Keys.Q, KeyModifiers.Alt); + HotKeyManager.HotKeyPressed += HotKeyManager_HotKeyPressed; + + static void HotKeyManager_HotKeyPressed(object sender, HotKeyEventArgs e) { + switch (e.Key) { + case Keys.D1: + SwitchToGame(0); + break; + case Keys.D2: + SwitchToGame(1); + break; + case Keys.D3: + SwitchToGame(2); + break; + case Keys.D4: + SwitchToGame(3); + break; + case Keys.D5: + SwitchMainGame(); + break; + case Keys.Q: + NerfAll(); + break; + } + } + + while (true) { + Thread.Sleep(2000); + } + } + } +} \ No newline at end of file