个人练习 —— 使用c#、Winform窗体 编写鼠标连点器(附代码和工具逻辑)

鼠标连点工具:

个人练习 —— 使用c#、Winform窗体 编写鼠标连点器(附代码和工具逻辑)_第1张图片

 

工具编写背景:

因在游戏公司工作,游戏运行测试,偶尔需要测试升级或其他操作需要鼠标持续点击,网上下载的连点器广告太多,所以想自己编写了一款鼠标连点工具。

工具需求:

通过命令或操作,使鼠标特定按键 持续、有规律的点击屏幕指定位置。

实现原理:

热键相关:

使用Hook(钩子),监听键盘按下事件。

根据按键获取到按下按键的键值(Keys)。

判断该键值是否为命令热键(快捷键),(是否为 开始 | 结束)。

如果是开始,则判断当前工具的状态是否为已开始,如果是,则不执行,否则执行开启连点器功能。

如果是结束,则判断当前工具的状态是否为已开始,如果是,则执行结束命令,否则不执行。

判断该键值是否为紧急结束功能快捷键(ESC键)

为了防止误触,判定需要连续按键4次以上,且每次按键间隔不超过1.5秒。则为有效执行。否则视为无效操作。

鼠标点击相关:

调用了Windows自带的Dll动态连接库 user32.dll  操作鼠标左键的按下、左键抬起,右键按下、右键抬起、移动鼠标等。

使用Timer控件,实现了定时执行点击命令。

其他相关:

使用 Configuration 保存工具配置信息。

具体代码:

钩子相关:

KeyboardHookLib.cs类


using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Diagnostics;
using Microsoft.Win32;
using System.Windows.Forms;
namespace MouseClicker
{
    public class KeyboardHookLib
    {
        private const int WH_KEYBOARD_LL = 13; //键盘 

        //键盘处理事件委托 ,当捕获键盘输入时调用定义该委托的方法. 
        private delegate int HookHandle(int nCode, int wParam, IntPtr lParam);

        //客户端键盘处理事件 
        public delegate void ProcessKeyHandle(HookStruct param, out bool handle);

        //接收SetWindowsHookEx返回值 
        private static int _hHookValue = 0;

        //勾子程序处理事件 
        private HookHandle _KeyBoardHookProcedure;

        //Hook结构 
        [StructLayout(LayoutKind.Sequential)]
        public class HookStruct
        {
            public int vkCode;
            public int scanCode;
            public int flags;
            public int time;
            public int dwExtraInfo;
        }

        //设置钩子 
        [DllImport("user32.dll")]
        private static extern int SetWindowsHookEx(int idHook, HookHandle lpfn, IntPtr hInstance, int threadId);

        //取消钩子 
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        private static extern bool UnhookWindowsHookEx(int idHook);

        //调用下一个钩子 
        [DllImport("user32.dll")]
        private static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);

        //获取当前线程ID 
        [DllImport("kernel32.dll")]
        private static extern int GetCurrentThreadId();

        //Gets the main module for the associated process. 
        [DllImport("kernel32.dll")]
        private static extern IntPtr GetModuleHandle(string name);

        private IntPtr _hookWindowPtr = IntPtr.Zero;

        //构造器 
        public KeyboardHookLib() { }

        //外部调用的键盘处理事件 
        private static ProcessKeyHandle _clientMethod = null;

        ///  
              /// 安装勾子 
              ///  
              /// 外部调用的键盘处理事件 
        public void InstallHook(ProcessKeyHandle clientMethod)
        {
            _clientMethod = clientMethod;

            // 安装键盘钩子 
            if (_hHookValue == 0)
            {
                _KeyBoardHookProcedure = new HookHandle(OnHookProc);

                _hookWindowPtr = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);

                _hHookValue = SetWindowsHookEx(
                WH_KEYBOARD_LL,
                _KeyBoardHookProcedure,
                _hookWindowPtr,
                0);

                //如果设置钩子失败. 
                if (_hHookValue == 0) UninstallHook();
            }
        }

        //取消钩子事件 
        public void UninstallHook()
        {
            if (_hHookValue != 0)
            {
                bool ret = UnhookWindowsHookEx(_hHookValue);
                if (ret) _hHookValue = 0;
            }
        }

        //钩子事件内部调用,调用_clientMethod方法转发到客户端应用。 
        private static int OnHookProc(int nCode, int wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                //转换结构 
                HookStruct hookStruct = (HookStruct)Marshal.PtrToStructure(lParam, typeof(HookStruct));
               // hookStruct.vkCode = 0;
                if (_clientMethod != null)
                {
                    bool handle = false;
                    //调用客户提供的事件处理程序。 
                    _clientMethod(hookStruct, out handle);
                    if (handle) return 1; //1:表示拦截键盘,return 退出 
                }
            }
            return CallNextHookEx(_hHookValue, nCode, wParam, lParam);
        }

    }
}

鼠标操作 + 逻辑处理

Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MouseClicker
{
    public partial class frmMain : Form
    {
        public frmMain()
        {
            InitializeComponent();
        }

        Timer timer = new Timer();

        private bool updateLock = false;


        //紧急按钮功能
        private int exigencyButtonClick = 0;
        private long exigencyLastDownTime = 0;
        private int exigencyHoldTime = 1500;//紧急事件处理等待时长 两次紧急处理时间间隔不得大于 超过则无效 

        private bool runsLock = false;

        private bool ResetFlag = false;

        private KeyboardHookLib _keyboardHook = null;

        private List keyFilter = null;

        private EnumKeyType KeyType = EnumKeyType.none;

        private Keys updateKey = Keys.None;

        private delegate void Operate(EnumKeyType enumKey,Keys keyIndex);
    //    private List OperateList = new List();



        //  [System.Runtime.InteropServices.DllImport("user32")]
        [DllImport("user32.dll")]
        private static extern int mouse_event(int dwFlags, int dx, int dy, int dwData, int dwExtraInfo);
       
        [DllImport("user32.dll")]
        private static extern int SetCursorPos(int x, int y);
        /// 
        /// 移动鼠标到指定的坐标点
        /// 

        //移动鼠标 
        const int MOUSEEVENTF_MOVE = 0x0001;
        //模拟鼠标左键按下 
        const int MOUSEEVENTF_LEFTDOWN = 0x0002;
        //模拟鼠标左键抬起 
        const int MOUSEEVENTF_LEFTUP = 0x0004;
        //模拟鼠标右键按下 
        const int MOUSEEVENTF_RIGHTDOWN = 0x0008;
        //模拟鼠标右键抬起 
        const int MOUSEEVENTF_RIGHTUP = 0x0010;
        //模拟鼠标中键按下 
        const int MOUSEEVENTF_MIDDLEDOWN = 0x0020;
        //模拟鼠标中键抬起 
        const int MOUSEEVENTF_MIDDLEUP = 0x0040;
        //标示是否采用绝对坐标 
        const int MOUSEEVENTF_ABSOLUTE = 0x8000;
        //模拟鼠标滚轮滚动操作,必须配合dwData参数
        const int MOUSEEVENTF_WHEEL = 0x0800;

        int screenHeight = Screen.PrimaryScreen.Bounds.Height;
        int screenWidth = Screen.PrimaryScreen.Bounds.Width;

     
        public void MoveMouseToPoint(Point p)
        {
            SetCursorPos(p.X, p.Y);
        }
        /// 
        /// 设置鼠标的移动范围
        /// 
        public void SetMouseRectangle(Rectangle rectangle)
        {
            System.Windows.Forms.Cursor.Clip = rectangle;
        }
        /// 
        /// 设置鼠标位于屏幕中心
        /// 
        public void SetMouseAtCenterScreen()
        {
            int winHeight = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height;
            int winWidth = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width;
            Point centerP = new Point(winWidth / 2, winHeight / 2);
            MoveMouseToPoint(centerP);
        }



        [Obsolete]
        private void Form1_Load(object sender, EventArgs e)
        {
            lbl_screen_whVal.Text = string.Format("{0} * {1}",screenWidth,screenHeight);
            getMousePoint();

            //开启钩子
            _keyboardHook = new KeyboardHookLib();
            _keyboardHook.InstallHook(this.OnKeyPress);
            Console.WriteLine("钩子已开启..");
            LoadHotKey();
        }

        [Obsolete]
        private void LoadHotKey() 
        {
            string StartHotKey = ConfigurationSettings.AppSettings["StartHotKey"].ToString();

            string EndHotKey = ConfigurationSettings.AppSettings["EndHotKey"].ToString();

            keyFilter = new List();

            Keys keys = Keys.None;
            Enum.TryParse(StartHotKey, true, out keys);

            keyFilter.Add(keys);
            if (string.IsNullOrEmpty(StartHotKey) || keys == Keys.None)
            {
                lbl_start_hot_key.Text = "未设置";
                keyFilter.Remove(keys);
            }
            else
            {
                lbl_start_hot_key.Text = Enum.GetName(typeof(Keys),keys);
            }

            Enum.TryParse(EndHotKey, true, out keys);

            keyFilter.Add(keys);

            if (string.IsNullOrEmpty(EndHotKey) || keys == Keys.None)
            {
                lbl_end_hot_key.Text = "未设置";
                keyFilter.Remove(keys);
            }
            else
            {
                lbl_end_hot_key.Text = Enum.GetName(typeof(Keys), keys);
            }

            if (keyFilter.Contains(Keys.None))
            {
                keyFilter.Remove(Keys.None);
            }

        }


        private void SaveHotKey(EnumKeyType keyType,Keys key) 
        {
            //获取Configuration对象
            Configuration config = System.Configuration.ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            //写入元素的Value

            int val = (int)key;

            string startKey = config.AppSettings.Settings["StartHotKey"].Value;
            string endKey = config.AppSettings.Settings["EndHotKey"].Value;

            if (KeyType == EnumKeyType.start)
            {
                if (startKey.Equals(val.ToString()))
                {
                    return;
                } else if (endKey.Equals(val.ToString()))
                {
                    config.AppSettings.Settings["EndHotKey"].Value ="";
                }
                config.AppSettings.Settings["StartHotKey"].Value = val.ToString();
            }
            else if (KeyType == EnumKeyType.end)
            {

                if (endKey.Equals(val.ToString()))
                {
                    return;
                }
                else if (startKey.Equals(val.ToString()))
                {
                    config.AppSettings.Settings["StartHotKey"].Value = "";
                }
                config.AppSettings.Settings["EndHotKey"].Value = val.ToString();
            }

            //一定要记得保存,写不带参数的config.Save()也可以
            config.Save(ConfigurationSaveMode.Modified);
            //刷新,否则程序读取的还是之前的值(可能已装入内存)
            System.Configuration.ConfigurationManager.RefreshSection("appSettings");
        }


        private Point getMousePoint() 
        {
            Point point = Control.MousePosition;

            lbl_mouse_point.Text = string.Format("({0},{1})",point.X,point.Y);

            if (updateLock == false) 
            {
                txt_mouse_x_point.Text = point.X.ToString();
                txt_mouse_y_point.Text = point.Y.ToString();
            }
           
            return point;
        }


        public void OnKeyPress(KeyboardHookLib.HookStruct hookStruct, out bool handle)
        {
            handle = false;


            Keys key = (Keys)hookStruct.vkCode;


            //处理紧急结束按键
            if (key == Keys.Escape) 
            {
                long nowTime = DateUtil.DateTimeToLongTimeStamp(DateTime.Now);

                exigencyButtonClick++;

                if ((exigencyLastDownTime + exigencyHoldTime) <= nowTime) 
                {
                    // 紧急处理时长 过长  清空本次紧急处理的记录
                    exigencyButtonClick = 0;
                    exigencyLastDownTime = 0;
                }
                exigencyLastDownTime = nowTime;

                if (exigencyButtonClick >= 6) 
                {
                    exigencyButtonClick = 0;
                    if (isRun()) 
                    {
                        stopRun();

                        DialogResult result = MessageBox.Show("是否关闭连点器?", "提示", MessageBoxButtons.YesNo);

                        if (result == DialogResult.Yes)
                        {
                            Application.Exit();
                        }
                    }
                    else
                    {
                        Application.Exit();
                    }
                }
            }



            if (KeyType!= EnumKeyType.none) 
            {
                Operate operate = new Operate(resetHotKey);
                operate(EnumKeyType.none, key);
                return;
            }

            string StartHotKey = ConfigurationSettings.AppSettings["StartHotKey"].ToString();

            string EndHotKey = ConfigurationSettings.AppSettings["EndHotKey"].ToString();

            int startKey = 0;

            int endKey = 0;

            if (IsNumber(StartHotKey)) 
            {
                startKey = Convert.ToInt32(StartHotKey);
            }

            if (IsNumber(EndHotKey))
            {
                endKey = Convert.ToInt32(EndHotKey);
            }

            if (key == (Keys)startKey)
            {
                if (isRun() == false) 
                {
                    Run();
                }
            }
            else if (key == (Keys)endKey) 
            {
                if (isRun())
                {
                    stopRun();
                }
            }

        }


        private bool isRun()
        {
            return runsLock;
        }

        private void stopRun() 
        {
            Button button = GetControlOfName("btn_run", this.Controls) as Button;

            if (button != null)
            {
                button.Text = "运行";
            }

            this.WindowState = FormWindowState.Normal; // 最小化
            runsLock = false;
            timer_clicker.Enabled = false;
            timer_clicker.Stop();
        }

        private void Run() 
        {
            Button button = GetControlOfName("btn_run", this.Controls) as Button;

            if (button != null) 
            {
                button.Text = "停止";
            }

            this.WindowState = FormWindowState.Minimized; // 最小化
            runsLock = true;
            timer_clicker.Enabled = true;
            timer_clicker.Start();
        }

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
        }

        private void timer_mouse_Tick(object sender, EventArgs e)
        {
            getMousePoint();
        }

        private void cbx_unLock_CheckedChanged(object sender, EventArgs e)
        {
            updateLock = cbx_unLock.Checked;
        }

        private void txt_mouse_x_point_TextChanged(object sender, EventArgs e)
        {
            MouseChangePoint(txt_mouse_x_point.Text, txt_mouse_y_point.Text);
        }


        private void MouseChangePoint(string pointX,string pointY) 
        {
            string xpoint = pointX;

            string ypoint = pointY;

            if (updateLock == false)
                return;

            if (IsNumber(xpoint) == false && IsNumber(ypoint) == false)
                return;

            int x = 0;
            int y = 0;

            if (IsNumber(xpoint))
            {
                x = Convert.ToInt32(xpoint);
            }

            if (IsNumber(ypoint))
            {
                y = Convert.ToInt32(ypoint);
            }

            Point point = new Point(x,y);

            // clearMousePoint();

            // mouse_event(MOUSEEVENTF_MOVE, x, y, 0, 0);

            SetMouseAtCenterScreen();//将鼠标置于屏幕中心

            MoveMouseToPoint(point);

        }

        private bool IsNumber(string text)
        {
            if (string.IsNullOrEmpty(text))
                return false;

            try
            {
                Convert.ToInt32(text);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        private void Form1_KeyPress(object sender, KeyPressEventArgs e)
        {
           /* if (e.KeyChar == 27)
            {
                Application.Exit();
            }*/
        }

        private void txt_mouse_y_point_TextChanged(object sender, EventArgs e)
        {
            MouseChangePoint(txt_mouse_x_point.Text, txt_mouse_y_point.Text);
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            UnInstallHook();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            UnInstallHook();
        }

        private void UnInstallHook() 
        {
            //移除钩子

            if (_keyboardHook != null)
            {
                _keyboardHook.UninstallHook();
                Console.WriteLine("钩子移除成功..");
            }
        }

        private void btn_reset_start_Click(object sender, EventArgs e)
        {
            if (isSave()) 
            {
                saveHotKey();
                return;
            }

            if (updateState() == false)
                return;

            resetHotKey(EnumKeyType.start);
        }

        private bool isSave()
        {
            return KeyType != EnumKeyType.none && updateKey != Keys.None;
        }
        private void btn_reset_end_Click(object sender, EventArgs e)
        {
            if (isSave())
            {
                saveHotKey();
                return;
            }

            if (updateState() == false)
                return;

            resetHotKey(EnumKeyType.end);
        }
        
        private void saveHotKey() 
        {
            if (KeyType != EnumKeyType.none && updateKey != Keys.None) 
            {
                //
                SaveHotKey(KeyType,updateKey);

                resetState(KeyType);

                LoadHotKey();
            }
        }


        private Control GetControlOfName(string controlName, Control.ControlCollection containChildControlWindow)
        {
            if (string.IsNullOrEmpty(controlName)) return null;

            foreach (Control item in containChildControlWindow)
            {
                if (item.Name.Equals(controlName))
                {
                    return item;
                }
            }

            return null;
        }



        private bool updateState() 
        {
            if (ResetFlag)
                return !ResetFlag;

            ResetFlag = !ResetFlag;
            return ResetFlag;
        }

        private void resetState(EnumKeyType type) 
        {

            ResetFlag = false;

            KeyType = EnumKeyType.none;

            updateKey = Keys.None;

            Button button = GetControlOfName(string.Format("{0}", type == EnumKeyType.start ? "btn_reset_start" : "btn_reset_end"), this.Controls) as Button;

            if (button == null)
                return;

            button.Text = "重置";
        }

        private void resetHotKey(EnumKeyType type,Keys keys = Keys.None)
        {

            if (type != EnumKeyType.none) 
            {
                DialogResult result = MessageBox.Show(string.Format("是否重置{0}连点器按键?", type == EnumKeyType.start ? "开启" : "结束"), "提示", MessageBoxButtons.YesNo);

                if (result == DialogResult.Yes)
                {

                    Button button = GetControlOfName(string.Format("{0}",type == EnumKeyType.start ? "btn_reset_start" : "btn_reset_end"), this.Controls) as Button;

                    if (button == null)
                    {
                        return;
                    }

                    Label label = GetControlOfName(string.Format("{0}", type == EnumKeyType.start ? "lbl_start_hot_key" : "lbl_end_hot_key"), this.Controls) as Label;

                    if (label == null)
                    {
                        return;
                    }

                    label.Text = "未设置";

                    button.Text = "保存";

                    KeyType = type;
                }
                else
                {
                    resetState(type);
                }
            }
            else
            {
                if (KeyType != EnumKeyType.none) 
                {
                    updateKey = keys;

                    Label label = GetControlOfName(string.Format("{0}", KeyType == EnumKeyType.start ? "lbl_start_hot_key" : "lbl_end_hot_key"), this.Controls) as Label;

                    if (label == null)
                    {
                        return;
                    }

                    label.Text = Enum.GetName(typeof(Keys),keys);
                }
                else
                {
                    resetState(KeyType);
                }
            }
          
        }

        private void nud_speed_check_ValueChanged(object sender, EventArgs e)
        {
            updateTick();
        }

        private void updateTick() 
        {
            if (isRun())
            {
                stopRun();//暂停一下
                if (nud_speed_check.Value <= 0 || nud_speed_check.Value >= 9999999)
                {
                    nud_speed_check.Value = 10000;
                }

                timer_clicker.Interval = (int)nud_speed_check.Value;
                Run();//继续
            }
            else
            {
                if (nud_speed_check.Value <= 0 || nud_speed_check.Value >= 9999999)
                {
                    nud_speed_check.Value = 10000;
                }

                timer_clicker.Interval = (int)nud_speed_check.Value;
            }
        }


        public int number = 0;
        private void timer_clicker_Tick(object sender, EventArgs e)
        {
            if (rdb_left.Checked)
            {
                mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, Convert.ToInt32(txt_mouse_x_point.Text), Convert.ToInt32(txt_mouse_y_point.Text), 0, 0);
            }
            else
            {
                mouse_event(MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP, Convert.ToInt32(txt_mouse_x_point.Text), Convert.ToInt32(txt_mouse_y_point.Text), 0, 0);
            }
            //Console.WriteLine($"开始点击屏幕{number++}!!!!");
        }

        private void nud_speed_check_FontChanged(object sender, EventArgs e)
        {
           
        }

        private void nud_speed_check_KeyPress(object sender, KeyPressEventArgs e)
        {
            updateTick();
        }

        private void btn_run_Click(object sender, EventArgs e)
        {
            if (isRun() == false) 
            {
                Run();
            }
            else
            {
                stopRun();
            }
        }

        private void rdb_right_CheckedChanged(object sender, EventArgs e)
        {
            if (rdb_right.Checked) 
            {
                rdb_left.Checked = false;
            }
            else
            {
                rdb_left.Checked = true;
            }
            
        }

        private void rdb_left_CheckedChanged(object sender, EventArgs e)
        {
            if (rdb_left.Checked)
            {
                rdb_right.Checked = false;
            }
            else
            {
                rdb_right.Checked = true;
            }
        }
    }


    public enum EnumKeyType 
    {
        none,
        start,
        end,
    }

}

时间操作工具类

DateUtil.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MouseClicker
{
  public class DateUtil
    {
        /// 
        /// 时间戳计时开始时间
        /// 
        private static DateTime timeStampStartTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        /// 
        /// DateTime转换为10位时间戳(单位:秒)
        /// 
        ///  DateTime
        /// 10位时间戳(单位:秒)
        public static long DateTimeToTimeStamp(DateTime dateTime)
        {
            return (long)(dateTime.ToUniversalTime() - timeStampStartTime).TotalSeconds;
        }
        /// 
        /// DateTime转换为13位时间戳(单位:毫秒)
        /// 
        ///  DateTime
        /// 13位时间戳(单位:毫秒)
        public static long DateTimeToLongTimeStamp(DateTime dateTime)
        {
            return (long)(dateTime.ToUniversalTime() - timeStampStartTime).TotalMilliseconds;
        }
        /// 
        /// 10位时间戳(单位:秒)转换为DateTime
        /// 
        /// 10位时间戳(单位:秒)
        /// DateTime
        public static DateTime TimeStampToDateTime(long timeStamp)
        {
            return timeStampStartTime.AddSeconds(timeStamp).ToLocalTime();
        }
        /// 
        /// 13位时间戳(单位:毫秒)转换为DateTime
        /// 
        /// 13位时间戳(单位:毫秒)
        /// DateTime
        public static DateTime LongTimeStampToDateTime(long longTimeStamp)
        {
            return timeStampStartTime.AddMilliseconds(longTimeStamp).ToLocalTime();
        }


    }
}

配置文件:

App.config



     
        
    
	
		
		
	

你可能感兴趣的:(c#,工具,c#,开发语言,测试工具)