/ src / runner / hotkey_conflict_detector.h
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  }