CH340串口通信CH9329 模拟真实键盘鼠标 可防游戏检测
// 键盘按键编码定义
#define KEY_A 0x04
#define KEY_B 0x05
#define KEY_C 0x06
#define KEY_D 0x07
#define KEY_E 0x08
#define KEY_F 0x09
#define KEY_G 0x0A
#define KEY_H 0x0B
#define KEY_I 0x0C
#define KEY_J 0x0D
#define KEY_K 0x0E
#define KEY_L 0x0F
#define KEY_M 0x10
#define KEY_N 0x11
#define KEY_O 0x12
#define KEY_P 0x13
#define KEY_Q 0x14
#define KEY_R 0x15
#define KEY_S 0x16
#define KEY_T 0x17
#define KEY_U 0x18
#define KEY_V 0x19
#define KEY_W 0x1A
#define KEY_X 0x1B
#define KEY_Y 0x1C
#define KEY_Z 0x1D
// 数字按键编码定义
#define KEY_· 0x35
#define KEY_1 0x1E
#define KEY_2 0x1F
#define KEY_3 0x20
#define KEY_4 0x21
#define KEY_5 0x22
#define KEY_6 0x23
#define KEY_7 0x24
#define KEY_8 0x25
#define KEY_9 0x26
#define KEY_0 0x27
// 功能按键编码定义
#define KEY_F1 0x3A
#define KEY_F2 0x3B
#define KEY_F3 0x3C
#define KEY_F4 0x3D
#define KEY_F5 0x3E
#define KEY_F6 0x3F
#define KEY_F7 0x40
#define KEY_F8 0x41
#define KEY_F9 0x42
#define KEY_F10 0x43
#define KEY_F11 0x44
#define KEY_F12 0x45
#define KEY_ESC 0x29
#define KEY_BACKSPACE 0x2A
#define KEY_TAB 0x2B
#define KEY_ENTER 0x28
#define KEY_SPACE 0x2C // 键盘的空格键
#define KEY_MINUS 0x2D // 键盘的 - 键
#define KEY_EQUAL 0x2E // 键盘的 = 键
#define KEY_LEFT_BRACKET 0x2F // 键盘的 [ 键
#define KEY_RIGHT_BRACKET 0x30 // 键盘的 ] 键
#define KEY_BACKSLASH 0x31 // 键盘的 \ 键
#define KEY_SEMICOLON 0x33 // 键盘的 ; 键
#define KEY_QUOTE 0x34 // 键盘的 ' 键
#define KEY_COMMA 0x36 // 键盘的 , 键
#define KEY_PERIOD 0x37 // 键盘的 . 键
#define KEY_SLASH 0x38 // 键盘的 / 键
#define KEY_CAPS_LOCK 0x39
#define KEY_PRINT_SCREEN 0x46
#define KEY_SCROLL_LOCK 0x47
#define KEY_PAUSE 0x48
#define KEY_INSERT 0x49
#define KEY_HOME 0x4A
#define KEY_PAGE_UP 0x4B
#define KEY_DELETE 0x4C
#define KEY_END 0x4D
#define KEY_PAGE_DOWN 0x4E
#define KEY_RIGHT 0x4F
#define KEY_LEFT 0x50
#define KEY_DOWN 0x51
#define KEY_UP 0x52
#define KEY_NUM_LOCK 0x53
#define KEY_NUM_SLASH 0x54 // 键盘的小键盘 / 键
#define KEY_NUM_ASTERISK 0x55 // 键盘的小键盘 * 键
#define KEY_NUM_MINUS 0x56 // 键盘的小键盘 - 键
#define KEY_NUM_PLUS 0x57 // 键盘的小键盘 + 键
#define KEY_NUM_ENTER 0x58
#define KEY_NUM_1 0x59
#define KEY_NUM_2 0x5A
#define KEY_NUM_3 0x5B
#define KEY_NUM_4 0x5C
#define KEY_NUM_5 0x5D
#define KEY_NUM_6 0x5E
#define KEY_NUM_7 0x5F
#define KEY_NUM_8 0x60
#define KEY_NUM_9 0x61
#define KEY_NUM_0 0x62
#define KEY_NUM_PERIOD 0x63 // 键盘的小数点键
// 其他可能的特殊功能编码定义(已确认)
#define KEY_WIN_LEFT 0x08
#define KEY_WIN_RIGHT 0x80
#define KEY_ALT_LEFT 0xE2
#define KEY_ALT_RIGHT 0xE6
#define KEY_SHIFT_LEFT 0xE1
#define KEY_SHIFT_RIGHT 0xE5
#define KEY_CTRL_LEFT 0xE0
#define KEY_CTRL_RIGHT 0xE4
// CH9329 接收数据包结构体,由14个 unsigned char 构成
typedef struct CH9329_ReceiveDataFrame {
unsigned char frameHeader1; // 帧头(固定2字节,0x57 0xAB)
unsigned char frameHeader2;
unsigned char addressCode; // 地址码(1字节)
unsigned char commandCode; // 命令码(1字节)
unsigned char dataLength; // 后续数据长度(1字节)
union DataPacket{ // 后续数据部分(8个字节),用联合体(union)根据命令码适配不同的数据结构
struct KeyData{ // 普通键盘数据包相关数据结构(示例,对应CMD_SEND_KB_GENERAL_DATA等类似键盘命令)
unsigned char ControlKeys; // 控制键(1字节=8二进制位), bit7--bit0 每个bin位表示1个按键,
// 具体:r_win、r_alt、r_shift、r_ctrl、l_win、l_alt、l_shift、l_ctrl
unsigned char Key_Reserved1; // 1个字节 0x00, 该字节必须为0x00;
unsigned char KeyValues1; // 第3-8 个字节:6 个字节普通按键值,最多可以表示6 个按键按下,如果无按键按 下则填写0x00;
unsigned char KeyValues2;
unsigned char KeyValues3;
unsigned char KeyValues4;
unsigned char KeyValues5;
unsigned char KeyValues6;
}KeyData;
struct absMouseData{
unsigned char absMouseXYMode; // 鼠标坐标模式(1字节),相对鼠标坐标:0x01 或 绝对鼠标坐标:0x02
unsigned char absMouseKey; // 鼠标按键状态(1字节),bit2--bit0 每个bin位表示1个按键,具体:中键、右键、左键
unsigned char X_Hi; // 鼠标X轴绝对坐标的高位(1字节)
unsigned char X_Lo; // 鼠标X轴绝对坐标的低位(1字节)
unsigned char Y_Hi; // 鼠标Y轴绝对坐标的高位(1字节)
unsigned char Y_Lo; // 鼠标Y轴绝对坐标的低位(1字节)
unsigned char absWheelStatus; // 鼠标滚轮状态(1字节),具体:(0x01-0x7F)向上、(0x81-xFF)向下滚动的齿数, 0x00表示无滚动
unsigned char absMS_Reserved1; // 空余1个字节 0x00, 该字节必须为0x00;
}absMouseData;
struct relMouseData {
unsigned char relMouseXYMode; // 鼠标坐标模式(1字节),相对鼠标坐标:0x01 或 绝对鼠标坐标:0x02
unsigned char relMouseKey; // 鼠标按键状态(1字节),bit2--bit0 每个bin位表示1个按键,具体:中键、右键、左键
unsigned char Xoffset; // 鼠标X方向移动(1字节) [0x01-0x7F]表示向右移动、[0x81-0xFF]表示向左移动,.0x00表示无移动,0x100 - [...] 为实际移动像素值
unsigned char Yoffset; // 鼠标Y方向移动(1字节) [0x01-0x7F]表示向右移动、[0x81-0xFF]表示向左移动,.0x00表示无移动
unsigned char relWheelStatus; // 鼠标滚轮状态(1字节),具体:(0x01-0x7F)向上、(0x81-xFF)向下滚动的齿数, 0x00表示无滚动
unsigned char relMS_Reserved1; // 空余1个字节 0x00, 该字节必须为0x00;
unsigned char relMS_Reserved2; // 空余1个字节 0x00, 该字节必须为0x00;
unsigned char relMS_Reserved3; // 空余1个字节 0x00, 该字节必须为0x00;
}relMouseData;
}DataPacket;
unsigned char checksum; // 累加和(1字节)== (frameHeader1 + frameHeader2 + addressCode + commandCode + dataLength + 后续数据部分)
}SendDataFrame, *PDataFrame;
// CH340 串口 向 9329 发送 信息 模拟 键盘和鼠标
// 实测 向英雄联盟 发送 有效
// HANDLE openSerialPort(const wchar_t* portName, DWORD baudRate) 打开串口
// SendDataFrame ConstructKeyEncode(const int ControlKey, const int GeneralKey1, const int GeneralKey2) 构建发送数据包
// void* CH340rxCH9329(HANDLE hSerial, void* rxBuffer) 读串口数据
// void CH340txCH9329(HANDLE hSerial, SendDataFrame* data) 写串口数据
HANDLE openSerialPort(const wchar_t* portName, DWORD baudRate) {
HANDLE hSerial = CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hSerial == INVALID_HANDLE_VALUE) {
std::cout << "无法打开串口" << std::endl;
return INVALID_HANDLE_VALUE;
}
// 设置串口参数
DCB dcbSerialParams = { 0 };
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (!GetCommState(hSerial, &dcbSerialParams)) {
std::cout << "无法获取串口参数" << std::endl;
CloseHandle(hSerial);
return INVALID_HANDLE_VALUE;
}
dcbSerialParams.BaudRate = baudRate;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONE5STOPBITS;
dcbSerialParams.Parity = NOPARITY;
if (!SetCommState(hSerial, &dcbSerialParams)) {
std::cout << "无法设置串口参数" << std::endl;
CloseHandle(hSerial);
return INVALID_HANDLE_VALUE;
}
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (!SetCommTimeouts(hSerial, &timeouts)) {
std::cout << "无法设置串口超时" << std::endl;
CloseHandle(hSerial);
return INVALID_HANDLE_VALUE;
}
return hSerial;
}
// 构建发送数据包即CH9329接收数据 自动计算 校验和
SendDataFrame ConstructKeyEncode(const int ControlKey, const int GeneralKey1, const int GeneralKey2) {
SendDataFrame baseData;
baseData = { 0x57, 0xAB, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C }; // 基础键 = 释放键
if (ControlKey) {
baseData.DataPacket.KeyData.ControlKeys = ControlKey;
baseData.checksum += baseData.DataPacket.KeyData.ControlKeys; // 累加到校验和
if (GeneralKey1) {
baseData.DataPacket.KeyData.KeyValues1 = GeneralKey1 ;
baseData.checksum += baseData.DataPacket.KeyData.KeyValues1;
}
if (GeneralKey2) {
baseData.DataPacket.KeyData.KeyValues2 = GeneralKey2 ;
baseData.checksum += baseData.DataPacket.KeyData.KeyValues2;
}
} else {
if (GeneralKey1) {
baseData.DataPacket.KeyData.KeyValues1 = GeneralKey1 ;
baseData.checksum += baseData.DataPacket.KeyData.KeyValues1;
}
if (GeneralKey2) {
baseData.DataPacket.KeyData.KeyValues2 = GeneralKey2 ;
baseData.checksum += baseData.DataPacket.KeyData.KeyValues2;
}
}
return baseData;
}
// 发送构建的数据
void CH340txCH9329(HANDLE hSerial, SendDataFrame* data) {
PurgeComm(hSerial, PURGE_RXCLEAR); // 清理串口的接收rx缓存和发送tx缓存
PurgeComm(hSerial, PURGE_TXCLEAR);
DWORD bytesWritten;
BOOL success = WriteFile(hSerial, (void*)data, sizeof(SendDataFrame), &bytesWritten, NULL);
if (success == 0 ) {
std::cout << "写入失败" << std::endl;
} else {
}
return;
}
///// 使用示例 英雄联盟 无法屏蔽按键操作
const wchar_t* lpPort = L"COM4";
HANDLE hCom = openSerialPort(lpPort, 9600);
SendDataFrame* CH340SendData = new SendDataFrame[sizeof(SendDataFrame)];
*CH340SendData = ConstructKeyEncode(0, KEY_CAPS_LOCK, 0);
CH340toCH9329(hCom, CH340SendData);
结合其他截图功能(后台截图、全屏截图),可以实现后台截图分析游戏画面,发送按键释放技能,自动战斗

浙公网安备 33010602011771号