/ src / modules / keyboardmanager / dll / dllmain.cpp
dllmain.cpp
  1  #include "pch.h"
  2  #include <interface/powertoy_module_interface.h>
  3  #include <common/SettingsAPI/settings_objects.h>
  4  #include <common/utils/resources.h>
  5  #include "Generated Files/resource.h"
  6  #include <keyboardmanager/common/KeyboardManagerConstants.h>
  7  #include <common/utils/winapi_error.h>
  8  #include <keyboardmanager/dll/trace.h>
  9  #include <shellapi.h>
 10  #include <common/utils/logger_helper.h>
 11  #include <common/interop/shared_constants.h>
 12  
 13  BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*lpReserved*/)
 14  {
 15      switch (ul_reason_for_call)
 16      {
 17      case DLL_PROCESS_ATTACH:
 18          Trace::RegisterProvider();
 19          break;
 20      case DLL_THREAD_ATTACH:
 21      case DLL_THREAD_DETACH:
 22          break;
 23      case DLL_PROCESS_DETACH:
 24          Trace::UnregisterProvider();
 25          break;
 26      }
 27  
 28      return TRUE;
 29  }
 30  
 31  // Implement the PowerToy Module Interface and all the required methods.
 32  class KeyboardManager : public PowertoyModuleIface
 33  {
 34  private:
 35      // The PowerToy state.
 36      bool m_enabled = false;
 37  
 38      // The PowerToy name that will be shown in the settings.
 39      const std::wstring app_name = GET_RESOURCE_STRING(IDS_KEYBOARDMANAGER);
 40  
 41      //contains the non localized key of the powertoy
 42      std::wstring app_key = KeyboardManagerConstants::ModuleName;
 43  
 44      HANDLE m_hProcess = nullptr;
 45  
 46      HANDLE m_hTerminateEngineEvent = nullptr;
 47  
 48  public:
 49      // Constructor
 50      KeyboardManager()
 51      {
 52          LoggerHelpers::init_logger(KeyboardManagerConstants::ModuleName, L"ModuleInterface", LogSettings::keyboardManagerLoggerName);
 53  
 54          std::filesystem::path oldLogPath(PTSettingsHelper::get_module_save_folder_location(app_key));
 55          oldLogPath.append("Logs");
 56          LoggerHelpers::delete_old_log_folder(oldLogPath);
 57  
 58          m_hTerminateEngineEvent = CreateDefaultEvent(CommonSharedConstants::TERMINATE_KBM_SHARED_EVENT);
 59          if (!m_hTerminateEngineEvent)
 60          {
 61              Logger::error(L"Failed to create terminate Engine event");
 62              auto message = get_last_error_message(GetLastError());
 63              if (message.has_value())
 64              {
 65                  Logger::error(message.value());
 66              }
 67          }
 68      };
 69  
 70      // Destroy the powertoy and free memory
 71      virtual void destroy() override
 72      {
 73          delete this;
 74      }
 75  
 76      // Return the localized display name of the powertoy
 77      virtual const wchar_t* get_name() override
 78      {
 79          return app_name.c_str();
 80      }
 81  
 82      // Return the non localized key of the powertoy, this will be cached by the runner
 83      virtual const wchar_t* get_key() override
 84      {
 85          return app_key.c_str();
 86      }
 87  
 88      // Return the configured status for the gpo policy for the module
 89      virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override
 90      {
 91          return powertoys_gpo::getConfiguredKeyboardManagerEnabledValue();
 92      }
 93  
 94      // Return JSON with the configuration options.
 95      virtual bool get_config(wchar_t* buffer, int* buffer_size) override
 96      {
 97          HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
 98  
 99          // Create a Settings object.
100          PowerToysSettings::Settings settings(hinstance, get_name());
101          settings.set_description(IDS_SETTINGS_DESCRIPTION);
102          settings.set_overview_link(L"https://aka.ms/PowerToysOverview_KeyboardManager");
103  
104          return settings.serialize_to_buffer(buffer, buffer_size);
105      }
106  
107      // Signal from the Settings editor to call a custom action.
108      virtual void call_custom_action(const wchar_t* /*action*/) override
109      {
110      }
111  
112      // Called by the runner to pass the updated settings values as a serialized JSON.
113      virtual void set_config(const wchar_t* config) override
114      {
115          try
116          {
117              // Parse the input JSON string.
118              PowerToysSettings::PowerToyValues values =
119                  PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
120  
121              // If you don't need to do any custom processing of the settings, proceed
122              // to persists the values calling:
123              values.save_to_settings_file();
124          }
125          catch (std::exception&)
126          {
127              // Improper JSON.
128          }
129      }
130  
131      // Enable the powertoy
132      virtual void enable()
133      {
134          m_enabled = true;
135          // Log telemetry
136          Trace::EnableKeyboardManager(true);
137  
138          unsigned long powertoys_pid = GetCurrentProcessId();
139          std::wstring executable_args = L"";
140          executable_args.append(std::to_wstring(powertoys_pid));
141  
142          SHELLEXECUTEINFOW sei{ sizeof(sei) };
143          sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
144          sei.lpFile = L"KeyboardManagerEngine\\PowerToys.KeyboardManagerEngine.exe";
145          sei.nShow = SW_SHOWNORMAL;
146          sei.lpParameters = executable_args.data();
147          if (ShellExecuteExW(&sei) == false)
148          {
149              Logger::error(L"Failed to start keyboard manager engine");
150              auto message = get_last_error_message(GetLastError());
151              if (message.has_value())
152              {
153                  Logger::error(message.value());
154              }
155          }
156          else
157          {
158              m_hProcess = sei.hProcess;
159              if (m_hProcess)
160              {
161                  SetPriorityClass(m_hProcess, REALTIME_PRIORITY_CLASS);
162              }
163          }
164      }
165  
166      // Disable the powertoy
167      virtual void disable()
168      {
169          m_enabled = false;
170          // Log telemetry
171          Trace::EnableKeyboardManager(false);
172  
173          if (m_hProcess)
174          {
175              SetEvent(m_hTerminateEngineEvent);
176              WaitForSingleObject(m_hProcess, 1500);
177  
178              TerminateProcess(m_hProcess, 0);
179              m_hProcess = nullptr;
180          }
181      }
182  
183      // Returns if the powertoys is enabled
184      virtual bool is_enabled() override
185      {
186          return m_enabled;
187      }
188  
189      // Returns whether the PowerToys should be enabled by default
190      virtual bool is_enabled_by_default() const override
191      {
192          return false;
193      }
194  
195  };
196  
197  extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
198  {
199      return new KeyboardManager();
200  }