#include "pch.h" #include "HotkeyManager.h" using namespace interop; HotkeyManager::HotkeyManager() { keyboardEventCallback = gcnew KeyboardEventCallback(this, &HotkeyManager::KeyboardEventProc); isActiveCallback = gcnew IsActiveCallback(this, &HotkeyManager::IsActiveProc); filterKeyboardCallback = gcnew FilterKeyboardEvent(this, &HotkeyManager::FilterKeyboardProc); keyboardHook = gcnew KeyboardHook( keyboardEventCallback, isActiveCallback, filterKeyboardCallback); hotkeys = gcnew Dictionary(); pressedKeys = gcnew Hotkey(); keyboardHook->Start(); } HotkeyManager::~HotkeyManager() { delete keyboardHook; } // When all Shortcut keys are pressed, fire the HotkeyCallback event. void HotkeyManager::KeyboardEventProc(KeyboardEvent ^ ev) { // pressedKeys always stores the latest keyboard state auto pressedKeysHandle = GetHotkeyHandle(pressedKeys); if (hotkeys->ContainsKey(pressedKeysHandle)) { hotkeys[pressedKeysHandle]->Invoke(); // After invoking the hotkey send a dummy key to prevent Start Menu from activating INPUT dummyEvent[1] = {}; dummyEvent[0].type = INPUT_KEYBOARD; dummyEvent[0].ki.wVk = 0xFF; dummyEvent[0].ki.dwFlags = KEYEVENTF_KEYUP; SendInput(1, dummyEvent, sizeof(INPUT)); } } // Hotkeys are intended to be global, therefore they are always active no matter the // context in which the keypress occurs. bool HotkeyManager::IsActiveProc() { return true; } // KeyboardEvent callback is only fired for relevant key events. bool HotkeyManager::FilterKeyboardProc(KeyboardEvent ^ ev) { // Updating the pressed keys here so we know if the keypress event should be propagated or not. pressedKeys->Win = (GetAsyncKeyState(VK_LWIN) & 0x8000) || (GetAsyncKeyState(VK_RWIN) & 0x8000); pressedKeys->Ctrl = GetAsyncKeyState(VK_CONTROL) & 0x8000; pressedKeys->Alt = GetAsyncKeyState(VK_MENU) & 0x8000; pressedKeys->Shift = GetAsyncKeyState(VK_SHIFT) & 0x8000; pressedKeys->Key = ev->key; // Convert to hotkey handle auto pressedKeysHandle = GetHotkeyHandle(pressedKeys); // Check if any hotkey matches the pressed keys if the current key event is a key down event if ((ev->message == WM_KEYDOWN || ev->message == WM_SYSKEYDOWN) && hotkeys->ContainsKey(pressedKeysHandle)) { return true; } return false; } // NOTE: Replaces old hotkey if one already present. HOTKEY_HANDLE HotkeyManager::RegisterHotkey(Hotkey ^ hotkey, HotkeyCallback ^ callback) { auto handle = GetHotkeyHandle(hotkey); hotkeys[handle] = callback; return handle; } void HotkeyManager::UnregisterHotkey(HOTKEY_HANDLE handle) { hotkeys->Remove(handle); } HOTKEY_HANDLE HotkeyManager::GetHotkeyHandle(Hotkey ^ hotkey) { HOTKEY_HANDLE handle = hotkey->Key; handle |= hotkey->Win << 8; handle |= hotkey->Ctrl << 9; handle |= hotkey->Shift << 10; handle |= hotkey->Alt << 11; return handle; }