Loading [MathJax]/jax/input/TeX/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >12.2 实现键盘模拟按键

12.2 实现键盘模拟按键

原创
作者头像
王 瑞
发布于 2023-10-08 07:58:28
发布于 2023-10-08 07:58:28
61900
代码可运行
举报
运行总次数:0
代码可运行

本节将向读者介绍如何使用键盘鼠标操控模拟技术,键盘鼠标操控模拟技术是一种非常实用的技术,可以自动化执行一些重复性的任务,提高工作效率,在Windows系统下,通过使用各种键盘鼠标控制函数实现动态捕捉和模拟特定功能的操作。

键盘鼠标的模拟是实现自动化的必备流程,通常我们可以使用keybd_event()实现对键盘的击键模拟,使用SetCursorPos()实现对鼠标的模拟,使用两者的配合读者可以很容易的实现对键盘鼠标的控制,本节将依次封装实现,模拟键盘鼠标控制功能,读者可根据自己的实际需求选用不同的函数片段。

12.2.1 模拟键盘按键

模拟按键的核心功能是通过调用keybd_event()函数实现的,如下是这段代码的完整实现,首先MySetKeyBig()函数该函数用于设置键盘状态是否为大小写,用户可以传入一个状态值来设置当前输入法大小写模式,MyAnalogKey()函数用于实现模拟键盘按键,该函数接收一个英文字符串,并自动实现击键操作,代码实现并不复杂,读者可自行测试功能。

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#include <windows.h>
#include <iostream>

using namespace std;

// 设置键盘大小写状态 为TRUE则切换大写状态,否则切换小写状态
VOID MySetKeyBig(BOOL big = FALSE)
{
  // 判断键盘CapsLock键是否开启状态,开启状态则为大写,否则为小写
  if (GetKeyState(VK_CAPITAL))
  {
    // 如果当前键盘状态为大写,要求改小写,则模拟按键CapsLock切换状态
    if (!big)
    {
      keybd_event(VK_CAPITAL, NULL, KEYEVENTF_EXTENDEDKEY | 0, NULL);
      keybd_event(VK_CAPITAL, NULL, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, NULL);
    }

    std::cout << "[键盘状态] " << "切换大写" << std::endl;
  }
  else
  {
    // 如果当前键盘状态为小写,要求改大写,则模拟按键CapsLock切换状态
    if (big)
    {
      keybd_event(VK_CAPITAL, NULL, KEYEVENTF_EXTENDEDKEY | 0, NULL);
      keybd_event(VK_CAPITAL, NULL, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, NULL);
    }

    std::cout << "[键盘状态] " << "切换小写" << std::endl;
  }
}

// 模拟键盘按键
VOID MyAnalogKey(char* str)
{
  int iLen = 0;
  char* tmp = NULL;
  INPUT* keys = NULL;
  BOOL bOldState = FALSE;

  // 保存此操作前的键盘状态
  bOldState = (BOOL)GetKeyState(VK_CAPITAL);
  iLen = lstrlen(str);
  tmp = (char*)malloc(iLen);
  memmove(tmp, str, iLen);
  for (int i = 0; i < iLen; i++)
  {
    // 某些符号非直属键盘按键,这里只过滤转换两个,以后用到其它字符自行添加过滤
    if (tmp[i] == ' ')
    {
      // 产生一个击键消息步骤:按下->抬起
      keybd_event(VK_SPACE, NULL, KEYEVENTF_EXTENDEDKEY | 0, NULL);
      keybd_event(VK_SPACE, NULL, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, NULL);
    }
    else if (tmp[i] == ',')
    {
      keybd_event(VK_OEM_COMMA, NULL, KEYEVENTF_EXTENDEDKEY | 0, NULL);
      keybd_event(VK_OEM_COMMA, NULL, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, NULL);
    }
    else if (tmp[i] >= 'a' && tmp[i] <= 'z')
    {
      // 根据字符大小写切换键盘大小写状态
      MySetKeyBig(0);
      // keybd_event只识别大写
      keybd_event((BYTE)tmp[i] - 32, NULL, KEYEVENTF_EXTENDEDKEY | 0, NULL);
      keybd_event((BYTE)tmp[i] - 32, NULL, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, NULL);
    }
    else if ((tmp[i] >= 'A' && tmp[i] <= 'Z') || (tmp[i] >= '0' && tmp[i] <= '9'))
    {
      MySetKeyBig(1);
      keybd_event((BYTE)tmp[i], NULL, KEYEVENTF_EXTENDEDKEY | 0, NULL);
      keybd_event((BYTE)tmp[i], NULL, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, NULL);
    }
    else
    {
      keybd_event((BYTE)tmp[i] + 64, NULL, KEYEVENTF_EXTENDEDKEY | 0, NULL);
      keybd_event((BYTE)tmp[i] + 64, NULL, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, NULL);
    }
    Sleep(50);
  }
  // 恢复此操作之前的键盘状态
  MySetKeyBig(bOldState);
  free(tmp);
}

int main(int argc, char *argv[])
{
  Sleep(5000);
  MyAnalogKey((char*)"Love life , Love LyShark WelCome LyShark Cpp Home ...");

  system("pause");
  return 0;
}

读者可自行编译并运行上述代码片段,将光标移动到记事本中,等待五秒钟,则会依次敲击如下所示的键盘按键;

12.2.2 设置窗体最大化

如下代码实现了设置一个窗体置顶并将该窗体最大化显示的效果,该代码实现原理是通过使用EnumWindows函数传递一个回调函数,实现对特定窗体的枚举,当找到对应窗体句柄后则将该窗体句柄传递给global_hwnd全局句柄中,当获取到Google浏览器句柄之后则通过GetSystemMetrics函数得到当前全屏窗体的像素比,通过调用SetWindowPos可将一个窗体设置为置顶显示,最后可调用SendMessage函数向特定窗体句柄发送最大化消息,使其填充满整个屏幕,代码如下所示;

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <windows.h>

using namespace std;

HWND global_hwnd = 0;

// 将字符串逆序
char * Reverse(char str[])
{
  int n = strlen(str);
  int i;
  char temp;
  for (i = 0; i < (n / 2); i++)
  {
    temp = str[i];
    str[i] = str[n - i - 1];
    str[n - i - 1] = temp;
  }
  return str;
}

// 窗体枚举回调函数
BOOL CALLBACK lpEnumFunc(HWND hwnd, LPARAM lParam)
{
  char WindowName[MAXBYTE] = { 0 };
  DWORD ThreadId, ProcessId = 0;

  GetWindowText(hwnd, WindowName, sizeof(WindowName));
  ThreadId = GetWindowThreadProcessId(hwnd, &ProcessId);
  printf("句柄: %-9d --> 线程ID: %-6d --> 进程ID: %-6d --> 名称: %s \n", hwnd, ThreadId, ProcessId, WindowName);

  // 首先逆序输出字符串,然后比较前13个字符
  if (strncmp(Reverse(WindowName), "emorhC elgooG", 13) == 0)
  {
    global_hwnd = hwnd;
  }
  return TRUE;
}

int main(int argc, char* argv[])
{
  // 枚举Google浏览器句柄
  EnumWindows(lpEnumFunc, 0);
  std::cout << "浏览器句柄: " << global_hwnd << std::endl;

  if (global_hwnd != 0)
  {
    // 获取系统屏幕宽度与高度 (像素)
    int cx = GetSystemMetrics(SM_CXSCREEN);
    int cy = GetSystemMetrics(SM_CYSCREEN);
    std::cout << "屏幕X: " << cx << " 屏幕Y: " << cy << std::endl;

    // 传入指定的HWND句柄
    HWND hForeWnd = GetForegroundWindow();
    DWORD dwCurID = GetCurrentThreadId();
    DWORD dwForeID = GetWindowThreadProcessId(hForeWnd, NULL);
    AttachThreadInput(dwCurID, dwForeID, TRUE);

    // 将该窗体呼出到顶层
    ShowWindow(global_hwnd, SW_SHOWNORMAL);
    SetWindowPos(global_hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
    SetWindowPos(global_hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
    SetForegroundWindow(global_hwnd);
    AttachThreadInput(dwCurID, dwForeID, FALSE);

    // 发送最大化消息
    SendMessage(global_hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);    // 最大化
    // SendMessage(global_hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0); // 最小化
    // SendMessage(global_hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);    // 关闭
  }

  system("pause");
  return 0;
}

读者可自行编译并运行上述程序,此时会将谷歌浏览器全屏并置顶显示,输出信息如下图所示;

12.2.3 读取与设置剪辑板

读取与设置剪辑版可用于对数据的拷贝与设置,调用setClipbar函数并传入一段字符串可实现将传入字符串拷贝到剪辑版的功能,使用getClipBoardValue则可实现读取剪辑版中的内容到程序内。

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <windows.h>
#include <time.h>

// 将字符串写入到剪切板
BOOL setClipbar(const char* data)
{
  int contentSize = strlen(data) + 1;
  HGLOBAL hMemory; LPTSTR lpMemory;

  // 打开剪切板
  if (!OpenClipboard(NULL))
  {
    return FALSE;
  }
  // 清空剪切板
  if (!EmptyClipboard())
  {
    return FALSE;
  }
  // 对剪切板分配内存
  if (!(hMemory = GlobalAlloc(GMEM_MOVEABLE, contentSize)))
  {
    return FALSE;
  }
  // 锁定内存区域
  if (!(lpMemory = (LPTSTR)GlobalLock(hMemory)))
  {
    return FALSE;
  }

  // 复制数据到内存区域,解除内存锁定
  memcpy_s(lpMemory, contentSize, data, contentSize);
  GlobalUnlock(hMemory);

  // 设置剪切板数据
  if (!SetClipboardData(CF_TEXT, hMemory))
  {
    return FALSE;
  }
  
  // std::cout << "已复制: " << data << " 长度: " << contentSize << std::endl;
  return CloseClipboard();
}

// 获取剪切板内容
char* getClipBoardValue()
{
  // 初始化
  char* url, *pData;
  size_t length;

  // 打开剪切板
  if (!OpenClipboard(NULL))
  {
    return FALSE;
  }

  // 获取剪切板内的数据
  HANDLE hData = GetClipboardData(CF_TEXT);
  if (hData == NULL)
  {
    return FALSE;
  }

  // 获取数据长度
  length = GlobalSize(hData);
  url = (char*)malloc(length + 1);

  // 将数据转换为字符
  pData = (char*)GlobalLock(hData);
  strcpy_s(url, length, pData);

  // 清理工作
  url[length] = 0;
  GlobalUnlock(hData);
  CloseClipboard();

  // 返回结果并释放内存
  char* result = _strdup(url);
  free(url);
  return result;
}

int main(int argc, char *argv[])
{
  Sleep(5000);

  for (size_t i = 0; i < 10; i++)
  {
    // 填充字符串
    char MyData[256] = { 0 };
    sprintf(MyData, "hello lyshark --> %d", i);

    // 设置到剪辑版
    BOOL set_flag = setClipbar(MyData);
    if (set_flag == TRUE)
    {
      // std::cout << "[*] 已设置" << std::endl;

      // 获取剪辑版
      char *data = getClipBoardValue();
      std::cout << "[剪辑版数据] = " << data << std::endl;
    }
  }

  system("pause");
  return 0;
}

运行上述程序,依次实现填充字符串并设置到剪辑版,最后再通过getClipBoardValue函数从剪辑版内读出数据,如下图所示;

本文作者: 王瑞

本文链接: https://www.lyshark.com/post/95b1ad6c.html

版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Electron中使用Node-ffi模拟键鼠操作
折腾这个东西就是要实现一个很简单的功能:在我的应用中控制处于后台的PPT进行翻页。
码客说
2020/05/09
4.7K0
模拟键盘与鼠标操作 C++
今天给大家带来,模拟键盘与鼠标操作的C++代码 都是独立的函数模块 废话不多说,直接上代码 #include "stdafx.h" #include "Shunli.h" #include "conio.h" #include <iostream> #include <sstream> #include <string> #include <algorithm> #include <vector> #include <imm.h> #include <stdio.h> #include <Wi
Shunnet
2021/06/11
2K0
C++实现一键关闭桌面
本程序使用C语言编写,调用的Windows API,所以只能在windows上运行
芯动大师
2023/10/14
3250
C++实现一键关闭桌面
Python PyWin32 模块
Python的生产效率极高,通过使用pypiwin32模块可以快速调用windows API函数,结合Python的高效开发能力,同等时间内比C++能更快的达到目标,pypiwin32模块封装了Win32下的常用定义,函数方法等。
王 瑞
2022/12/28
2.3K0
Python PyWin32 模块
外挂基础_开挂的正确姿势
  所谓游戏外挂,其实是一种游戏外辅程序,它可以协助玩家自动产生游戏动作、修改游戏网络数据包以及修改游戏内存数据等,以实现玩家用最少的时间和金钱去完成功力升级和过关斩将。虽然,现在对游戏外挂程序的“合法”身份众说纷纭,在这里我不想对此发表任何个人意见,让时间去说明一切吧。
全栈程序员站长
2022/11/10
2.6K0
WPF桌面端开发-音视频录制、获取缩略图(使用OpenCvSharp)
音视频分开录制,音频如果麦克风和扬声器都录制的话,也要分开录制,最后再合并所有的流。
码客说
2023/07/11
1.8K0
C#实现的三种方式实现模拟键盘按键
SendKeys.SendWait // 同步模拟按键(会阻塞UI直到对方处理完消息后返回)
用户7108768
2021/09/23
2.3K0
使用VC内嵌Python实现的一个代码检测工具
        最近组内准备整顿代码,领导让我写个简单的python脚本分析代码中注释的行数和无效注释。因为这个需求不是很急,所以我想把简单的事情做复杂点。于是就写了一个用VC内嵌Python,并通过模拟按键和发消息去控制其他软件的工具。(转载请指明出处)
方亮
2019/01/16
1.1K0
C#控制键盘按键(大小写按键等)
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; namespace sn设置键盘大小写 { public partial class Form1
用户8671053
2021/11/02
1.5K0
C/C++ 实现模拟键盘鼠标
今天写了点代码,功能是筛选桌面中符合某些条件的窗口,模拟鼠标键盘实现全选 → 复制 → 检测剪切板 → 判断是否存在某些敏感字符串。
王 瑞
2022/12/28
1.7K0
python模拟键盘输入_python控制鼠标键盘
该函数原型:keybd_event(bVk, bScan, dwFlags, dwExtraInfo)
全栈程序员站长
2022/11/18
2K0
python win32api中文手册_python 模拟鼠标和键盘输入
# FindWindow(lpClassName=None, lpWindowName=None) 窗口类名 窗口标题名
全栈程序员站长
2022/11/07
6.9K0
FindWindow使用方法_find do
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/170225.html原文链接:https://javaforall.cn
全栈程序员站长
2022/09/21
7230
pywin32模拟鼠标键盘操作
第三个参数:函数操作的一个标志位,如果值为KEYEVENTF_EXTENDEDKEY则该键被按下,也可设置为0即可,如果值为KEYEVENTF_KEYUP则该按键被释放;
周小董
2019/03/25
2.9K0
12.1 使用键盘鼠标监控钩子
本节将介绍如何使用Windows API中的SetWindowsHookEx和RegisterHotKey函数来实现键盘鼠标的监控。这些函数可以用来设置全局钩子,通过对特定热键挂钩实现监控的效果,两者的区别在于SetWindowsHookEx函数可以对所有线程进行监控,包括其他进程中的线程,而RegisterHotKey函数只能对当前线程进行监控。
王 瑞
2023/10/07
6440
12.1 使用键盘鼠标监控钩子
python-sendkeys 模拟键
因为特殊需要, 想找一套能简单发送键盘消息,模拟键盘操作的模块。  类似于 C#.net  或 VB  的  sendKeys  函数。
py3study
2020/01/13
2.3K0
Python编写渗透工具学习笔记一 | 0x07 Python实现键盘记录器
0x07 Python实现键盘记录器 这份代码比较经典,里面的注释也写的很详细,我也就直接放出来给大家一起学习一下。 简单说一说 我们定义了pyhook的hookmanager管理器,然后将我们自定义的回调函数keystroke与keydown事件进行了绑定。之后我们通过pyhook勾住了所有的按键事件,然后继续消息循环,当目标按下键盘上的一个键时,我们的keystroke函数就会被调用,它唯一的一个参数就是触发这个事件的对象。在这个函数中,我们要做的第一件事是检查用户是否切换了窗口,如果切换了窗口,我们需
安恒网络空间安全讲武堂
2018/02/06
2.4K0
Python编写渗透工具学习笔记一 | 0x07 Python实现键盘记录器
Python模拟键盘输入和鼠标操作
一、Python键盘输入模拟: import win32api import win32con win32api.keybd_event(17,0,0,0)  #ctrl键位码是17 win32api.keybd_event(86,0,0,0)  #v键位码是86 win32api.keybd_event(86,0,win32con.KEYEVENTF_KEYUP,0) #释放按键 win32api.keybd_event(17,0,win32con.KEYEVENTF_KEYUP,0) 附个键位码表:
用户7705674
2021/11/01
1.4K0
游戏编程之七 例程之初始化部分
首先调用DirectDrawEnumerate(),这个函数的作用在第五章 DirectDraw深入篇第三节选择DirectDraw驱动程序中已经谈到了。在本例程中这个函数的参数是&DDEnumCallback和NULL,&DDEnumCallback是指回调函数DDEnumCallback()的地址,NULL是指没有这个指向应用程序数据的指针。
张哥编程
2024/12/17
910
python之模拟键盘
对于python来说,模拟键盘的方式据我了解有三种方式,其中有pyuserinput,win32api,以及winio。
sjw1998
2019/09/28
5.6K0
相关推荐
Electron中使用Node-ffi模拟键鼠操作
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档