Created
September 29, 2023 04:34
-
-
Save ekussa/f94c1dc570c6770c98a9d7ec50ebe218 to your computer and use it in GitHub Desktop.
ShortcutLauncher
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Windows.h> | |
#include <time.h> | |
#include <iostream> | |
#include <set> | |
#include <algorithm> | |
#include <vector> | |
#include <functional> | |
#include <thread> | |
static LRESULT __stdcall HookCallback(int nCode, WPARAM wParam, LPARAM lParam); | |
void printer(const std::string& data) | |
{ | |
std::cout << data; | |
} | |
//C++ string to WINDOWS UNICODE string | |
std::wstring s2ws(const std::string& s) | |
{ | |
auto slength = s.length() + 1; | |
auto len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0); | |
wchar_t* buf = new wchar_t[len]; | |
MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len); | |
std::wstring r(buf); | |
delete[] buf; | |
return r; | |
} | |
void runner(const std::string& data) | |
{ | |
std::thread([data] | |
{ | |
//https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-startupinfoexa | |
STARTUPINFO info; | |
//https://learn.microsoft.com/en-us/windows/win32/procthread/process-creation-flags | |
PROCESS_INFORMATION processInfo; | |
ZeroMemory(&info, sizeof(info)); | |
info.cb = sizeof(info); | |
ZeroMemory(&processInfo, sizeof(processInfo)); | |
wchar_t text[512]; | |
std::size_t x = 0; | |
mbstowcs_s(&x, text, 512, data.c_str(), data.size()); | |
if (CreateProcessW(L"cmd.exe", (LPWSTR)text, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &info, &processInfo)) | |
{ | |
WaitForSingleObject(processInfo.hProcess, INFINITE); | |
CloseHandle(processInfo.hProcess); | |
CloseHandle(processInfo.hThread); | |
} | |
} | |
); | |
} | |
void printerAndRunner(const std::string& data) | |
{ | |
printer(data); | |
runner(data); | |
} | |
class CombinationEvent | |
{ | |
//https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes | |
std::set<int32_t> _combination; | |
std::string _data; | |
const std::function<void(const std::string&)> _onMatch; | |
template <typename Map> | |
bool map_compare(Map const& lhs, Map const& rhs) | |
{ | |
return lhs.size() == rhs.size() && | |
std::equal(lhs.begin(), lhs.end(), rhs.begin()); | |
} | |
public: | |
CombinationEvent( | |
const std::set<int32_t>& combination, | |
const std::string& data, | |
const std::function<void(const std::string&)> onMatch = printer) : | |
_combination(combination), | |
_data(data), | |
_onMatch(onMatch) | |
{ | |
} | |
bool matches(const std::set<int32_t>& combination) | |
{ | |
return map_compare(_combination, combination); | |
} | |
void run() | |
{ | |
return _onMatch(_data); | |
} | |
}; | |
static HHOOK _hook; | |
class ShortcutLauncher | |
{ | |
bool _debugMode; | |
std::vector<CombinationEvent> _combinationEvents; | |
std::set<int32_t> _keysPressed; | |
public: | |
ShortcutLauncher(bool debugMode) : | |
_debugMode(debugMode) | |
{ | |
} | |
void add(CombinationEvent& combinationEvent) | |
{ | |
_combinationEvents.push_back(combinationEvent); | |
} | |
void activate() | |
{ | |
_hook = SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback, nullptr, 0); | |
if (_hook == nullptr) | |
MessageBoxA(nullptr, "Failed to install hook!", "Error", MB_ICONERROR); | |
} | |
void blockPumpingMessages() | |
{ | |
MSG msg; | |
while (GetMessage(&msg, nullptr, 0, 0)) {} | |
} | |
void deactivate() | |
{ | |
UnhookWindowsHookEx(_hook); | |
} | |
bool hasNewEvent(WPARAM _event, DWORD vkCode) | |
{ | |
if (_event == WM_KEYDOWN || _event == WM_SYSKEYDOWN) | |
_keysPressed.insert(vkCode); | |
if (_event == WM_KEYUP || _event == WM_SYSKEYUP) | |
_keysPressed.erase(vkCode); | |
if (_debugMode) | |
{ | |
for (const auto& k : _keysPressed) | |
std::cout << k << " "; | |
std::cout << std::endl; | |
} | |
for (auto& combinationEvent : _combinationEvents) | |
{ | |
if (!combinationEvent.matches(_keysPressed)) | |
continue; | |
combinationEvent.run(); | |
return true; | |
} | |
return false; | |
} | |
}; | |
static ShortcutLauncher* _shortcutLauncher; | |
static LRESULT __stdcall HookCallback(int nCode, WPARAM wParam, LPARAM lParam) | |
{ | |
if (nCode >= 0) | |
{ | |
if (wParam == WM_KEYDOWN || wParam == WM_KEYUP || wParam == WM_SYSKEYDOWN || wParam == WM_SYSKEYUP) | |
{ | |
auto vkCode = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam)->vkCode; | |
bool captured = _shortcutLauncher->hasNewEvent( wParam, vkCode); | |
if (captured == true) | |
return -1; | |
} | |
} | |
return CallNextHookEx(_hook, nCode, wParam, lParam); | |
} | |
int main(int argc, char* argv[]) | |
{ | |
bool debugMode = false; | |
if (argc == 2) | |
debugMode = std::string(argv[1]) == "Debug"; | |
_shortcutLauncher = new ShortcutLauncher(debugMode); | |
std::set<int32_t> m1{ VK_LMENU, VK_SPACE }; | |
std::string p1("C:\\Program Files\\Notepad++\\notepad++.exe"); | |
CombinationEvent c1(m1, p1, printerAndRunner); | |
_shortcutLauncher->add(c1); | |
std::set<int32_t> m2{ VK_LCONTROL, VK_SPACE }; | |
std::string p2("C:\\Program Files\\Notepad++\\notepad++.exe"); | |
CombinationEvent c2(m2, p2, printerAndRunner); | |
_shortcutLauncher->add(c2); | |
_shortcutLauncher->activate(); | |
_shortcutLauncher->blockPumpingMessages(); | |
_shortcutLauncher->deactivate(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment