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 }