欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[Easyx\C++]一个简单的QQ聊天机器人的实现

程序员文章站 2022-07-14 22:12:54
...

最近看到个很智能的聊天机器人,于是我也想着自己是不是也可以做一个

于是经过一番查询,我发现方法有很多(识图,买机器人服务之类的),比较麻烦。

然后这时候我蹦出了一个清奇的想法…

我可不可以直接右键聊天内容,复制到剪贴板,然后再对内容进行操作之后塞入剪贴板,再给贴回去从而达到目的呢?

经过一番操作后,发现可以!(我知道这个方法很取巧,是我太菜了23333)

然后写了写…

代码如下:

#include <Windows.h>
#include <iostream>
#include <thread>
#include <string>
#include <graphics.h>
#include <fstream>
using namespace std;
bool live = true;
bool getn = false;
wifstream fp;//文件引导
void run() {
	GetAsyncKeyState(VK_UP);
	GetAsyncKeyState(VK_DOWN);
	while (live) {
		if (GetAsyncKeyState(VK_UP) & 1) {
			getn = !getn;
			wcout << (getn ?TEXT("开启\n") :TEXT("关闭\n"));
		}
		else if (GetAsyncKeyState(VK_DOWN) & 1)
			live = false;
		Sleep(30);
	}
}
void gress() {
	wstring str;
	TCHAR str_get[600]{ 0 };
	OpenClipboard(NULL);//打开剪贴板,成功了返回true
	if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
		str.insert(0, (TCHAR*)GetClipboardData(CF_UNICODETEXT));
		wcout <<TEXT("发现句子:") << str << endl;
		wcout <<TEXT("正在比对字符串...") << endl;
		fp.seekg(0, ios::beg);//移到开头
		fp.clear();
		while (fp.good()) {
			fp.getline(str_get, 600, TEXT('\n'));
			if ((-1 != str.find(str_get)) && (lstrlen(str_get) > 0)) {//如果有
				wcout <<TEXT("抓取的关键词是:") << str_get << endl;
				fp.getline(str_get, 600, '\n');
				wcout <<TEXT("反馈句子是:") << str_get << endl;
				EmptyClipboard();//清空剪贴板
				HGLOBAL h = GlobalAlloc(GMEM_DDESHARE, (lstrlen(str_get) + 1)*sizeof(TCHAR));//分配内存
				if (!h) {//如果获取内存失败
					CloseClipboard();//关闭剪贴板
					return;
				}
				memcpy(GlobalLock(h), str_get, (lstrlen(str_get) + 1) * sizeof(TCHAR));
				GlobalUnlock(h);
				SetClipboardData(CF_UNICODETEXT, h);
				break;
			}
			else {//如果没有
				fp.getline(str_get, 600, TEXT('\n'));
				fp.getline(str_get, 600, TEXT('\n'));
			}
		}
		wcout <<TEXT("比对完成!") << endl;
	}
	CloseClipboard();//关闭剪贴板,成功了返回非0,否则返回0
}
int main() {
	wcout.imbue(locale("chs"));
	wcin.imbue(locale("chs"));
	fp.imbue(locale("zh_CN.UTF-8"));
	wcout << TEXT("使用提示:启动程序后请不要移动指定的QQ窗口\n方向键up启动/暂停,方向键down关闭程序\n");
	wstring str;
	COLORREF begin[2000], end[2000];
	const int WX = 100;
	const int WY = 100;
	const int line = 543;
	const int we = 74;
	IMAGE img{ 100,20 };
	int i, j;
	HWND hwnd;
	fp.open(TEXT("data.data"), ios::in);
	if (!fp.is_open()) {
		MessageBox(NULL,TEXT("必需文件不存在!"),TEXT("tip"), 0);
		return 0;
	}
	do {
		wcout <<TEXT("请输入已经打开了的QQ窗口的标题名:");
		wcin >> str;
		hwnd = FindWindow(NULL, str.c_str());//warma沃玛粉丝流浪窝
		if (hwnd == NULL)
			wcout <<endl<<TEXT("没找到!") << endl;
	} while (hwnd == NULL);
	wcout << TEXT("准备完毕!\n");
	HDC srcDC = GetDC(NULL);	// 获取桌面 DC
	HDC dstDC = GetImageHDC(&img);	// 获取 IMAGE 对象的 DC
	BitBlt(dstDC, 0, 0, 100, 20, srcDC, WX + we, WY + line, SRCCOPY);
	DWORD *p = GetImageBuffer(&img);
	SetWindowPos(hwnd, NULL, WX, WY, 888, 758, SWP_NOSIZE);
	for (i = 0; i < 20; ++i) {
		for (j = 0; j < 100; ++j)
			begin[i + j * 20] = end[i + j * 20] = p[i + j * 20];
	}
	thread var(run);
	while (live)
	{
		if (getn) {
			BitBlt(dstDC, 0, 0, 100, 20, srcDC, WX + we, WY + line, SRCCOPY);
			for (i = 0; i < 20; ++i) {
				for (j = 0; j < 100; ++j)
					end[i + j * 20] = p[i + j * 20];
			}
			for (i = 0; i < 1000; ++i) {
				if (begin[i] != end[i]) {
					SetCursorPos(WX + we, WY + line); Sleep(2);
					mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0); Sleep(2);
					mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0); Sleep(300);
					keybd_event('C', 0, 0, 0); Sleep(3);
					keybd_event('C', 0, KEYEVENTF_KEYUP, 0); Sleep(300);
					gress();
					SetCursorPos(WX + we, WY + line + 120); Sleep(2);
					mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); Sleep(2);
					mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); Sleep(2);
					PostMessage(hwnd, WM_PASTE, 0, 0); Sleep(200);
					SendMessage(hwnd, WM_KEYDOWN, VK_RETURN, 0); Sleep(300);
					BitBlt(dstDC, 0, 0, 100, 20, srcDC, WX + we, WY + line, SRCCOPY);
					for (i = 0; i < 20; ++i) {
						for (j = 0; j < 100; ++j)
							begin[i + j * 20] = end[i + j * 20] = p[i + j * 20];
					}
					break;
				}
			}
		}
		else {
			BitBlt(dstDC, 0, 0, 100, 20, srcDC, WX + we, WY + line, SRCCOPY);
			for (i = 0; i < 20; ++i) {
				for (j = 0; j < 100; ++j)
					begin[i + j * 20] = p[i + j * 20];
			}
		}
		Sleep(30);
	}
	fp.close();
	var.join();
	return 0;
}

之后只需要在程序旁边建立一个名为data.data的文件,并在里面按照如下格式写预设的对答就好了:

关键词1
关键词1的回复
空行
关键词2
关键词2的回复
空行
关键词3
关键词3的回复
空行
...

以下给出一个文档例子:

唱歌
我会唱好多歌?想听吗?

算了
那该怎么办?

有啊
真的有吗?

什么
不知道

猫
说喵星人干什么?

布吉岛
神马岛?

笨蛋
我是很笨哦,聪明的话就不跟你聊天了.

就是
我也说不清楚啊!

我的
没关系~我有着宽广的胸怀.

方式
什么方式?你喜欢什么方式

实际使用效果图(用的不是上面那个例子的data.data):
[Easyx\C++]一个简单的QQ聊天机器人的实现
目前缺陷:
1.只能回答单个关键词的单个回答,暂时不能在同一个关键词的情况下,实现回答随机,或根据关键词出现次数出现特定回答的能力
2.在没有找到关键词的情况只会复读。
3.当对方发出的是语音消息是,会无法处理或错误处理。

其中,第一跟第二点都是通过更新代码实现相应逻辑来解决,第三点的话目前我还没想到什么法子解决_(:з」∠)_

注意事项:
只能获取独立出去了的QQ窗口的句柄,当QQ窗口时多窗口合并的时候,会无法获取窗口句柄
最后:
本文就介绍到这里了,原创的想法,原创的代码逻辑,供各位参考,也希望大佬多多包涵。

相关标签: 原创 c++