/ src / modules / keyboardmanager / common / MappingConfiguration.cpp
MappingConfiguration.cpp
  1  #include "pch.h"
  2  #include "MappingConfiguration.h"
  3  
  4  #include <common/SettingsAPI/settings_objects.h>
  5  #include <common/SettingsAPI/settings_helpers.h>
  6  #include <common/logger/logger.h>
  7  
  8  #include "KeyboardManagerConstants.h"
  9  #include "Shortcut.h"
 10  #include "RemapShortcut.h"
 11  #include "Helpers.h"
 12  
 13  // Function to clear the OS Level shortcut remapping table
 14  void MappingConfiguration::ClearOSLevelShortcuts()
 15  {
 16      osLevelShortcutReMap.clear();
 17      osLevelShortcutReMapSortedKeys.clear();
 18  }
 19  
 20  // Function to clear the Keys remapping table.
 21  void MappingConfiguration::ClearSingleKeyRemaps()
 22  {
 23      singleKeyReMap.clear();
 24      scanMap.clear();
 25  }
 26  
 27  // Function to clear the Keys remapping table.
 28  void MappingConfiguration::ClearSingleKeyToTextRemaps()
 29  {
 30      singleKeyToTextReMap.clear();
 31  }
 32  
 33  // Function to clear the App specific shortcut remapping table
 34  void MappingConfiguration::ClearAppSpecificShortcuts()
 35  {
 36      appSpecificShortcutReMap.clear();
 37      appSpecificShortcutReMapSortedKeys.clear();
 38  }
 39  
 40  // Function to add a new OS level shortcut remapping
 41  bool MappingConfiguration::AddOSLevelShortcut(const Shortcut& originalSC, const KeyShortcutTextUnion& newSC)
 42  {
 43      // Check if the shortcut is already remapped
 44      auto it = osLevelShortcutReMap.find(originalSC);
 45      if (it != osLevelShortcutReMap.end())
 46      {
 47          return false;
 48      }
 49  
 50      osLevelShortcutReMap[originalSC] = RemapShortcut(newSC);
 51      osLevelShortcutReMapSortedKeys.push_back(originalSC);
 52      Helpers::SortShortcutVectorBasedOnSize(osLevelShortcutReMapSortedKeys);
 53  
 54      return true;
 55  }
 56  
 57  // Function to add a new single key to key/shortcut remapping
 58  bool MappingConfiguration::AddSingleKeyRemap(const DWORD& originalKey, const KeyShortcutTextUnion& newRemapKey)
 59  {
 60      // Check if the key is already remapped
 61      auto it = singleKeyReMap.find(originalKey);
 62      if (it != singleKeyReMap.end())
 63      {
 64          return false;
 65      }
 66  
 67      singleKeyReMap[originalKey] = newRemapKey;
 68      if (Helpers::IsNumpadKeyThatIsAffectedByShift(originalKey))
 69      {
 70          // Numpad keys might get altered by shift being pressed. We need to save their scancode instead to try and detect that they were unpressed when they are mapped to shift.
 71          auto scanCode = MapVirtualKey(originalKey, MAPVK_VK_TO_VSC);
 72          if (scanCode != 0)
 73          {
 74              scanMap[MapVirtualKey(originalKey, MAPVK_VK_TO_VSC)] = originalKey;
 75          }
 76      }
 77      return true;
 78  }
 79  
 80  bool MappingConfiguration::AddSingleKeyToTextRemap(const DWORD originalKey, const std::wstring& text)
 81  {
 82      if (auto it = singleKeyToTextReMap.find(originalKey); it != end(singleKeyToTextReMap))
 83      {
 84          return false;
 85      }
 86      else
 87      {
 88          singleKeyToTextReMap[originalKey] = text;
 89          return true;
 90      }
 91  }
 92  
 93  // Function to add a new App specific shortcut remapping
 94  bool MappingConfiguration::AddAppSpecificShortcut(const std::wstring& app, const Shortcut& originalSC, const KeyShortcutTextUnion& newSC)
 95  {
 96      // Convert app name to lower case
 97      std::wstring process_name;
 98      process_name.resize(app.length());
 99      std::transform(app.begin(), app.end(), process_name.begin(), towlower);
100  
101      // Check if there are any app specific shortcuts for this app
102      auto appIt = appSpecificShortcutReMap.find(process_name);
103      if (appIt != appSpecificShortcutReMap.end())
104      {
105          // Check if the shortcut is already remapped
106          auto shortcutIt = appSpecificShortcutReMap[process_name].find(originalSC);
107          if (shortcutIt != appSpecificShortcutReMap[process_name].end())
108          {
109              return false;
110          }
111      }
112      else
113      {
114          appSpecificShortcutReMapSortedKeys[process_name] = std::vector<Shortcut>();
115      }
116  
117      appSpecificShortcutReMap[process_name][originalSC] = RemapShortcut(newSC);
118      appSpecificShortcutReMapSortedKeys[process_name].push_back(originalSC);
119      Helpers::SortShortcutVectorBasedOnSize(appSpecificShortcutReMapSortedKeys[process_name]);
120      return true;
121  }
122  
123  bool MappingConfiguration::LoadSingleKeyRemaps(const json::JsonObject& jsonData)
124  {
125      bool result = true;
126  
127      try
128      {
129          auto remapKeysData = jsonData.GetNamedObject(KeyboardManagerConstants::RemapKeysSettingName);
130          ClearSingleKeyRemaps();
131  
132          if (remapKeysData)
133          {
134              auto inProcessRemapKeys = remapKeysData.GetNamedArray(KeyboardManagerConstants::InProcessRemapKeysSettingName);
135              for (const auto& it : inProcessRemapKeys)
136              {
137                  try
138                  {
139                      auto originalKey = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
140                      auto newRemapKey = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewRemapKeysSettingName);
141  
142                      // If remapped to a shortcut
143                      if (std::wstring(newRemapKey).find(L";") != std::string::npos)
144                      {
145                          AddSingleKeyRemap(std::stoul(originalKey.c_str()), Shortcut(newRemapKey.c_str()));
146                      }
147  
148                      // If remapped to a key
149                      else
150                      {
151                          AddSingleKeyRemap(std::stoul(originalKey.c_str()), std::stoul(newRemapKey.c_str()));
152                      }
153                  }
154                  catch (...)
155                  {
156                      Logger::error(L"Improper Key Data JSON. Try the next remap.");
157                      result = false;
158                  }
159              }
160          }
161      }
162      catch (...)
163      {
164          Logger::error(L"Improper JSON format for single key remaps. Skip to next remap type");
165          result = false;
166      }
167  
168      return result;
169  }
170  
171  bool MappingConfiguration::LoadSingleKeyToTextRemaps(const json::JsonObject& jsonData)
172  {
173      bool result = true;
174  
175      try
176      {
177          auto remapKeysData = jsonData.GetNamedObject(KeyboardManagerConstants::RemapKeysToTextSettingName);
178          ClearSingleKeyToTextRemaps();
179  
180          if (!remapKeysData)
181          {
182              return result;
183          }
184  
185          auto inProcessRemapKeys = remapKeysData.GetNamedArray(KeyboardManagerConstants::InProcessRemapKeysSettingName);
186          for (const auto& it : inProcessRemapKeys)
187          {
188              try
189              {
190                  auto originalKey = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
191                  auto newText = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewTextSettingName);
192  
193                  // undo dummy data for backwards compatibility
194                  if (newText == L"*Unsupported*")
195                  {
196                      newText == L"";
197                  }
198  
199                  AddSingleKeyToTextRemap(std::stoul(originalKey.c_str()), newText.c_str());
200              }
201              catch (...)
202              {
203                  Logger::error(L"Improper Key Data JSON. Try the next remap.");
204                  result = false;
205              }
206          }
207      }
208      catch (...)
209      {
210          Logger::error(L"Improper JSON format for single key to text remaps. Skip to next remap type");
211          result = false;
212      }
213  
214      return result;
215  }
216  
217  bool MappingConfiguration::LoadAppSpecificShortcutRemaps(const json::JsonObject& remapShortcutsData)
218  {
219      bool result = true;
220  
221      try
222      {
223          auto appSpecificRemapShortcuts = remapShortcutsData.GetNamedArray(KeyboardManagerConstants::AppSpecificRemapShortcutsSettingName);
224          for (const auto& it : appSpecificRemapShortcuts)
225          {
226              try
227              {
228                  auto originalKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
229                  auto newRemapKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewRemapKeysSettingName, {});
230                  auto newRemapText = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewTextSettingName, {});
231                  auto targetApp = it.GetObjectW().GetNamedString(KeyboardManagerConstants::TargetAppSettingName);
232                  auto operationType = it.GetObjectW().GetNamedNumber(KeyboardManagerConstants::ShortcutOperationType, 0);
233                  auto exactMatch = it.GetObjectW().GetNamedBoolean(KeyboardManagerConstants::ShortcutExactMatch, false);
234                  auto originalShortcut = Shortcut(originalKeys.c_str());
235                  originalShortcut.exactMatch = exactMatch;
236                  // undo dummy data for backwards compatibility
237                  if (newRemapText == L"*Unsupported*")
238                  {
239                      newRemapText == L"";
240                  }
241  
242                  // check Shortcut::OperationType
243                  if (operationType == 1)
244                  {
245                      auto runProgramFilePath = it.GetObjectW().GetNamedString(KeyboardManagerConstants::RunProgramFilePathSettingName, L"");
246                      auto runProgramArgs = it.GetObjectW().GetNamedString(KeyboardManagerConstants::RunProgramArgsSettingName, L"");
247                      auto runProgramStartInDir = it.GetObjectW().GetNamedString(KeyboardManagerConstants::RunProgramStartInDirSettingName, L"");
248                      auto runProgramElevationLevel = it.GetObjectW().GetNamedNumber(KeyboardManagerConstants::RunProgramElevationLevelSettingName, 0);
249                      auto runProgramAlreadyRunningAction = it.GetObjectW().GetNamedNumber(KeyboardManagerConstants::RunProgramAlreadyRunningAction, 0);
250                      auto runProgramStartWindowType = it.GetObjectW().GetNamedNumber(KeyboardManagerConstants::RunProgramStartWindowType, 0);
251  
252                      auto tempShortcut = Shortcut(newRemapKeys.c_str());
253                      tempShortcut.operationType = Shortcut::OperationType::RunProgram;
254                      tempShortcut.runProgramFilePath = runProgramFilePath;
255                      tempShortcut.runProgramArgs = runProgramArgs;
256                      tempShortcut.runProgramStartInDir = runProgramStartInDir;
257                      tempShortcut.elevationLevel = static_cast<Shortcut::ElevationLevel>(runProgramElevationLevel);
258                      tempShortcut.alreadyRunningAction = static_cast<Shortcut::ProgramAlreadyRunningAction>(runProgramAlreadyRunningAction);
259                      tempShortcut.startWindowType = static_cast<Shortcut::StartWindowType>(runProgramStartWindowType);
260  
261                      AddAppSpecificShortcut(targetApp.c_str(), originalShortcut, tempShortcut);
262                  }
263                  else if (operationType == 2)
264                  {
265                      auto tempShortcut = Shortcut(newRemapKeys.c_str());
266                      tempShortcut.operationType = Shortcut::OperationType::OpenURI;
267                      tempShortcut.uriToOpen = it.GetObjectW().GetNamedString(KeyboardManagerConstants::ShortcutOpenURI, L"");
268  
269                      AddAppSpecificShortcut(targetApp.c_str(), originalShortcut, tempShortcut);
270                  }
271  
272                  if (!newRemapKeys.empty())
273                  {
274                      // If remapped to a shortcut
275                      if (std::wstring(newRemapKeys).find(L";") != std::string::npos)
276                      {
277                          AddAppSpecificShortcut(targetApp.c_str(), originalShortcut, Shortcut(newRemapKeys.c_str()));
278                      }
279  
280                      // If remapped to a key
281                      else
282                      {
283                          AddAppSpecificShortcut(targetApp.c_str(), originalShortcut, std::stoul(newRemapKeys.c_str()));
284                      }
285                  }
286                  else
287                  {
288                      AddAppSpecificShortcut(targetApp.c_str(), originalShortcut, newRemapText.c_str());
289                  }
290              }
291              catch (...)
292              {
293                  Logger::error(L"Improper Key Data JSON. Try the next shortcut.");
294                  result = false;
295              }
296          }
297      }
298      catch (...)
299      {
300          Logger::error(L"Improper JSON format for os level shortcut remaps. Skip to next remap type");
301          result = false;
302      }
303  
304      return result;
305  }
306  
307  bool MappingConfiguration::LoadShortcutRemaps(const json::JsonObject& jsonData, const std::wstring& objectName)
308  {
309      bool result = true;
310  
311      try
312      {
313          auto remapShortcutsData = jsonData.GetNamedObject(objectName);
314          if (remapShortcutsData)
315          {
316              // Load os level shortcut remaps
317              try
318              {
319                  auto globalRemapShortcuts = remapShortcutsData.GetNamedArray(KeyboardManagerConstants::GlobalRemapShortcutsSettingName);
320                  for (const auto& it : globalRemapShortcuts)
321                  {
322                      try
323                      {
324                          auto originalKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
325                          auto newRemapKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewRemapKeysSettingName, {});
326                          auto newRemapText = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewTextSettingName, {});
327                          auto operationType = it.GetObjectW().GetNamedNumber(KeyboardManagerConstants::ShortcutOperationType, 0);
328  
329                          auto originalShortcut = Shortcut(originalKeys.c_str());
330                          originalShortcut.exactMatch = it.GetObjectW().GetNamedBoolean(KeyboardManagerConstants::ShortcutExactMatch, false);
331                          // undo dummy data for backwards compatibility
332                          if (newRemapText == L"*Unsupported*")
333                          {
334                              newRemapText == L"";
335                          }
336  
337                          // check Shortcut::OperationType
338                          if (operationType == 1)
339                          {
340                              auto runProgramFilePath = it.GetObjectW().GetNamedString(KeyboardManagerConstants::RunProgramFilePathSettingName, L"");
341                              auto runProgramArgs = it.GetObjectW().GetNamedString(KeyboardManagerConstants::RunProgramArgsSettingName, L"");
342                              auto runProgramStartInDir = it.GetObjectW().GetNamedString(KeyboardManagerConstants::RunProgramStartInDirSettingName, L"");
343                              auto runProgramElevationLevel = it.GetObjectW().GetNamedNumber(KeyboardManagerConstants::RunProgramElevationLevelSettingName, 0);
344                              auto runProgramStartWindowType = it.GetObjectW().GetNamedNumber(KeyboardManagerConstants::RunProgramStartWindowType, 0);
345                              auto runProgramAlreadyRunningAction = it.GetObjectW().GetNamedNumber(KeyboardManagerConstants::RunProgramAlreadyRunningAction, 0);
346  
347                              auto tempShortcut = Shortcut(newRemapKeys.c_str());
348                              tempShortcut.operationType = Shortcut::OperationType::RunProgram;
349                              tempShortcut.runProgramFilePath = runProgramFilePath;
350                              tempShortcut.runProgramArgs = runProgramArgs;
351                              tempShortcut.runProgramStartInDir = runProgramStartInDir;
352                              tempShortcut.elevationLevel = static_cast<Shortcut::ElevationLevel>(runProgramElevationLevel);
353                              tempShortcut.alreadyRunningAction = static_cast<Shortcut::ProgramAlreadyRunningAction>(runProgramAlreadyRunningAction);
354                              tempShortcut.startWindowType = static_cast<Shortcut::StartWindowType>(runProgramStartWindowType);
355  
356                              AddOSLevelShortcut(originalShortcut, tempShortcut);
357                          }
358                          else if (operationType == 2)
359                          {
360                              auto tempShortcut = Shortcut(newRemapKeys.c_str());
361                              tempShortcut.operationType = Shortcut::OperationType::OpenURI;
362                              tempShortcut.uriToOpen = it.GetObjectW().GetNamedString(KeyboardManagerConstants::ShortcutOpenURI, L"");
363  
364                              AddOSLevelShortcut(originalShortcut, tempShortcut);
365                          }
366                          else if (!newRemapKeys.empty())
367                          {
368                              // If remapped to a shortcut
369                              if (std::wstring(newRemapKeys).find(L";") != std::string::npos)
370                              {
371                                  AddOSLevelShortcut(originalShortcut, Shortcut(newRemapKeys.c_str()));
372                              }
373                              // If remapped to a key
374                              else
375                              {
376                                  AddOSLevelShortcut(originalShortcut, std::stoul(newRemapKeys.c_str()));
377                              }
378                          }
379                          else
380                          {
381                              AddOSLevelShortcut(originalShortcut, newRemapText.c_str());
382                          }
383                      }
384                      catch (...)
385                      {
386                          Logger::error(L"Improper Key Data JSON. Try the next shortcut.");
387                          result = false;
388                      }
389                  }
390              }
391              catch (...)
392              {
393                  Logger::error(L"Improper JSON format for os level shortcut remaps. Skip to next remap type");
394                  result = false;
395              }
396  
397              // Load app specific shortcut remaps
398              result = result && LoadAppSpecificShortcutRemaps(remapShortcutsData);
399          }
400      }
401      catch (...)
402      {
403          Logger::error(L"Improper JSON format for shortcut remaps. Skip to next remap type");
404          result = false;
405      }
406  
407      return result;
408  }
409  
410  bool MappingConfiguration::LoadSettings()
411  {
412      Logger::trace(L"SettingsHelper::LoadSettings()");
413      try
414      {
415          PowerToysSettings::PowerToyValues settings = PowerToysSettings::PowerToyValues::load_from_settings_file(KeyboardManagerConstants::ModuleName);
416          auto current_config = settings.get_string_value(KeyboardManagerConstants::ActiveConfigurationSettingName);
417  
418          if (!current_config)
419          {
420              return false;
421          }
422  
423          currentConfig = *current_config;
424  
425          // Read the config file and load the remaps.
426          auto configFile = json::from_file(PTSettingsHelper::get_module_save_folder_location(KeyboardManagerConstants::ModuleName) + L"\\" + *current_config + L".json");
427          if (!configFile)
428          {
429              return false;
430          }
431  
432          bool result = LoadSingleKeyRemaps(*configFile);
433          ClearOSLevelShortcuts();
434          ClearAppSpecificShortcuts();
435          result = LoadShortcutRemaps(*configFile, KeyboardManagerConstants::RemapShortcutsSettingName) && result;
436          result = LoadShortcutRemaps(*configFile, KeyboardManagerConstants::RemapShortcutsToTextSettingName) && result;
437          result = LoadSingleKeyToTextRemaps(*configFile) && result;
438  
439          return result;
440      }
441      catch (...)
442      {
443          Logger::error(L"SettingsHelper::LoadSettings() failed");
444      }
445  
446      return false;
447  }
448  
449  // Save the updated configuration.
450  bool MappingConfiguration::SaveSettingsToFile()
451  {
452      bool result = true;
453      json::JsonObject configJson;
454      json::JsonObject remapShortcuts;
455      json::JsonObject remapShortcutsToText;
456  
457      json::JsonObject remapKeys;
458      json::JsonObject remapKeysToText;
459  
460      json::JsonArray inProcessRemapKeysArray;
461      json::JsonArray inProcessRemapKeysToTextArray;
462  
463      json::JsonArray appSpecificRemapShortcutsArray;
464      json::JsonArray appSpecificRemapShortcutsToTextArray;
465  
466      json::JsonArray globalRemapShortcutsArray;
467      json::JsonArray globalRemapShortcutsToTextArray;
468  
469      for (const auto& it : singleKeyReMap)
470      {
471          json::JsonObject keys;
472          keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(winrt::to_hstring(static_cast<unsigned int>(it.first))));
473  
474          // For key to key remapping
475          if (it.second.index() == 0)
476          {
477              keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(winrt::to_hstring((unsigned int)std::get<DWORD>(it.second))));
478          }
479  
480          // For key to shortcut remapping
481          else
482          {
483              keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(std::get<Shortcut>(it.second).ToHstringVK()));
484          }
485  
486          inProcessRemapKeysArray.Append(keys);
487      }
488  
489      for (const auto& [code, text] : singleKeyToTextReMap)
490      {
491          json::JsonObject keys;
492          keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(winrt::to_hstring(static_cast<unsigned int>(code))));
493          keys.SetNamedValue(KeyboardManagerConstants::NewTextSettingName, json::value(std::get<std::wstring>(text)));
494          inProcessRemapKeysToTextArray.Append(keys);
495      }
496  
497      for (const auto& it : osLevelShortcutReMap)
498      {
499          json::JsonObject keys;
500  
501          keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(it.first.ToHstringVK()));
502  
503          keys.SetNamedValue(KeyboardManagerConstants::ShortcutExactMatch, json::JsonValue::CreateBooleanValue(it.first.exactMatch));
504          bool remapToText = false;
505  
506          // For shortcut to key remapping
507          if (it.second.targetShortcut.index() == 0)
508          {
509              keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(winrt::to_hstring((unsigned int)std::get<DWORD>(it.second.targetShortcut))));
510          }
511          // For shortcut to shortcut remapping
512          else if (it.second.targetShortcut.index() == 1)
513          {
514              auto targetShortcut = std::get<Shortcut>(it.second.targetShortcut);
515  
516              if (targetShortcut.operationType == Shortcut::OperationType::RunProgram)
517              {
518                  keys.SetNamedValue(KeyboardManagerConstants::RunProgramElevationLevelSettingName, json::value(static_cast<unsigned int>(targetShortcut.elevationLevel)));
519  
520                  keys.SetNamedValue(KeyboardManagerConstants::ShortcutOperationType, json::value(static_cast<unsigned int>(targetShortcut.operationType)));
521                  keys.SetNamedValue(KeyboardManagerConstants::RunProgramAlreadyRunningAction, json::value(static_cast<unsigned int>(targetShortcut.alreadyRunningAction)));
522                  keys.SetNamedValue(KeyboardManagerConstants::RunProgramStartWindowType, json::value(static_cast<unsigned int>(targetShortcut.startWindowType)));
523  
524                  keys.SetNamedValue(KeyboardManagerConstants::RunProgramFilePathSettingName, json::value(targetShortcut.runProgramFilePath));
525                  keys.SetNamedValue(KeyboardManagerConstants::RunProgramArgsSettingName, json::value(targetShortcut.runProgramArgs));
526                  keys.SetNamedValue(KeyboardManagerConstants::RunProgramStartInDirSettingName, json::value(targetShortcut.runProgramStartInDir));
527  
528                  // we need to add this dummy data for backwards compatibility
529                  keys.SetNamedValue(KeyboardManagerConstants::NewTextSettingName, json::value(L"*Unsupported*"));
530              }
531              else if (targetShortcut.operationType == Shortcut::OperationType::OpenURI)
532              {
533                  keys.SetNamedValue(KeyboardManagerConstants::RunProgramElevationLevelSettingName, json::value(static_cast<unsigned int>(targetShortcut.elevationLevel)));
534                  keys.SetNamedValue(KeyboardManagerConstants::ShortcutOperationType, json::value(static_cast<unsigned int>(targetShortcut.operationType)));
535  
536                  keys.SetNamedValue(KeyboardManagerConstants::ShortcutOpenURI, json::value(targetShortcut.uriToOpen));
537  
538                  // we need to add this dummy data for backwards compatibility
539                  keys.SetNamedValue(KeyboardManagerConstants::NewTextSettingName, json::value(L"*Unsupported*"));
540              }
541              else
542              {
543                  keys.SetNamedValue(KeyboardManagerConstants::ShortcutOperationType, json::value(static_cast<unsigned int>(targetShortcut.operationType)));
544                  keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(targetShortcut.ToHstringVK()));
545              }
546          }
547          // For shortcut to text remapping
548          else if (it.second.targetShortcut.index() == 2)
549          {
550              remapToText = true;
551              keys.SetNamedValue(KeyboardManagerConstants::NewTextSettingName, json::value(std::get<std::wstring>(it.second.targetShortcut)));
552          }
553  
554          if (!remapToText)
555              globalRemapShortcutsArray.Append(keys);
556          else
557              globalRemapShortcutsToTextArray.Append(keys);
558      }
559  
560      for (const auto& itApp : appSpecificShortcutReMap)
561      {
562          // Iterate over apps
563          for (const auto& itKeys : itApp.second)
564          {
565              json::JsonObject keys;
566              keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(itKeys.first.ToHstringVK()));
567              keys.SetNamedValue(KeyboardManagerConstants::ShortcutExactMatch, json::JsonValue::CreateBooleanValue(itKeys.first.exactMatch));
568              bool remapToText = false;
569  
570              // For shortcut to key remapping
571              if (itKeys.second.targetShortcut.index() == 0)
572              {
573                  keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(winrt::to_hstring((unsigned int)std::get<DWORD>(itKeys.second.targetShortcut))));
574              }
575  
576              // For shortcut to shortcut remapping
577              else if (itKeys.second.targetShortcut.index() == 1)
578              {
579                  auto targetShortcut = std::get<Shortcut>(itKeys.second.targetShortcut);
580  
581                  if (targetShortcut.operationType == Shortcut::OperationType::RunProgram)
582                  {
583                      keys.SetNamedValue(KeyboardManagerConstants::RunProgramElevationLevelSettingName, json::value(static_cast<unsigned int>(targetShortcut.elevationLevel)));
584  
585                      keys.SetNamedValue(KeyboardManagerConstants::ShortcutOperationType, json::value(static_cast<unsigned int>(targetShortcut.operationType)));
586                      keys.SetNamedValue(KeyboardManagerConstants::RunProgramAlreadyRunningAction, json::value(static_cast<unsigned int>(targetShortcut.alreadyRunningAction)));
587                      keys.SetNamedValue(KeyboardManagerConstants::RunProgramStartWindowType, json::value(static_cast<unsigned int>(targetShortcut.startWindowType)));
588  
589                      keys.SetNamedValue(KeyboardManagerConstants::RunProgramFilePathSettingName, json::value(targetShortcut.runProgramFilePath));
590                      keys.SetNamedValue(KeyboardManagerConstants::RunProgramArgsSettingName, json::value(targetShortcut.runProgramArgs));
591                      keys.SetNamedValue(KeyboardManagerConstants::RunProgramStartInDirSettingName, json::value(targetShortcut.runProgramStartInDir));
592  
593                      // we need to add this dummy data for backwards compatibility
594                      keys.SetNamedValue(KeyboardManagerConstants::NewTextSettingName, json::value(L"*Unsupported*"));
595                  }
596                  else if (targetShortcut.operationType == Shortcut::OperationType::OpenURI)
597                  {
598                      keys.SetNamedValue(KeyboardManagerConstants::RunProgramElevationLevelSettingName, json::value(static_cast<unsigned int>(targetShortcut.elevationLevel)));
599                      keys.SetNamedValue(KeyboardManagerConstants::ShortcutOperationType, json::value(static_cast<unsigned int>(targetShortcut.operationType)));
600  
601                      keys.SetNamedValue(KeyboardManagerConstants::ShortcutOpenURI, json::value(targetShortcut.uriToOpen));
602  
603                      // we need to add this dummy data for backwards compatibility
604                      keys.SetNamedValue(KeyboardManagerConstants::NewTextSettingName, json::value(L"*Unsupported*"));
605                  }
606                  else
607                  {
608                      keys.SetNamedValue(KeyboardManagerConstants::ShortcutOperationType, json::value(static_cast<unsigned int>(targetShortcut.operationType)));
609                      keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(std::get<Shortcut>(itKeys.second.targetShortcut).ToHstringVK()));
610                  }
611              }
612              else if (itKeys.second.targetShortcut.index() == 2)
613              {
614                  keys.SetNamedValue(KeyboardManagerConstants::NewTextSettingName, json::value(std::get<std::wstring>(itKeys.second.targetShortcut)));
615                  remapToText = true;
616              }
617  
618              keys.SetNamedValue(KeyboardManagerConstants::TargetAppSettingName, json::value(itApp.first));
619  
620              if (!remapToText)
621                  appSpecificRemapShortcutsArray.Append(keys);
622              else
623                  appSpecificRemapShortcutsToTextArray.Append(keys);
624          }
625      }
626  
627      remapShortcuts.SetNamedValue(KeyboardManagerConstants::GlobalRemapShortcutsSettingName, globalRemapShortcutsArray);
628      remapShortcuts.SetNamedValue(KeyboardManagerConstants::AppSpecificRemapShortcutsSettingName, appSpecificRemapShortcutsArray);
629  
630      remapShortcutsToText.SetNamedValue(KeyboardManagerConstants::GlobalRemapShortcutsSettingName, globalRemapShortcutsToTextArray);
631      remapShortcutsToText.SetNamedValue(KeyboardManagerConstants::AppSpecificRemapShortcutsSettingName, appSpecificRemapShortcutsToTextArray);
632  
633      remapKeys.SetNamedValue(KeyboardManagerConstants::InProcessRemapKeysSettingName, inProcessRemapKeysArray);
634      remapKeysToText.SetNamedValue(KeyboardManagerConstants::InProcessRemapKeysSettingName, inProcessRemapKeysToTextArray);
635      configJson.SetNamedValue(KeyboardManagerConstants::RemapKeysSettingName, remapKeys);
636      configJson.SetNamedValue(KeyboardManagerConstants::RemapKeysToTextSettingName, remapKeysToText);
637      configJson.SetNamedValue(KeyboardManagerConstants::RemapShortcutsSettingName, remapShortcuts);
638      configJson.SetNamedValue(KeyboardManagerConstants::RemapShortcutsToTextSettingName, remapShortcutsToText);
639  
640      try
641      {
642          json::to_file((PTSettingsHelper::get_module_save_folder_location(KeyboardManagerConstants::ModuleName) + L"\\" + currentConfig + L".json"), configJson);
643      }
644      catch (...)
645      {
646          result = false;
647          Logger::error(L"Failed to save the settings");
648      }
649  
650      if (result)
651      {
652          auto hEvent = CreateEvent(nullptr, false, false, KeyboardManagerConstants::SettingsEventName.c_str());
653          if (hEvent)
654          {
655              SetEvent(hEvent);
656              Logger::trace(L"Signaled {} event", KeyboardManagerConstants::SettingsEventName);
657          }
658          else
659          {
660              Logger::error(L"Failed to signal {} event", KeyboardManagerConstants::SettingsEventName);
661          }
662      }
663  
664      return result;
665  }