hotkey_conflict_detector.h
1 #pragma once 2 #include "pch.h" 3 #include <unordered_map> 4 #include <unordered_set> 5 #include <string> 6 7 #include "../modules/interface/powertoy_module_interface.h" 8 #include "centralized_hotkeys.h" 9 #include "common/utils/json.h" 10 11 namespace HotkeyConflictDetector 12 { 13 using Hotkey = PowertoyModuleIface::Hotkey; 14 using HotkeyEx = PowertoyModuleIface::HotkeyEx; 15 using Shortcut = CentralizedHotkeys::Shortcut; 16 17 struct HotkeyConflictInfo 18 { 19 Hotkey hotkey; 20 std::wstring moduleName; 21 int hotkeyID = 0; 22 23 inline bool operator==(const HotkeyConflictInfo& other) const 24 { 25 return hotkey == other.hotkey && 26 moduleName == other.moduleName && 27 hotkeyID == other.hotkeyID; 28 } 29 }; 30 31 Hotkey ShortcutToHotkey(const CentralizedHotkeys::Shortcut& shortcut); 32 33 enum HotkeyConflictType 34 { 35 NoConflict = 0, 36 SystemConflict = 1, 37 InAppConflict = 2, 38 }; 39 40 class HotkeyConflictManager 41 { 42 public: 43 static HotkeyConflictManager& GetInstance(); 44 45 HotkeyConflictType HasConflict(const Hotkey& hotkey, const wchar_t* moduleName, const int hotkeyID); 46 HotkeyConflictType HotkeyConflictManager::HasConflict(Hotkey const& _hotkey); 47 std::vector<HotkeyConflictInfo> HotkeyConflictManager::GetAllConflicts(Hotkey const& hotkey); 48 bool AddHotkey(const Hotkey& hotkey, const wchar_t* moduleName, const int hotkeyID, bool isEnabled); 49 std::vector<HotkeyConflictInfo> RemoveHotkeyByModule(const std::wstring& moduleName); 50 51 void EnableHotkeyByModule(const std::wstring& moduleName); 52 void DisableHotkeyByModule(const std::wstring& moduleName); 53 54 json::JsonObject GetHotkeyConflictsAsJson(); 55 56 private: 57 static std::mutex instanceMutex; 58 static HotkeyConflictManager* instance; 59 60 std::mutex hotkeyMutex; 61 // Hotkey in hotkeyMap means the hotkey has been registered successfully 62 std::unordered_map<uint16_t, HotkeyConflictInfo> hotkeyMap; 63 // Hotkey in sysConflictHotkeyMap means the hotkey has conflict with system defined hotkeys 64 std::unordered_map<uint16_t, std::unordered_set<HotkeyConflictInfo>> sysConflictHotkeyMap; 65 // Hotkey in inAppConflictHotkeyMap means the hotkey has conflict with other modules 66 std::unordered_map<uint16_t, std::unordered_set<HotkeyConflictInfo>> inAppConflictHotkeyMap; 67 68 std::unordered_map<std::wstring, std::vector<HotkeyConflictInfo>> disabledHotkeys; 69 70 uint16_t GetHotkeyHandle(const Hotkey&); 71 bool HasConflictWithSystemHotkey(const Hotkey&); 72 73 HotkeyConflictManager() = default; 74 }; 75 }; 76 77 namespace std 78 { 79 template<> 80 struct hash<HotkeyConflictDetector::HotkeyConflictInfo> 81 { 82 size_t operator()(const HotkeyConflictDetector::HotkeyConflictInfo& info) const 83 { 84 85 size_t hotkeyHash = 86 (info.hotkey.win ? 1ULL : 0ULL) | 87 ((info.hotkey.ctrl ? 1ULL : 0ULL) << 1) | 88 ((info.hotkey.shift ? 1ULL : 0ULL) << 2) | 89 ((info.hotkey.alt ? 1ULL : 0ULL) << 3) | 90 (static_cast<size_t>(info.hotkey.key) << 4); 91 92 size_t moduleHash = std::hash<std::wstring>{}(info.moduleName); 93 size_t idHash = std::hash<int>{}(info.hotkeyID); 94 95 return hotkeyHash ^ 96 ((moduleHash << 1) | (moduleHash >> (sizeof(size_t) * 8 - 1))) ^ // rotate left 1 bit 97 ((idHash << 2) | (idHash >> (sizeof(size_t) * 8 - 2))); // rotate left 2 bits 98 } 99 }; 100 }