/ src / modules / interface / powertoy_module_interface.h
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)();