Windows/Linux模拟键盘鼠标操作

本文介绍在Windows和Linux平台上模拟鼠标键盘操作的方法。Windows下通过调用API实现键盘鼠标模拟,如Ctrl+V组合键发送、鼠标移动点击等;Linux下使用libXtst库模拟键盘鼠标操作,适用于自动化测试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在开发一些类似于向日葵或者VNC的远程桌面或者远控软件的时候,我们往往需要模拟键盘操作模拟鼠标操作。通过模拟操作,我们可以在不安装硬件外设的时候实现对电脑的控制。这里介绍一下在Windows和Linux平台下模拟鼠标键盘的实现方式,希望对有相关开发需求的人有帮助。

Windows模拟鼠标键盘操作

在windows下我们可以通过调用对应的windowsAPI实现对应的键盘鼠标操作模拟

模拟键盘操作

组合键的发送方式

#include <Windows.h>
//模拟键盘发送Ctrl+V贴操作
void SendCtrlV()
{
    // Create a generic keyboard event structure
    INPUT ip;
    ip.type = INPUT_KEYBOARD;
    ip.ki.wScan = 0;
    ip.ki.time = 0;
    ip.ki.dwExtraInfo = 0;

    // Press the "Ctrl" key
    ip.ki.wVk = VK_CONTROL;
    ip.ki.dwFlags = 0; // 0 for key press
    SendInput(1, &ip, sizeof(INPUT));

    // Press the "V" key
    ip.ki.wVk = 'V';
    ip.ki.dwFlags = 0; // 0 for key press
    SendInput(1, &ip, sizeof(INPUT));

    // Release the "V" key
    ip.ki.wVk = 'V';
    ip.ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(1, &ip, sizeof(INPUT));

    // Release the "Ctrl" key
    ip.ki.wVk = VK_CONTROL;
    ip.ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(1, &ip, sizeof(INPUT));
}

单键的发送方式

#include <Windows.h>
//模拟键盘发送单个的V按键
void SendCtrlV()
{
    // Create a generic keyboard event structure
    INPUT ip;
    ip.type = INPUT_KEYBOARD;
    ip.ki.wScan = 0;
    ip.ki.time = 0;
    ip.ki.dwExtraInfo = 0;
    
    // Press the "V" key
    ip.ki.wVk = 'V';
    ip.ki.dwFlags = 0; // 0 for key press
    SendInput(1, &ip, sizeof(INPUT));

    // Release the "V" key
    ip.ki.wVk = 'V';
    ip.ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(1, &ip, sizeof(INPUT));
}

常用的物理按键的值列表如下:

#define VK_SHIFT          0x10  //Shift键
#define VK_CONTROL        0x11  //Ctrl键
#define VK_MENU           0x12  //Alt键
#define VK_CAPITAL        0x14  //CapsLock大小写转换键 
#define VK_RETURN         0x0D  //Enter回车键
#define VK_ESCAPE         0x1B  //ESC键
#define VK_SPACE          0x20  //空格键
#define VK_PRIOR          0x21  //PageUp键
#define VK_NEXT           0x22  //PageDown键
#define VK_END            0x23  //End键
#define VK_HOME           0x24  //Home键
#define VK_TAB            0x09   //Tab 键
#define VK_MULTIPLY       0x6A  //乘
#define VK_ADD            0x6B  //加
#define VK_SEPARATOR      0x6C  //除
#define VK_SUBTRACT       0x6D  //减
#define VK_DECIMAL        0x6E  //小数点
#define VK_SNAPSHOT       0x2C  //Print Screen 键
#define VK_INSERT         0x2D  //Insert键
#define VK_DELETE         0x2E  //Delete键
#define VK_LBUTTON        0x01  //鼠标左键
#define VK_RBUTTON        0x02  //鼠标右键 
#define VK_MBUTTON        0x04  //鼠标中键
#define VK_F1             0x70  //功能键F1-F24
#define VK_F2             0x71
#define VK_F3             0x72
#define VK_F4             0x73
#define VK_F5             0x74
#define VK_F6             0x75
#define VK_F7             0x76
#define VK_F8             0x77
#define VK_F9             0x78
#define VK_F10            0x79
#define VK_F11            0x7A
#define VK_F12            0x7B
0~9可以直接使用ASCII字符表示 '0'~'9'
a-z/A-Z也可以直接 'a'~'z' 'A'~'Z'表示

模拟鼠标移动和点击需要使用mouse_event函数

VOID mouse_event(
  DWORD     dwFlags,     //移动和点击的标志位
  DWORD     dx,          //水平位置
  DWORD     dy,          //垂直位置
  DWORD     dwData,      //滚轮位移
  ULONG_PTR dwExtraInfo  //应用定义的信息
);

//dwFlags常用标志信息
MOUSEEVENTF_MOVE = 0x0001;        //移动鼠标
MOUSEEVENTF_LEFTDOWN = 0x0002;   //模拟鼠标左键按下
MOUSEEVENTF_LEFTUP = 0x0004;     //模拟鼠标左键抬起
MOUSEEVENTF_RIGHTDOWN = 0x0008;  //模拟鼠标右键按下
MOUSEEVENTF_RIGHTUP = 0x0010;    //模拟鼠标右键抬起
MOUSEEVENTF_MIDDLEDOWN = 0x0020; //模拟鼠标中键按下
MOUSEEVENTF_MIDDLEUP = 0x0040;   //模拟鼠标中键抬起
MOUSEEVENTF_ABSOLUTE = 0x8000;   //标示是否采用绝对坐标
//模拟将鼠标移动到x,y位置
void mouse_move(int x,int y)
{
	mouse_event(MOUSEEVENTF_MOVE|MOUSEEVENTF_ABSOLUTE,x*65536/1024,y*65536/768,0,0);
}

//模拟鼠标移动到x,y位置并进行左键点击
void mouse_move_and_left_click(int x,int y)
{
	mouse_event(MOUSEEVENTF_MOVE|MOUSEEVENTF_ABSOLUTE,x*65536/1024,y*65536/768,0,0);
	mouse_event(MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_LEFTUP,0,0,0,0);
}

//模拟鼠标移动到x,y位置并进行右键点击
void mouse_move_and_right_click(int x,int y)
{
	mouse_event(MOUSEEVENTF_MOVE|MOUSEEVENTF_ABSOLUTE,x*65536/1024,y*65536/768,0,0);
	mouse_event(MOUSEEVENTF_RIGHTDOWN|MOUSEEVENTF_RIGHTUP,0,0,0,0);
}

//模拟鼠标移动到x,y并双击
void mouse_move_and_double_left_click(int x,int y)
{
	mouse_event(MOUSEEVENTF_MOVE|MOUSEEVENTF_ABSOLUTE,x*65536/1024,y*65536/768,0,0);
	mouse_event(MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_LEFTUP,0,0,0,0);
	mouse_event(MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_LEFTUP,0,0,0,0);
}

Linux模拟键盘鼠标操作

在Linux下我们可以使用libXtst模拟鼠标键盘操作,通过模拟鼠标键盘操作我们可以实现自动化测试。

如果系统里面没有libXtst库,我们可以通过下面的命令进行安装

sudo apt update
sudo apt install libxtst-dev

系统安装之后我们就可以使用libXtst库了,如果是Qt工程可以通过下面的配置引入Xtst库

LIBS += -lXtst 

如果是CMake项目我们可以通过下面的命令引入Xtst库

LINK_LIBRARIES(Xtst)

引入了对应的库之后我们就可以在代码中模拟键盘鼠标操作了

键盘操作

模拟单一的按键操作

#include <X11/extensions/XTest.h>
#include <X11/Xlib.h>
#include <X11/keysymdef.h>

int SimulateSingleKey()
{
    Display* disp = XOpenDisplay(NULL);
    if(disp == NULL)
    {
        return 0;
    }   
    //模拟键盘上的A键的点击                                   
    XTestFakeKeyEvent(disp, XKeysymToKeycode(disp, XK_A), True, CurrentTime);
    XTestFakeKeyEvent(disp, XKeysymToKeycode(disp, XK_A), False, CurrentTime);

    XCloseDisplay(disp);
    return 1;
}

模拟组合键的操作

#include <X11/extensions/XTest.h>
#include <X11/Xlib.h>
#include <X11/keysymdef.h>
void simulateMultiKey()
{
    Display* disp = XOpenDisplay(NULL);
    if(disp == NULL)
    {
        return;
    }
    //模拟Ctrl+A的组合键操作
    int ctrl_value = XK_Control_L;
    int key_value = XK_A;
    KeyCode keycode = 0, modcode = 0;

    keycode = XKeysymToKeycode (disp, key_value);
    if (keycode == 0) return;
    XTestGrabControl (disp, True);
   
     //保持Ctrl键
    if (ctrl_value != 0)
    {
        modcode = XKeysymToKeycode(disp, ctrl_value);
        XTestFakeKeyEvent (disp, modcode, True, 0);
    }

    //模拟A键按下
    XTestFakeKeyEvent (disp, keycode, True, 0);
    XTestFakeKeyEvent (disp, keycode, False, 0);

    //释放Ctrl键
    if (ctrl_value != 0)
        XTestFakeKeyEvent (disp, modcode, False, 0);

    XSync (disp, False);
    XTestGrabControl (disp, False);

    XCloseDisplay(disp);
}

Xtst中常用的物理按键的值列表如下:

#define XK_Shift_L                       0xffe1  //左Shift
#define XK_Shift_R                       0xffe2  //右Shift
#define XK_Control_L                     0xffe3  //左Ctrl
#define XK_Control_R                     0xffe4  //右Ctrl
#define XK_Caps_Lock                     0xffe5  //CapsLock
#define XK_Shift_Lock                    0xffe6  //ShiftLock
#define XK_Alt_L                         0xffe9  //左Alt
#define XK_Alt_R                         0xffea  //右Alt
#define XK_Meta_L                        0xffe7  //左Windows键
#define XK_Meta_R                        0xffe8  //右windows键
#define XK_BackSpace                     0xff08  //backspace键
#define XK_Tab                           0xff09  //tab键
#define XK_Return                        0xff0d  //回车换行
#define XK_Escape                        0xff1b  //ESC键
#define XK_space                         0x0020  //空格键
#define XK_plus                          0x002b  //加   
#define XK_minus                         0x002d  //减
#define XK_multiply                      0x00d7  //乘 
#define XK_A                             0x0041  
#define XK_B                             0x0042  
#define XK_C                             0x0043  
#define XK_D                             0x0044  
#define XK_E                             0x0045  
#define XK_F                             0x0046  
#define XK_G                             0x0047  
#define XK_H                             0x0048  
#define XK_I                             0x0049  
#define XK_J                             0x004a  
#define XK_K                             0x004b  
#define XK_L                             0x004c  
#define XK_M                             0x004d  
#define XK_N                             0x004e  
#define XK_O                             0x004f  
#define XK_P                             0x0050  
#define XK_Q                             0x0051  
#define XK_R                             0x0052  
#define XK_S                             0x0053  
#define XK_T                             0x0054  
#define XK_U                             0x0055  
#define XK_V                             0x0056  
#define XK_W                             0x0057  
#define XK_X                             0x0058  
#define XK_Y                             0x0059  
#define XK_Z                             0x005a  
#define XK_0                             0x0030  
#define XK_1                             0x0031  
#define XK_2                             0x0032  
#define XK_3                             0x0033  
#define XK_4                             0x0034  
#define XK_5                             0x0035  
#define XK_6                             0x0036  
#define XK_7                             0x0037  
#define XK_8                             0x0038  
#define XK_9                             0x0039  
#define XK_F1                            0xffbe
#define XK_F2                            0xffbf
#define XK_F3                            0xffc0
#define XK_F4                            0xffc1
#define XK_F5                            0xffc2
#define XK_F6                            0xffc3
#define XK_F7                            0xffc4
#define XK_F8                            0xffc5
#define XK_F9                            0xffc6
#define XK_F10                           0xffc7
#define XK_F11                           0xffc8
#define XK_F12                           0xffc9
//更多按键参考keysymdef.h文件

Linux下模拟鼠标移动和点击操作

//模拟将鼠标移动到x,y位置
void simulate_mouse_move(int x,int y)
{
   Display* disp = XOpenDisplay(NULL);
    if(disp == NULL)
    {
        return;
    }
    XTestGrabControl(disp, True);
   XTestFakeMotionEvent(disp, 0, x, y, CurrentTime);
   XTestGrabControl(disp, False);
   XFlush(disp);
   XCloseDisplay(disp); 
}
//模拟将鼠标移动到x,y位置然后点击鼠标按键
void simulate_mouse_move_and_click(int x,int y)
{
   Display* disp = XOpenDisplay(NULL);
    if(disp == NULL)
    {
        return;
    }
    XTestGrabControl(disp, True);
    //鼠标移动
   XTestFakeMotionEvent(disp, 0, x, y, CurrentTime);
   //鼠标模拟按键
   //@1:屏幕的指针
   //@2:按键类型:1(鼠标左键) 3(鼠标右键) 2(鼠标中键)
   //4(滚轮正方向滚动) 5(滚轮反方向滚动)
   //@3操作的标志位:true(按键按下) false(按键抬起)
   //@4操作延时,设置成0就行
   XTestFakeButtonEvent(disp,  1, true, CurrentTime);
   XTestGrabControl(disp, False);
   XFlush(disp);
   XCloseDisplay(disp); 
}

通过采用Xtst库我们就可以实现各种鼠标键盘操作的模拟了。通过物理操作的模拟可以实现远控和自动化测试等之前无法实现的功能了。

WinAPI-Wrapper 模拟鼠标点击 用于模拟鼠标移动、点击、窗口操作等的Windows API包装器类。 API 下面是一些可用的方法的总结。有更多的方法和类,比下面列出的要多,但目的是要大致了解包装器能做什么。要查看关于特定方法的详细信息和参数的详细信息,请查看代码本身,因为它的注释很好。 Mouse.cs public static void LeftClick(); public static void RightClick(); public static void MiddleClick(); public static void LeftDown(); public static void LeftUp(); public static void RightDown(); public static void RightUp(); public static void MiddleDown(); public static void MiddleUp(); public static void Move(int x, int y); public static void LeftDrag(Point point1, Point point2, int interval, int lag); Window.cs public static bool DoesExist(string windowTitle); public static IntPtr Get(string windowTitle); public static IntPtr GetFocused(); public static void SetFocused(IntPtr hWnd); public static bool IsFocused(IntPtr hWnd); public static void Move(IntPtr hWnd, int x, int y); public static void Resize(IntPtr hWnd, int width, int height); public static void Hide(IntPtr hWnd); public static void Show(IntPtr hWnd); public static Rectangle GetDimensions(IntPtr hWnd); public static Size GetSize(IntPtr hWnd); public static Point GetLocation(IntPtr hWnd); public static string GetTitle(IntPtr hWnd); public static void SetTitle(IntPtr hWnd, string title); public static void Maximize(IntPtr hWnd); public static void Minimize(IntPtr hWnd); public static void Normalize(IntPtr hWnd); public static Bitmap Screenshot(IntPtr hWnd); public static void RemoveMenu(IntPtr hWnd); public static void Close(IntPtr hWnd); public static void DisableCloseButton(IntPtr hWnd); public static void DisableMaximizeButton(IntPtr hWnd); public static void DisableMinimizeButton(IntPtr hWnd); public static void EnableMouseTransparency(IntPtr hWnd); public static Point ConvertToWindowCoordinates(IntPtr hWnd, int x, int y); public static Point GetCoordinateRelativeToWindow(IntPtr hWnd); Desktop.cs public static Bitmap Screenshot(); public static void HideTaskBar(); public static void ShowTaskBar(); public static int GetWidth(); public static int GetHeight(); 使用 在windows api文件夹中编译代码会产生一个.dll文件。任何引用这个.dll的ccode都可以使用包装器。
模拟鼠标键盘 注意:不支持Windows 8 / 8.1。 Interceptor是Windows键盘驱动程序的包装器(包装http://oblita.com/Interception)。 使用驱动程序,Interceptor可以模拟按键和鼠标点击... 使用DirectX的游戏,通常不接受使用SendInput()的击键 Windows的受保护区域,如Windows登录屏幕或UAC调暗屏幕 任何应用程序 因为驱动程序模拟击键和鼠标单击,所以目标窗口必须处于活动状态(即,在发送击键和鼠标点击时,不能在另一个窗口上执行多任务)。 如何使用 下载并构建此项目并在项目中引用其DLL。 下载'interception.dll',这是一个由驱动程序作者编写的独立库。将它放在与可执行文件相同的目录中。这是必需的。 从作者的网页下载并安装“install-interception.exe”。安装后重新启动计算机。 在您的代码中,要加载驱动程序,请调用(阅读下面的代码注释;您必须设置过滤模式以捕获按键事件或发送按键操作!): Input input = new Input(); // Be sure to set your keyboard filter to be able to capture key presses and simulate key presses // KeyboardFilterMode.All captures all events; 'Down' only captures presses for non-special keys; 'Up' only captures releases for non-special keys; 'E0' and 'E1' capture presses/releases for special keys input.KeyboardFilterMode = KeyboardFilterMode.All; // You can set a MouseFilterMode as well, but you don't need to set a MouseFilterMode to simulate mouse clicks // Finally, load the driver input.Load(); 做你的东西。 input.MoveMouseTo(5, 5); // Please note this doesn't use the driver to move the mouse; it uses System.Windows.Forms.Cursor.Position input.MoveMouseBy(25, 25); // Same as above ^ input.SendLeftClick(); input.KeyDelay = 1; // See below for explanation; not necessary in non-game apps input.SendKeys(Keys.Enter); // Presses the ENTER key down and then up (this constitutes a key press) // Or you can do the same thing above using these two lines of code input.SendKeys(Keys.Enter, KeyState.Down); Thread.Sleep(1); // For use in games, be sure to sleep the thread so the game can capture all events. A lagging game cannot process input quickly, and you so you may have to adjust this to as much as 40 millisecond delay. Outside of a game, a delay of even 0 milliseconds can work (instant key presses). input.SendKeys(Keys.Enter, KeyState.Up); input.SendText("hello, I am typing!"); /* All these following characters / numbers / symbols work */ input.SendText("abcdefghijklmnopqrstuvwxyz"); input.SendText("1234567890"); input.SendText("!@#$%^&*()"); input.SendText("[]\\;',./"); input.SendText("{}|:\"?"); // And finally input.Unload(); 笔记: BadImageFormatException如果您没有为解决方案中的所有项目(包括此项目)使用正确的体系结构(x86或x64),则可能会获得。因此,您可能必须下载此项目的源代码才能将其重建为正确的体系结构。这应该很简单,构建过程应该没有错误。 您必须从http://oblita.com/Interception下载'interception.dll' 。 如果你已经完成了以上所有操作(正确安装了拦截驱动程序,将interception.dll放在你的项目文件夹中),你仍然无法发送击键: 驱动程序有一个限制,即它不能在不接收至少一次击键的情况下发送击键。这是因为驱动程序不知道键盘是哪个设备ID,因此它必须等待接收击键以从击键中推断出设备ID。 总之,在发送击键之前,请始终按键盘一次。点按任意键。然后你可以发送击键。这不适用于接收击键,因为通过接收击键,您当然已经按下了一个键。 MoveMouseTo()和MoveMouseBy()完全忽略键盘驱动程序。它使用System.Windows.Forms.Position来设置和获取游标的位置(它为下面的各个函数调用标准的Win32 API)。 原因是,在探索键盘驱动程序的鼠标移动功能时,我注意到它没有按像素单位移动光标,而是似乎通过加速移动光标。当我想将光标移动到某个位置时,这会不断产生不一致的值。因为Win32游标设置API通常不被游戏等阻止,所以我发现只需调用这些标准API即可,而无需使用驱动程序。请注意,这仅适用于设置光标位置。拦截光标仍然可以正常工作。例如,您可以使用Interceptor反转鼠标的x和y轴。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农飞飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值