C# Windows登录界面进行截图,控制鼠标键盘等操作实现(二)

这篇具有很好参考价值的文章主要介绍了C# Windows登录界面进行截图,控制鼠标键盘等操作实现(二)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

上一篇:C# Windows登录界面进行截图,控制鼠标键盘等操作实现(一) - log9527 - 博客园 (cnblogs.com) 我们了解了要实现在Windows登录界面进行截图等操作必须满足的条件,这一篇我们主要通过代码实现这些条件。

首先先建一个项目A

下面一些windows自带非托管dll的调用类。

/// <summary>
    /// WtsApi32.dll导入帮助类
    /// </summary>
    public static class WtsApi32
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct WtsSessionInfo
        {
            public int SessionID;
            [MarshalAs(UnmanagedType.LPStr)]
            public string pWinStationName;
            public WtsConnectStateClass State;
        }

        public enum WtsConnectStateClass
        {
            WtsActive,
            WtsConnected,
            WtsConnectQuery,
            WtsShadow,
            WtsDisconnected,
            WtsIdle,
            WtsListen,
            WtsReset,
            WtsDown,
            WtsInit
        }

        public static IntPtr WtsCurrentServerHandle = IntPtr.Zero;

        [DllImport("wtsapi32.dll", SetLastError = true)]
        public static extern int WTSEnumerateSessions(
            IntPtr hServer,
            int reserved,
            int version,
            ref IntPtr ppSessionInfo,
            ref int pCount);
    }
/// <summary>
    /// user32.dll导入帮助类
    /// </summary>
    public static class User32
    {
        #region Constants

        public const int DesktopCapabilityIndex = 118;
        
        #endregion

        #region Enums

        [Flags]
        public enum AccessMask : uint
        {
            Delete = 0x00010000,
            ReadControl = 0x00020000,
            WriteDac = 0x00040000,
            WriteOwner = 0x00080000,
            Synchronize = 0x00100000,

            StandardRightsRequired = 0x000F0000,

            StandardRightsRead = 0x00020000,
            StandardRightsWrite = 0x00020000,
            StandardRightsExecute = 0x00020000,

            StandardRightsAll = 0x001F0000,

            SpecificRightsAll = 0x0000FFFF,

            AccessSystemSecurity = 0x01000000,

            MaximumAllowed = 0x02000000,

            GenericRead = 0x80000000,
            GenericWrite = 0x40000000,
            GenericExecute = 0x20000000,
            GenericAll = 0x10000000,

            DesktopReadObjects = 0x00000001,
            DesktopCreateWindow = 0x00000002,
            DesktopCreateMenu = 0x00000004,
            DesktopHookcontrol = 0x00000008,
            DesktopJournalrecord = 0x00000010,
            DesktopJournalplayback = 0x00000020,
            DesktopEnumerate = 0x00000040,
            DesktopWriteobjects = 0x00000080,
            DesktopSwitchdesktop = 0x00000100,

            WinstaEnumdesktops = 0x00000001,
            WinstaReadattributes = 0x00000002,
            WinstaAccessclipboard = 0x00000004,
            WinstaCreatedesktop = 0x00000008,
            WinstaWriteattributes = 0x00000010,
            WinstaAccessglobalatoms = 0x00000020,
            WinstaExitwindows = 0x00000040,
            WinstaEnumerate = 0x00000100,
            WinstaReadscreen = 0x00000200,

            WinstaAllAccess = 0x0000037F
        }

        #endregion

        #region DLL Imports

        [DllImport("gdi32.dll")]
        public static extern int GetDeviceCaps(
            IntPtr hdc, // handle to DC
            int nIndex // index of capability
        );

        [DllImport("user32.dll")]
        public static extern IntPtr GetDesktopWindow();

        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool SwitchDesktop(IntPtr hDesktop);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr OpenInputDesktop(uint dwFlags, bool fInherit, AccessMask dwDesiredAccess);

        [return: MarshalAs(UnmanagedType.Bool)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern bool CloseWindowStation(IntPtr hWinsta);

        [DllImport("User32.dll")]
        public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool SetThreadDesktop(IntPtr hDesktop);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool CloseDesktop(IntPtr hDesktop);

        [DllImport("user32.dll")]
        public static extern IntPtr GetDC(IntPtr hWnd);

        #endregion
    }
/// <summary>
    /// 非托管dll引入帮助类
    /// </summary>
    public static class Kernel32
    {
        #region DLL Imports

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool CloseHandle(IntPtr hSnapshot);

        [DllImport("kernel32.dll")]
        public static extern uint WTSGetActiveConsoleSessionId();

        [DllImport("kernel32.dll")]
        public static extern bool ProcessIdToSessionId(uint dwProcessId, ref uint pSessionId);

        [DllImport("kernel32.dll")]
        public static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);

        #endregion
    }
/// <summary>
    /// 非托管dll引入帮助类
    /// </summary>
    public static class AdvApi32
    {
        #region Structs

        [StructLayout(LayoutKind.Sequential)]
        public struct SECURITY_ATTRIBUTES
        {
            public int Length;
            public IntPtr lpSecurityDescriptor;
            public bool bInheritHandle;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct PROCESS_INFORMATION
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public int dwProcessId;
            public int dwThreadId;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct STARTUP_INFO
        {
            public Int32 cb;
            public string lpReserved;
            public string lpDesktop;
            public string lpTitle;
            public Int32 dwX;
            public Int32 dwY;
            public Int32 dwXSize;
            public Int32 dwYSize;
            public Int32 dwXCountChars;
            public Int32 dwYCountChars;
            public Int32 dwFillAttribute;
            public Int32 dwFlags;
            public Int16 wShowWindow;
            public Int16 cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }

        #endregion

        #region Enums
        
        public enum TOKEN_TYPE : int
        {
            TokenPrimary = 1,
            TokenImpersonation = 2
        }

        public enum SECURITY_IMPERSONATION_LEVEL : int
        {
            SecurityAnonymous = 0,
            SecurityIdentification = 1,
            SecurityImpersonation = 2,
            SecurityDelegation = 3,
        }

        #endregion

        #region Constants

        public const int TOKEN_DUPLICATE = 0x0002;
        public const uint MAXIMUM_ALLOWED = 0x2000000;
        public const int CREATE_NEW_CONSOLE = 0x00000010;
        public const int CREATE_NO_WINDOW = 0x08000000;
        public const int DETACHED_PROCESS = 0x00000008;
        public const int NORMAL_PRIORITY_CLASS = 0x20;
        public const int UOI_NAME = 2;

        #endregion

        #region DLL Imports

        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern bool CreateProcessAsUser(
            IntPtr hToken,
            string lpApplicationName,
            string lpCommandLine,
            ref SECURITY_ATTRIBUTES lpProcessAttributes,
            ref SECURITY_ATTRIBUTES lpThreadAttributes,
            bool bInheritHandles,
            uint dwCreationFlags,
            IntPtr lpEnvironment,
            string lpCurrentDirectory,
            ref STARTUP_INFO lpStartupInfo,
            out PROCESS_INFORMATION lpProcessInformation);

        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool AllocateLocallyUniqueId(out IntPtr pLuid);

        [DllImport("advapi32", SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
        public static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public extern static bool DuplicateTokenEx(
            IntPtr hExistingToken,
            uint dwDesiredAccess,
            ref SECURITY_ATTRIBUTES lpTokenAttributes,
            SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
            TOKEN_TYPE TokenType,
            out IntPtr phNewToken);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool GetUserObjectInformationW(IntPtr hObj, int nIndex,
             [Out] byte[] pvInfo, uint nLength, out uint lpnLengthNeeded);

        #endregion
    }

外部调用入口类为Win32Interop,包含创建桌面会话进程、将当前进程切换到Desktop等主要功能

/// <summary>
    /// 切换会话状态帮助类
    /// </summary>
    public class Win32Interop
    {
        [DllImport("kernel32.dll")]
        public static extern uint WTSGetActiveConsoleSessionId();

        /// <summary>
        /// 获取当前桌面名称
        /// </summary>
        /// <returns></returns>
        public static string GetCurrentDesktop()
        {
            // 打开接收用户输入的桌面。
            var inputDesktop = OpenInputDesktop();
            var deskBytes = new byte[256];
            // 检索有关指定窗口站或桌面对象的信息。(这里检索名字)
            var success = GetUserObjectInformationW(inputDesktop, UOI_NAME, deskBytes, 256, out var lenNeeded);
            if (!success)
            {
                CloseDesktop(inputDesktop);
                return "Default";
            }

            // 返回窗口站或桌面的名字
            var desktopName = Encoding.Unicode.GetString(deskBytes.Take((int)lenNeeded).ToArray()).Replace("\0", "");
            // 关闭桌面对象的打开句柄。
            CloseDesktop(inputDesktop);
            return desktopName;
        }

        /// <summary>
        /// 获取会话列表
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<WtsApi32.WtsSessionInfo> EnumerateSessions()
        {
            var ppSessionInfo = IntPtr.Zero;
            var count = 0;

            // 检索远程桌面会话主机(RD 会话主机)服务器上的会话列表。
            var retrieval = WtsApi32.WTSEnumerateSessions(WtsApi32.WtsCurrentServerHandle, 0, 1, ref ppSessionInfo, ref count);
            var dataSize = Marshal.SizeOf(typeof(WtsApi32.WtsSessionInfo));
            var current = (long)ppSessionInfo;

            if (retrieval == 0) yield break;
            for (var i = 0; i < count; i++)
            {
                var sessionInf = (WtsApi32.WtsSessionInfo)Marshal.PtrToStructure((System.IntPtr)current, typeof(WtsApi32.WtsSessionInfo));
                current += dataSize;
                yield return sessionInf;
            }
        }

        /// <summary>
        /// 获取Rdp会话
        /// </summary>
        /// <returns></returns>
        public static uint GetRdpSession()
        {
            // 返回远程桌面会话主机(RD 会话主机)服务器上的会话列表信息
            var sessionList = EnumerateSessions();
            uint retVal = 0;

            // pWinStationName 指向包含此会话的 WinStation 名称的 null 终止字符串的指针。 WinStation 名称是 Windows 与会话关联的名称,例如“services”、“console”或“RDP-Tcp#0”。
            // 「rdp-tcp#0」和「console」是两种不同的远程桌面协议(Remote Desktop Protocol)的连接方式。 「rdp-tcp#0」是使用TCP 协议的RDP 连接,它可以通过网络与远程主机进行连接。 「console」则代表通过本地控制台连接,它只能在本地机器上直接连接到远程主机。
            var wtsSessionInfos = sessionList.ToList();
            var rdpSession = wtsSessionInfos.FirstOrDefault(ses => ses.pWinStationName.ToLower().Contains("rdp") && ses.State == 0);
            if (wtsSessionInfos.Any(ses => ses.pWinStationName.ToLower().Contains("rdp") && ses.State == 0))
            {
                retVal = (uint)rdpSession.SessionID;
            }
            return retVal;
        }

        /// <summary>
        /// 打开输入桌面
        /// </summary>
        /// <returns></returns>
        public static IntPtr OpenInputDesktop()
        {
            return User32.OpenInputDesktop(0, false, AccessMask.GenericAll);
        }

        /// <summary>
        /// 创建桌面会话进程
        /// </summary>
        /// <param name="applicationName"></param>
        /// <param name="desktopName"></param>
        /// <param name="hiddenWindow"></param>
        /// <param name="dwSessionId"></param>
        /// <param name="procInfo"></param>
        /// <returns></returns>
        public static bool OpenInteractiveProcess(string applicationName, string desktopName, bool hiddenWindow, uint dwSessionId, out PROCESS_INFORMATION procInfo)
        {
            uint winlogonPid = 0;
            var hPToken = IntPtr.Zero;
            procInfo = new PROCESS_INFORMATION();

            // Obtain the process ID of the winlogon process that is running within the currently active session.
            var processes = Process.GetProcessesByName("winlogon");
            foreach (var p in processes)
            {
                if ((uint)p.SessionId == dwSessionId)
                {
                    winlogonPid = (uint)p.Id;
                }
            }

            // Obtain a handle to the winlogon process.
            // 打开现有的本地进程对象。
            var hProcess = Kernel32.OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);

            // Obtain a handle to the access token of the winlogon process.
            // OpenProcessToken函数打开与进程关联的访问令牌。
            if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken))
            {
                Kernel32.CloseHandle(hProcess);
                return false;
            }

            // Security attribute structure used in DuplicateTokenEx and CreateProcessAsUser.
            var sa = new SECURITY_ATTRIBUTES();
            sa.Length = Marshal.SizeOf(sa);

            // Copy the access token of the winlogon process; the newly created token will be a primary token.
            // DuplicateTokenEx函数创建一个新的访问令牌来复制现有令牌。此函数可以创建主令牌或模拟令牌。
            if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, TOKEN_TYPE.TokenPrimary, out var hUserTokenDup))
            {
                Kernel32.CloseHandle(hProcess);
                Kernel32.CloseHandle(hPToken);
                return false;
            }

            // By default, CreateProcessAsUser creates a process on a non-interactive window station, meaning
            // the window station has a desktop that is invisible and the process is incapable of receiving
            // user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user 
            // interaction with the new process.
            var si = new STARTUP_INFO();
            si.cb = Marshal.SizeOf(si);
            si.lpDesktop = @"winsta0\" + desktopName;

            // Flags that specify the priority and creation method of the process.
            uint dwCreationFlags;
            if (hiddenWindow)
            {
                dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | DETACHED_PROCESS;
            }
            else
            {
                dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
            }

            // Create a new process in the current user's logon session.
            // 创建一个新进程及其主线程。新进程在指定令牌表示的用户的安全上下文中运行。
            // 通常,调用CreateProcessAsUser函数的进程 必须具有SE_INCREASE_QUOTA_NAME权限,并且如果令牌不可分配,则可能需要SE_ASSIGNPRIMARYTOKEN_NAME权限。如果此函数失败并出现ERROR_PRIVILEGE_NOT_HELD(1314),请改用CreateProcessWithLogonW函数。CreateProcessWithLogonW不需要特殊权限,但必须允许指定的用户帐户以交互方式登录。通常,最好使用CreateProcessWithLogonW创建具有备用凭据的进程。
            var result = CreateProcessAsUser(hUserTokenDup, null, applicationName, ref sa, ref sa, false, dwCreationFlags, IntPtr.Zero, null, ref si, out procInfo);

            // Invalidate the handles.
            Kernel32.CloseHandle(hProcess);
            Kernel32.CloseHandle(hPToken);
            Kernel32.CloseHandle(hUserTokenDup);

            return result;
        }

        /// <summary>
        /// 将当前进程切换到Desktop
        /// </summary>
        public static void SwitchToInputDesktop()
        {
            var inputDesktop = OpenInputDesktop();
            SwitchDesktop(inputDesktop);
            SetThreadDesktop(inputDesktop);
            CloseDesktop(inputDesktop);
        }
    }

然后再建一个新项目B,用于启动一个新进程进行截图。进程名就叫WinLogonScreenShot。

项目A中继续写以下代码用于启动项目B中的进程WinLogonScreenShot:

        /// <summary>
        /// 创建新进程
        /// </summary>
        /// <returns></returns>
        internal bool Create()
        {
            try
            {
                // 返回值为uint类型,不要写int类型
                uint dwSessionId = Win32Interop.WTSGetActiveConsoleSessionId();
                Log.Info($"检索控制台会话的会话标识符句柄:{dwSessionId}");

                var desktopName = Win32Interop.GetCurrentDesktop();

                Log.Info($"返回窗口站或桌面的名字:{desktopName}");

                // 返回rdpSession会话id
                var rdpSessionId = Win32Interop.GetRdpSession();

                Log.Info($"返回rdpSession会话id:{rdpSessionId}");

                if (rdpSessionId > 0)
                {
                    if (dwSessionId != rdpSessionId)
                        desktopName = "winlogon";
                    dwSessionId = rdpSessionId;
                }

                Log.Info($"desktopName:{desktopName};dwSessionId:{dwSessionId}");

                var res = CreateProcessAsUser(dwSessionId, desktopName, _winLogonType);

                Log.Info($"CreateProcessAsUser:{res}");

                Log.Info($"Service started.");

                return res;
            }
            catch (Exception ex)
            {
                ServiceCenters.Log.Error(ex);
                return false;
            }
        }

        /// <summary>
        /// 守护会话ID>0的进程
        /// </summary>
        /// <returns></returns>
        internal async Task StartMonitorAsync()
        {
            await Task.Run(MonitorProcess);
        }

        /// <summary>
        /// 守护会话ID>0的进程
        /// </summary>
        private async Task MonitorProcess()
        {
            while (true)
            {
                try
                {
                    var process = Process.GetProcessesByName("WinLogonScreenShot");
                    if (process.Length == 0)
                    {
                        Log.Info($"创建会话ID=1的新进程");
                        var activeSessionId = Kernel32.WTSGetActiveConsoleSessionId(); //获取活动会话
                        Log.Info($"检索控制台会话的会话标识符句柄:{activeSessionId}");
                        var desktop = Win32Interop.GetCurrentDesktop();
                        var isOk = CreateProcessAsUser(activeSessionId, desktop, _winLogonType);
                        Log.Info($"新建进程结果:{isOk}");
                    }

                    await Task.Delay(1000);
                }
                catch (Exception ex)
                {
                    ServiceCenters.Log.Error(ex);
                }
            }
        }

        /// <summary>
        /// 创建用户进程
        /// </summary>
        /// <param name="dwSessionId"></param>
        /// <param name="desktopName"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        private bool CreateProcessAsUser(uint dwSessionId, string desktopName, WinLogonType type)
        {//用户进程启动
            var result = Win32Interop.OpenInteractiveProcess("WinLogonScreenShot", desktopName, true, dwSessionId, out _);
            return result;
        }

需要把项目B生成到项目A运行目录下。上面就是创建一个满足在登录界面截图的进程WinLogonScreenShot,并且守护该进程的操作。

然后在项目A中截图/控制鼠标键盘等操作前,必须先调将当前进程切换到Desktop的方法文章来源地址https://www.toymoban.com/news/detail-662759.html

Win32Interop.SwitchToInputDesktop();

到了这里,关于C# Windows登录界面进行截图,控制鼠标键盘等操作实现(二)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 键盘怎么控制鼠标?键盘控制鼠标实现点击和移动

    鼠标在电脑操作过程中非常重要,可是有时遇到尴尬的问题,就是摸鱼的时候觉得一直点击鼠标声音太大,或者舍友都睡觉了,你突然之间需要浏览一些网页,一直点击鼠标会产生很大的噪声,这时候该怎么办呢?如果你是笔记本,配合鼠标版可以解决。如果你正好有一个静

    2024年02月06日
    浏览(39)
  • 安装黑苹果进入语言选择界面,鼠标/键盘无法使用?

    是因为 EFI 文件中没有 USB 驱动,或你使用的 EFI 文件定制了 USB 端口,但和你的主板不匹配。可以放一个 USBInjectAll.kext 到 EFI/Clover/Kexts/other ( Clover 方式),或 EFI/OC/Kexts ( OpenCore 方式),并删除同目录下的 USBPorts.kext ,或删除 ACPI/Patched 下的 ssdt-uiac.aml ( OpenCore 在 ACPI 目录,也可能

    2024年02月12日
    浏览(29)
  • 工具-Snipaste与ScreenToGif 生产力工具,对截图进行勾画操作,并可将截图贴至电脑任意界面;快捷动态截图成gif

    进入官网,可根据系统进行下载 https://zh.snipaste.com/ 傻瓜式安装成功后,电脑的右下角有个小图标,有些是彩色,有些是黑灰色,影响不大 傻瓜式安装,默认的截图快捷键就很好用 摁下F1,进行截屏,用工具可进行勾画,直接ctrl CV可以复制粘贴使用 摁下F1,勾画完成后,点击

    2024年02月01日
    浏览(26)
  • JAVA 鼠标控制与键盘输入控制

    该类是JDK定义的电脑系统的抽象类,可以用来模拟实现鼠标点击与键盘输入等信息 简单实现一个自动抢票代码: InputEvent.BUTTON1_MASK 左键 (食指点击) InputEvent.BUTTON2_MASK 中键 (滚轮) InputEvent.BUTTON3_MASK 右键(中指点击) 得到的信息需要根据屏幕--显示设置--缩放与布局的百分

    2024年02月13日
    浏览(27)
  • C# 监测全局键盘和鼠标事件

    在 C# 中,我们可以编写代码来监测全局键盘和鼠标事件。通过捕捉这些事件,我们可以实现一些有趣的功能,比如记录按键操作、截获特定的快捷键,或者在鼠标点击时执行特定的操作。 下面是一个示例代码,演示了如何在 C# 中监测全局键盘和鼠标事件:

    2024年02月02日
    浏览(34)
  • C#实现键盘鼠标模拟器

    下面程序可指定一连串重复动作,按顺序执行   using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Text.RegularExpressions; using System.Windows.Forms; namespace Simulator {     public partial class Form1 : Form     {         [System.Runtime.InteropServices.DllImp

    2024年02月16日
    浏览(34)
  • C# 实现按键精灵 记录录制键盘鼠标

     是一个非常实用的键盘鼠标脚本录制工具,通过它你可以轻松地进行脚本录制,简单易用,不需要任何编程知识就能做出功能强大的脚本,只要你在电脑前用双手可以完成的动作,都可以替你完成。                下载软件 1.运行录制脚步时模拟过程 比按键精灵 更加流畅

    2024年02月11日
    浏览(30)
  • python编程控制键盘鼠标

    1.安装Pywin32 下载完成后直接运行。 2. 模拟按键      keybd_event(bVk, bScan, dwFlags, dwExtraInfo)       第一个参数:虚拟键码(键盘键码对照表见附录);       第二个参数:硬件扫描码,一般设置为0即可;       第三个参数:函数操作的一个标志位,如果值为KEYEVENTF_EXTENDEDKEY则

    2024年02月08日
    浏览(29)
  • python读取控制鼠标键盘

    目录 一,工具 二,鼠标 1,实时显示鼠标位置 2,控制移动鼠标 3,控制点击鼠标 三,键盘 1,单键输入 2,组合键输入 四,实用demo 1,多网页依次点击固定位置的按钮 2,收集多个网页的链接 pyautogui库 命令:pip3 install pyautogui==0.9.50 如果不指定版本,可能会在使用时报错:

    2024年04月10日
    浏览(30)
  • python 如何控制鼠标键盘

    你可以使用Python的第三方库pyautogui来控制鼠标和键盘。pyautogui库是一个跨平台的GUI自动化库,可以模拟鼠标和键盘操作,以及截屏、获取窗口句柄等功能。 下面是一些常用的鼠标和键盘控制示例: 鼠标移动到指定位置 鼠标点击

    2024年02月11日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包