C++ Qt 鼠标键盘录制回放软件:实时监控鼠标键盘事件并生成脚本
#include 'mainwindow.h' #include 'ui_mainwindow.h' MainWindow pThis;//UI指针 //创建线程 RunScript runscript; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) {
ui->setupUi(this);
pThis=this;//将自身对象暴露给外部全局变量指针,这样在回调函数中就可以访问了
//水平表格头显示和隐藏
ui->tw_process->horizontalHeader()->setVisible(false);
//垂直表格头显示和隐藏
ui->tw_process->verticalHeader()->setVisible(false);
//设置窗口透明度:
this->setWindowOpacity(0.8);
this->setWindowFlags(Qt::WindowStaysOnTopHint);
connect(ui->bt_load,&QPushButton::clicked,this,&clicked_bt_load);
connect(ui->bt_save,&QPushButton::clicked,this,&clicked_bt_save);
connect(ui->bt_save_as,&QPushButton::clicked,this,&clicked_bt_save_as);
connect(ui->bt_replace,&QPushButton::clicked,this,&clicked_bt_replace);
//获取窗口的句柄
HWND hwnd=(HWND)(this->winId());
//hook原始输入数据 键盘
if (lanrenAPI::hookRawInputData(hwnd,HID_USAGE_GENERIC_KEYBOARD)==0){
QMessageBox::information(this,'错误!','创建原始键盘数据设备失败!');
}
//hook原始输入数据 鼠标
if (lanrenAPI::hookRawInputData(hwnd,HID_USAGE_GENERIC_MOUSE)==0){
QMessageBox::information(this,'错误!','创建原始鼠标数据设备失败!');
}
//建立消息机制,收到数据会通知
lpPrevWndFunc=(WNDPROC)SetWindowLongPtr(hwnd,GWLP_WNDPROC,(LONG_PTR)&func_Message);
qDebug()<<lpPrevWndFunc;
}
MainWindow::~MainWindow() { delete ui; }
void MainWindow::clicked_bt_load(bool clicked){
QString fileName= QFileDialog::getOpenFileName(this,'导入脚本','C:\Users\Administrator',tr('TEXT (*.txt)'));
//读取内容 放到textEdit中
//默认编码格式是 utf-8
QFile file(fileName);
//设置打开方式
file.open(QIODeviceBase::ReadOnly);
while(!file.atEnd()){
QByteArray array= file.readLine();
QTextCodec * codec=QTextCodec::codecForName(GetCorrectUnicode(array).toLatin1());
ui->pte_jb->moveCursor(QTextCursor::End);
ui->pte_jb->insertPlainText(codec->toUnicode(array));
}
//关闭文件
file.close();
ui->cb_history->addItem(fileName);
updataJBList();
} void MainWindow::clicked_bt_save(bool clicked){
QString str=ui->pte_jb->toPlainText();
char* ch;
QByteArray ba = str.toUtf8(); // must
ch=ba.data();
QFile file(ui->cb_history->currentText());
//写文件
file.open(QIODevice::WriteOnly);
file.write(ch);
file.close();
updataJBList();
} void MainWindow::clicked_bt_save_as(bool clicked){ QString fileName= QFileDialog::getSaveFileName(this,'另存脚本','C:\Users\Administrator',tr('TEXT (.txt)')); char ch; QByteArray ba = fileName.toUtf8(); // must ch=ba.data();
QFile file(ui->cb_history->currentText());
//写文件
file.open(QIODevice::WriteOnly);
file.write(ch);
file.close();
}
void MainWindow::clicked_bt_replace(bool clicked){
qDebug() << lanrenAPI::setWindowsMousePenetrate(hwnd,true);
}
void MainWindow::updataJBList() {
ui->tw_process->setVisible(false);
jbList.clear();
int index=0;
QChar del_1 = '\n';
QStringList result;
JB_TYPE jb;
jb.jbText='';
jb.idex=0;
jb.name='';
//用换行符分割
result=ui->pte_jb->toPlainText().split('\n');
//lanrenAPI::splitText(ui->pte_jb->toPlainText(), del_1,result);
int length=(int)result.length();
for (int i=0;i<length;i++){
index=index+(result[i]+'\n').length();
if(result[i].indexOf('##')==-1){
jb.jbText=jb.jbText+result[i]+'\n';
if(i==length-1){
jbList.push_back(jb);
jb.jbText='';
break;
}
if(result[i+1].indexOf('##')!=-1){
jbList.push_back(jb);
jb.jbText='';
}
}else{
jb.name=result[i];
jb.idex=index-1;
}
}
//qDebug()<<jbList[0].name<<jbList[0].jbText;
//将分好的组放入列表中
ui->tw_process->setRowCount(jbList.size());
ui->tw_process->setColumnCount(1);
//ui->tw_process->setVerticalHeaderLabels({'流程名'});
for (int i=0;i<jbList.size();i++){
QTableWidgetItem * Item =new QTableWidgetItem(jbList[i].name.replace('##',''));
Item->setCheckState(Qt::Checked);//
ui->tw_process->setItem(i, 0, Item);
}
//自动调整大小
ui->tw_process->resizeRowsToContents();
ui->tw_process->resizeColumnsToContents();
ui->tw_process->setVisible(true);
} LRESULT CALLBACK MainWindow::func_Message(HWND hwnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (uMsg==WM_INPUT){
static UINT dwSize = 48;
static LONGLONG inTimeKeyboard=0;
static LONGLONG inTimeMouse=0;
static QString nowTimeText;
static QString keyMouse,typeMouse;
static QString ret;
static POINT lpPint;
// 第一次调用函数传NULL获取需要的缓冲区大小 已经知道了就直接填48
//GetRawInputData((HRAWINPUT)lParam, (UINT)RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
//分配指定的缓冲区大小
static LPBYTE lpbBuffer = new BYTE[dwSize];
// 取数据到缓冲区
GetRawInputData((HRAWINPUT)lParam, (UINT)RID_INPUT, (LPVOID)lpbBuffer, (PUINT)&dwSize, (UINT)sizeof(RAWINPUTHEADER));
static RAWINPUT* rawdata = (RAWINPUT *)lpbBuffer;
if(rawdata->header.dwType==RIM_TYPEKEYBOARD){
inTimeKeyboard=updateIntervalKeyboard();
switch(rawdata->data.keyboard.VKey){
case(VK_F8):{//按下F8开始录制
if(rawdata->data.keyboard.Message==WM_KEYUP){
if(isRec==false)
{
if(isRecall==true){
goto endCall;
}
isRec =true;
isRecall=false;
nowTimeText=lanrenAPI::getNowTimeText();
GetCursorPos(&lpPint);//获取当前鼠标相对于桌面的位置
if(isResetRec==false){
jbText=pThis->ui->pte_jb->toPlainText();
jbText+=jbText+'##' + nowTimeText + '##' + '\n鼠标初始 ' + QString::number(lpPint.x) + ' ' + QString::number(lpPint.y) + '\n';
}else{
jbText= '鼠标初始 ' + QString::number(lpPint.x) + ' ' + QString::number(lpPint.y) + '\n';
}
pThis->updataState();
LARGE_INTEGER a;
QueryPerformanceCounter(&a);
intervalKeyboard=a.QuadPart;
intervalMose=intervalKeyboard;
}else{
isRec =false;
isRecall=false;
pThis->ui->pte_jb->setPlainText(jbText);
pThis->updataState();
}
}
break;
}
case(VK_F9):{//按下F9开始回放
if(rawdata->data.keyboard.Message==WM_KEYUP){
if(isRecall==false)
{
if(isRec==true){
goto endCall;
}
isRecall=true;
isRec=false;
pThis->updataState();
runTime=pThis->ui->led_time->text().toInt();
jbText=pThis->ui->pte_jb->toPlainText();
runscript=new RunScript;
//绑定
connect(pThis,&MainWindow::setRunDatas,runscript ,&RunScript::setRunDatas );
//将参数发送过去
// 将函数指针转换为整型变量
FunctionPointer funcPtr = pThis->updataState;
int funcPtrInt = reinterpret_cast<uintptr_t>(funcPtr);
emit pThis->setRunDatas(runTime,jbList,funcPtrInt);
//启动线程
runscript->start();
}else{
isRecall=false;
isRec=false;
pThis->updataState();
}
}
break;
}//case end
case(VK_F7):{//按下F7
if(rawdata->data.keyboard.Message==WM_KEYUP){
pThis->ui->pte_jb->clear();
jbText='';
pThis->ui->tw_process->clear();
}
break;
}//case end
case(VK_F10):{//按下F10
if(rawdata->data.keyboard.Message==WM_KEYUP){
jbText+='等待键 ' + QString::number(inTimeKeyboard) + '\n---标记 弹起--\n';
}else{
jbText+='等待键 ' + QString::number(inTimeKeyboard) + '\n---标记 按下--\n';
}
break;
}//case end
case(VK_F11):{//按下F11
if(rawdata->data.keyboard.Message==WM_KEYUP && isRec==true){
isRec=false;
isRecall=false;
pThis->updataState();
}
break;
}//case end
default:{
if(isRec==false){
goto endCall;
}
ret='\n按键 ' + lanrenAPI::keyIntToText(rawdata->data.keyboard.VKey) + ' ' + QString::number(rawdata->data.keyboard.Message-255);
jbText+='等待键 ' + QString::number(inTimeKeyboard) + ret + '\n';
break;
}
}//switch end
}else if(rawdata->header.dwType==RIM_TYPEMOUSE){
inTimeMouse=updateIntervalMouse();
switch (rawdata->data.mouse.usButtonFlags){
case(0):{
keyMouse='0';
typeMouse='0';
break;
}//case_end
case(1):{
keyMouse='1';
typeMouse='1';
break;
}//case_end
case(2):{
keyMouse='1';
typeMouse='2';
break;
}//case_end
case(4):{
keyMouse='2';
typeMouse='1';
break;
}//case_end
case(8):{
keyMouse='2';
typeMouse='2';
break;
}//case_end
case(16):{
keyMouse='3';
typeMouse='1';
break;
}//case_end
case(32):{
keyMouse='3';
typeMouse='2';
break;
}//case_end
case(1024):{
//将data.mouse.usButtonData强制转换为有符号的short类型
short wheelDelta = static_cast<short>(rawdata->data.mouse.usButtonData);
keyMouse='4';
typeMouse='3';
ret='\n鼠标 ' + keyMouse + ' ' + typeMouse + ' ' + QString::number(rawdata->data.mouse.lLastX) + ' ' + QString::number(rawdata->data.mouse.lLastY) + ' ' + QString::number(wheelDelta);
jbText+='等待鼠 ' + QString::number(inTimeMouse) + ret + '\n';
break;
}//case_end
}//switch_end
if(isRec==false){
goto endCall;
}
ret='\n鼠标 ' + keyMouse + ' ' + typeMouse + ' ' + QString::number(rawdata->data.mouse.lLastX) + ' ' + QString::number(rawdata->data.mouse.lLastY);
jbText+='等待鼠 ' + QString::number(inTimeMouse) + ret + '\n';
qDebug() << '鼠标数据到达' << rawdata->data.mouse.lLastX << rawdata->data.mouse.lLastY << rawdata->data.mouse.usButtonFlags << rawdata->data.mouse.usButtonData << inTimeMouse;
}
}
endCall:
return CallWindowProcA (lpPrevWndFunc, hwnd, uMsg, wParam, lParam);
} void MainWindow::updataState(){ HWND hwnd=(HWND)(pThis->winId()); if (isRec==false && isRecall==false){ pThis->ui->lb_state->setText('待机中'); pThis->setWindowOpacity(0.8); pThis->ui->lb_state->setStyleSheet('color: rgb(0, 255, 255);'); lanrenAPI::setWindowsMousePenetrate(hwnd,false);
}else if(isRec==true && isRecall==false){
if(isResetRec){
pThis->ui->lb_state->setText('重录中');
}else{
pThis->ui->lb_state->setText('录制中');
}
pThis->setWindowOpacity(0.6);
pThis->ui->lb_state->setStyleSheet('color: rgb(0, 255, 0);');
lanrenAPI::setWindowsMousePenetrate(hwnd,true);
}else if(isRec==false && isRecall==true){
pThis->ui->lb_state->setText('回放中');
pThis->setWindowOpacity(0.6);
pThis->ui->lb_state->setStyleSheet('color: rgb(255, 255, 0);');
lanrenAPI::setWindowsMousePenetrate(hwnd,true);
}else{
isRecall=false;
isRec=false;
pThis->ui->lb_state->setText('待机中');
pThis->setWindowOpacity(0.8);
pThis->ui->lb_state->setStyleSheet('color: rgb(0, 255, 255);');
lanrenAPI::setWindowsMousePenetrate(hwnd,false);
}
} //自动判断编码格式 QString MainWindow::GetCorrectUnicode(const QByteArray &ba) { QTextCodec::ConverterState state; QTextCodec *codec = QTextCodec::codecForName('UTF-8'); QString text = codec->toUnicode( ba.constData(), ba.size(), &state); if (state.invalidChars > 0) { text = QTextCodec::codecForName( 'GBK' )->toUnicode(ba); return QString('GBK'); } else { text = ba; return QString('UTF-8'); } }
//更新鼠标间隔 LONGLONG updateIntervalMouse(){ LARGE_INTEGER a; LONGLONG ret; QueryPerformanceCounter(&a); ret= a.QuadPart-intervalMose; intervalMose=a.QuadPart; return ret; } //更新键盘间隔 LONGLONG updateIntervalKeyboard(){ LARGE_INTEGER a; LONGLONG ret; QueryPerformanceCounter(&a); ret= a.QuadPart-intervalKeyboard; intervalKeyboard=a.QuadPart; return ret; }
原文地址: https://www.cveoy.top/t/topic/nwzl 著作权归作者所有。请勿转载和采集!