powertoy_module_interface.h
1 #pragma once 2 3 #include <compare> 4 #include <common/utils/gpo.h> 5 6 /* 7 DLL Interface for PowerToys. The powertoy_create() (see below) must return 8 an object that implements this interface. 9 10 See tools/project_template/ModuleTemplate for simple, noop, PowerToy implementation. 11 12 The PowerToys runner will, for each PowerToy DLL: 13 - load the DLL, 14 - call powertoy_create() to create the PowerToy. 15 16 On the received object, the runner will call: 17 - get_key() to get the non localized ID of the PowerToy, 18 - enable() to initialize the PowerToy. 19 - get_hotkeys() to register the hotkeys that the PowerToy uses. 20 21 While running, the runner might call the following methods between create_powertoy() 22 and destroy(): 23 - disable()/enable()/is_enabled() to change or get the PowerToy's enabled state, 24 - get_config() to get the available configuration settings, 25 - set_config() to set various settings, 26 - call_custom_action() when the user selects clicks a custom action in settings, 27 - get_hotkeys() when the settings change, to make sure the hotkey(s) are up to date. 28 - on_hotkey() when the corresponding hotkey is pressed. 29 30 When terminating, the runner will: 31 - call destroy() which should free all the memory and delete the PowerToy object, 32 - unload the DLL. 33 34 The runner will call on_hotkey() even if the module is disabled. 35 */ 36 37 class PowertoyModuleIface 38 { 39 public: 40 /* Describes a hotkey which can trigger an action in the PowerToy */ 41 struct Hotkey 42 { 43 bool win = false; 44 bool ctrl = false; 45 bool shift = false; 46 bool alt = false; 47 unsigned char key = 0; 48 // The id is used to identify the hotkey in the module. The order in module interface should be the same as in the settings. 49 int id = 0; 50 // Currently, this is only used by AdvancedPaste to determine if the hotkey is shown in the settings. 51 bool isShown = true; 52 53 std::strong_ordering operator<=>(const Hotkey& other) const 54 { 55 // Compare bool fields first 56 if (auto cmp = (win <=> other.win); cmp != 0) 57 return cmp; 58 if (auto cmp = (ctrl <=> other.ctrl); cmp != 0) 59 return cmp; 60 if (auto cmp = (shift <=> other.shift); cmp != 0) 61 return cmp; 62 if (auto cmp = (alt <=> other.alt); cmp != 0) 63 return cmp; 64 65 // Compare key value only 66 return key <=> other.key; 67 68 // Note: Deliberately NOT comparing 'name' field 69 } 70 71 bool operator==(const Hotkey& other) const 72 { 73 return win == other.win && 74 ctrl == other.ctrl && 75 shift == other.shift && 76 alt == other.alt && 77 key == other.key; 78 } 79 }; 80 81 struct HotkeyEx 82 { 83 WORD modifiersMask = 0; 84 WORD vkCode = 0; 85 int id = 0; 86 }; 87 88 /* Returns the localized name of the PowerToy*/ 89 virtual const wchar_t* get_name() = 0; 90 /* Returns non localized name of the PowerToy, this will be cached by the runner. */ 91 virtual const wchar_t* get_key() = 0; 92 /* Fills a buffer with the available configuration settings. 93 * If 'buffer' is a null ptr or the buffer size is not large enough 94 * sets the required buffer size in 'buffer_size' and return false. 95 * Returns true if successful. 96 */ 97 virtual bool get_config(wchar_t* buffer, int* buffer_size) = 0; 98 /* Sets the configuration values. */ 99 virtual void set_config(const wchar_t* config) = 0; 100 /* Call custom action from settings screen. */ 101 virtual void call_custom_action(const wchar_t* /*action*/){}; 102 /* Enables the PowerToy. */ 103 virtual void enable() = 0; 104 /* Disables the PowerToy, should free as much memory as possible. */ 105 virtual void disable() = 0; 106 /* Should return if the PowerToys is enabled or disabled. */ 107 virtual bool is_enabled() = 0; 108 /* Destroy the PowerToy and free all memory. */ 109 virtual void destroy() = 0; 110 111 /* Get the list of hotkeys. Should return the number of available hotkeys and 112 * fill up the buffer to the minimum of the number of hotkeys and its size. 113 * Modules do not need to override this method, it will return zero by default. 114 * This method is called even when the module is disabled. 115 */ 116 virtual size_t get_hotkeys(Hotkey* /*buffer*/, size_t /*buffer_size*/) 117 { 118 return 0; 119 } 120 121 virtual std::optional<HotkeyEx> GetHotkeyEx() 122 { 123 return std::nullopt; 124 } 125 126 virtual void OnHotkeyEx() 127 { 128 } 129 130 /* Called when one of the registered hotkeys is pressed. Should return true 131 * if the key press is to be swallowed. 132 */ 133 virtual bool on_hotkey(size_t /*hotkeyId*/) 134 { 135 return false; 136 } 137 138 /* These are for enabling the legacy behavior of showing the shortcut guide after pressing the win key. 139 * keep_track_of_pressed_win_key returns true if the module wants to keep track of the win key being pressed. 140 * milliseconds_win_key_must_be_pressed returns the number of milliseconds the win key should be pressed before triggering the module. 141 * Don't use these for new modules. 142 */ 143 virtual bool keep_track_of_pressed_win_key() { return false; } 144 virtual UINT milliseconds_win_key_must_be_pressed() { return 0; } 145 146 virtual void send_settings_telemetry() 147 { 148 } 149 150 virtual bool is_enabled_by_default() const { return true; } 151 152 /* Provides the GPO configuration value for the module. This should be overridden by the module interface to get the proper gpo policy setting. */ 153 virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() 154 { 155 return powertoys_gpo::gpo_rule_configured_not_configured; 156 } 157 158 // Some actions like AdvancedPaste generate new inputs, which we don't want to catch again. 159 // The flag was purposefully chose to not collide with other keyboard manager flags. 160 const static inline ULONG_PTR CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG = 0x110; 161 162 protected: 163 HANDLE CreateDefaultEvent(const wchar_t* eventName) 164 { 165 SECURITY_ATTRIBUTES sa; 166 sa.nLength = sizeof(sa); 167 sa.bInheritHandle = false; 168 sa.lpSecurityDescriptor = NULL; 169 return CreateEventW(&sa, FALSE, FALSE, eventName); 170 } 171 }; 172 173 /* 174 Typedef of the factory function that creates the PowerToy object. 175 176 Must be exported by the DLL as powertoy_create(), e.g.: 177 178 extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create() 179 180 Called by the PowerToys runner to initialize each PowerToy. 181 It will be called only once before a call to destroy() method is made. 182 183 Returned PowerToy should be in disabled state. The runner will call 184 the enable() method to start the PowerToy. 185 186 In case of errors return nullptr. 187 */ 188 typedef PowertoyModuleIface*(__cdecl* powertoy_create_func)();