C#制作录制自动化执行Windows操作脚本工具-类似于按键精灵

我们知道,如果要对一个网站进行自动化测试,可以使用Python的selenium对获取网页的元素进行一系列操作。同样,对于Windows应用,可以使用C#或者AutoIt(也是一种脚本语言,相比较与C#,AutoIt更适合做Windows应用的自动化脚本)捕获窗体句柄进行操作。

今天主要记录一下使用WPF制作可以录制自动化执行Windows操作脚本工具,类似于按键精灵的录制脚本的操作。主要使用勾子捕获鼠标键盘事件。

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        

using System;using System.Collections.Generic;using System.Configuration;using System.IO;using System.Linq;using System.Threading;using System.Threading.Tasks;using System.Windows;using Newtonsoft.Json;using Path = System.IO.Path;namespace AutoOperationTool{    ///     /// MainWindow.xaml 的交互逻辑    ///     public partial class MainWindow : Window    {        // 用于取消任务的执行        private CancellationTokenSource cancelTokenSource = new CancellationTokenSource();        private Task ExecTask { get; set; }        private KeyAction KeyAction { get; set; }        public MainWindow()        {            InitializeComponent();            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);            txtScriptPath.Text = config.AppSettings.Settings["path"].Value;            KeyAction = new KeyAction();            btnEnd.IsEnabled = false;            btnCancel.IsEnabled = false;        }        private bool KMHook_MouseCallback(object arg)        {            if (arg is long[] arrs && arrs.Length == 3)            {                var type = arrs[0];                var x = arrs[1];                var y = arrs[2];                if (type == 1)                {                    var model = new MouseOperation();                    model.MouseOperationType = MouseOperationTypeEnum.Click;                    model.Point = new Point(){ X = x, Y = y};                    model.Time = DateTime.Now;                    model.OperationType = OperationType.Mouse;                    PrintLog.WriteTxt.GetInstance().AppendInfoLog(JsonConvert.SerializeObject(model));                }                xPoint.Text = x.ToString();                yPoint.Text = y.ToString();                Console.WriteLine(#34;X:{x};Y:{y}");            }            return true;        }        private bool KMHook_KeyCallback(object arg)        {            if (arg is long[] arrs && arrs.Length == 3)            {                var type = arrs[0];                var code = arrs[1];                var time = arrs[2];                var model = new KeyOperation();                if (type == 0)                {                    model.KeyOperationType = KeyOperationTypeEnum.Press;                }                else if (type == 1)                {                    model.KeyOperationType = KeyOperationTypeEnum.Up;                }                model.KeyCode = (Key)Enum.Parse(typeof(Key), code.ToString());                model.OperationType = OperationType.Key;                model.Time = DateTime.Now;                PrintLog.WriteTxt.GetInstance().AppendInfoLog(JsonConvert.SerializeObject(model));            }            return true;        }        private void Start_OnClick(object sender, RoutedEventArgs e)        {            btnEnd.IsEnabled = true;            btnStart.IsEnabled = false;            btnExec.IsEnabled = false;            btnCancel.IsEnabled = false;            // 如果存在脚本名称,序号往前加            PrintLog.WriteTxt.GetInstance().FileLogName = "script1.txt";            var fileLogName = PrintLog.WriteTxt.GetInstance().FileLogName;            if (File.Exists(PrintLog.WriteTxt.GetInstance().FileStartupPath + PrintLog.WriteTxt.GetInstance().FileLogName))            {                var fileName = PrintLog.WriteTxt.GetInstance().FileLogName;                while (File.Exists(PrintLog.WriteTxt.GetInstance().FileStartupPath + fileName))                {                    if (fileName.StartsWith("script") && fileName.EndsWith(".txt"))                    {                        var strCount = fileName.Replace("script", "").Replace(".txt", "");                        int count;                        if (int.TryParse(strCount, out count))                        {                            count++;                            fileName = #34;script{count}.txt";                        }                    }                    else                    {                        Directory.Delete(PrintLog.WriteTxt.GetInstance().FileStartupPath + PrintLog.WriteTxt.GetInstance().FileLogName);                        break;                    }                }                fileLogName = fileName;            }            PrintLog.WriteTxt.GetInstance().FileLogName = fileLogName;            txtScriptPath.Text = Path.Combine(PrintLog.WriteTxt.GetInstance().FileStartupPath, fileLogName);            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);            config.AppSettings.Settings["path"].Value = txtScriptPath.Text;            config.Save();            KMHook.MouseCallback += KMHook_MouseCallback;            KMHook.KeyCallback += KMHook_KeyCallback;            KMHook.InsertHook();        }        private void End_OnClick(object sender, RoutedEventArgs e)        {            KMHook.MouseCallback -= KMHook_MouseCallback;            KMHook.KeyCallback -= KMHook_KeyCallback;            KMHook.RemoveHook();            btnStart.IsEnabled = true;            btnEnd.IsEnabled = !btnStart.IsEnabled;            btnExec.IsEnabled = true;            btnCancel.IsEnabled = !btnExec.IsEnabled;        }        private void Exec_OnClick(object sender, RoutedEventArgs e)        {            btnStart.IsEnabled = false;            btnEnd.IsEnabled = !btnStart.IsEnabled;            btnExec.IsEnabled = false;            btnCancel.IsEnabled = !btnExec.IsEnabled;            var listOperations = new List();            var path = txtScriptPath.Text;            var listStrs = File.ReadLines(path)?.ToList();            if (listStrs != null && listStrs.Count > 0)            {                foreach (var strScript in listStrs)                {                    try                    {                        var operation = JsonConvert.DeserializeObject(strScript);                        if (operation.OperationType == OperationType.Mouse)                        {                            var mouseOperation = JsonConvert.DeserializeObject(strScript);                            listOperations.Add(mouseOperation);                        }                        else if (operation.OperationType == OperationType.Key)                        {                            var keyOperation = JsonConvert.DeserializeObject(strScript);                            listOperations.Add(keyOperation);                        }                    }                    catch (Exception ex)                    {                        throw ex;                    }                }            }            int count;            if (int.TryParse(txtCycleCount.Text, out count))            {                ExecTask = Task.Factory.StartNew(() =>                {                    if (count < 1) count = 1;                    for (int i = 0; i < count; i++)                    {                        DateTime lastTime = new DateTime();                        DateTime nextTime = new DateTime();                        for (int j = 0; j < listOperations.Count; j++)                        {                            if (lastTime == new DateTime())                            {                                lastTime = listOperations[j].Time;                                Exec(listOperations, j);                            }                            else                            {                                nextTime = listOperations[j].Time;                                if (j > 0)                                {                                    lastTime = listOperations[j - 1].Time;                                }                                Thread.Sleep(nextTime - lastTime);                                Exec(listOperations, j);                            }                        }                        Thread.Sleep(1000);                    }                    Application.Current.Dispatcher.Invoke(() =>                    {                        btnStart.IsEnabled = true;                        btnEnd.IsEnabled = !btnStart.IsEnabled;                        btnExec.IsEnabled = true;                        btnCancel.IsEnabled = !btnExec.IsEnabled;                    });                }, cancelTokenSource.Token);            }        }        private void Exec(List listOperations, int j)        {            if (listOperations[j].OperationType == OperationType.Mouse)            {                var mouse = listOperations[j] as MouseOperation;                MouseAction.DoClick((int)mouse.Point.X, (int)mouse.Point.Y);            }            else if (listOperations[j].OperationType == OperationType.Key)            {                var key = listOperations[j] as KeyOperation;                if (key.KeyOperationType == KeyOperationTypeEnum.Press)                {                    KeyAction.MykeyDown(key.KeyCode);                }                else if (key.KeyOperationType == KeyOperationTypeEnum.Up)                {                    KeyAction.MykeyUp(key.KeyCode);                }            }        }        private void CancelExec_OnClick(object sender, RoutedEventArgs e)        {            if (ExecTask != null)            {                for (int i = 0; i < 3; i++)                {                    try                    {                        cancelTokenSource.Cancel();                        if (cancelTokenSource.IsCancellationRequested)                        {                            cancelTokenSource = new CancellationTokenSource();                            ExecTask.Dispose();                            btnStart.IsEnabled = true;                            btnEnd.IsEnabled = !btnStart.IsEnabled;                            btnExec.IsEnabled = true;                            btnCancel.IsEnabled = !btnExec.IsEnabled;                            break;                        }                    }                    catch (Exception)                    {                    }                }            }        }    }}

勾子监听键盘鼠标事件

using System;using System.Runtime.InteropServices;namespace AutoOperationTool{    public class KMHook    {        public static bool InsertHook()        {            bool iRet;            iRet = InsertKeyboardHook();            if (!iRet)            {                return false;            }            iRet = InsertMouseHook();            if (!iRet)            {                removeKeyboardHook();                return false;            }            return true;        }        public static bool RemoveHook()        {            bool iRet;            iRet = removeKeyboardHook();            if (iRet)            {                iRet = removeMouseHook();            }            return iRet;        }        public static event Func MouseCallback;        public static event Func KeyCallback;        internal struct Keyboard_LL_Hook_Data        {            public UInt32 vkCode;            public UInt32 scanCode;            public UInt32 flags;            public UInt32 time;            public IntPtr extraInfo;        }        internal struct Mouse_LL_Hook_Data        {            internal long yx;            internal readonly int mouseData;            internal readonly uint flags;            internal readonly uint time;            internal readonly IntPtr dwExtraInfo;        }        private static IntPtr pKeyboardHook = IntPtr.Zero;        private static IntPtr pMouseHook = IntPtr.Zero;        //钩子委托声明        public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);        private static HookProc keyboardHookProc;        private static HookProc mouseHookProc;        //安装钩子        [DllImport("user32.dll")]        public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr pInstance, int threadID);        //卸载钩子        [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]        public static extern bool UnhookWindowsHookEx(IntPtr pHookHandle);        [DllImport("user32.dll")]        public static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); //parameter 'hhk' is ignored.        private static int keyboardHookCallback(int code, IntPtr wParam, IntPtr lParam)        {            if (code < 0)            {                return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);            }            Keyboard_LL_Hook_Data khd = (Keyboard_LL_Hook_Data)Marshal.PtrToStructure(lParam, typeof(Keyboard_LL_Hook_Data));            System.Diagnostics.Debug.WriteLine(#34;key event:{wParam}, key code:{khd.vkCode}, event time:{khd.time}");            var keyType = 0L;            var iWParam = (int)wParam;            if (iWParam == 256)            {                keyType = 0;            }            else if (iWParam == 257)            {                keyType = 1;            }            else            {                keyType = 0;            }            KeyCallback?.Invoke(new long[3] { keyType, (int)khd.vkCode, (int)khd.time });            return 0;        }        private static int mouseHookCallback(int code, IntPtr wParam, IntPtr lParam)        {            if (code < 0)            {                return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);            }            Mouse_LL_Hook_Data mhd = (Mouse_LL_Hook_Data)Marshal.PtrToStructure(lParam, typeof(Mouse_LL_Hook_Data));            System.Diagnostics.Debug.WriteLine(#34;mouse event:{wParam}, ({mhd.yx & 0xffffffff},{mhd.yx >> 32})");            var mouseType = 0L;            var iWParam = (int)wParam;            if (iWParam == 513)            {                mouseType = 1;            }            else if (iWParam == 514)            {                mouseType = 2;            }            else            {                mouseType = 0;            }            MouseCallback?.Invoke(new long[3]{ mouseType , mhd.yx & 0xffffffff, mhd.yx >> 32 });            return 0;        }        //安装钩子方法        private static bool InsertKeyboardHook()        {            if (pKeyboardHook == IntPtr.Zero)//不存在钩子时            {                //创建钩子                keyboardHookProc = keyboardHookCallback;                pKeyboardHook = SetWindowsHookEx(13, //13表示全局键盘事件。                    keyboardHookProc,                    (IntPtr)0,                    0);                if (pKeyboardHook == IntPtr.Zero)//如果安装钩子失败                {                    removeKeyboardHook();                    return false;                }            }            return true;        }        private static bool InsertMouseHook()        {            if (pMouseHook == IntPtr.Zero)            {                mouseHookProc = mouseHookCallback;                pMouseHook = SetWindowsHookEx(14, //14表示全局鼠标事件                    mouseHookProc,                    (IntPtr)0,                    0);                if (pMouseHook == IntPtr.Zero)                {                    removeMouseHook();                    return false;                }            }            return true;        }        private static bool removeKeyboardHook()        {            if (pKeyboardHook != IntPtr.Zero)            {                if (UnhookWindowsHookEx(pKeyboardHook))                {                    pKeyboardHook = IntPtr.Zero;                }                else                {                    return false;                }            }            return true;        }        private static bool removeMouseHook()        {            if (pMouseHook != IntPtr.Zero)            {                if (UnhookWindowsHookEx(pMouseHook))                {                    pMouseHook = IntPtr.Zero;                }                else                {                    return false;                }            }            return true;        }    }}

操作键盘按键

using System;using System.Runtime.InteropServices;namespace AutoOperationTool{    public class KeyAction    {        [DllImport("user32.dll", SetLastError = true)]        public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);        /// key down        public void MykeyDown(Key vKeyCoad)        {            PressKey(vKeyCoad, false);        }        /// Key up        public void MykeyUp(Key vKeyCoad)        {            PressKey(vKeyCoad, true);        }        private void PressKey(Key key, bool up)        {            const int KEYEVENTF_EXTENDEDKEY = 0x1;            const int KEYEVENTF_KEYUP = 0x2;            if (up)            {                keybd_event((byte)key, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, (UIntPtr)0);            }            else            {                keybd_event((byte)key, 0x45, KEYEVENTF_EXTENDEDKEY, (UIntPtr)0);            }        }    }}

操作鼠标移动及单击

using System.Runtime.InteropServices;namespace AutoOperationTool{    public class MouseAction    {        [DllImport("user32")]        public static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);        [DllImport("User32.dll")]        public static extern bool SetCursorPos(int X, int Y);        public static void DoClick(int x, int y)        {            SetCursorPos(x, y);            mouse_event((int)MouseType.MOUSEEVENTF_LEFTDOWN | (int)MouseType.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);        }    }}

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章