RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1248816
Accepted
Ivan Andreev
Ivan Andreev
Asked:2022-02-26 08:34:26 +0000 UTC2022-02-26 08:34:26 +0000 UTC 2022-02-26 08:34:26 +0000 UTC

在 C# 中调用 WinApi SendInput 时屏幕变为空白

  • 772

调用 SendInput 函数后,屏幕变为空白。为什么会这样?又该如何避免呢?这是屏幕变为空白的 c# 代码:

    [DllImport("user32.dll")]
    static extern uint SendInput(uint nInputs, [MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize);

      public static void ClickM(IntPtr wHandle, int X = 0, int Y = 0, int delay = 100)
        {
            if (wHandle == IntPtr.Zero)
            {
                MessageBox.Show("App is not running.");
                return;
            }
            INPUT[] Inputs = new INPUT[3];
            INPUT Input = new INPUT();
            Input.type = 0; 
            Input.U.mi.dx = X;
            Input.U.mi.dy = Y;
            Input.U.mi.time = (uint)delay;
            Input.U.mi.dwFlags = MOUSEEVENTF.MOVE;
            Inputs[0] = Input;

            Input.type = 0; 
            Input.U.mi.dx = X;
            Input.U.mi.dy = Y;
            Input.U.mi.time = (uint)delay;
            Input.U.mi.dwFlags = MOUSEEVENTF.LEFTDOWN;
            Inputs[1] = Input;

            Input.type = 0; 
            Input.U.mi.dx = X;
            Input.U.mi.dy = Y;
            Input.U.mi.time = (uint)delay;
            Input.U.mi.dwFlags = MOUSEEVENTF.LEFTUP;
            Inputs[2] = Input;

            SendInput((uint)Inputs.Length, Inputs, INPUT.Size);
        }

    [StructLayout(LayoutKind.Sequential)]
    public struct INPUT
    {
        internal InputType type;
        internal InputUnion U;
        internal static int Size
        {
            get { return Marshal.SizeOf(typeof(INPUT)); }
        }
    }

此外,其中一台显示器会在几秒钟后挂起,而第二台显示器则保持死机,直到您关闭程序/按“Esc”。在 Delphi 上的一个类似问题中,该案例在“非归零数组”中,并且正在处理 ZeroMemory,但据我所知,这种方法在 C# 中不相关,还是我弄错了?!顺便说一句,我还无法应用 ZeroMemory,但我正在努力 :) 该程序以管理员权限启动,Windows 10 用户帐户控制不会影响这一点:我试图完全禁用它 - 没有变化。我知道有自动脚本形式的替代方案,例如,可以实现类似的目标,但是当我的程序专门执行操作时,我有兴趣使用这种特殊机制。

将通话分为 3 个部分。

    SendInput((uint)1, Inputs1, INPUT.Size);
    SendInput((uint)1, Inputs2, INPUT.Size);
    SendInput((uint)1, Inputs3, INPUT.Size);

当调用 move 和 Leftdown 时,一切正常(我不确定会发生什么,因为窗口中的焦点不会消失:)),但是当我调用最后一个函数来释放按钮时,屏幕变为空白。

这些是我使用的关键定义:

[Flags]
        public enum MOUSEEVENTF
        {
            MOVE = 0x01,
            LEFTDOWN = 0x02,
            LEFTUP = 0x04,
            RIGHTDOWN = 0x08,
            RIGHTUP = 0x10
        }
c#
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    aepot
    2022-02-26T16:14:06Z2022-02-26T16:14:06Z

    使用 P/Invoke Windows API 函数时,首先要做的是仔细阅读文档。其次,您需要确保结构正确编组。

    显示器可能会因为 Windows 错误地感知您的输入而变为空白,例如,作为某种鼠标手势(任何不可预知的行为),甚至可以将屏幕倒置,我不知道您的系统是如何配置的。

    我已经准备好SendInput为键盘和鼠标生成输入的代码。

    internal static class NativeMethods
    {
        [Flags]
        public enum KeyboardFlags : uint
        {
            None = 0,
    
            /// <summary>
            /// KEYEVENTF_EXTENDEDKEY = 0x0001 (If specified, the scan code was preceded by a prefix byte that has the value 0xE0 (224).)
            /// </summary>
            ExtendedKey = 1,
    
            /// <summary>
            /// KEYEVENTF_KEYUP = 0x0002 (If specified, the key is being released. If not specified, the key is being pressed.)
            /// </summary>
            KeyUp = 2,
    
            /// <summary>
            /// KEYEVENTF_UNICODE = 0x0004 (If specified, wScan identifies the key and wVk is ignored.)
            /// </summary>
            Unicode = 4,
    
            /// <summary>
            /// KEYEVENTF_SCANCODE = 0x0008 (Windows 2000/XP: If specified, the system synthesizes a VK_PACKET keystroke. The wVk parameter must be zero. This flag can only be combined with the KEYEVENTF_KEYUP flag. For more information, see the Remarks section.)
            /// </summary>
            ScanCode = 8,
        }
    
        [Flags]
        public enum MouseFlags : uint
        {
            /// <summary>
            /// Specifies that movement occurred.
            /// </summary>
            Move = 0x0001,
    
            /// <summary>
            /// Specifies that the left button was pressed.
            /// </summary>
            LeftDown = 0x0002,
    
            /// <summary>
            /// Specifies that the left button was released.
            /// </summary>
            LeftUp = 0x0004,
    
            /// <summary>
            /// Specifies that the right button was pressed.
            /// </summary>
            RightDown = 0x0008,
    
            /// <summary>
            /// Specifies that the right button was released.
            /// </summary>
            RightUp = 0x0010,
    
            /// <summary>
            /// Specifies that the middle button was pressed.
            /// </summary>
            MiddleDown = 0x0020,
    
            /// <summary>
            /// Specifies that the middle button was released.
            /// </summary>
            MiddleUp = 0x0040,
    
            /// <summary>
            /// Windows 2000/XP: Specifies that an X button was pressed.
            /// </summary>
            XDown = 0x0080,
    
            /// <summary>
            /// Windows 2000/XP: Specifies that an X button was released.
            /// </summary>
            XUp = 0x0100,
    
            /// <summary>
            /// Windows NT/2000/XP: Specifies that the wheel was moved, if the mouse has a wheel. The amount of movement is specified in mouseData. 
            /// </summary>
            VerticalWheel = 0x0800,
    
            /// <summary>
            /// Specifies that the wheel was moved horizontally, if the mouse has a wheel. The amount of movement is specified in mouseData. Windows 2000/XP:  Not supported.
            /// </summary>
            HorizontalWheel = 0x1000,
    
            /// <summary>
            /// Windows 2000/XP: Maps coordinates to the entire desktop. Must be used with MOUSEEVENTF_ABSOLUTE.
            /// </summary>
            VirtualDesk = 0x4000,
    
            /// <summary>
            /// Specifies that the dx and dy members contain normalized absolute coordinates. If the flag is not set, dxand dy contain relative data (the change in position since the last reported position). This flag can be set, or not set, regardless of what kind of mouse or other pointing device, if any, is connected to the system. For further information about relative mouse motion, see the following Remarks section.
            /// </summary>
            Absolute = 0x8000,
        }
    
        [StructLayout(LayoutKind.Sequential)]
        public struct KEYBDINPUT
        {
            public ushort virtualKey;
            public ushort scanCode;
            public KeyboardFlags flags;
            public uint timeStamp;
            public IntPtr extraInfo;
        }
    
        [StructLayout(LayoutKind.Sequential)]
        public struct MOUSEINPUT
        {
            public int deltaX;
            public int deltaY;
            public int mouseData;
            public MouseFlags flags;
            public uint time;
            public IntPtr extraInfo;
        }
    
        [StructLayout(LayoutKind.Sequential)]
        public struct HARDWAREINPUT
        {
            public uint message;
            public ushort wParamL;
            public ushort wParamH;
        }
    
        [StructLayout(LayoutKind.Explicit)]
        public struct InputUnion
        {
            [FieldOffset(0)]
            public MOUSEINPUT mouse;
            [FieldOffset(0)]
            public KEYBDINPUT keyboard;
            [FieldOffset(0)]
            public HARDWAREINPUT hardware;
        }
        public enum InputType : int
        {
            Mouse = 0,
            Keyboard = 1,
            Hardware = 2
        }
        public struct INPUT
        {
            public InputType type;
            public InputUnion union;
        }
    
        [DllImport("user32.dll")]
        public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
    }
    

    即使有 XML 注释。

    接下来,让我们重写您的方法来修复错误。主要错误是您在字段中传递了一些数字 100 time。它不会延迟,但会在按下键时为应用程序提供信息 - 时间戳。

    time
    类型:DWORD
    事件的时间戳,以毫秒为单位。如果此参数为 0,系统将提供自己的时间戳。

    也就是说,你需要在那里传递 0 。

    而对于点击之间的延迟,你需要在你的应用程序中明确地等待,例如,Thread.Sleep(100)甚至更好await Task.Delay(100)。但是,让我们立即开始吧。

    public static void ClickMouse(int x, int y)
    {
        INPUT[] inputs = new INPUT[3];
    
        inputs[0] = new INPUT
        {
            type = InputType.Mouse, 
            union = new InputUnion
            {
                mouse = new MOUSEINPUT
                {
                    deltaX = x,
                    deltaY = y,
                    flags = MouseFlags.Move
                }
            }
        };
    
        inputs[1] = new INPUT
        {
            type = InputType.Mouse,
            union = new InputUnion
            {
                mouse = new MOUSEINPUT
                {
                    flags = MouseFlags.LeftDown
                }
            }
        };
    
        inputs[2] = new INPUT
        {
            type = InputType.Mouse,
            union = new InputUnion
            {
                mouse = new MOUSEINPUT
                {
                    flags = MouseFlags.LeftUp
                }
            }
        };
    
        SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));
    }
    

    没有额外的东西。顺便说一句,有SendInput一个返回值。

    返回值
    类型:UINT
    函数返回成功插入键盘或鼠标输入流的事件数。如果函数返回零,则输入已被另一个线程阻塞。

    也就是说,通过这个数字,您可以确定有多少来自数组的输入被成功处理。

    • 1

相关问题

  • 使用嵌套类导出 xml 文件

  • 分层数据模板 [WPF]

  • 如何在 WPF 中为 ListView 手动创建列?

  • 在 2D 空间中,Collider 2D 挂在玩家身上,它对敌人的重量相同,我需要它这样当它们碰撞时,它们不会飞向不同的方向。统一

  • 如何在 c# 中使用 python 神经网络来创建语音合成?

  • 如何知道类中的方法是否属于接口?

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    表格填充不起作用

    • 2 个回答
  • Marko Smith

    提示 50/50,有两个,其中一个是正确的

    • 1 个回答
  • Marko Smith

    在 PyQt5 中停止进程

    • 1 个回答
  • Marko Smith

    我的脚本不工作

    • 1 个回答
  • Marko Smith

    在文本文件中写入和读取列表

    • 2 个回答
  • Marko Smith

    如何像屏幕截图中那样并排排列这些块?

    • 1 个回答
  • Marko Smith

    确定文本文件中每一行的字符数

    • 2 个回答
  • Marko Smith

    将接口对象传递给 JAVA 构造函数

    • 1 个回答
  • Marko Smith

    正确更新数据库中的数据

    • 1 个回答
  • Marko Smith

    Python解析不是css

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5