diff --git a/.gitignore b/.gitignore index 3e759b7..aba541f 100644 --- a/.gitignore +++ b/.gitignore @@ -328,3 +328,4 @@ ASALocalRun/ # MFractors (Xamarin productivity tool) working folder .mfractor/ +/UiTests diff --git a/SekiroSpeedrunUtil.sln b/SekiroSpeedrunUtil.sln index 9994b5b..3854080 100644 --- a/SekiroSpeedrunUtil.sln +++ b/SekiroSpeedrunUtil.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.28606.126 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SekiroSpeedrunUtil", "SekiroSpeedrunUtil\SekiroSpeedrunUtil.csproj", "{B3A8E464-E789-42B2-9A20-F7B055790FF8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UiTests", "UiTests\UiTests.csproj", "{BDC316F6-055D-447C-86BD-F510E0A72F72}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +23,14 @@ Global {B3A8E464-E789-42B2-9A20-F7B055790FF8}.Release|Any CPU.Build.0 = Release|Any CPU {B3A8E464-E789-42B2-9A20-F7B055790FF8}.Release|x64.ActiveCfg = Release|x64 {B3A8E464-E789-42B2-9A20-F7B055790FF8}.Release|x64.Build.0 = Release|x64 + {BDC316F6-055D-447C-86BD-F510E0A72F72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BDC316F6-055D-447C-86BD-F510E0A72F72}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BDC316F6-055D-447C-86BD-F510E0A72F72}.Debug|x64.ActiveCfg = Debug|x64 + {BDC316F6-055D-447C-86BD-F510E0A72F72}.Debug|x64.Build.0 = Debug|x64 + {BDC316F6-055D-447C-86BD-F510E0A72F72}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BDC316F6-055D-447C-86BD-F510E0A72F72}.Release|Any CPU.Build.0 = Release|Any CPU + {BDC316F6-055D-447C-86BD-F510E0A72F72}.Release|x64.ActiveCfg = Release|Any CPU + {BDC316F6-055D-447C-86BD-F510E0A72F72}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SekiroSpeedrunUtil/HotKeyManager.cs b/SekiroSpeedrunUtil/HotKeyManager.cs new file mode 100644 index 0000000..f0dbe84 --- /dev/null +++ b/SekiroSpeedrunUtil/HotKeyManager.cs @@ -0,0 +1,93 @@ +using System; +using System.Threading; +using System.Windows.Forms; + +namespace SekiroSpeedrunUtil { + public static class HotKeyManager { + + public static event EventHandler HotKeyPressed; + private static volatile MessageWindow _wnd; + private static volatile IntPtr _hwnd; + private static readonly ManualResetEvent _windowReadyEvent = new ManualResetEvent(false); + + 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 delegate void RegisterHotKeyDelegate(IntPtr hwnd, int id, uint modifiers, uint key); + + private delegate void UnRegisterHotKeyDelegate(IntPtr hwnd, int id); + + private static void RegisterHotKeyInternal(IntPtr hwnd, int id, uint modifiers, uint key) => Native.RegisterHotKey(hwnd, id, modifiers, key); + + private static void UnRegisterHotKeyInternal(IntPtr hwnd, int id) => Native.UnregisterHotKey(_hwnd, id); + + private static void OnHotKeyPressed(HotKeyEventArgs e) => HotKeyPressed?.Invoke(null, e); + + + static HotKeyManager() { + var messageLoop = new Thread(delegate () { + Application.Run(new MessageWindow()); + }) { + Name = "MessageLoopThread", + IsBackground = true + }; + messageLoop.Start(); + } + + private class MessageWindow : Form { + public MessageWindow() { + _wnd = this; + _hwnd = this.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) => base.SetVisibleCore(false); + + private const int WM_HOTKEY = 0x312; + } + + private static int _id; + } + + + public class HotKeyEventArgs : EventArgs + { + public readonly Keys Key; + public readonly KeyModifiers Modifiers; + + public HotKeyEventArgs(Keys key, KeyModifiers modifiers = KeyModifiers.NoRepeat) { + 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 + } +} diff --git a/SekiroSpeedrunUtil/KeyboardHook.cs b/SekiroSpeedrunUtil/KeyboardHook.cs index f0dbe84..be20e84 100644 --- a/SekiroSpeedrunUtil/KeyboardHook.cs +++ b/SekiroSpeedrunUtil/KeyboardHook.cs @@ -1,93 +1,106 @@ using System; -using System.Threading; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; using System.Windows.Forms; +using Newtonsoft.Json; +using SekiroSpeedrunUtil.structs; namespace SekiroSpeedrunUtil { - public static class HotKeyManager { - - public static event EventHandler HotKeyPressed; - private static volatile MessageWindow _wnd; - private static volatile IntPtr _hwnd; - private static readonly ManualResetEvent _windowReadyEvent = new ManualResetEvent(false); - - 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 class KeyboardHook : IDisposable { - public static void UnregisterHotKey(int id) => _wnd.Invoke(new UnRegisterHotKeyDelegate(UnRegisterHotKeyInternal), _hwnd, id); + //private List _hotkeys; - private delegate void RegisterHotKeyDelegate(IntPtr hwnd, int id, uint modifiers, uint key); + public KeyboardHook() { + _keyboardProc = Callback; + /* + _keyboardProc = Callback; + var hotkeyFile = "hotkeys2.json"; + if (File.Exists($"{Utils.DataDir()}/hotkeys2.json")) hotkeyFile = $"{Utils.DataDir()}/hotkeys2.json"; - private delegate void UnRegisterHotKeyDelegate(IntPtr hwnd, int id); + _hotkeys = JsonConvert.DeserializeObject >(File.ReadAllText(hotkeyFile)); + */ + } - private static void RegisterHotKeyInternal(IntPtr hwnd, int id, uint modifiers, uint key) => Native.RegisterHotKey(hwnd, id, modifiers, key); + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern IntPtr SetWindowsHookEx(int idHook, KeyboardHook.KeyboardProc lpfn, IntPtr hMod, uint dwThreadId); - private static void UnRegisterHotKeyInternal(IntPtr hwnd, int id) => Native.UnregisterHotKey(_hwnd, id); + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool UnhookWindowsHookEx(IntPtr hookId); - private static void OnHotKeyPressed(HotKeyEventArgs e) => HotKeyPressed?.Invoke(null, e); + [DllImport("user32", CallingConvention = CallingConvention.StdCall)] + public static extern IntPtr CallNextHookEx(IntPtr hookId, int nCode, IntPtr wParam, IntPtr lParam); - - static HotKeyManager() { - var messageLoop = new Thread(delegate () { - Application.Run(new MessageWindow()); - }) { - Name = "MessageLoopThread", - IsBackground = true - }; - messageLoop.Start(); - } + [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + public static extern short GetKeyState(int keyCode); - private class MessageWindow : Form { - public MessageWindow() { - _wnd = this; - _hwnd = this.Handle; - _windowReadyEvent.Set(); - } + //Modifier key vkCode constants + private const int VK_SHIFT = 0x10; + private const int VK_CONTROL = 0x11; + private const int VK_MENU = 0x12; + private const int VK_CAPITAL = 0x14; - protected override void WndProc(ref Message m) { - if (m.Msg == WM_HOTKEY) { - var e = new HotKeyEventArgs(m.LParam); - OnHotKeyPressed(e); - } + private const int WH_KEYBOARD_LL = 13; + private const int WM_KEYDOWN = 0x0100; - base.WndProc(ref m); - } + public delegate IntPtr KeyboardProc(int nCode, IntPtr wParam, IntPtr lParam); + + private Keys GetModifiers () { + var key = new Keys(); + if ((GetKeyState(VK_SHIFT) & 0x8000) != 0) key |= Keys.Shift; + if ((GetKeyState(VK_CONTROL) & 0x8000) != 0) key |= Keys.Control; + if ((GetKeyState(VK_MENU) & 0x8000) != 0) key |= Keys.Alt; + return key; + } + + public event EventHandler OnKeyPressed; - protected override void SetVisibleCore(bool value) => base.SetVisibleCore(false); + private static KeyboardProc _keyboardProc; + private IntPtr _hookId = IntPtr.Zero; - private const int WM_HOTKEY = 0x312; + public void Hook() { + _hookId = SetWindowsHookEx(WH_KEYBOARD_LL, _keyboardProc, IntPtr.Zero, 0); } - private static int _id; - } + private IntPtr Callback(int nCode, IntPtr wParam, IntPtr lParam) { + if(nCode < 0 || wParam != (IntPtr)WM_KEYDOWN) return CallNextHookEx(_hookId, nCode, wParam, lParam); - public class HotKeyEventArgs : EventArgs - { - public readonly Keys Key; - public readonly KeyModifiers Modifiers; + try { + var vkCode = Marshal.ReadInt32(lParam); + var eargs = new KeyPressEventArgs { + KeyPressed = (Keys)vkCode, + Modifiers = GetModifiers() + }; + var modifiers = GetModifiers(); + OnKeyPressed?.Invoke(this, eargs); + } catch (Exception ex) { + Diag.WriteLine($"[KeyboardHook] {ex.Message}"); + } - public HotKeyEventArgs(Keys key, KeyModifiers modifiers = KeyModifiers.NoRepeat) { - Key = key; - Modifiers = modifiers; + return CallNextHookEx(_hookId, nCode, wParam, lParam); } - public HotKeyEventArgs(IntPtr hotKeyParam) { - var param = (uint)hotKeyParam.ToInt64(); - Key = (Keys)((param & 0xffff0000) >> 16); - Modifiers = (KeyModifiers)(param & 0x0000ffff); + public void Dispose() { + if (_hookId == IntPtr.Zero) return; + UnhookWindowsHookEx(_hookId); } - } - [Flags] - public enum KeyModifiers { - Alt = 1, - Control = 2, - Shift = 4, - Windows = 8, - NoRepeat = 0x4000 + public struct KeyPressEventArgs { + public Keys KeyPressed; + public Keys Modifiers; + } + + /* + public class KeyPressedArgs : EventArgs { + public Key KeyPressed { get; } + + public KeyPressedArgs(Key key) { + KeyPressed = key; + } + } + */ } } diff --git a/SekiroSpeedrunUtil/Properties/AssemblyInfo.cs b/SekiroSpeedrunUtil/Properties/AssemblyInfo.cs index 5423f73..a61b6b7 100644 --- a/SekiroSpeedrunUtil/Properties/AssemblyInfo.cs +++ b/SekiroSpeedrunUtil/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.3.3.0")] -[assembly: AssemblyFileVersion("0.3.3.0")] +[assembly: AssemblyVersion("0.3.4.0")] +[assembly: AssemblyFileVersion("0.3.4.0")] diff --git a/SekiroSpeedrunUtil/SekiroSpeedrunUtil.csproj b/SekiroSpeedrunUtil/SekiroSpeedrunUtil.csproj index 0b8fe8f..4969fbb 100644 --- a/SekiroSpeedrunUtil/SekiroSpeedrunUtil.csproj +++ b/SekiroSpeedrunUtil/SekiroSpeedrunUtil.csproj @@ -128,11 +128,13 @@ + + diff --git a/SekiroSpeedrunUtil/hotkeys.json b/SekiroSpeedrunUtil/hotkeys.json index 56f4bdb..1cb54f8 100644 --- a/SekiroSpeedrunUtil/hotkeys.json +++ b/SekiroSpeedrunUtil/hotkeys.json @@ -3,36 +3,48 @@ "HotkeyString": "Shift+F1", "Name": "SaveCurrentCoordinates", "Key": 112, - "Modifiers": 4 + "Modifiers": 65536, + "Invalid": false, + "Unset": false }, { "HotkeyString": "Shift+F2", "Name": "TeleportToCoordinates", "Key": 113, - "Modifiers": 4 + "Modifiers": 65536, + "Invalid": false, + "Unset": false }, { "HotkeyString": "Shift+F3", "Name": "BackupSave", "Key": 114, - "Modifiers": 4 + "Modifiers": 65536, + "Invalid": false, + "Unset": false }, { "HotkeyString": "Shift+F4", "Name": "LoadSave", "Key": 115, - "Modifiers": 4 + "Modifiers": 65536, + "Invalid": false, + "Unset": false }, { "HotkeyString": "Shift+F5", "Name": "LoadLastQuickSave", "Key": 116, - "Modifiers": 4 + "Modifiers": 65536, + "Invalid": false, + "Unset": false }, { "HotkeyString": "Shift+F6", "Name": "ForceQuit", "Key": 117, - "Modifiers": 4 + "Modifiers": 65536, + "Invalid": false, + "Unset": false } ] \ No newline at end of file diff --git a/SekiroSpeedrunUtil/structs/Hotkey.cs b/SekiroSpeedrunUtil/structs/Hotkey.cs new file mode 100644 index 0000000..cc309b2 --- /dev/null +++ b/SekiroSpeedrunUtil/structs/Hotkey.cs @@ -0,0 +1,12 @@ +using System.Windows.Forms; + +namespace SekiroSpeedrunUtil.structs { + public class Hotkey { + public string HotkeyString; + public string Name; + public Keys Key; + public Keys Modifiers; + public bool Invalid; + public bool Unset; + } +} diff --git a/SekiroSpeedrunUtil/ui/FormMain.Designer.cs b/SekiroSpeedrunUtil/ui/FormMain.Designer.cs index 801471c..e57203b 100644 --- a/SekiroSpeedrunUtil/ui/FormMain.Designer.cs +++ b/SekiroSpeedrunUtil/ui/FormMain.Designer.cs @@ -31,6 +31,9 @@ private void InitializeComponent() { System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle4 = new System.Windows.Forms.DataGridViewCellStyle(); System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle5 = new System.Windows.Forms.DataGridViewCellStyle(); System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle6 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.TreeNode treeNode1 = new System.Windows.Forms.TreeNode("Something"); + System.Windows.Forms.TreeNode treeNode2 = new System.Windows.Forms.TreeNode("Render Flags", new System.Windows.Forms.TreeNode[] { + treeNode1}); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormMain)); this.btnTest = new MetroFramework.Controls.MetroButton(); this.cboxAreaTeleport = new MetroFramework.Controls.MetroComboBox(); @@ -83,6 +86,7 @@ private void InitializeComponent() { this.tabPage1 = new MetroFramework.Controls.MetroTabPage(); this.pageHotkeys = new MetroFramework.Controls.MetroTabPage(); this.metroPanel4 = new MetroFramework.Controls.MetroPanel(); + this.metroLabel20 = new MetroFramework.Controls.MetroLabel(); this.btnRemoveFlagToggle = new MetroFramework.Controls.MetroButton(); this.btnAddFlagToggle = new MetroFramework.Controls.MetroButton(); this.flagToggleList = new MetroFramework.Controls.MetroListView(); @@ -102,6 +106,7 @@ private void InitializeComponent() { this.hotkeySaveCurrentCoordinates = new MetroFramework.Controls.MetroTextBox(); this.metroLabel9 = new MetroFramework.Controls.MetroLabel(); this.tabSaveManager = new MetroFramework.Controls.MetroTabPage(); + this.quitOnLoad = new MetroFramework.Controls.MetroCheckBox(); this.smPseudoReadonly = new MetroFramework.Controls.MetroCheckBox(); this.smQuickSave = new MetroFramework.Controls.MetroTextBox(); this.metroLabel15 = new MetroFramework.Controls.MetroLabel(); @@ -134,11 +139,13 @@ private void InitializeComponent() { this.dataGridViewTextBoxColumn2 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.metroTabPage2 = new MetroFramework.Controls.MetroTabPage(); this.tbDebug = new MetroFramework.Controls.MetroTextBox(); + this.metroTabPage5 = new MetroFramework.Controls.MetroTabPage(); + this.treeView1 = new System.Windows.Forms.TreeView(); this.toast = new MetroFramework.Controls.MetroPanel(); this.toastMsg = new MetroFramework.Controls.MetroLabel(); this.btnInfo = new MetroFramework.Controls.MetroLink(); this.lblTinyTitle = new MetroFramework.Controls.MetroLabel(); - this.metroLabel20 = new MetroFramework.Controls.MetroLabel(); + this.metroLabel21 = new MetroFramework.Controls.MetroLabel(); this.groupBox4.SuspendLayout(); this.metroPanel1.SuspendLayout(); this.metroPanel3.SuspendLayout(); @@ -154,6 +161,7 @@ private void InitializeComponent() { this.metroTabPage4.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.injectorGrid)).BeginInit(); this.metroTabPage2.SuspendLayout(); + this.metroTabPage5.SuspendLayout(); this.toast.SuspendLayout(); this.SuspendLayout(); // @@ -885,6 +893,7 @@ private void InitializeComponent() { this.mainTabControl.Controls.Add(this.metroTabPage1); this.mainTabControl.Controls.Add(this.metroTabPage4); this.mainTabControl.Controls.Add(this.metroTabPage2); + this.mainTabControl.Controls.Add(this.metroTabPage5); this.mainTabControl.ItemSize = new System.Drawing.Size(50, 30); this.mainTabControl.Location = new System.Drawing.Point(23, 73); this.mainTabControl.Name = "mainTabControl"; @@ -934,6 +943,7 @@ private void InitializeComponent() { // // metroPanel4 // + this.metroPanel4.Controls.Add(this.metroLabel21); this.metroPanel4.Controls.Add(this.metroLabel20); this.metroPanel4.Controls.Add(this.btnRemoveFlagToggle); this.metroPanel4.Controls.Add(this.btnAddFlagToggle); @@ -966,6 +976,19 @@ private void InitializeComponent() { this.metroPanel4.VerticalScrollbarHighlightOnWheel = false; this.metroPanel4.VerticalScrollbarSize = 10; // + // metroLabel20 + // + this.metroLabel20.AutoSize = true; + this.metroLabel20.Enabled = false; + this.metroLabel20.Location = new System.Drawing.Point(383, 48); + this.metroLabel20.Name = "metroLabel20"; + this.metroLabel20.Size = new System.Drawing.Size(97, 19); + this.metroLabel20.Style = MetroFramework.MetroColorStyle.Teal; + this.metroLabel20.TabIndex = 34; + this.metroLabel20.Text = "Flags to toggle"; + this.metroLabel20.Theme = MetroFramework.MetroThemeStyle.Dark; + this.metroLabel20.Visible = false; + // // btnRemoveFlagToggle // this.btnRemoveFlagToggle.Enabled = false; @@ -1362,6 +1385,7 @@ private void InitializeComponent() { // tabSaveManager // this.tabSaveManager.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(17)))), ((int)(((byte)(17)))), ((int)(((byte)(17))))); + this.tabSaveManager.Controls.Add(this.quitOnLoad); this.tabSaveManager.Controls.Add(this.smPseudoReadonly); this.tabSaveManager.Controls.Add(this.smQuickSave); this.tabSaveManager.Controls.Add(this.metroLabel15); @@ -1387,6 +1411,19 @@ private void InitializeComponent() { this.tabSaveManager.VerticalScrollbarHighlightOnWheel = false; this.tabSaveManager.VerticalScrollbarSize = 10; // + // quitOnLoad + // + this.quitOnLoad.AutoSize = true; + this.quitOnLoad.CheckAlign = System.Drawing.ContentAlignment.MiddleRight; + this.quitOnLoad.Location = new System.Drawing.Point(477, 338); + this.quitOnLoad.Name = "quitOnLoad"; + this.quitOnLoad.Size = new System.Drawing.Size(89, 15); + this.quitOnLoad.Style = MetroFramework.MetroColorStyle.Yellow; + this.quitOnLoad.TabIndex = 34; + this.quitOnLoad.Text = "Quit on load"; + this.quitOnLoad.Theme = MetroFramework.MetroThemeStyle.Dark; + this.quitOnLoad.UseSelectable = true; + // // smPseudoReadonly // this.smPseudoReadonly.AutoSize = true; @@ -1452,7 +1489,7 @@ private void InitializeComponent() { this.metroLabel14.FontWeight = MetroFramework.MetroLabelWeight.Bold; this.metroLabel14.Location = new System.Drawing.Point(235, 301); this.metroLabel14.Name = "metroLabel14"; - this.metroLabel14.Size = new System.Drawing.Size(297, 23); + this.metroLabel14.Size = new System.Drawing.Size(221, 23); this.metroLabel14.Style = MetroFramework.MetroColorStyle.Teal; this.metroLabel14.TabIndex = 30; this.metroLabel14.Text = "Doubleclick a save to rename"; @@ -1461,9 +1498,9 @@ private void InitializeComponent() { // // smDelete // - this.smDelete.Location = new System.Drawing.Point(441, 330); + this.smDelete.Location = new System.Drawing.Point(361, 330); this.smDelete.Name = "smDelete"; - this.smDelete.Size = new System.Drawing.Size(95, 23); + this.smDelete.Size = new System.Drawing.Size(63, 23); this.smDelete.Style = MetroFramework.MetroColorStyle.Teal; this.smDelete.TabIndex = 20; this.smDelete.Text = "Delete"; @@ -1473,9 +1510,9 @@ private void InitializeComponent() { // // smLoad // - this.smLoad.Location = new System.Drawing.Point(340, 330); + this.smLoad.Location = new System.Drawing.Point(300, 330); this.smLoad.Name = "smLoad"; - this.smLoad.Size = new System.Drawing.Size(95, 23); + this.smLoad.Size = new System.Drawing.Size(55, 23); this.smLoad.Style = MetroFramework.MetroColorStyle.Teal; this.smLoad.TabIndex = 19; this.smLoad.Text = "Load"; @@ -1487,7 +1524,7 @@ private void InitializeComponent() { // this.smSave.Location = new System.Drawing.Point(239, 330); this.smSave.Name = "smSave"; - this.smSave.Size = new System.Drawing.Size(95, 23); + this.smSave.Size = new System.Drawing.Size(55, 23); this.smSave.Style = MetroFramework.MetroColorStyle.Teal; this.smSave.TabIndex = 18; this.smSave.Text = "Save"; @@ -1930,6 +1967,34 @@ private void InitializeComponent() { this.tbDebug.WaterMarkColor = System.Drawing.Color.FromArgb(((int)(((byte)(109)))), ((int)(((byte)(109)))), ((int)(((byte)(109))))); this.tbDebug.WaterMarkFont = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Pixel); // + // metroTabPage5 + // + this.metroTabPage5.Controls.Add(this.treeView1); + this.metroTabPage5.HorizontalScrollbarBarColor = true; + this.metroTabPage5.HorizontalScrollbarHighlightOnWheel = false; + this.metroTabPage5.HorizontalScrollbarSize = 10; + this.metroTabPage5.Location = new System.Drawing.Point(4, 34); + this.metroTabPage5.Name = "metroTabPage5"; + this.metroTabPage5.Size = new System.Drawing.Size(792, 362); + this.metroTabPage5.TabIndex = 8; + this.metroTabPage5.Text = "metroTabPage5"; + this.metroTabPage5.VerticalScrollbarBarColor = true; + this.metroTabPage5.VerticalScrollbarHighlightOnWheel = false; + this.metroTabPage5.VerticalScrollbarSize = 10; + // + // treeView1 + // + this.treeView1.Location = new System.Drawing.Point(3, 3); + this.treeView1.Name = "treeView1"; + treeNode1.Name = "Node1"; + treeNode1.Text = "Something"; + treeNode2.Name = "Node0"; + treeNode2.Text = "Render Flags"; + this.treeView1.Nodes.AddRange(new System.Windows.Forms.TreeNode[] { + treeNode2}); + this.treeView1.Size = new System.Drawing.Size(786, 356); + this.treeView1.TabIndex = 2; + // // toast // this.toast.Controls.Add(this.toastMsg); @@ -1983,18 +2048,16 @@ private void InitializeComponent() { this.lblTinyTitle.Theme = MetroFramework.MetroThemeStyle.Dark; this.lblTinyTitle.Visible = false; // - // metroLabel20 + // metroLabel21 // - this.metroLabel20.AutoSize = true; - this.metroLabel20.Enabled = false; - this.metroLabel20.Location = new System.Drawing.Point(383, 48); - this.metroLabel20.Name = "metroLabel20"; - this.metroLabel20.Size = new System.Drawing.Size(97, 19); - this.metroLabel20.Style = MetroFramework.MetroColorStyle.Teal; - this.metroLabel20.TabIndex = 34; - this.metroLabel20.Text = "Flags to toggle"; - this.metroLabel20.Theme = MetroFramework.MetroThemeStyle.Dark; - this.metroLabel20.Visible = false; + this.metroLabel21.AutoSize = true; + this.metroLabel21.Location = new System.Drawing.Point(13, 33); + this.metroLabel21.Name = "metroLabel21"; + this.metroLabel21.Size = new System.Drawing.Size(309, 19); + this.metroLabel21.Style = MetroFramework.MetroColorStyle.Teal; + this.metroLabel21.TabIndex = 35; + this.metroLabel21.Text = "Press ESC to remove hotkey while hotkey is focused"; + this.metroLabel21.Theme = MetroFramework.MetroThemeStyle.Dark; // // FormMain // @@ -2041,6 +2104,7 @@ private void InitializeComponent() { this.metroTabPage4.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.injectorGrid)).EndInit(); this.metroTabPage2.ResumeLayout(false); + this.metroTabPage5.ResumeLayout(false); this.toast.ResumeLayout(false); this.ResumeLayout(false); this.PerformLayout(); @@ -2156,5 +2220,9 @@ private void InitializeComponent() { private MetroFramework.Controls.MetroButton btnAddFlagToggle; private MetroFramework.Controls.MetroListView flagToggleList; private MetroFramework.Controls.MetroLabel metroLabel20; + private MetroFramework.Controls.MetroTabPage metroTabPage5; + private System.Windows.Forms.TreeView treeView1; + private MetroFramework.Controls.MetroCheckBox quitOnLoad; + private MetroFramework.Controls.MetroLabel metroLabel21; } } \ No newline at end of file diff --git a/SekiroSpeedrunUtil/ui/FormMain.cs b/SekiroSpeedrunUtil/ui/FormMain.cs index 3807596..5904e88 100644 --- a/SekiroSpeedrunUtil/ui/FormMain.cs +++ b/SekiroSpeedrunUtil/ui/FormMain.cs @@ -111,8 +111,11 @@ private void FormMain_Load(object sender, EventArgs e) { _mouseDetector = new MouseDetector(); } + private bool _toasting; private void Toast(string msg, Color background, Color foreground, SystemSound sound = null) { if (Height <= 100) return; + if (_toasting) return; + _toasting = true; if (cbToastSounds.Checked) { if (sound == null) sound = SystemSounds.Asterisk; sound.Play(); @@ -125,7 +128,7 @@ private void Toast(string msg, Color background, Color foreground, SystemSound s toast.Show(); toast.SlideToDestination(430, 2, () => { Thread.Sleep(3000); - toast.SlideToDestination(520, 2, () => {}); + toast.SlideToDestination(520, 2, () => { _toasting = false;}); }); }); }); diff --git a/SekiroSpeedrunUtil/ui/FormMainHotkeys.cs b/SekiroSpeedrunUtil/ui/FormMainHotkeys.cs index 499f751..8e2d99e 100644 --- a/SekiroSpeedrunUtil/ui/FormMainHotkeys.cs +++ b/SekiroSpeedrunUtil/ui/FormMainHotkeys.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Windows.Forms; using Newtonsoft.Json; +using SekiroSpeedrunUtil.structs; namespace SekiroSpeedrunUtil.ui { public partial class FormMain { @@ -15,7 +17,126 @@ public partial class FormMain { private HotkeyStruct _forceQuit; private HotkeyStruct _flagToggle; + private KeyboardHook _keyboardHook; + private List _hotkeys; + public void InitHotkeys() { + Diag.WriteLine("Init Hotkeys"); + mainTabControl.SelectedIndexChanged += (sender, args) => { + _hotkeysDisabled = mainTabControl.SelectedIndex == 1; + }; + _keyboardHook = new KeyboardHook(); + _keyboardHook.OnKeyPressed += OnKeyPressed; + + _keyboardHook.Hook(); + FormClosing += (sender, args) => _keyboardHook.Dispose(); + + var defaultHotkeys = JsonConvert.DeserializeObject>(File.ReadAllText("hotkeys.json")); + _hotkeys = defaultHotkeys; + if (File.Exists($@"{Utils.DataDir()}/hotkeysv2.json")) { + var userHotkeys = JsonConvert.DeserializeObject(File.ReadAllText($@"{Utils.DataDir()}/hotkeysv2.json")); + foreach (var userHotkey in userHotkeys) { + var index = HotkeyIndex(userHotkey.Name); + if (index < 0) { + _hotkeys.Add(userHotkey); + continue; + } + + ReplaceHotkey(userHotkey.Name, userHotkey); + } + } + + foreach (var hotkey in _hotkeys) { + switch (hotkey.Name) { + case "SaveCurrentCoordinates": + hotkeySaveCurrentCoordinates.InvokeIfRequired(() => { + hotkeySaveCurrentCoordinates.Text = hotkey.HotkeyString; + }); + break; + case "TeleportToCoordinates": + hotkeyTeleportToCoordinates.InvokeIfRequired(() => { + hotkeyTeleportToCoordinates.Text = hotkey.HotkeyString; + }); + break; + case "LoadSave": + hotkeyLoadSave.InvokeIfRequired(() => { + hotkeyLoadSave.Text = hotkey.HotkeyString; + }); + break; + case "BackupSave": + hotkeyBackupSave.InvokeIfRequired(() => { + hotkeyBackupSave.Text = hotkey.HotkeyString; + }); + break; + case "LoadLastQuickSave": + hotkeyLoadQuick.InvokeIfRequired(() => { + hotkeyLoadQuick.Text = hotkey.HotkeyString; + }); + break; + case "ForceQuit": + hotkeyQuit.InvokeIfRequired(() => { + hotkeyQuit.Text = hotkey.HotkeyString; + }); + break; + } + } + + hotkeySaveCurrentCoordinates.KeyDown += HotkeySaveCurrentCoordinatesOnKeyDown; + hotkeyTeleportToCoordinates.KeyDown += HotkeyTeleportToCoordinatesOnKeyDown; + hotkeyBackupSave.KeyDown += HotkeyBackupSaveOnKeyDown; + hotkeyLoadSave.KeyDown += HotkeyLoadSaveOnKeyDown; + hotkeyLoadQuick.KeyDown += HotkeyLoadQuickOnKeyDown; + hotkeyQuit.KeyDown += HotkeyQuitOnKeyDown; + } + + private Hotkey HotkeyByName(string name) { + return _hotkeys.Find(hk => hk.Name == name); + } + + private int HotkeyIndex(string name) { + return _hotkeys.FindIndex(hk => hk.Name == name); + } + + private void ReplaceHotkey(string name, Hotkey hotkey) { + var index = HotkeyIndex(name); + _hotkeys[index] = hotkey; + SaveHotkeys2(); + } + + private bool _hotkeysDisabled; + private void OnKeyPressed(object sender, KeyboardHook.KeyPressEventArgs e) { + if (_hotkeysDisabled) return; + foreach (var hotkey in _hotkeys) { + if(hotkey.Unset || hotkey.Key != e.KeyPressed || hotkey.Modifiers != e.Modifiers) continue; + HotkeyPressed(hotkey); + return; + } + } + + private void HotkeyPressed(Hotkey hotkey) { + switch (hotkey.Name) { + case "SaveCurrentCoordinates": + btnLoadCurrentCoords.InvokeIfRequired(() => btnLoadCurrentCoords.PerformClick()); + break; + case "TeleportToCoordinates": + btnTeleportToCoordinates.InvokeIfRequired(() => btnTeleportToCoordinates.PerformClick()); + break; + case "BackupSave": + QuickSave(); + break; + case "LoadSave": + QuickLoad(); + break; + case "LoadLastQuickSave": + QuickLoadQuick(); + break; + case "ForceQuit": + ForceQuit(); + break; + } + } + + public void InitHotkeys2() { var hotkeyFile = "hotkeys.json"; if (File.Exists($"{Utils.DataDir()}/hotkeys.json")) hotkeyFile = $"{Utils.DataDir()}/hotkeys.json"; @@ -126,91 +247,84 @@ private void FlagToggleOnKeyDown(object sender, KeyEventArgs e) { } private void HotkeyQuitOnKeyDown(object sender, KeyEventArgs e) { - var hotkey = ResolveHotkey(e); + const string hkName = "ForceQuit"; + var hotkey = ResolveHotkeyNew(e, hkName); if (hotkey.Invalid) return; - if (hotkey.Clear) { - hotkeyQuit.Text = ""; - metroLabel9.Focus(); - return; - } hotkeyQuit.Text = hotkey.HotkeyString; - if (_loadSave.Id > 0) { - HotKeyManager.UnregisterHotKey(_forceQuit.Id); + ReplaceHotkey(hkName, hotkey); + metroLabel9.Focus(); + } + + private Hotkey ResolveHotkeyNew(KeyEventArgs e, string name) { + var converter = new KeysConverter(); + var keyString = converter.ConvertToString(e.KeyCode); + + switch (e.KeyCode) { + case Keys.Escape: + return new Hotkey { + HotkeyString = "Not Set", + Name = name, + Unset = true + }; + // Ignore modifier only + case Keys.Shift: + case Keys.ShiftKey: + case Keys.Control: + case Keys.ControlKey: + case Keys.Alt: + case Keys.Menu: + case Keys.LWin: + case Keys.RWin: + case Keys.LMenu: + case Keys.RMenu: + return new Hotkey { Invalid = true }; } - _forceQuit = hotkey; - _forceQuit.Name = "ForceQuit"; - _forceQuit.Id = HotKeyManager.RegisterHotKey(hotkey.Key, hotkey.Modifiers); - metroLabel9.Focus(); - SaveHotkeys(); + if (e.Modifiers != Keys.None) { + keyString = $"{e.Modifiers}+{keyString}"; + } + + return new Hotkey() { + Key = e.KeyCode, + Modifiers = e.Modifiers, + HotkeyString = keyString, + Name = name + }; } private void HotkeyLoadSaveOnKeyDown(object sender, KeyEventArgs e) { - var hotkey = ResolveHotkey(e); + const string hkName = "LoadSave"; + var hotkey = ResolveHotkeyNew(e, hkName); if (hotkey.Invalid) return; - if (hotkey.Clear) { - hotkeyLoadSave.Text = ""; - metroLabel9.Focus(); - return; - } hotkeyLoadSave.Text = hotkey.HotkeyString; - if (_loadSave.Id > 0) { - HotKeyManager.UnregisterHotKey(_loadSave.Id); - } - - _loadSave = hotkey; - _loadSave.Name = "LoadSave"; - _loadSave.Id = HotKeyManager.RegisterHotKey(hotkey.Key, hotkey.Modifiers); + ReplaceHotkey(hkName, hotkey); metroLabel9.Focus(); - SaveHotkeys(); } private void HotkeyLoadQuickOnKeyDown(object sender, KeyEventArgs e) { - var hotkey = ResolveHotkey(e); + const string hkName = "LoadLastQuickSave"; + var hotkey = ResolveHotkeyNew(e, hkName); if (hotkey.Invalid) return; - if (hotkey.Clear) { - hotkeyLoadQuick.Text = ""; - metroLabel9.Focus(); - return; - } hotkeyLoadQuick.Text = hotkey.HotkeyString; - if (_loadQuick.Id > 0) { - HotKeyManager.UnregisterHotKey(_loadQuick.Id); - } - - _loadQuick = hotkey; - _loadQuick.Name = "LoadLastQuickSave"; - _loadQuick.Id = HotKeyManager.RegisterHotKey(hotkey.Key, hotkey.Modifiers); + ReplaceHotkey(hkName, hotkey); metroLabel9.Focus(); - SaveHotkeys(); } private void HotkeyBackupSaveOnKeyDown(object sender, KeyEventArgs e) { - var hotkey = ResolveHotkey(e); + const string hkName = "BackupSave"; + var hotkey = ResolveHotkeyNew(e, hkName); if (hotkey.Invalid) return; - if (hotkey.Clear) { - hotkeyBackupSave.Text = ""; - metroLabel9.Focus(); - return; - } hotkeyBackupSave.Text = hotkey.HotkeyString; - if (_backupSave.Id > 0) { - HotKeyManager.UnregisterHotKey(_backupSave.Id); - } - - _backupSave = hotkey; - _backupSave.Name = "BackupSave"; - _backupSave.Id = HotKeyManager.RegisterHotKey(hotkey.Key, hotkey.Modifiers); + ReplaceHotkey(hkName, hotkey); metroLabel9.Focus(); - SaveHotkeys(); } private void SaveHotkeys() { @@ -225,6 +339,10 @@ private void SaveHotkeys() { })); } + private void SaveHotkeys2() { + File.WriteAllText($"{Utils.DataDir()}/hotkeysv2.json", JsonConvert.SerializeObject(_hotkeys)); + } + private void HotkeyPressed(object sender, HotKeyEventArgs e) { if (e.Key == _saveCurrentCoordinates.Key && e.Modifiers == _saveCurrentCoordinates.Modifiers) { btnLoadCurrentCoords.InvokeIfRequired(() => btnLoadCurrentCoords.PerformClick()); @@ -278,47 +396,25 @@ private void ForceQuit() { } private void HotkeySaveCurrentCoordinatesOnKeyDown(object sender, KeyEventArgs e) { - var hotkey = ResolveHotkey(e); + const string hkName = "SaveCurrentCoordinates"; + var hotkey = ResolveHotkeyNew(e, hkName); if (hotkey.Invalid) return; - if (hotkey.Clear) { - hotkeySaveCurrentCoordinates.Text = ""; - metroLabel9.Focus(); - return; - } hotkeySaveCurrentCoordinates.Text = hotkey.HotkeyString; - if (_saveCurrentCoordinates.Id > 0) { - HotKeyManager.UnregisterHotKey(_saveCurrentCoordinates.Id); - } - - _saveCurrentCoordinates = hotkey; - _saveCurrentCoordinates.Name = "SaveCurrentCoordinates"; - _saveCurrentCoordinates.Id = HotKeyManager.RegisterHotKey(hotkey.Key, hotkey.Modifiers); + ReplaceHotkey(hkName, hotkey); metroLabel9.Focus(); - SaveHotkeys(); } private void HotkeyTeleportToCoordinatesOnKeyDown(object sender, KeyEventArgs e) { - var hotkey = ResolveHotkey(e); + const string hkName = "TeleportToCoordinates"; + var hotkey = ResolveHotkeyNew(e, hkName); if (hotkey.Invalid) return; - if (hotkey.Clear) { - hotkeyTeleportToCoordinates.Text = ""; - metroLabel9.Focus(); - return; - } hotkeyTeleportToCoordinates.Text = hotkey.HotkeyString; - if (_teleportToCoordinates.Id > 0) { - HotKeyManager.UnregisterHotKey(_teleportToCoordinates.Id); - } - - _teleportToCoordinates = hotkey; - _teleportToCoordinates.Name = "TeleportToCoordinates"; - _teleportToCoordinates.Id = HotKeyManager.RegisterHotKey(hotkey.Key, hotkey.Modifiers); + ReplaceHotkey(hkName, hotkey); metroLabel9.Focus(); - SaveHotkeys(); } private static HotkeyStruct ResolveHotkey(KeyEventArgs e) { diff --git a/SekiroSpeedrunUtil/ui/Main.cs b/SekiroSpeedrunUtil/ui/Main.cs index 0101de9..355c982 100644 --- a/SekiroSpeedrunUtil/ui/Main.cs +++ b/SekiroSpeedrunUtil/ui/Main.cs @@ -20,6 +20,7 @@ public partial class FormMain { private void InitLogic() { SetStatus("Loading definitions", Color.OrangeRed); LoadDefs(); + InitHotkeys(); SetStatus("Waiting for Sekiro", Color.OrangeRed); InitItemInjector(); StartProcessThread(); @@ -36,8 +37,6 @@ private void Init() { return; } - InitHotkeys(); - foreach (var flag in Defs.Flags.FastReverse()) { flag.RenderFlag(this); } diff --git a/SekiroSpeedrunUtil/ui/MainSaveMan.cs b/SekiroSpeedrunUtil/ui/MainSaveMan.cs index 61be95d..c7df36f 100644 --- a/SekiroSpeedrunUtil/ui/MainSaveMan.cs +++ b/SekiroSpeedrunUtil/ui/MainSaveMan.cs @@ -103,6 +103,9 @@ private void QuickLoad() { var fPath = $@"{ProfileDir(true)}/{_smQuickLoadLastItem}"; File.Copy(fPath, $@"{_sekiroDir}/S0000.sl2", true); Toast("Quickload Success!", Color.MediumAquamarine, Color.Black); + quitOnLoad.InvokeIfRequired(() => { + if(quitOnLoad.Checked) ForceQuit(); + }); } catch (Exception ex) { MetroMessageBox.Show(this, ex.Message, @@ -119,6 +122,9 @@ private void QuickLoadQuick() { var fPath = $@"{ProfileDir(true)}/{_smQuickLoadLastQuick}"; File.Copy(fPath, $@"{_sekiroDir}/S0000.sl2", true); Toast("Quickload Success!", Color.MediumAquamarine, Color.Black); + quitOnLoad.InvokeIfRequired(() => { + if (quitOnLoad.Checked) ForceQuit(); + }); } catch (Exception ex) { MetroMessageBox.Show(this, ex.Message, @@ -159,6 +165,9 @@ private void SmLoad_Click(object sender, EventArgs e) { var fPath = $@"{ProfileDir()}/{smSavesList.SelectedItems[0].Text}"; File.Copy(fPath, $@"{_sekiroDir}/S0000.sl2", true); Toast("Save Loaded!", Color.Black, Color.MediumAquamarine); + quitOnLoad.InvokeIfRequired(() => { + if (quitOnLoad.Checked) ForceQuit(); + }); } catch (Exception ex) { MetroMessageBox.Show(this, ex.Message,