部分代码来自于github 自己加入了绝对鼠标移动,windows下配合这俩啊硬件做什么,我觉得大家都明白,多数是模拟按键过检测,使用方式包含此头文件 Ch9329::KeyInput(key值);

#pragma once
#include <windows.h>
#include <iostream>
#define COMNAME "\\\\.\\COM5" //或许需要更改
#define MOUSE_LEFT 0
#define MOUSE_RIGHT 1
#define MOUSE_MID 2
#define CHKEY_A 0x04
#define CHKEY_B 0x05
#define CHKEY_C 0x06
#define CHKEY_D 0x07
#define CHKEY_E 0x08
#define CHKEY_F 0x09
#define CHKEY_G 0x0a
#define CHKEY_H 0x0b
#define CHKEY_I 0x0c
#define CHKEY_J 0x0d
#define CHKEY_K 0x0e
#define CHKEY_L 0x0f
#define CHKEY_M 0x10
#define CHKEY_N 0x11
#define CHKEY_O 0x12
#define CHKEY_P 0x13
#define CHKEY_Q 0x14
#define CHKEY_R 0x15
#define CHKEY_S 0x16
#define CHKEY_T 0x17
#define CHKEY_U 0x18
#define CHKEY_V 0x19
#define CHKEY_W 0x1a
#define CHKEY_X 0x1b
#define CHKEY_Y 0x1c
#define CHKEY_Z 0x1d
#define CHKEY_0 0x27
#define CHKEY_1 0x1e
#define CHKEY_2 0x1f
#define CHKEY_3 0x20
#define CHKEY_4 0x21
#define CHKEY_5 0x22
#define CHKEY_6 0x23
#define CHKEY_7 0x24
#define CHKEY_8 0x25
#define CHKEY_9 0x26
//大写需要|0x80 这些按键基本够用了不够自己封装

typedef struct buffer{
	int len;
	char data[70];
}BUFFER;

typedef struct keyevent{
	uint8_t  press;
	uint8_t  code;
}KEYEVENT;


typedef struct uart_fmt{
	uint8_t  HEAD[2]; // 帧头:占 2 个字节,固定为 0x57、0xAB
	uint8_t  ADDR; // 地址码:占 1 个字节,默认为 0x00,可接收任意地址码的命令包,如果芯片地址设置成 0x01---0xFE,则只能接收对应地址码或地址码为 0xFF 的命令包。0xFF 为广播包,芯片不需 要进行应答;
	uint8_t  CMD; // 命令码:占 1 个字节,外围串口设备发起的帧的命令码有效范围为:0x01---0x3F,CH9329 芯片发送正常应答包时的命令码为:原命令码 | 0x80;CH9329 芯片发送异常应答包时的命 令码为:原命令码 | 0xC0;
	uint8_t  LEN; // 后续数据长度:占 1 个字节,主要用于记录该包实际后续数据的长度,仅包含后续数据部分,不包括帧头字节、地址码、命令码和累加和字节; 
	uint8_t  DATA[64]; // 后续数据:占 N 个字节,N 有效范围为 0---64。typedef 
	uint8_t  SUM; // 累加和:占 1 个字节,计算方式为: SUM = HEAD+ADDR+CMD+LEN+DATA
}UART_FMT;

typedef struct ch9329cmd{
	uint8_t  GET_INFO; //获取芯片版本等信息 通过该命令向芯片获取版本号、 USB 枚举状态、键盘大小写指示灯 状态等信息 
	uint8_t  SEND_KB_GENERAL_DATA; //发送 USB 键盘普通数据 通过该命令向芯片发送普通键盘 数据包,模拟普通按键按下或释放 动作
	uint8_t  SEND_KB_MEDIA_DATA; //发送 USB 键盘多媒体数据 通过该命令向芯片发送多媒体键 盘数据包,模拟多媒体按键按下或 释放动作 
	uint8_t  SEND_MS_ABS_DATA; //发送 USB 绝对鼠标数据 通过该命令向芯片发送绝对鼠标 数据包,模拟绝对鼠标相关动作 
	uint8_t  SEND_MS_REL_DATA; //发送 USB 相对鼠标数据 通过该命令向芯片发送相对鼠标 数据包,模拟相对鼠标相关动作 
	uint8_t  SEND_MY_HID_DATA; //发送 USB 自定义 HID 设备数据 通过该命令向芯片发送自定义 HID 类设备数据包
	uint8_t  READ_MY_HID_DATA; //读取 USB 自定义 HID 设备数据 通过该命令从芯片读取自定义 HID 类设备数据包 注:PC 机向芯片下传 1 包自定义 HID 数据包后,由芯片串口自动打 包发送给外围串口设备 
	uint8_t  GET_PARA_CFG; //获取参数配置 通过该命令向芯片获取当前参数 配置信息
	uint8_t  SET_PARA_CFG; //设置参数配置 通过该命令向芯片设置当前参数 配置信息 
	uint8_t  GET_USB_STRING; //获取字符串描述符配置 通过该命令向芯片获取当前所使 用的 USB 字符串描述符配置 
	uint8_t  SET_USB_STRING; //设置字符串描述符配置 
	uint8_t  SET_DEFAULT_CFG; //恢复出厂默认配置 通过该命令将芯片的参数配置及 字符串配置信息恢复到出厂默认 设置 
	uint8_t  RESET; //复位芯片 通过该命令控制芯片进行软件复 位控制 
}CH9329CMD;


class Ch9329 
{
	public:
		static void MouseMove(int x, int y, bool is_abs = true);
		static void KeyInput(uint8_t code);
		static void MouseClickLeft();
		static void MouseClickRight();
		static void MouseClickMid();
		static void MouseWheel(char num);
		
	private:
		static Ch9329 chip;
		HANDLE hComm;
		char  ctrbyte { 0 };
		char  mousebyte{ 0 };
		char  mousexbyte{ 0 };
		char  mouseybyte{ 0 };
		char  mousewbyte{ 0 };
		KEYEVENT ctrkeys[8]{ 0 };
		KEYEVENT keys[6]{ 0 };
		KEYEVENT mousekeys[3]{ 0 };
		struct ch9329cmd cmd;
	
	private:
		Ch9329();
		~Ch9329();
		void openCom();
		int write(BUFFER buf);
		int read(BUFFER* buf);
		void purge();
		void close();
		BUFFER getKeyData();
		BUFFER getMouseData();
		uint8_t  getBit(char  byte, int position);
		void setSum(UART_FMT* data);
		BUFFER getOutData(UART_FMT data);
		BUFFER keyDown(uint8_t code);
		BUFFER keyUp(uint8_t code);
		BUFFER mouseDown(uint8_t code);
		BUFFER mouseUp(uint8_t code);
		BUFFER mouseMove(int  x, int  y, bool is_abs = true);
		BUFFER mouseWheel(char num);
};

#include "Ch9329.h"

Ch9329::Ch9329()
{
	//初始化cmd对应的数值
	cmd = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x7, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0F };
	openCom();//打开串口



}

BUFFER Ch9329::keyDown(uint8_t code)
{
	
	for(int i=0;i<8;i++) 
	{
		if(ctrkeys[i].code == code) 
		{
			ctrkeys[i].press = 1; 
			return getKeyData();
		} 
	}
	
	for(int i=0;i<6;i++) 
	{
		if(keys[i].press == 1 && keys[i].code == code) 
		{
			return getKeyData();
		} 
	}
	
	for(int i=0;i<6;i++) 
	{
		if(keys[i].press == 0) 
		{
			keys[i].press = 1; 
			keys[i].code = code;
			return getKeyData();
		} 
	}

	return getKeyData();
}
BUFFER Ch9329::keyUp(uint8_t code)
{

	for(int i=0;i<8;i++) 
	{
		if(ctrkeys[i].code == code) 
		{
			ctrkeys[i].press = 0; 
			return getKeyData();
		} 
	}
	for(int i=0;i<6;i++) 
	{
		if(keys[i].code == code) 
		{
			keys[i].press = 0; 
			keys[i].code = 0;
			return getKeyData();
		} 
	}
	return getKeyData();
}


BUFFER Ch9329::mouseDown(uint8_t code)
{
	if(code>=0 && code<3)
		mousekeys[code].press = 1;

	return getMouseData();
}

BUFFER Ch9329::mouseUp(uint8_t code)
{
	if(code>=0 && code<3)
		mousekeys[code].press = 0;

	return getMouseData();
}

BUFFER Ch9329::mouseMove(int x, int y,bool is_abs)
{

	if (is_abs)
	{
		//初始化一次,因为游戏中应该不会有切换显示器分辨率的傻逼
		static int full_x = ::GetSystemMetrics(SM_CXSCREEN);
		static int full_y = ::GetSystemMetrics(SM_CYSCREEN);
		UART_FMT fmt = { 0x57,0xAB,0x00,0x04,0x07,{0x02,0x02,},0x00 };
		fmt.CMD = cmd.SEND_MS_ABS_DATA;
		fmt.DATA[1] = 0x0;//鼠标左键被按下
		int result_x = x * 4096 / full_x;
		fmt.DATA[2] = (result_x & 0xFF);//x低位
		fmt.DATA[3] = (result_x >> 8 & 0xFF);//x高位
		int result_y = y * 4096 / full_y;
		fmt.DATA[4] = (result_y & 0xFF);//y低位
		fmt.DATA[5] = (result_y >> 8 & 0xFF);//y高位
		fmt.DATA[6] = 0;
		setSum(&fmt);
		return getOutData(fmt);
	}
	else {
	
		// 0x01 - 0x7f 为向右移动 0x80 - 0xff 为向左移动
		//相对本人距离 默认 左边- 右边+
		if (x > -128 && x < 128)
		{
			if (x < 0)
			{
				mousexbyte = 0xFF + x + 1;
			}
			else
			{
				mousexbyte = x;
			}
		}
		if (y > -128 && y < 128)
		{
			if (y < 0)
			{
				mouseybyte = 0xFF + y + 1;
			}
			else
			{
				mouseybyte = y;
			}
		}

		return getMouseData();
	}
	

	


	

}



BUFFER Ch9329::mouseWheel(char num)
{
	if(num > -128 && num< 128)
	{
		if(num<0)
		{
			mousewbyte = 0xFF + num + 1;
		}
		else
		{
			mousewbyte = num;	
		} 
	} 
	return getMouseData();
}

void Ch9329::MouseMove(int x, int y, bool is_abs)
{
	auto res=Ch9329::chip.mouseMove(x, y, is_abs);
	
	Ch9329::chip.write(res);

}

void Ch9329::KeyInput(uint8_t code)
{
	Ch9329::chip.write(Ch9329::chip.keyDown(code));
	Ch9329::chip.write(Ch9329::chip.keyUp(code));
}

void Ch9329::MouseClickLeft()
{
	Ch9329::chip.write(Ch9329::chip.mouseDown(MOUSE_LEFT));
	Ch9329::chip.write(Ch9329::chip.mouseUp(MOUSE_LEFT));
}

void Ch9329::MouseClickRight()
{
	Ch9329::chip.write(Ch9329::chip.mouseDown(MOUSE_RIGHT));
	Ch9329::chip.write(Ch9329::chip.mouseUp(MOUSE_RIGHT));
}

void Ch9329::MouseClickMid()
{
	Ch9329::chip.write(Ch9329::chip.mouseDown(MOUSE_MID));
	Ch9329::chip.write(Ch9329::chip.mouseUp(MOUSE_MID));
}

void Ch9329::MouseWheel(char num)
{
	Ch9329::chip.write(Ch9329::chip.mouseWheel(num));
}

BUFFER Ch9329::getKeyData()
{
	UART_FMT fmt = {0x57,0xAB,0x00,0x02,0x08,{0x00,},0x00};
	//fmt.CMD = cmd.SEND_KB_GENERAL_DATA;
	//fmt.LEN = 8;
	char ctr = 0;
	for(int i=0;i<8;i++) 
	{
		if(ctrkeys[i].press == 1) 
		{
			ctr |= 1<<i;
		} 
	}
	ctrbyte = ctr; 
	fmt.DATA[0] = ctr;
	
	for(int i=0;i<6;i++) 
	{
		if(keys[i].press == 1) 
		{
			fmt.DATA[i+2] = keys[i].code;
		} 
	}
	
	setSum(&fmt);
	
	return getOutData(fmt);
	
}

BUFFER Ch9329::getMouseData()
{
	UART_FMT fmt = {0x57,0xAB,0x00,0x05,0x05,{0x00,},0x00};
	//fmt.CMD = cmd.SEND_MS_REL_DATA;
	//fmt.LEN = 5;
	char key = 0;
	for(int i=0;i<3;i++) 
	{
		if(mousekeys[i].press == 1) 
		{
			key |= 1<<i;
		} 
	}
	mousebyte = key; 
	fmt.DATA[0] = 0x01;
	fmt.DATA[1] = key;

	fmt.DATA[2] = mousexbyte;
	fmt.DATA[3] = mouseybyte;
	fmt.DATA[4] = mousewbyte;
	mousexbyte = 0;
	mouseybyte = 0;
	mousewbyte = 0;
	
	setSum(&fmt);
	
	return getOutData(fmt);
}

BUFFER Ch9329::getOutData(UART_FMT data)
{
	BUFFER buf;
	buf.len = data.LEN + 6;
	buf.data[0] = data.HEAD[0];
	buf.data[1] = data.HEAD[1];
	buf.data[2] = data.ADDR;
	buf.data[3] = data.CMD;
	buf.data[4] = data.LEN;
	for(int i=0;i<data.LEN;i++) 
	{
		buf.data[5 + i] = data.DATA[i];
	}
	buf.data[5 + data.LEN] = data.SUM;
	return buf;
}

uint8_t Ch9329::getBit(char byte, int position)
{
	return byte & (1 << position);
}

void Ch9329::setSum(UART_FMT* data)
{
	int t = data->HEAD[0] + data->HEAD[1] + data->ADDR + data->CMD + data->LEN;
	for(int i=0;i<data->LEN;i++)
	{
		t +=  data->DATA[i];
	} 
	data->SUM = t & 0xFF;
}

Ch9329::~Ch9329()
{
	close();
}

void Ch9329::openCom()
{

	hComm = CreateFile(COMNAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	if (hComm == INVALID_HANDLE_VALUE) {
		std::cerr << "Error opening com: " << GetLastError() << std::endl;
	}
	else
	{
		printf("%s is opened \n",COMNAME);
	}

	// 配置串口参数
	DCB dcbSerialParams = { 0 };
	dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
	if (!GetCommState(hComm, &dcbSerialParams)) {
		std::cerr << "Error getting serial port state: " << GetLastError() << std::endl;
		CloseHandle(hComm);
	}

	// 设置波特率,数据位,停止位和奇偶校验 这里默认就行不行自己调整
	dcbSerialParams.BaudRate = CBR_9600;     // 设置波特率为 9600
	dcbSerialParams.ByteSize = 8;            // 数据位 8
	dcbSerialParams.StopBits = ONESTOPBIT;  // 停止位 1
	dcbSerialParams.Parity = NOPARITY;      // 无奇偶校验


	if (!SetCommState(hComm, &dcbSerialParams)) {
		std::cerr << "Error setting serial port state: " << GetLastError() << std::endl;
		CloseHandle(hComm);
	}

	// 设置超时
	COMMTIMEOUTS timeouts = { 0 };
	timeouts.ReadIntervalTimeout = 50;     // 每次读取之间的最大间隔
	timeouts.ReadTotalTimeoutConstant = 50; // 总读取超时时间
	timeouts.ReadTotalTimeoutMultiplier = 10;
	timeouts.WriteTotalTimeoutConstant = 50;
	timeouts.WriteTotalTimeoutMultiplier = 10;

	if (!SetCommTimeouts(hComm, &timeouts)) {
		std::cerr << "Error setting timeouts: " << GetLastError() << std::endl;
		CloseHandle(hComm);
	}

}

int Ch9329::write(BUFFER buf)
{
	DWORD written_cnt; // 实际写入串口的字节数
	WriteFile(hComm, (void*)buf.data, buf.len, &written_cnt, NULL);
	int arr[] = { 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00 };
	WriteFile(hComm, (void*)arr, buf.len, &written_cnt, NULL);
	return written_cnt;
}

int Ch9329::read(BUFFER* buf)
{
	DWORD toread_cnt = 70; // 要从串口读入的字节数
	DWORD read_cnt;        // 实际从串口读入的字节数

	auto res=ReadFile(hComm, (void*)buf->data, toread_cnt, &read_cnt, NULL);
	std::cout << "len: " << toread_cnt << std::endl;
	buf->len = toread_cnt;

	return read_cnt;
}

void Ch9329::purge()
{
	//清缓存
	PurgeComm(hComm, PURGE_RXCLEAR);
}

void Ch9329::close()
{
	CloseHandle(hComm);
}

Ch9329 Ch9329::chip;

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐