【问题标题】:C# - MOUSEINPUT coordinates not setting properly when using SendInputC# - 使用 SendInput 时未正确设置 MOUSEINPUT 坐标
【发布时间】:2016-04-07 16:45:57
【问题描述】:

我正在尝试使用 SendInput 方法模拟鼠标输入。点击等工作正常,但坐标设置不正确。每次执行输入时,鼠标光标都会移动到屏幕的右下角。我尝试将 MOUSEINPUT X 和 Y 坐标更改为长数据类型as listed in the MSDN documentation,但 SendInput 方法总是返回错误并且输入不执行。

下面是我用来尝试这个的代码。我已经从创建和执行 KEYBDINPUT 结构的类似实现中移植了这段代码。该实现工作完美,所以我很困惑为什么不这样做。我确信它是非常小的东西,因为鼠标点击等成功执行它只是导致问题的坐标。

如果有人对这里出了什么问题有任何见解,我们将不胜感激。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace SequenceAutomation
{
    #region Stucture declarations

    public struct MOUSEINPUT
    {
        public int X;
        public int Y;
        public uint MouseData;
        public uint Flags;
        public uint Time;
        public IntPtr ExtraInfo;
    }

    public struct HARDWAREINPUT
    {
        public uint Msg;
        public ushort ParamL;
        public ushort ParamH;
    }

    public struct KEYBDINPUT
    {
        public ushort KeyCode;
        public ushort Scan; 
        public uint Flags;
        public uint Time; 
        public IntPtr ExtraInfo;
    }

    [StructLayout(LayoutKind.Explicit)]
    public struct MOUSEKEYBDHARDWAREINPUT
    {
        [FieldOffset(0)]
        public MOUSEINPUT Mouse;

        [FieldOffset(0)]
        public KEYBDINPUT Keyboard;

        [FieldOffset(0)]
        public HARDWAREINPUT Hardware;
    }

    public struct INPUT
    {
        public uint Type;
        public MOUSEKEYBDHARDWAREINPUT Data; 
    }

    #endregion

    public class PlayRecording
    {
        #region Variable declarations

        public bool stopPlayback;
        private RecordingManager recManager;
        private float timeFactor; 
        private Dictionary<long, Dictionary<IntPtr, Dictionary<string, int>>> mouseDict;
        private Dictionary<long, INPUT[]> keysToPlay; 
        private Stopwatch watch;
        private long currentEntry;

        #endregion

        #region Libary importations

        // Importation of native libraries
        [DllImport("user32.dll", SetLastError = true)]
        private static extern uint SendInput(uint numberOfInputs, INPUT[] inputs, int sizeOfInputStructure);

        #endregion

        #region Public methods

        public PlayRecording(string inputJson, float timeFactor)
        {
            currentEntry = 0;
            this.timeFactor = timeFactor;
            stopPlayback = false;
            watch = new Stopwatch();

            recManager = new RecordingManager(inputJson);
            recManager.getDictionaries(inputJson);
            mouseDict = recManager.mouseDict;

            inputsToPlay = new Dictionary<long, INPUT[]>();
            prepareInputsToPlay();
        }

        public void Start()
        {
            currentEntry = 0; 
            watch.Reset();
            watch.Start();
            IEnumerator<long> enumerator = inputsToPlay.Keys.GetEnumerator(); 
            while (enumerator.MoveNext())
            {
                while (watch.ElapsedTicks < (enumerator.Current * timeFactor)) { }

                if (!stopPlayback)
                    uint err = SendInput((uint)keysToPlay[enumerator.Current].Length, keysToPlay[enumerator.Current], Marshal.SizeOf(typeof(INPUT)));

                currentEntry = enumerator.Current; 
            }
        }


        public bool Stop()
        {
            watch.Stop();
            return true;
        }

        #endregion

        #region Private methods

        private void prepareInputsToPlay()
        {
            foreach (KeyValuePair<long, Dictionary<IntPtr, Dictionary<string, int>>> kvp in mouseDict)
            {
                List<INPUT> inputs = new List<INPUT>();

                foreach (KeyValuePair<IntPtr, Dictionary<string, int>> kvp2 in kvp.Value)
                {
                    int x = 0;
                    int y = 0;
                    foreach (KeyValuePair<string, int> kvp3 in kvp2.Value)
                    {
                        if (kvp3.Key == "X")
                            x = Convert.ToInt32(kvp3.Value);
                        if (kvp3.Key == "Y")
                            y = Convert.ToInt32(kvp3.Value);
                    }
                    inputs.Add(loadMouse(x, y, getFlags(kvp2.Key)));
                }
                inputsToPlay.Add(kvp.Key, inputs.ToArray());
            }
        }

        // This is where the flags are set
        private uint getFlags(IntPtr activity)
        {
            string activityInt = Convert.ToString(activity);
            switch(activityInt)
            {
                    return 0x0002;
                case "512":
                    return 0x0001;
                case "513":
                    return 0x0002;
                case "514":
                    return 0x0004;
                case "516":
                    return 0x0008;
                case "517":
                    return 0x0010;
                case "522":
                    return 0x0800;
                default:
                    return 0;
            }
        }

        // This is where the input structures are being created
        private INPUT loadMouse(int x, int y, uint flags)
        {
            return new INPUT
            {
                Type = 0,
                Data =
                {
                    Mouse = new MOUSEINPUT
                    {
                        X = x,
                        Y = y,
                        MouseData = 0,
                        Flags = flags,
                        Time = 0,
                        ExtraInfo = IntPtr.Zero
                    }
                }
            };
        }

        #endregion
    }
}

【问题讨论】:

    标签: c# .net winforms dictionary


    【解决方案1】:

    除非您包含标志MOUSEEVENTF_ABSOLUTE (0x8000),否则鼠标坐标是相对坐标。如果您在没有此标志的情况下传递绝对坐标,鼠标将快速移动到屏幕的一个角

    【讨论】:

    • 如何在传递该标志的同时传递其他标志,如左键单击、右键单击等?另外,如果我需要使用绝对坐标怎么办?我正在尝试精确地记录和模拟鼠标输入,所以我需要坐标来匹配那些最初记录的
    • 只需将该数字与您需要使用的任何其他标志进行或。输入中的getFlags(kvp2.Key) | 0x8000 之类的东西。添加行
    • 好的,所以我对代码进行了这个更改,现在光标射到左上角而不是右下角。然而,它确实四处移动。它完全按照记录的方式模仿动作,但只在左上角的一个小区域。有什么想法吗?就好像应用程序认为屏幕尺寸约为 2cm x 2cm。这与坐标是整数而不是长整数有关吗?
    • 数值范围是 0-65535,不是像素。如果您有像素坐标,则需要检查 PrimaryScreen 的大小并转换数字。像x = 65535 * x / Screen.PrimaryScreen.WorkingArea.Width 这样的东西。但是查找一次屏幕的大小并存储它会更整洁。坐标的含义都在MOUSEINPUT docs的备注里
    • 感谢您的帮助。我已将您的答案标记为解决方案。
    猜你喜欢
    • 1970-01-01
    • 2020-11-07
    • 1970-01-01
    • 2017-01-26
    • 1970-01-01
    • 1970-01-01
    • 2021-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多