简易按键精灵制作
参考链接:https://docs.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-sendinput?redirectedfrom=MSDN、https://www.fluentcpp.com/2018/12/28/timer-cpp/、https://github.com/99x/timercpp
具体实现见代码,同时可以设置定时器进行定时操作按键。
按键代码实现(注意必须通过管理员身份运行生成的可执行文件才有效):
// The reference between key and code connection can be found below:
// https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
/***************************************************************/
/* 全局定义 */
/***************************************************************/
constexpr size_t ARRAY_MAX_SIZE = 4;
/*****************************************************************
功能描述: 发送按键消息
其他说明:
*******************************************************************/
void GenerateKeyMsg(HWND hwnd, DWORD keyVal)
{
std::cout << "Post message start. -->";
LPARAM lparam = (MapVirtualKey(keyVal, 0) << 16) + 1;
PostMessage(hwnd, WM_KEYDOWN, keyVal, lparam);
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<size_t>(50)));
PostMessage(hwnd, WM_KEYUP, keyVal, lparam);
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<size_t>(10)));
std::cout << " Post message finish." << std::endl;
}
int main()
{
std::cout << "Input time interval:" << std::endl;
int delay;
std::cin >> delay;
// 获取MapleStory句柄
auto ms = FindWindow(NULL, _T("MapleStory"));
if (ms == NULL)
{
std::cout << "No game is found." << std::endl;
return 0;
}
// 界面最前显示
if (!SetForegroundWindow(ms))
return 0;
Timer timer;
timer.setInterval(std::bind(GenerateKeyMsg, ms, 0x43), delay);
timer.loop();
return 0;
}
定时器实现:
class Timer
{
bool clear = false;
public:
void setTimeout(std::function<void(void)> func, float delay);
void setInterval(std::function<void(void)> func, float delay);
void stop();
void loop();
};
void Timer::setTimeout(std::function<void(void)> func, float delay)
{
this->clear = false;
std::thread t([=]() {
if (this->clear) return;
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<size_t>(delay * 1000)));
if (this->clear) return;
func();
});
t.detach();
}
void Timer::setInterval(std::function<void(void)> func, float delay)
{
this->clear = false;
std::thread t([=]() {
while (true)
{
if (this->clear) return;
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<size_t>(delay * 1000)));
if (this->clear) return;
func();
}
});
t.detach();
}
void Timer::stop()
{
this->clear = true;
}
void Timer::loop()
{
while (!this->clear)
{
}
}
完善后包含有按键处理的代码,可以使用notepad测试
// The reference between key and code connection can be found below:
// https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
/***************************************************************/
/* 全局定义 */
/***************************************************************/
/*****************************************************************
功能描述: 发送按键消息
其他说明: 发送给全部窗口
*******************************************************************/
void GenerateKeyMsgForActiveWindow(WORD virKey = 0x41, WORD flag = 0)
{
INPUT ip;
// Set up a generic keyboard event.
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0; // hardware scan code for key
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;
// Press the "A" key
ip.ki.wVk = virKey; // virtual-key code for the "a" key
ip.ki.dwFlags = flag; // 0 for key press
auto uSent = SendInput(1, &ip, sizeof(INPUT));
// Release the "A" key
//ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
//SendInput(1, &ip, sizeof(INPUT));
if (uSent != 1)
{
std::cout << "[ERROR] Send Key Message failed: " << HRESULT_FROM_WIN32(GetLastError()) << std::endl;
}
}
/*****************************************************************
功能描述: 发送按键消息
其他说明: 发送给单个窗口
*******************************************************************/
void GenerateKeyMsgForInactiveWindow(HWND hwnd, DWORD keyVal)
{
LPARAM lparam = (MapVirtualKey(keyVal, 0) << 16) + 1;
PostMessage(hwnd, WM_KEYDOWN, keyVal, lparam);
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<size_t>(50)));
PostMessage(hwnd, WM_KEYUP, keyVal, lparam);
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<size_t>(10)));
// PostMessage(hwnd, WM_CLOSE, NULL, NULL);
// std::cout << GetLastError() << std::endl;
}
/*****************************************************************
功能描述: 主程序入口
其他说明:
*******************************************************************/
int main()
{
Input input;
Timer timer;
bool loop = false;
while (!input.exit())
{
if(!loop)
input.parser();
const auto keyMap = input.getKeyBoard();
auto hwnd = FindWindow(NULL, _T("new 1 - Notepad++ [Administrator]"));
if (hwnd == NULL)
{
std::cout << "[WARN] No Application is Found." << std::endl;
return 0;
}
// 界面最前显示
if (!SetForegroundWindow(hwnd))
return 0;
for (auto& key : keyMap)
{
if (key.first == VK_ESCAPE)
continue;
std::cout << "[INFO] Key Value: " << key.first << " / Time Interval: " << key.second << std::endl;
timer.setInterval(std::bind(GenerateKeyMsgForInactiveWindow, hwnd, key.first), key.second);
}
input.parser();
timer.stop();
loop = true;
}
return 0;
}
class Input
{
public:
Input()
{
std::cout << "Please enter the time interval of each key you want " << std::endl
<< "and set 'start' value as 1 to start application." << std::endl << std::endl;
}
void parser()
{
std::string line;
while (std::getline(std::cin, line))
{
if (line == "start")
{
break;
}
std::string key, time;
for (size_t pos = 0; pos < line.length(); ++pos)
{
if (pos > 0 && key.empty() && line[pos - 1] != ' ' && line[pos] == ' ')
{
key = line.substr(0, pos);
}
if (pos + 1 < line.length() && time.empty()
&& line[pos] == ' ' && line[pos + 1] != ' ' && key != "quit")
{
time = line.substr(pos + 1, line.length() - 1 - pos);
keyBoardRec[ConvertIntoKeyValue(key)] = atof(time.c_str());
}
}
}
}
const std::map<int, float>& getKeyBoard() const {
return keyBoardRec;
}
bool exit() {
return keyBoardRec.find(VK_ESCAPE) != keyBoardRec.end();
}
private:
std::map<int, float> keyBoardRec;
int ConvertIntoKeyValue(const std::string& key)
{
if (key.length() == 1)
{
int off = key[0] - 'a';
if (off >= 0 && off <= 26)
{
return 0x41 + off; /* a */
}
off = key[0] - '0';
if (off >= 0 && off <= 9)
{
return 0x30 + off; /* 0 */
}
}
if (key == "shift")
{
return VK_SHIFT;
}
if (key == "ctrl")
{
return VK_CONTROL;
}
if (key == "alt")
{
return VK_MENU;
}
if (key == "space")
{
return VK_SPACE;
}
if (key == "delete")
{
return VK_DELETE;
}
if (key == "end")
{
return VK_END;
}
if (key == "pagedown")
{
return VK_NEXT;
}
if (key == "pageup")
{
return VK_PRIOR;
}
if (key == "esc")
{
return VK_ESCAPE;
}
return 0x0;
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2017-11-24 windows服务和进程的区别和联系
2017-11-24 Daemon Process
2017-11-24 C++11中的原子操作(atomic operation)
2013-11-24 MFC消息顺序