自动连击左键,F键和自动按住W键工具

用途,减少腱鞘炎发生。鼠标坏了可以换,手废了,就别想当码农了。

  • 按住副按键1,自动连击鼠标左键
  • 单击副按键2,自动按住W键前进,再次单击副按键2,取消按住W键前进
  • 滚轮滚动,自动连击F键拾取物品
  • 单击键盘R_CTRL+P键,切换工具启动和停止

副按键是特殊按键。我这里的鼠标是 m618 plus。其他鼠标请自行改键码。

使用了 C++20 的 format 库,编译需要vs2019 开 lastest 编译。或者需要vs2022。
或者可以直接屏蔽掉那几句语句,不使用c++20特性。

仅提供完整代码,不提供已编译的程序。
一是不通用,二是都有现成的鼠标宏,不差我这个。
三是想学习原理的才会看这,既然想学习,那肯定有基础了。

编译后生成后,需要使用 管理员权限启动 才能发送按键到游戏中。
这是因为windows的限制,低等级程序不允许对高级别程序发送消息。

/*
* 用于原神的PC的工具
* 按住副按键1,自动连击鼠标左键
* 单击副按键2,自动按住W键前进,再次单击副按键2,取消按住W键前进
* 滚轮滚动,自动连击F键拾取物品
* 单击键盘R_CTRL+P键,切换工具启动和停止
* 
* 用于减少腱鞘炎的发生概率。
*/

#include <Windows.h>
#include <iostream>
#include <format>
#include <string>
#include <thread>
#include <mutex>
#include <list>
using namespace std;

HHOOK keyboardHook = 0;
HHOOK mouseHook = 0;

bool need_quit = false;
bool do_auto_left_click = false;
int n_auto_f_repeat = false;
bool do_auto_w_press = false;

bool is_pause = true;

// 简单的多线程日志打印工具,避免命令行无法打印字符时导致死锁
mutex log_mutex;
list<string> log_queue;

void add_log_str(const string s)
{
	unique_lock<mutex>(log_mutex);
	while (log_queue.size() > 10)
		log_queue.pop_front();
	log_queue.push_back(s);
}

bool get_log_str(string& s)
{
	if (log_queue.size() == 0)
		return false;

	unique_lock<mutex>(log_mutex);
	s = log_queue.front();
	log_queue.pop_front();
	return true;
}

void log_run()
{
	while (!need_quit)
	{
		string s;
		if (get_log_str(s))
		{
			cout << s << endl;
		}
		else
		{
			Sleep(500);
		}
	}
}
// -------------------------------------------------


/*
* 对指定数值进行一些随机偏移
*/
int get_random_offset(int d1, int of1)
{
	float percent = rand() / (float)RAND_MAX;
	percent = percent * 2 - 1;
	d1 = d1 + of1 * percent;
	return d1;
}

/*
* 自动连击左键线程体
*/
void auto_left_click_run()
{
	while (!need_quit)
	{
		if (is_pause)
		{
			Sleep(500);
			do_auto_left_click = false;
			continue;
		}

		if (do_auto_left_click)
		{
			//cout << "Send left click." << endl;
			add_log_str("Send left click.");

			INPUT  Input ={ 0 };
			Input.type = INPUT_MOUSE;
			Input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;	// 模拟按下
			SendInput(1, &Input, sizeof(INPUT));
			Sleep(get_random_offset(70, 30));
			Input.mi.dwFlags = MOUSEEVENTF_LEFTUP;		// 模拟弹起
			SendInput(1, &Input, sizeof(INPUT));
			Sleep(get_random_offset(70, 30));
		}
		else
		{
			Sleep(100);
		}
	}
}

/*
* 自动连击F键线程体
*/
void auto_press_f_run()
{
	while (!need_quit)
	{
		if (is_pause)
		{
			Sleep(500);
			n_auto_f_repeat = 0;
			continue;
		}

		// 限制最大连按3次。
		n_auto_f_repeat = min(n_auto_f_repeat, 3);
		if (n_auto_f_repeat > 0)
		{
			n_auto_f_repeat -= 1;
			//cout << "Send F key." << endl;
			add_log_str("Send F key.");
			INPUT  Input ={ 0 };
			Input.type = INPUT_KEYBOARD;
			Input.ki.wVk = 'F';
			Input.ki.wScan = VkKeyScanA('F');
			//Input.ki.dwFlags = KEYEVENTF_SCANCODE;
			Input.ki.dwFlags = 0;
			SendInput(1, &Input, sizeof(INPUT));
			Sleep(get_random_offset(70, 30));
			//Input.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
			Input.ki.dwFlags = KEYEVENTF_KEYUP;
			SendInput(1, &Input, sizeof(INPUT));
			Sleep(get_random_offset(70, 30));
		}
		else
		{
			Sleep(100);
		}
	}
}

/*
* 自动按住W键线程体
*/
void auto_toggle_press_w_run()
{
	while (!need_quit)
	{
		if (is_pause)
		{
			Sleep(500);
			do_auto_w_press = false;
			continue;
		}

		if (do_auto_w_press)
		{
			do_auto_w_press = false;

			INPUT  Input ={ 0 };
			Input.type = INPUT_KEYBOARD;
			Input.ki.wVk = 'W';
			Input.ki.wScan = VkKeyScanA('F');

			if (GetAsyncKeyState('W') & 0x8000)
			{
				//cout << "Send W up key." << endl;
				add_log_str("Send W up key.");
				Input.ki.dwFlags = KEYEVENTF_KEYUP;
				SendInput(1, &Input, sizeof(INPUT));
			}
			else
			{
				//cout << "Send W down key." << endl;
				add_log_str("Send W down key.");
				Input.ki.dwFlags = 0;
			}
			SendInput(1, &Input, sizeof(INPUT));
			Sleep(get_random_offset(70, 30));
		}
		else
		{
			Sleep(100);
		}
	}
}

LRESULT CALLBACK KbHookCallback(int code, WPARAM wParam, LPARAM lParam)
{
	KBDLLHOOKSTRUCT* ks = (KBDLLHOOKSTRUCT*)lParam;
	
	//auto s = format("vkCode:0x{:x} wParam:0x{:x} flags:0x{:x}", ks->vkCode, wParam, ks->flags);
	//cout << s << endl;

	if (ks->vkCode == 'P' && (GetAsyncKeyState(VK_RCONTROL) & 0x8000))
	{
		if (wParam == 0x101)
		{
			is_pause = !is_pause;
			if (is_pause)
				//cout << "工作已暂停" << endl;
				add_log_str("工作已暂停");
			else
				//cout << "工作已恢复" << endl;
				add_log_str("工作已恢复");
		}

		return 1;
	}
	return CallNextHookEx(0, code, wParam, lParam);
}

LRESULT CALLBACK MsHookCallback(int code, WPARAM wParam, LPARAM lParam)
{
	MSLLHOOKSTRUCT* ms = (MSLLHOOKSTRUCT*)lParam;
	
	// 当鼠标输入特殊键时,mouseData 不为 0。
	if (ms->mouseData != 0)
	{
		auto s = format("mouseData:0x{:x} wParam:0x{:x} flags:0x{:x}", ms->mouseData, wParam, ms->flags);
		//cout << s << endl;
		add_log_str(s);
		
		//cout << hex << "mouseData:0x" << ms->mouseData << "wParam:0x" << wParam << "flags:0x" << ms->flags << endl;

		// 按下副按键1时,自动连击左键
		if (ms->mouseData == 0x20000)
		{
			if (wParam == 0x20b)
			{
				// 按键按下
				do_auto_left_click = true;
				return 1;
			}
			else if (wParam == 0x20c)
			{
				// 按键弹起
				do_auto_left_click = false;
				return 1;
			}
		}

		// 按下副按键2时,切换自动跑步键
		else if (ms->mouseData == 0x10000)
		{
			if (wParam == 0x20b)
			{
				// 按键按下
				do_auto_w_press = true;
				return 1;
			}
			//else if (wParam == 0x20c)
			//{
			//	// 按键弹起
			//	do_auto_w_press = false;
			//	return 1;
			//}
		}

		// 滚动滚轮时,自动点击F键
		else if (ms->mouseData == 0xff880000 || ms->mouseData == 0x780000)
		{
			if (wParam == 0x20a)
			{
				// 滚动
				n_auto_f_repeat += 1;
				// 滚轮滚动事件不要吞掉。
				// return 1;
			}
		}

	}

	return CallNextHookEx(0, code, wParam, lParam);
}


int main()
{

	cout << "用于原神PC版的自动连击工具。\n\n按住副按键1,自动连击鼠标左键。\n点击副按键2,自动切换按住W键\n滚动滑轮,自动连击F键\nR_CTRL+P键切换开始和停止\n\n用于减少腱鞘炎的发生概率。\n" << endl;

	keyboardHook = SetWindowsHookExA(WH_KEYBOARD_LL, KbHookCallback, GetModuleHandleA(0), 0);
	if (keyboardHook == 0)
	{
		cout << "挂钩键盘失败" << endl;
		return -1;
	}

	mouseHook = SetWindowsHookExA(WH_MOUSE_LL, MsHookCallback, GetModuleHandleA(0), 0);
	if (mouseHook == 0)
	{
		cout << "挂钩鼠标失败" << endl;
		return -1;
	}

	// 启动连击工作线程
	auto t = thread(auto_left_click_run);
	auto t2 = thread(auto_press_f_run);
	auto t3 = thread(auto_toggle_press_w_run);
	auto t4 = thread(log_run);

	cout << "程序正常运行" << endl;

	cout << "按下 R_CTRL+P 组合键开始工作" << endl;

	//不可漏掉消息处理,不然程序会卡死
	MSG msg;
	while (GetMessageA(&msg, 0, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessageW(&msg);
	}
	need_quit = true;
	UnhookWindowsHookEx(keyboardHook);
	UnhookWindowsHookEx(mouseHook);

	cout << "程序正常退出。" << endl;

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值