cpp_win32实现模拟windows鼠标键盘操作

⌚Time: 2022-09-17 13:27:45

👨‍💻Author: Jack Ge

使用到INPUT结构体


typedef struct tagINPUT {

  DWORD type;

  union {

    MOUSEINPUT mi;

    KEYBDINPUT ki;

    HARDWAREINPUT hi; 

  };

} INPUT, *PINPUT, FAR* LPINPUT;

type指定设备信息,可以为

INPUT_HARDWARE 硬件输入, hi union有效

INPUT_KEYBOARD 键盘输入,ki union有效

NPUT_MOUSE 鼠标输入,mi union有效

共用体

mi 是一个包含模拟鼠标输入信息的MOUSEINPUT结构体

ki 是一个包含模拟键盘输入信息的KEYBDINPUT结构体

hi 是一个包含模拟硬件输入信息的HARDWAREINPUT结构体

Windows嵌入式CE不支持类型成员中的INPUT_HARDWARE值。


对于键盘输入结构体


typedef struct tagKEYBDINPUT {

  WORD      wVk;

  WORD      wScan;

  DWORD     dwFlags;

  DWORD     time;

  ULONG_PTR dwExtraInfo;

} KEYBDINPUT, *PKEYBDINPUT, *LPKEYBDINPUT;

wVk

虚拟码(vkCode)。代码必须是1到254范围内的值。如果dwFlags成员指定KEYEVENTF_UNICODE,则wVk必须为0。

wScan

键盘扫描码(ScanCode)。如果dwFlags指定KEYEVENTF_UNICODE,则wScan指定要发送到前台应用程序的UNICODE字符。

dwFlags

指定击键的各个方面。此成员可以是以下值的某些组合。

|值|含义 |

|--|--|

| KEYEVENTF_EXTENDEDKEY 0x0001| 如果指定,则扫描代码前面是值为0xE0的前缀字节(224)。|

|KEYEVENTF_KEYUP 0x0002| 如果指定,则抬起键盘。如果未指定,则表示正在按下该键。|

|KEYEVENTF_SCANCODE 0x0008|如果指定,wScan将表示按键,并忽略wVk。|

|KEYEVENTF_UNICODE 0x0004|如果指定,系统合成VK_PACKET击键。wVk参数必须为零。此标志只能与KEYEVENTF_KEYUP标志组合使用。|

time

事件的时间戳,以毫秒为单位。如果此参数为零,系统将提供自己的时间戳。

dwExtraInfo

与击键关联的附加值


对于鼠标输入结构体


typedef struct tagMOUSEINPUT {

  LONG      dx;

  LONG      dy;

  DWORD     mouseData;

  DWORD     dwFlags;

  DWORD     time;

  ULONG_PTR dwExtraInfo;

} MOUSEINPUT, *PMOUSEINPUT, *LPMOUSEINPUT;

dx

鼠标的绝对位置,或自上次生成鼠标事件以来的运动量,取决于dwFlags成员的值。绝对数据指定为鼠标的x坐标;相对数据指定为移动的像素数。

dy

鼠标的绝对位置,或自上次生成鼠标事件以来的运动量,取决于dwFlags成员的值。绝对数据指定为鼠标的y坐标;相对数据指定为移动的像素数。

mouseData

如果dwFlags包含MOUSEEVENTF_WHEEL,则mouseData指定滚轮移动量。正值表示车轮向前旋转,远离用户;负值表示车轮向后旋转,朝向用户。一次滚轮点击定义为wheel_DELTA,即120。

Windows Vista:如果dwFlags包含MOUSEEVENTF_HWHEEL,则dwData指定车轮移动量。正值表示车轮向右旋转;负值表示车轮已向左旋转。一次滚轮点击定义为wheel_DELTA,即120。

如果dwFlags不包含MOUSEEVENTF_WHEEL、mouseeven tf_ XDOWN或mouseeeventf_XUP,则mouseData应为零。

如果dwFlags包含MOUSEEVENTF_XDOWN或MOUSEEVENTF_XUP,则mouseData指定按下或释放了哪些X按钮。该值可以是以下标志的任意组合。

|值| 含义 |

|--|--|

| XBUTTON1 0x0001| 第一个x按钮(鼠标左键)被按下或者抬起 |

|XBUTTON2 0x0002|第二个x按钮(鼠标右键)被按下或者抬起|

dwFlags

一组位标志,用于指定鼠标运动和按钮单击的各个方面。此成员中的位可以是以下值的任何合理组合。

指定鼠标按钮状态的位标志被设置为指示状态的更改,而不是正在进行的条件。例如,如果按住鼠标左键,则第一次按下鼠标左键时会设置MOUSEEVENTF_LEFTDOWN,但不会用于后续运动。类似地,仅当首次释放按钮时,才会设置MOUSEEVENTF_LEFTUP。

不能在dwFlags参数中同时指定MOUSEEVENTF_WHEEL标志和MOUSEEVENTF_XDOWN或MOUSEEEVENTF_XUP标志,因为它们都需要使用mouseData字段。

|值|含义 |

|--|--|

| MOUSEEVENTF_MOVE 0x0001| Movement occurred. |

|MOUSEEVENTF_LEFTDOWN 0x0002|The left button was pressed.

|MOUSEEVENTF_LEFTUP 0x0004|The left button was released.

|MOUSEEVENTF_RIGHTDOWN 0x0008|The right button was pressed.

|MOUSEEVENTF_RIGHTUP 0x0010|The right button was released.

|MOUSEEVENTF_MIDDLEDOWN 0x0020|The middle button was pressed.

|MOUSEEVENTF_MIDDLEUP 0x0040|The middle button was released.

|MOUSEEVENTF_XDOWN 0x0080|An X button was pressed.

|MOUSEEVENTF_XUP 0x0100|An X button was released.

|MOUSEEVENTF_WHEEL 0x0800|The wheel was moved, if the mouse has a wheel. The amount of movement is specified in mouseData.

|MOUSEEVENTF_HWHEEL 0x1000|The wheel was moved horizontally, if the mouse has a wheel. The amount of movement is specified in mouseData.Windows XP/2000: This value is not supported.

|MOUSEEVENTF_MOVE_NOCOALESCE 0x2000|The WM_MOUSEMOVE messages will not be coalesced. The default behavior is to coalesce WM_MOUSEMOVE messages.Windows XP/2000: This value is not supported.

|MOUSEEVENTF_VIRTUALDESK 0x4000|Maps coordinates to the entire desktop. Must be used with MOUSEEVENTF_ABSOLUTE.

|MOUSEEVENTF_ABSOLUTE 0x8000|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.

time

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

dwExtraInfo

与鼠标事件关联的附加值。

如果鼠标已经移动,由MOUSEEVENTF_MOVE表示,dx和dy指定有关该移动的信息。信息被指定为绝对或相对整数值。

如果指定了MOUSEEVENTF_ABSOLUTE value,则dx和dy包含0和65535之间的标准化绝对坐标。事件过程将这些坐标映射到显示表面。坐标(0,0)映射到显示表面的左上角;坐标(6553565535)映射到右下角。在多监视器系统中,坐标映射到主监视器。

如果指定了MOUSEEVENTF_VIRTUALDESK,则坐标映射到整个虚拟桌面。

如果未指定MOUSEEVENTF_ABSOLUTE值,则dx和dy指定相对于上一个鼠标事件(上次报告的位置)的移动。正值表示鼠标向右(或向下)移动;负值表示鼠标向左(或向上)移动。

相对鼠标运动受鼠标速度和两个鼠标阈值的影响。用户使用控制面板的鼠标属性表的指针速度滑块设置这三个值。可以使用SystemParametersInfo函数获取和设置这些值。

系统对指定的相对鼠标移动应用两个测试。如果沿x轴或y轴的指定距离大于第一个鼠标阈值,并且鼠标速度不为零,则系统将该距离加倍。如果沿x轴或y轴的指定距离大于第二鼠标阈值,并且鼠标速度等于2,则系统将使应用第一阈值测试产生的距离加倍。因此,系统可以将沿x轴或y轴的指定相对鼠标移动乘以四倍。

对于MOUSEEVENTF_ABSOLUTE标志,如果未指定,dx与dy表示鼠标移动相对于当前鼠标的位置,单位为像素,而指定,则是移动到0-65535的绝对坐标位置

dwFlags表示是滚轮或者按键信息,并且不能同时指定,因为data存放的是滚轮或者鼠标按键的数据


对于SendInput函数,原型


UINT SendInput(

  [in] UINT    cInputs,

  [in] LPINPUT pInputs,

  [in] int     cbSize

);

cInputs

pInputs数组中的结构数。

pInputs

输入结构的数组。每个结构表示要插入键盘或鼠标输入流的事件。

cbSize

输入结构的大小(以字节为单位)。如果cbSize不是输入结构的大小,则函数失败。

返回值

函数返回成功插入键盘或鼠标输入流的事件数。如果函数返回零,则输入已被另一个线程阻止。要获取扩展错误信息,请调用GetLastError。该函数被UIPI阻止时失败。请注意,GetLastError和返回值都不表示故障是由UIPI阻塞引起的。


模拟按键win+D,显示和隐藏桌面




    printf("Sending 'Win-D'\r\n");

    INPUT inputs[4] = {};

    ZeroMemory(inputs, sizeof(inputs));



    inputs[0].type = INPUT_KEYBOARD;

    inputs[0].ki.wVk = VK_LWIN;

   

    inputs[1].type = INPUT_KEYBOARD;

    inputs[1].ki.wVk = 'D';



    inputs[2].type = INPUT_KEYBOARD;

    inputs[2].ki.wVk = 'D';

    inputs[2].ki.dwFlags = KEYEVENTF_KEYUP;



    inputs[3].type = INPUT_KEYBOARD;

    inputs[3].ki.wVk = VK_LWIN;

    inputs[3].ki.dwFlags = KEYEVENTF_KEYUP;



    UINT uSent = SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));

    if (uSent != ARRAYSIZE(inputs))

    {

        printf("SendInput failed: 0x%x\n", HRESULT_FROM_WIN32(GetLastError()));

    } 

对于鼠标事件的模拟




INPUT input;

input.type = INPUT_MOUSE;

//移动到屏幕坐标(30000,30000)的位置

input.mi.dx = 30000;

input.mi.dy = 30000;

input.mi.mouseData = 0;

input.mi.dwFlags =  MOUSEEVENTF_MOVE|MOUSEEVENTF_ABSOLUTE;

input.mi.time = 0;

input.mi.dwExtraInfo = 0;

SendInput(1,&input,sizeof(INPUT));



INPUT input;

input.type = INPUT_MOUSE;

//相对于当前鼠标位置,移动鼠标(30,-100)像素

input.mi.dx = 30;

input.mi.dy = -100;

input.mi.mouseData = 0;

input.mi.dwFlags =  MOUSEEVENTF_MOVE;

input.mi.time = 0;

input.mi.dwExtraInfo = 0;

SendInput(1,&input,sizeof(INPUT));

如果我想将鼠标移动到屏幕特定像素位置,如何进行操作?






            //获取屏幕分辨率

            int cx_screen = ::GetSystemMetrics(SM_CXSCREEN); 

            int cy_screen = ::GetSystemMetrics(SM_CYSCREEN);  

            //指定鼠标移动到屏幕(300,500)像素的地方

            int targetPixelX = 300;

            int targetPixelY = 500;

            //将像素转化为绝对坐标位置

            int absPosX = targetPixelX*65535/cx_screen;

            int absPosY = targetPixelY*65535/cy_screen;

            INPUT input;

            input.type = INPUT_MOUSE;

            input.mi.dx = absPosX;

            input.mi.dy = absPosY;

            input.mi.mouseData = 0;

            input.mi.dwFlags =  MOUSEEVENTF_MOVE|MOUSEEVENTF_ABSOLUTE;

            input.mi.time = 0;

            input.mi.dwExtraInfo = 0;

            SendInput(1,&input,sizeof(INPUT));