From 723a9f16f507193757896b17d31c1e208b1efc6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AD=B1=E5=82=91?= <840465812@qq.com> Date: Wed, 28 Apr 2021 18:43:41 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E5=A2=9E=E5=8A=A0=20=E7=AA=97=E5=8F=A3?= =?UTF-8?q?=E6=8E=A7=E5=88=B6=E5=B8=AE=E5=8A=A9=E7=B1=BB=202.=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20=E7=83=AD=E9=94=AE=E7=BC=96=E8=BE=91=E7=AA=97?= =?UTF-8?q?=E4=BD=93=203.=20=E5=A2=9E=E5=8A=A0=20=E8=BF=9B=E7=A8=8B?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E7=AA=97=E4=BD=93=204.=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=20KeyGo=E6=A0=B8=E5=BF=83=E5=8A=9F=E8=83=BD=E7=B1=BB=205.=20?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=20=E7=83=AD=E9=94=AE=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E5=88=B0XML=E6=96=87=E4=BB=B6IO=206.=20=E5=AE=9E=E7=8E=B0=20?= =?UTF-8?q?=E7=83=AD=E9=94=AE=E6=B3=A8=E5=86=8C=E4=B8=8E=E6=B3=A8=E9=94=80?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- KeyGo/AppControl.cs | 143 ++++++++++++++++++ KeyGo/AppHotKey.cs | 82 +++++------ KeyGo/FormHotKey.Designer.cs | 196 +++++++++++++++++++++++++ KeyGo/FormHotKey.cs | 62 ++++++++ KeyGo/FormHotKey.resx | 123 ++++++++++++++++ KeyGo/FormMain.Designer.cs | 28 ++-- KeyGo/FormMain.cs | 97 +++++++++---- KeyGo/FormProcessSelector.Designer.cs | 127 ++++++++++++++++ KeyGo/FormProcessSelector.cs | 56 ++++++++ KeyGo/FormProcessSelector.resx | 120 ++++++++++++++++ KeyGo/HotKeyItem.cs | 77 ++++++++++ KeyGo/KeyGo.cs | 199 ++++++++++++++++++++++++++ KeyGo/KeyGo.csproj | 24 ++++ KeyGo/Properties/AssemblyInfo.cs | 5 +- 14 files changed, 1247 insertions(+), 92 deletions(-) create mode 100644 KeyGo/AppControl.cs create mode 100644 KeyGo/FormHotKey.Designer.cs create mode 100644 KeyGo/FormHotKey.cs create mode 100644 KeyGo/FormHotKey.resx create mode 100644 KeyGo/FormProcessSelector.Designer.cs create mode 100644 KeyGo/FormProcessSelector.cs create mode 100644 KeyGo/FormProcessSelector.resx create mode 100644 KeyGo/HotKeyItem.cs create mode 100644 KeyGo/KeyGo.cs diff --git a/KeyGo/AppControl.cs b/KeyGo/AppControl.cs new file mode 100644 index 0000000..03905b2 --- /dev/null +++ b/KeyGo/AppControl.cs @@ -0,0 +1,143 @@ +using System; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace KeyGo +{ + public class AppControl + { + /// + /// 获取本应用程序当前正在运行的进程,若不存在则返回null + /// + /// 当前正在运行的进程 + private static Process GetCurrentRunningInstance() + { + Process current = Process.GetCurrentProcess(); + Process[] processes = Process.GetProcessesByName(current.ProcessName); + //遍历与当前进程名称相同的进程列表 + foreach (Process process in processes) + { + //如果实例已经存在则忽略当前进程 + if (process.Id != current.Id) + { + //保证要打开的进程同已经存在的进程来自同一文件路径 + if (Assembly.GetExecutingAssembly().Location.Replace('/', '\\') == current.MainModule.FileName) + { + //返回已经存在的进程 + return process; + } + } + } + return null; + } + + /// + /// 显示指定实例窗体 + /// + /// The instance. + private static void ShowWindow(Process instance) + { + if (instance != null && instance.MainWindowHandle != IntPtr.Zero) + ShowWindowAsync(instance.MainWindowHandle, (int)CmdShow.Show); + //SetForegroundWindow(instance.MainWindowHandle); + } + + /// + /// 隐藏指定实例窗体 + /// + /// The instance. + public static void HideWindow(Process instance) + { + if (instance != null && instance.MainWindowHandle != IntPtr.Zero) + ShowWindowAsync(instance.MainWindowHandle, (int)CmdShow.Hide); + } + + private enum CmdShow : int + { + /// + /// Minimizes a window, even if the thread that owns the window is not responding. + /// This flag should only be used when minimizing windows from a different thread. + /// + ForceMinimize = 11, + + /// + /// Hides the window and activates another window. + /// + Hide = 0, + + /// + /// Maximizes the specified window. + /// + Maximize = 3, + + /// + /// Minimizes the specified window and activates the next top-level window in the Z order. + /// + Minimize = 6, + + /// + /// Activates and displays the window. + /// If the window is minimized or maximized, + /// the system restores it to its original size and position. + /// An application should specify this flag when restoring a minimized window. + /// + Restore = 9, + + /// + /// Activates the window and displays it in its current size and position. + /// + Show = 5, + + /// + /// Sets the show state based on the SW_ value specified in the STARTUPINFO + /// structure passed to the CreateProcess function by the program that started + /// the application. + /// + ShowDefault = 10, + + /// + /// Activates the window and displays it as a maximized window. + /// + ShowMaximized = 3, + + /// + /// Activates the window and displays it as a minimized window. + /// + ShowMinimized = 2, + + /// + /// Displays the window as a minimized window. + /// This value is similar to SW_SHOWMINIMIZED, + /// except the window is not activated. + /// + ShowMinnoActive = 7, + + /// + /// Displays the window in its current size and position. + /// This value is similar to SW_SHOW, except that the window is not activated. + /// + ShowNA = 8, + + /// + /// Displays a window in its most recent size and position. + /// This value is similar to SW_SHOWNORMAL, except that the window is not activated. + /// + ShowNoactivate = 4, + + /// + /// Activates and displays a window. + /// If the window is minimized or maximized, + /// the system restores it to its original size and position. + /// An application should specify this flag when displaying the window for the first time. + /// + ShowNormal= 1, + } + + [DllImport("User32.dll")] + private static extern bool ShowWindowAsync(System.IntPtr hWnd, int cmdShow); + + [DllImport("User32.dll")] + private static extern bool SetForegroundWindow(System.IntPtr hWnd); + } +} \ No newline at end of file diff --git a/KeyGo/AppHotKey.cs b/KeyGo/AppHotKey.cs index a5abd64..6057a51 100644 --- a/KeyGo/AppHotKey.cs +++ b/KeyGo/AppHotKey.cs @@ -1,30 +1,56 @@ using System; -using System.Collections.Generic; using System.ComponentModel; -using System.Linq; using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; namespace KeyGo { public class AppHotKey { - [DllImport("kernel32.dll")] - public static extern uint GetLastError(); + /// + /// 注册热键 + /// + /// 窗口句柄 + /// 热键ID + /// 组合键 + /// 热键 + public static void RegKey(IntPtr hwnd, int hotKey_id, KeyModifiers keyModifiers, Keys key) + { + if (!RegisterHotKey(hwnd, hotKey_id, keyModifiers, key)) + { + throw new Win32Exception(); + //int code = Marshal.GetLastWin32Error(); + //if (code == 1409) + // MessageBox.Show("热键被占用!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + //else + // MessageBox.Show("注册热键失败!错误代码:" + code.ToString(), "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + /// + /// 注销热键 + /// + /// 窗口句柄 + /// 热键ID + public static void UnRegKey(IntPtr hwnd, int hotKey_id) + { + //注销Id号为hotKey_id的热键设定 + UnregisterHotKey(hwnd, hotKey_id); + } + + //如果函数执行成功,返回值不为0。 //如果函数执行失败,返回值为0。要得到扩展错误信息,调用GetLastError。 [DllImport("user32.dll", SetLastError = true)] - public static extern bool RegisterHotKey( + private static extern bool RegisterHotKey( IntPtr hWnd, //要定义热键的窗口的句柄 - int id, //定义热键ID(不能与其它ID重复) + int id, //定义热键ID(不能与其它ID重复) KeyModifiers fsModifiers, //标识热键是否在按Alt、Ctrl、Shift、Windows等键时才会生效 Keys vk //定义热键的内容 ); [DllImport("user32.dll", SetLastError = true)] - public static extern bool UnregisterHotKey( + private static extern bool UnregisterHotKey( IntPtr hWnd, //要取消热键的窗口的句柄 int id //要取消热键的ID ); @@ -39,41 +65,5 @@ namespace KeyGo Shift = 4, WindowsKey = 8 } - /// - /// 注册热键 - /// - /// 窗口句柄 - /// 热键ID - /// 组合键 - /// 热键 - public static void RegKey(IntPtr hwnd, int hotKey_id, KeyModifiers keyModifiers, Keys key) - { - //try - //{ - if (!RegisterHotKey(hwnd, hotKey_id, keyModifiers, key)) - { - throw new Win32Exception(); - //int code = Marshal.GetLastWin32Error(); - //if (code == 1409) - // MessageBox.Show("热键被占用!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); - //else - // MessageBox.Show("注册热键失败!错误代码:" + code.ToString(), "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - //} - //catch (Exception ex) - //{ - // MessageBox.Show("注册热键失败!异常信息:" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); - //} - } - /// - /// 注销热键 - /// - /// 窗口句柄 - /// 热键ID - public static void UnRegKey(IntPtr hwnd, int hotKey_id) - { - //注销Id号为hotKey_id的热键设定 - UnregisterHotKey(hwnd, hotKey_id); - } } -} +} \ No newline at end of file diff --git a/KeyGo/FormHotKey.Designer.cs b/KeyGo/FormHotKey.Designer.cs new file mode 100644 index 0000000..e29f853 --- /dev/null +++ b/KeyGo/FormHotKey.Designer.cs @@ -0,0 +1,196 @@ + +namespace KeyGo +{ + partial class FormHotKey + { + /// + /// 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.BtnAccept = new System.Windows.Forms.Button(); + this.BtnCancel = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.TxtProcessName = new System.Windows.Forms.TextBox(); + this.TxtStartupPath = new System.Windows.Forms.TextBox(); + this.TxtHotKey = new System.Windows.Forms.TextBox(); + this.BtnSelectProcess = new System.Windows.Forms.Button(); + this.BtnSelectStartupPath = new System.Windows.Forms.Button(); + this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); + this.SuspendLayout(); + // + // BtnAccept + // + this.BtnAccept.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.BtnAccept.Location = new System.Drawing.Point(320, 64); + this.BtnAccept.Name = "BtnAccept"; + this.BtnAccept.Size = new System.Drawing.Size(75, 23); + this.BtnAccept.TabIndex = 2; + this.BtnAccept.Text = "确定"; + this.BtnAccept.UseVisualStyleBackColor = true; + this.BtnAccept.Click += new System.EventHandler(this.BtnAccept_Click); + // + // BtnCancel + // + this.BtnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.BtnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.BtnCancel.Location = new System.Drawing.Point(401, 64); + this.BtnCancel.Name = "BtnCancel"; + this.BtnCancel.Size = new System.Drawing.Size(75, 23); + this.BtnCancel.TabIndex = 3; + this.BtnCancel.Text = "取消"; + this.BtnCancel.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(68, 17); + this.label1.TabIndex = 4; + this.label1.Text = "进程名称:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 38); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(68, 17); + this.label3.TabIndex = 6; + this.label3.Text = "启动路径:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 67); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(68, 17); + this.label2.TabIndex = 6; + this.label2.Text = "触发热键:"; + // + // TxtProcessName + // + this.TxtProcessName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.TxtProcessName.Location = new System.Drawing.Point(86, 6); + this.TxtProcessName.Name = "TxtProcessName"; + this.TxtProcessName.Size = new System.Drawing.Size(168, 23); + this.TxtProcessName.TabIndex = 7; + this.toolTip1.SetToolTip(this.TxtProcessName, "应用将通过该名称来查找窗口"); + // + // TxtStartupPath + // + this.TxtStartupPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.TxtStartupPath.Location = new System.Drawing.Point(86, 35); + this.TxtStartupPath.Name = "TxtStartupPath"; + this.TxtStartupPath.Size = new System.Drawing.Size(354, 23); + this.TxtStartupPath.TabIndex = 7; + this.toolTip1.SetToolTip(this.TxtStartupPath, "应用将通过该路径来启动程序"); + // + // TxtHotKey + // + this.TxtHotKey.BackColor = System.Drawing.Color.White; + this.TxtHotKey.Location = new System.Drawing.Point(86, 64); + this.TxtHotKey.Name = "TxtHotKey"; + this.TxtHotKey.ReadOnly = true; + this.TxtHotKey.Size = new System.Drawing.Size(120, 23); + this.TxtHotKey.TabIndex = 7; + this.TxtHotKey.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + this.toolTip1.SetToolTip(this.TxtHotKey, "应用将通过该热键来触发控制"); + this.TxtHotKey.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TxtHotKey_KeyDown); + // + // BtnSelectProcess + // + this.BtnSelectProcess.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.BtnSelectProcess.Location = new System.Drawing.Point(260, 6); + this.BtnSelectProcess.Name = "BtnSelectProcess"; + this.BtnSelectProcess.Size = new System.Drawing.Size(30, 23); + this.BtnSelectProcess.TabIndex = 8; + this.BtnSelectProcess.Text = "..."; + this.toolTip1.SetToolTip(this.BtnSelectProcess, "选择进程获取信息"); + this.BtnSelectProcess.UseVisualStyleBackColor = true; + this.BtnSelectProcess.Click += new System.EventHandler(this.BtnSelectProcess_Click); + // + // BtnSelectStartupPath + // + this.BtnSelectStartupPath.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.BtnSelectStartupPath.Location = new System.Drawing.Point(446, 35); + this.BtnSelectStartupPath.Name = "BtnSelectStartupPath"; + this.BtnSelectStartupPath.Size = new System.Drawing.Size(30, 23); + this.BtnSelectStartupPath.TabIndex = 9; + this.BtnSelectStartupPath.Text = "..."; + this.toolTip1.SetToolTip(this.BtnSelectStartupPath, "手动选择启动文件路径"); + this.BtnSelectStartupPath.UseVisualStyleBackColor = true; + this.BtnSelectStartupPath.Click += new System.EventHandler(this.BtnSelectStartupPath_Click); + // + // FormHotKey + // + this.AcceptButton = this.BtnAccept; + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.BtnCancel; + this.ClientSize = new System.Drawing.Size(488, 99); + this.Controls.Add(this.BtnSelectStartupPath); + this.Controls.Add(this.BtnSelectProcess); + this.Controls.Add(this.TxtHotKey); + this.Controls.Add(this.TxtStartupPath); + this.Controls.Add(this.TxtProcessName); + this.Controls.Add(this.label2); + this.Controls.Add(this.label3); + this.Controls.Add(this.label1); + this.Controls.Add(this.BtnCancel); + this.Controls.Add(this.BtnAccept); + this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "FormHotKey"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "热键设置"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private System.Windows.Forms.Button BtnAccept; + private System.Windows.Forms.Button BtnCancel; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox TxtProcessName; + private System.Windows.Forms.TextBox TxtStartupPath; + private System.Windows.Forms.TextBox TxtHotKey; + private System.Windows.Forms.Button BtnSelectProcess; + private System.Windows.Forms.Button BtnSelectStartupPath; + private System.Windows.Forms.ToolTip toolTip1; + } +} \ No newline at end of file diff --git a/KeyGo/FormHotKey.cs b/KeyGo/FormHotKey.cs new file mode 100644 index 0000000..8903464 --- /dev/null +++ b/KeyGo/FormHotKey.cs @@ -0,0 +1,62 @@ +using System; +using System.Windows.Forms; + +namespace KeyGo +{ + public partial class FormHotKey : Form + { + public FormHotKey() + { + InitializeComponent(); + } + + private void BtnAccept_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.OK; + } + + private void TxtHotKey_KeyDown(object sender, KeyEventArgs e) + { + if (e.Modifiers == Keys.None) + return; + if (e.KeyCode == Keys.ControlKey || e.KeyCode == Keys.ShiftKey || e.KeyCode == Keys.Menu) + return; + + string text = e.KeyCode.ToString(); + if (e.Shift) + text = "Shift+" + text; + if (e.Alt) + text = "Alt+" + text; + if (e.Control) + text = "Ctrl+" + text; + + TxtHotKey.Text = text; + } + + private void BtnSelectProcess_Click(object sender, EventArgs e) + { + var frm = new FormProcessSelector(); + if (frm.ShowDialog() == DialogResult.OK) + { + var p = frm.SelectedItem; + TxtProcessName.Text = p.ProcessName; + TxtStartupPath.Text = p.MainModule.FileName; + } + } + + private void BtnSelectStartupPath_Click(object sender, EventArgs e) + { + var frm = new OpenFileDialog() + { + Title = "请选择启动应用", + Filter = "Exe file (*.exe)|*.exe|All file (*.*)|*.*", + RestoreDirectory = true, + InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), + }; + if (frm.ShowDialog() == DialogResult.OK) + { + TxtStartupPath.Text = frm.FileName; + } + } + } +} \ No newline at end of file diff --git a/KeyGo/FormHotKey.resx b/KeyGo/FormHotKey.resx new file mode 100644 index 0000000..df8339b --- /dev/null +++ b/KeyGo/FormHotKey.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/KeyGo/FormMain.Designer.cs b/KeyGo/FormMain.Designer.cs index 0058ed3..84d69a9 100644 --- a/KeyGo/FormMain.Designer.cs +++ b/KeyGo/FormMain.Designer.cs @@ -29,41 +29,41 @@ namespace KeyGo /// private void InitializeComponent() { - this.TxtHotKey1 = new System.Windows.Forms.TextBox(); + this.BtnTest = new System.Windows.Forms.Button(); this.SuspendLayout(); // - // TxtHotKey1 + // BtnTest // - this.TxtHotKey1.BackColor = System.Drawing.Color.White; - this.TxtHotKey1.Location = new System.Drawing.Point(96, 122); - this.TxtHotKey1.Name = "TxtHotKey1"; - this.TxtHotKey1.ReadOnly = true; - this.TxtHotKey1.Size = new System.Drawing.Size(213, 23); - this.TxtHotKey1.TabIndex = 0; - this.TxtHotKey1.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; - this.TxtHotKey1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TxtHotKey1_KeyDown); + this.BtnTest.Location = new System.Drawing.Point(155, 162); + this.BtnTest.Name = "BtnTest"; + this.BtnTest.Size = new System.Drawing.Size(193, 66); + this.BtnTest.TabIndex = 0; + this.BtnTest.Text = "Test"; + this.BtnTest.UseVisualStyleBackColor = true; + this.BtnTest.Click += new System.EventHandler(this.button1_Click); // // FormMain // this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(482, 315); - this.Controls.Add(this.TxtHotKey1); + this.ClientSize = new System.Drawing.Size(564, 390); + this.Controls.Add(this.BtnTest); this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.MaximizeBox = false; this.Name = "FormMain"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "KeyGo!"; this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FormMain_FormClosed); this.Load += new System.EventHandler(this.FormMain_Load); this.ResumeLayout(false); - this.PerformLayout(); } #endregion - private System.Windows.Forms.TextBox TxtHotKey1; + private System.Windows.Forms.Button BtnTest; } } diff --git a/KeyGo/FormMain.cs b/KeyGo/FormMain.cs index f2acb4c..c861958 100644 --- a/KeyGo/FormMain.cs +++ b/KeyGo/FormMain.cs @@ -2,60 +2,82 @@ using System.Collections.Generic; using System.ComponentModel; using System.Data; +using System.Diagnostics; using System.Drawing; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using System.Xml.Serialization; namespace KeyGo { public partial class FormMain : Form { + static readonly string _DataFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "KeyGo", "HotKey.xml"); + readonly KeyGo _KeyGo; + public FormMain() { InitializeComponent(); + _KeyGo = LoadHotKeyItems(_DataFilePath); + _KeyGo.FormHandle = Handle; + _KeyGo.RegAllKey(); } - - void ProcessHotkey(int hotKey_id) - { - //if (hotKey_id == 100) - // MessageBox.Show("Test"); - } - - - - - - private void TxtHotKey1_KeyDown(object sender, KeyEventArgs e) - { - TxtHotKey1.Text = e.Modifiers.ToString(); - Console.WriteLine($"down\t{e.KeyData}"); - } - - - - - - - - - - private void FormMain_Load(object sender, EventArgs e) { - //AppHotKey.RegKey(Handle, 100, AppHotKey.KeyModifiers.Ctrl, Keys.W); + } + #region 数据文件IO + + private KeyGo LoadHotKeyItems(string xmlFilePath) + { + try + { + return KeyGo.LoadXml(xmlFilePath); + } + catch (Exception ex) + { + MessageBox.Show("载入数据文件异常:" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + return new KeyGo(); + } + + private void SaveHotKeyItems(KeyGo data) + { + try + { + data.SaveXml(_DataFilePath); + } + catch (Exception ex) + { + MessageBox.Show("保存数据文件异常:" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + #endregion + private void FormMain_FormClosed(object sender, FormClosedEventArgs e) { - //AppHotKey.UnRegKey(Handle, 100); + _KeyGo.UnRegAllKey(); } + + + + + + + + + + #region 窗体消息 热键回调 private const int WM_HOTKEY = 0x312; protected override void WndProc(ref Message m) @@ -64,10 +86,27 @@ namespace KeyGo switch (m.Msg) { case WM_HOTKEY: - ProcessHotkey(m.WParam.ToInt32()); + _KeyGo.ProcessHotkey(m.WParam.ToInt32()); break; } } #endregion + + + private void button1_Click(object sender, EventArgs e) + { + //_KeyGo.Items.Add(new HotKeyItem + //{ + // ProcessName = "QQ", + // StartupPath = "", + // HotKey = "Ctrl+Q", + // Enabled = true, + // TriggerCounter = 0, + // CreationTime = DateTime.Now, + // LastModifiedTime = DateTime.Now, + //}); + //SaveHotKeyItems(_KeyGo); + //new FormHotKey().ShowDialog(); + } } } \ No newline at end of file diff --git a/KeyGo/FormProcessSelector.Designer.cs b/KeyGo/FormProcessSelector.Designer.cs new file mode 100644 index 0000000..3041be9 --- /dev/null +++ b/KeyGo/FormProcessSelector.Designer.cs @@ -0,0 +1,127 @@ + +namespace KeyGo +{ + partial class FormProcessSelector + { + /// + /// 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.BtnCancel = new System.Windows.Forms.Button(); + this.BtnAccept = new System.Windows.Forms.Button(); + this.BtnRefresh = new System.Windows.Forms.Button(); + this.CmbProcesses = new System.Windows.Forms.ComboBox(); + this.LblInfo = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // BtnCancel + // + this.BtnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.BtnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.BtnCancel.Location = new System.Drawing.Point(397, 44); + this.BtnCancel.Name = "BtnCancel"; + this.BtnCancel.Size = new System.Drawing.Size(75, 23); + this.BtnCancel.TabIndex = 5; + this.BtnCancel.Text = "取消"; + this.BtnCancel.UseVisualStyleBackColor = true; + // + // BtnAccept + // + this.BtnAccept.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.BtnAccept.Location = new System.Drawing.Point(316, 44); + this.BtnAccept.Name = "BtnAccept"; + this.BtnAccept.Size = new System.Drawing.Size(75, 23); + this.BtnAccept.TabIndex = 4; + this.BtnAccept.Text = "确定"; + this.BtnAccept.UseVisualStyleBackColor = true; + this.BtnAccept.Click += new System.EventHandler(this.BtnAccept_Click); + // + // BtnRefresh + // + this.BtnRefresh.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.BtnRefresh.Location = new System.Drawing.Point(397, 12); + this.BtnRefresh.Name = "BtnRefresh"; + this.BtnRefresh.Size = new System.Drawing.Size(75, 23); + this.BtnRefresh.TabIndex = 7; + this.BtnRefresh.Text = "刷新"; + this.BtnRefresh.UseVisualStyleBackColor = true; + this.BtnRefresh.Click += new System.EventHandler(this.BtnRefresh_Click); + // + // CmbProcesses + // + this.CmbProcesses.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.CmbProcesses.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.CmbProcesses.FormattingEnabled = true; + this.CmbProcesses.Location = new System.Drawing.Point(12, 12); + this.CmbProcesses.Name = "CmbProcesses"; + this.CmbProcesses.Size = new System.Drawing.Size(379, 25); + this.CmbProcesses.TabIndex = 6; + // + // LblInfo + // + this.LblInfo.AutoSize = true; + this.LblInfo.Location = new System.Drawing.Point(9, 47); + this.LblInfo.Name = "LblInfo"; + this.LblInfo.Size = new System.Drawing.Size(0, 17); + this.LblInfo.TabIndex = 8; + // + // FormProcessSelector + // + this.AcceptButton = this.BtnAccept; + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.BtnCancel; + this.ClientSize = new System.Drawing.Size(484, 79); + this.Controls.Add(this.LblInfo); + this.Controls.Add(this.BtnRefresh); + this.Controls.Add(this.CmbProcesses); + this.Controls.Add(this.BtnCancel); + this.Controls.Add(this.BtnAccept); + this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "FormProcessSelector"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "请选择进程"; + this.Load += new System.EventHandler(this.FormProcessSelector_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button BtnCancel; + private System.Windows.Forms.Button BtnAccept; + private System.Windows.Forms.Button BtnRefresh; + private System.Windows.Forms.ComboBox CmbProcesses; + private System.Windows.Forms.Label LblInfo; + } +} \ No newline at end of file diff --git a/KeyGo/FormProcessSelector.cs b/KeyGo/FormProcessSelector.cs new file mode 100644 index 0000000..0321368 --- /dev/null +++ b/KeyGo/FormProcessSelector.cs @@ -0,0 +1,56 @@ +using System; +using System.Data; +using System.Diagnostics; +using System.Linq; +using System.Windows.Forms; + +namespace KeyGo +{ + public partial class FormProcessSelector : Form + { + public FormProcessSelector() + { + InitializeComponent(); + } + + public Process SelectedItem { get; private set; } + + private void FormProcessSelector_Load(object sender, EventArgs e) + { + LoadProcessesInfo(); + } + + private void BtnRefresh_Click(object sender, EventArgs e) + { + LoadProcessesInfo(); + } + + private class VOProcess + { + public string Text { get; set; } + public Process Process { get; set; } + } + + private void LoadProcessesInfo() + { + var processes = Process.GetProcesses().Where(p => p.MainWindowHandle != IntPtr.Zero); + CmbProcesses.BeginUpdate(); + CmbProcesses.DataSource = processes.Select(p => new VOProcess { Text = $"{p.ProcessName} | {p.MainWindowTitle}", Process = p }).ToList(); + CmbProcesses.DisplayMember = "Text"; + CmbProcesses.EndUpdate(); + } + + private void BtnAccept_Click(object sender, EventArgs e) + { + if (CmbProcesses.SelectedItem is VOProcess p) + { + SelectedItem = p.Process; + DialogResult = DialogResult.OK; + } + else + { + MessageBox.Show("未选择进程", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } +} \ No newline at end of file diff --git a/KeyGo/FormProcessSelector.resx b/KeyGo/FormProcessSelector.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/KeyGo/FormProcessSelector.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/KeyGo/HotKeyItem.cs b/KeyGo/HotKeyItem.cs new file mode 100644 index 0000000..fdb75ca --- /dev/null +++ b/KeyGo/HotKeyItem.cs @@ -0,0 +1,77 @@ +using System; +using System.Xml.Serialization; + +namespace KeyGo +{ + /// + /// 热键项 + /// + public class HotKeyItem + { + /// + /// Gets or sets the hot key identifier. + /// + /// + /// The hot key identifier. + /// + [XmlIgnore] + public int HotKeyID { get; set; } + + /// + /// Gets or sets the name of the process. + /// + /// + /// The name of the process. + /// + public string ProcessName { get; set; } + + /// + /// Gets or sets the startup path. + /// + /// + /// The startup path. + /// + public string StartupPath { get; set; } + + /// + /// Gets or sets the hot key. + /// 组合键之间使用+隔开,例如:"Ctrl+Shift+W" + /// + /// + /// The hot key. + /// + public string HotKey { get; set; } + + /// + /// Gets or sets a value indicating whether this is enabled. + /// + /// + /// true if enabled; otherwise, false. + /// + public bool Enabled { get; set; } + + /// + /// Gets or sets the trigger counter. + /// + /// + /// The trigger counter. + /// + public int TriggerCounter { get; set; } + + /// + /// Gets or sets the creation time. + /// + /// + /// The creation time. + /// + public DateTime CreationTime { get; set; } + + /// + /// Gets or sets the last modified time. + /// + /// + /// The last modified time. + /// + public DateTime LastModifiedTime { get; set; } + } +} \ No newline at end of file diff --git a/KeyGo/KeyGo.cs b/KeyGo/KeyGo.cs new file mode 100644 index 0000000..9a5385e --- /dev/null +++ b/KeyGo/KeyGo.cs @@ -0,0 +1,199 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Windows.Forms; +using System.Xml.Serialization; + +namespace KeyGo +{ + public class KeyGo + { + static int _RegMaxID; + + [XmlIgnore] + public IntPtr FormHandle { get; set; } + + public List Items { get; set; } = new List(); + + #region FILE IO + + /// + /// Loads the XML. + /// + /// The file path. + /// + public static KeyGo LoadXml(string filePath) + { + KeyGo data = null; + if (File.Exists(filePath)) + { + XmlSerializer formatter = new XmlSerializer(typeof(KeyGo)); + using (var stream = File.OpenRead(filePath)) + { + if (stream.Length > 0) + { + data = formatter.Deserialize(stream) as KeyGo; + } + } + } + return data; + } + + /// + /// Saves the XML. + /// + /// The file path. + public void SaveXml(string filePath) + { + if (!File.Exists(filePath)) + Directory.CreateDirectory(Path.GetDirectoryName(filePath)); + + XmlSerializer formatter = new XmlSerializer(typeof(KeyGo)); + using (var stream = File.Create(filePath)) + { + formatter.Serialize(stream, this); + } + } + + #endregion + + + /// + /// Processes the hotkey. + /// + /// The hot key identifier. + public void ProcessHotkey(int hotKey_id) + { + var hotkey = Items.Find(k => k.HotKeyID == hotKey_id); + if (hotkey != null) + { + ++hotkey.TriggerCounter; + MessageBox.Show($"ID:{hotkey.HotKeyID}\nKeys:{hotkey.HotKey}\nProcessName:{hotkey.ProcessName}\nStartupPath:{hotkey.StartupPath}", "HotKey", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + } + + + + + #region HotKey Register + + /// + /// Regs all key. + /// + public void RegAllKey() + { + foreach (var item in Items) + { + if (!item.Enabled) + continue; + + try + { + RegKey(item); + } + catch (Exception) + { + // 忽视异常,外部通过ID是否被设置判断执行结果 + } + } + } + + /// + /// Uns the reg all key. + /// + public void UnRegAllKey() + { + foreach (var item in Items) + { + try + { + UnRegKey(item); + } + catch (Exception) + { + // 忽视异常,外部通过ID是否被设置判断执行结果 + } + } + } + + /// + /// 注册热键 - 成功后,会设置 HotKeyID + /// + /// The item. + /// + /// item + /// or + /// HotKey - 热键不能为空! + /// + /// + /// 功能键不能为空! + /// or + /// 快捷键不能为空! + /// + public void RegKey(HotKeyItem item) + { + if (item is null) + throw new ArgumentNullException(nameof(item)); + if (string.IsNullOrWhiteSpace(item.HotKey)) + throw new ArgumentNullException(nameof(item.HotKey), "热键不能为空!"); + + // 如果注册过该热键,ID不为0。卸载热键会将ID置零。 + if (item.HotKeyID != 0) + return; + + int id = Interlocked.Increment(ref _RegMaxID); + + var keys = item.HotKey.Split('+'); + Keys keyCode = Keys.None; + AppHotKey.KeyModifiers keyModifiers = AppHotKey.KeyModifiers.None; + foreach (var key in keys) + { + switch (key.ToLower()) + { + case "ctrl": + keyModifiers |= AppHotKey.KeyModifiers.Ctrl; + break; + case "shift": + keyModifiers |= AppHotKey.KeyModifiers.Shift; + break; + case "alt": + keyModifiers |= AppHotKey.KeyModifiers.Alt; + break; + case "win": + keyModifiers |= AppHotKey.KeyModifiers.WindowsKey; + break; + default: + keyCode = (Keys)Enum.Parse(typeof(Keys), key); + break; + } + } + + if (keyModifiers == AppHotKey.KeyModifiers.None) + throw new InvalidOperationException("功能键不能为空!"); + if (keyCode == Keys.None) + throw new InvalidOperationException("快捷键不能为空!"); + + AppHotKey.RegKey(FormHandle, id, keyModifiers, keyCode); + item.HotKeyID = id; + } + + /// + /// 注销热键 - 完成后,会清零 HotKeyID + /// + /// The item. + /// item + public void UnRegKey(HotKeyItem item) + { + if (item is null) + throw new ArgumentNullException(nameof(item)); + if (item.HotKeyID == 0) + return; + + AppHotKey.UnRegKey(FormHandle, item.HotKeyID); + item.HotKeyID = 0; + } + + #endregion + } +} \ No newline at end of file diff --git a/KeyGo/KeyGo.csproj b/KeyGo/KeyGo.csproj index affed52..b148b9f 100644 --- a/KeyGo/KeyGo.csproj +++ b/KeyGo/KeyGo.csproj @@ -46,18 +46,39 @@ + + + Form + + + FormHotKey.cs + Form FormMain.cs + + Form + + + FormProcessSelector.cs + + + + + FormHotKey.cs + FormMain.cs + + FormProcessSelector.cs + ResXFileCodeGenerator Resources.Designer.cs @@ -80,5 +101,8 @@ + + + \ No newline at end of file diff --git a/KeyGo/Properties/AssemblyInfo.cs b/KeyGo/Properties/AssemblyInfo.cs index 8316384..009c528 100644 --- a/KeyGo/Properties/AssemblyInfo.cs +++ b/KeyGo/Properties/AssemblyInfo.cs @@ -1,16 +1,15 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // 有关程序集的一般信息由以下 // 控制。更改这些特性值可修改 // 与程序集关联的信息。 [assembly: AssemblyTitle("KeyGo")] -[assembly: AssemblyDescription("")] +[assembly: AssemblyDescription("通过注册热键 启动/切换到/最小化 预设应用的小工具")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("KeyGo")] -[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyCopyright("Copyright © 2021 jie65535")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")]