CH9329 +CH340 Windows 下的封装
部分代码来自于github 自己加入了绝对鼠标移动。
·
部分代码来自于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;
更多推荐


所有评论(0)