Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor ActionMap and Command to use ActionIDs #17162

Merged
merged 84 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from 61 commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
90627b3
add origin tag
PankajBhojwani Mar 5, 2024
9dff28f
update calls in tests
PankajBhojwani Mar 5, 2024
8bcbd0b
fix tests
PankajBhojwani Mar 5, 2024
052d063
ah one of the tests uses this
PankajBhojwani Mar 5, 2024
8cc82de
generated
PankajBhojwani Mar 5, 2024
642d0ab
inbox makes more sense
PankajBhojwani Mar 5, 2024
66fe08f
default ids
PankajBhojwani Mar 7, 2024
2bb1b6c
conflict
PankajBhojwani Mar 19, 2024
be193b2
merge origin
PankajBhojwani Mar 19, 2024
db528c9
generate IDs for user commands
PankajBhojwani Mar 26, 2024
7c907fe
nits
PankajBhojwani Mar 26, 2024
b43191d
spacing
PankajBhojwani Mar 26, 2024
2093660
line
PankajBhojwani Mar 26, 2024
6c32539
string of numbers is unsightly but it works
PankajBhojwani Mar 27, 2024
eccd87f
update comment
PankajBhojwani Mar 27, 2024
44510dc
move id generation to fixupusersettings
PankajBhojwani Mar 28, 2024
10d1fc8
this way is better
PankajBhojwani Mar 28, 2024
71bf90f
even better, also get the ID from json
PankajBhojwani Mar 28, 2024
d57c7a1
move this
PankajBhojwani Mar 28, 2024
5c2307c
fix test
PankajBhojwani Mar 28, 2024
9fc6972
add tests
PankajBhojwani Mar 29, 2024
dca7df5
excess line
PankajBhojwani Mar 29, 2024
dd25ed7
change tests
PankajBhojwani Apr 1, 2024
6e293a5
Everytime
PankajBhojwani Apr 1, 2024
af2d22f
defaults conflict
PankajBhojwani Apr 11, 2024
bdf42c2
first round of nits
PankajBhojwani Apr 11, 2024
12f3aa9
truncate and hex, debug assert
PankajBhojwani Apr 12, 2024
aa49212
null check
PankajBhojwani Apr 12, 2024
5ee630e
fmt is smart
PankajBhojwani Apr 12, 2024
360b92e
fmt_compile, fix test
PankajBhojwani Apr 17, 2024
5e70911
remove 0
PankajBhojwani Apr 17, 2024
ca3eb87
rename and comment
PankajBhojwani Apr 17, 2024
85933e2
midpoint
PankajBhojwani Apr 23, 2024
c134402
about to test stage 1
PankajBhojwani Apr 24, 2024
22ab936
works??
PankajBhojwani Apr 24, 2024
0a3e17e
edge cases
PankajBhojwani Apr 24, 2024
e28d478
some todos for later
PankajBhojwani Apr 24, 2024
f425746
remove keysmap
PankajBhojwani Apr 24, 2024
d0938e2
ugly way to make sure we fixup
PankajBhojwani Apr 25, 2024
12a61c5
shows up in sui and all keybindings work
PankajBhojwani Apr 26, 2024
f1633e0
overwritten IDs and overwritten keychords show up properly in the SUI
PankajBhojwani Apr 26, 2024
ddfac90
Merge branch 'main' of https://github.com/microsoft/terminal into dev…
PankajBhojwani Apr 26, 2024
3e7ab38
sui works?
PankajBhojwani Apr 26, 2024
ae16a5e
started stage 3
PankajBhojwani Apr 26, 2024
dc874c3
rename to special/standard
PankajBhojwani Apr 27, 2024
936afd6
_getactionbyid no longer returns optional
PankajBhojwani Apr 27, 2024
b3e9c26
remove check for invalid
PankajBhojwani Apr 27, 2024
5a1b822
reimplement populating all known keybindings
PankajBhojwani Apr 30, 2024
c51558f
unmark these
PankajBhojwani Apr 30, 2024
754bf04
mark gh todo
PankajBhojwani Apr 30, 2024
2f1d8d2
update defaults
PankajBhojwani Apr 30, 2024
2b4aeb2
don't check for special in standard
PankajBhojwani Apr 30, 2024
e62dfa2
some comments
PankajBhojwani Apr 30, 2024
e725f1e
resolve conflict
PankajBhojwani Apr 30, 2024
db00b90
spelling things
PankajBhojwani Apr 30, 2024
3d92f27
format
PankajBhojwani Apr 30, 2024
428821b
remove _idwasgenerated
PankajBhojwani Apr 30, 2024
6437b9f
fix user defaults file
PankajBhojwani Apr 30, 2024
4c744e6
misc
PankajBhojwani Apr 30, 2024
ca4015f
only one tojson
PankajBhojwani Apr 30, 2024
45cfcd6
just add duplicate pane auto to defaults
PankajBhojwani Apr 30, 2024
3c6015d
remove _getcumulativeactions
PankajBhojwani Apr 30, 2024
c2c75c8
bandaid temporary fix for name
PankajBhojwani May 1, 2024
3e601f5
better if
PankajBhojwani May 1, 2024
cdb907d
mark todo
PankajBhojwani May 1, 2024
f35bf20
Merge branch 'main' of https://github.com/microsoft/terminal into dev…
PankajBhojwani May 1, 2024
2b16acd
check for name, fix some tests
PankajBhojwani May 1, 2024
193e573
fix remaining tests
PankajBhojwani May 2, 2024
0480d65
this is better
PankajBhojwani May 2, 2024
02a1e37
correct GH todo
PankajBhojwani May 2, 2024
80fc299
some new tests
PankajBhojwani May 3, 2024
ebc03e9
another test
PankajBhojwani May 3, 2024
ccf1cc9
nits
PankajBhojwani May 3, 2024
7793c5c
schema
PankajBhojwani May 3, 2024
abef25d
move this to header
PankajBhojwani May 3, 2024
4d35c14
schema conflict
PankajBhojwani May 3, 2024
3e31bda
generate here instead
PankajBhojwani May 6, 2024
14d83b5
delete user actions that are identical to inbox actions
PankajBhojwani May 6, 2024
6c6dd46
leonard comments
PankajBhojwani May 20, 2024
b88a8c5
eraseif
PankajBhojwani May 30, 2024
9703815
nits n fixes
PankajBhojwani May 31, 2024
a80316d
1 more test
PankajBhojwani May 31, 2024
625753c
x86 hash
PankajBhojwani Jun 1, 2024
406312f
fix loops
PankajBhojwani Jun 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/cascadia/TerminalApp/TabBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TabBase::_UpdateSwitchToTabKeyChord()
{
const auto keyChord = _actionMap ? _actionMap.GetKeyBindingForAction(ShortcutAction::SwitchToTab, SwitchToTabArgs{ _TabViewIndex }) : nullptr;
const auto id = fmt::format(FMT_COMPILE(L"Terminal.SwitchToTab{}"), _TabViewIndex);
const auto keyChord{ _actionMap.GetKeyBindingForAction(id) };
const auto keyChordText = keyChord ? KeyChordSerialization::ToString(keyChord) : L"";

if (_keyChord == keyChordText)
Expand Down
7 changes: 4 additions & 3 deletions src/cascadia/TerminalApp/TerminalPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,7 @@ namespace winrt::TerminalApp::implementation
newTabFlyout.Items().Append(settingsItem);

auto actionMap = _settings.ActionMap();
const auto settingsKeyChord{ actionMap.GetKeyBindingForAction(ShortcutAction::OpenSettings, OpenSettingsArgs{ SettingsTarget::SettingsUI }) };
const auto settingsKeyChord{ actionMap.GetKeyBindingForAction(L"Terminal.OpenSettingsUI") };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh i really like how clean this feels now

if (settingsKeyChord)
{
_SetAcceleratorForMenuItem(settingsItem, settingsKeyChord);
Expand All @@ -848,7 +848,7 @@ namespace winrt::TerminalApp::implementation
commandPaletteFlyout.Click({ this, &TerminalPage::_CommandPaletteButtonOnClick });
newTabFlyout.Items().Append(commandPaletteFlyout);

const auto commandPaletteKeyChord{ actionMap.GetKeyBindingForAction(ShortcutAction::ToggleCommandPalette) };
const auto commandPaletteKeyChord{ actionMap.GetKeyBindingForAction(L"Terminal.ToggleCommandPalette") };
if (commandPaletteKeyChord)
{
_SetAcceleratorForMenuItem(commandPaletteFlyout, commandPaletteKeyChord);
Expand Down Expand Up @@ -1023,7 +1023,8 @@ namespace winrt::TerminalApp::implementation
// NewTab(ProfileIndex=N) action
NewTerminalArgs newTerminalArgs{ profileIndex };
NewTabArgs newTabArgs{ newTerminalArgs };
auto profileKeyChord{ _settings.ActionMap().GetKeyBindingForAction(ShortcutAction::NewTab, newTabArgs) };
const auto id = fmt::format(FMT_COMPILE(L"Terminal.OpenNewTabProfile{}"), profileIndex);
const auto profileKeyChord{ _settings.ActionMap().GetKeyBindingForAction(id) };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There 100% is a issue right now for "I rebound keys for new tab profile N, but the dropdown still has the old ones" and I'm guessing this will solve that (because people can rebind the key for the literal Terminal.OpenNewTabProfile5 rather than just making a new Command for it)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#13943 I think

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep this fixes that! Also fixes it in the cmd palette

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PankajBhojwani should this PR close that bug?


// make sure we find one to display
if (profileKeyChord)
Expand Down
630 changes: 211 additions & 419 deletions src/cascadia/TerminalSettingsModel/ActionMap.cpp

Large diffs are not rendered by default.

56 changes: 30 additions & 26 deletions src/cascadia/TerminalSettingsModel/ActionMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// queries
Model::Command GetActionByKeyChord(const Control::KeyChord& keys) const;
bool IsKeyChordExplicitlyUnbound(const Control::KeyChord& keys) const;
Control::KeyChord GetKeyBindingForAction(const ShortcutAction& action) const;
Control::KeyChord GetKeyBindingForAction(const ShortcutAction& action, const IActionArgs& actionArgs) const;
Control::KeyChord GetKeyBindingForAction(winrt::hstring cmdID) const;
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved

// population
void AddAction(const Model::Command& cmd);
Expand All @@ -69,9 +68,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
static com_ptr<ActionMap> FromJson(const Json::Value& json, const OriginTag origin = OriginTag::None);
std::vector<SettingsLoadWarnings> LayerJson(const Json::Value& json, const OriginTag origin, const bool withKeybindings = true);
Json::Value ToJson() const;
Json::Value KeyBindingsToJson() const;
bool FixUpsAppliedDuringLoad() const;

// modification
bool GenerateIDsForActions();
bool RebindKeys(const Control::KeyChord& oldKeys, const Control::KeyChord& newKeys);
void DeleteKeyBinding(const Control::KeyChord& keys);
void RegisterKeyBinding(Control::KeyChord keys, Model::ActionAndArgs action);
Expand All @@ -83,46 +83,50 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
winrt::Windows::Foundation::Collections::IVector<Model::Command> FilterToSendInput(winrt::hstring currentCommandline);

private:
std::optional<Model::Command> _GetActionByID(const InternalActionID actionID) const;
Model::Command _GetActionByID(const winrt::hstring actionID) const;
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
std::optional<winrt::hstring> _GetActionIdByKeyChordInternal(const Control::KeyChord& keys) const;
std::optional<Model::Command> _GetActionByKeyChordInternal(const Control::KeyChord& keys) const;

void _RefreshKeyBindingCaches();
void _PopulateAvailableActionsWithStandardCommands(std::unordered_map<hstring, Model::ActionAndArgs>& availableActions, std::unordered_set<InternalActionID>& visitedActionIDs) const;
void _PopulateNameMapWithSpecialCommands(std::unordered_map<hstring, Model::Command>& nameMap) const;
void _PopulateNameMapWithStandardCommands(std::unordered_map<hstring, Model::Command>& nameMap) const;
void _PopulateKeyBindingMapWithStandardCommands(std::unordered_map<Control::KeyChord, Model::Command, KeyChordHash, KeyChordEquality>& keyBindingsMap, std::unordered_set<Control::KeyChord, KeyChordHash, KeyChordEquality>& unboundKeys) const;
std::vector<Model::Command> _GetCumulativeActions() const noexcept;

void _TryUpdateActionMap(const Model::Command& cmd, Model::Command& oldCmd, Model::Command& consolidatedCmd);
void _TryUpdateName(const Model::Command& cmd, const Model::Command& oldCmd, const Model::Command& consolidatedCmd);
void _TryUpdateKeyChord(const Model::Command& cmd, const Model::Command& oldCmd, const Model::Command& consolidatedCmd);
std::vector<Model::Command> _GetCumulativeActions() const noexcept;
void _PopulateCumulativeKeyMap(std::unordered_map<Control::KeyChord, winrt::hstring, KeyChordHash, KeyChordEquality>& keyBindingsMap);
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
void _PopulateCumulativeActionMap(std::unordered_map<hstring, Model::Command>& actionMap);

void _recursiveUpdateCommandKeybindingLabels();
void _TryUpdateActionMap(const Model::Command& cmd);
void _TryUpdateKeyChord(const Model::Command& cmd);

Windows::Foundation::Collections::IMap<hstring, Model::ActionAndArgs> _AvailableActionsCache{ nullptr };
Windows::Foundation::Collections::IMap<hstring, Model::Command> _NameMapCache{ nullptr };
Windows::Foundation::Collections::IMap<Control::KeyChord, Model::Command> _GlobalHotkeysCache{ nullptr };
Windows::Foundation::Collections::IMap<Control::KeyChord, Model::Command> _KeyBindingMapCache{ nullptr };

Windows::Foundation::Collections::IVector<Model::Command> _ExpandedCommandsCache{ nullptr };

std::unordered_map<winrt::hstring, Model::Command> _NestedCommands;
std::vector<Model::Command> _IterableCommands;
std::unordered_map<Control::KeyChord, InternalActionID, KeyChordHash, KeyChordEquality> _KeyMap;
std::unordered_map<InternalActionID, Model::Command> _ActionMap;

// Masking Actions:
// These are actions that were introduced in an ancestor,
// but were edited (or unbound) in the current layer.
// _ActionMap shows a Command with keys that were added in this layer,
// whereas _MaskingActions provides a view that encompasses all of
// the valid associated key chords.
// Maintaining this map allows us to return a valid Command
// in GetKeyBindingForAction.
// Additionally, these commands to not need to be serialized,
// whereas those in _ActionMap do. These actions provide more data
// than is necessary to be serialized.
std::unordered_map<InternalActionID, Model::Command> _MaskingActions;

bool _fixUpsAppliedDuringLoad;
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved

void _AddKeyBindingHelper(const Json::Value& json, std::vector<SettingsLoadWarnings>& warnings);

// _KeyMap is the map of key chords -> action IDs defined in this layer
// _ActionMap is the map of action IDs -> commands defined in this layer
// These maps are the ones that we deserialize into when parsing the user json and vice-versa
std::unordered_map<Control::KeyChord, winrt::hstring, KeyChordHash, KeyChordEquality> _KeyMap;
std::unordered_map<winrt::hstring, Model::Command> _ActionMap;

// _CumulativeKeyMapCache is the map of key chords -> action IDs defined in all layers, with child layers overriding parent layers
Windows::Foundation::Collections::IMap<Control::KeyChord, winrt::hstring> _CumulativeKeyMapCache{ nullptr };
// _CumulativeActionMapCache is the map of action IDs -> commands defined in all layers, with child layers overriding parent layers
Windows::Foundation::Collections::IMap<winrt::hstring, Model::Command> _CumulativeActionMapCache{ nullptr };

// _ResolvedKeyActionMapCache is the map of key chords -> commands defined in all layers, with child layers overriding parent layers
// This is effectively a combination of _CumulativeKeyMapCache and _CumulativeActionMapCache and its purpose is so that
// we can give the SUI a view of the key chords and the commands they map to
Windows::Foundation::Collections::IMap<Control::KeyChord, Model::Command> _ResolvedKeyActionMapCache{ nullptr };

friend class SettingsModelUnitTests::KeyBindingsTests;
friend class SettingsModelUnitTests::DeserializationTests;
Expand Down
3 changes: 1 addition & 2 deletions src/cascadia/TerminalSettingsModel/ActionMap.idl
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ namespace Microsoft.Terminal.Settings.Model

Command GetActionByKeyChord(Microsoft.Terminal.Control.KeyChord keys);

Microsoft.Terminal.Control.KeyChord GetKeyBindingForAction(ShortcutAction action);
[method_name("GetKeyBindingForActionWithArgs")] Microsoft.Terminal.Control.KeyChord GetKeyBindingForAction(ShortcutAction action, IActionArgs actionArgs);
Microsoft.Terminal.Control.KeyChord GetKeyBindingForAction(String cmdID);

Windows.Foundation.Collections.IMapView<String, ActionAndArgs> AvailableActions { get; };

Expand Down
137 changes: 116 additions & 21 deletions src/cascadia/TerminalSettingsModel/ActionMapSerialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
}

// Method Description:
// - Deserialize an ActionMap from the array `json`. The json array should contain
// an array of serialized `Command` objects.
// - These actions are added to the `ActionMap`, where we automatically handle
// overwriting and unbinding actions.
// - Deserialize an ActionMap from the array `json`
// - The json array either contains an array of serialized `Command` objects,
// or an array of keybindings
// - The actions are added to _ActionMap and the keybindings are added to _KeyMap
// Arguments:
// - json: an array of Json::Value's to deserialize into our ActionMap.
// - json: an array of Json::Value's to deserialize into our _ActionMap and _KeyMap
// Return value:
// - a list of warnings encountered while deserializing the json
std::vector<SettingsLoadWarnings> ActionMap::LayerJson(const Json::Value& json, const OriginTag origin, const bool withKeybindings)
Expand All @@ -43,14 +43,50 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// settings phase, so we'll collect them now.
std::vector<SettingsLoadWarnings> warnings;

for (const auto& cmdJson : json)
for (const auto& jsonBlock : json)
{
if (!cmdJson.isObject())
if (!jsonBlock.isObject())
{
continue;
}

AddAction(*Command::FromJson(cmdJson, warnings, origin, withKeybindings));
// the json block may be 1 of 3 things:
// - the legacy style command block, that has the action, args and keys in it
// - the modern style command block, that has the action, args and an ID
// - the modern style keys block, that has the keys and an ID

// if the block contains a "command" field, it is either a legacy or modern style command block
// and we can call Command::FromJson on it (Command::FromJson can handle parsing both legacy or modern)

// if there is no "command" field, then it is a modern style keys block
// todo: use the CommandsKey / ActionKey static string view in Command.cpp somehow
if (jsonBlock.isMember(JsonKey("commands")) || jsonBlock.isMember(JsonKey("command")))
{
AddAction(*Command::FromJson(jsonBlock, warnings, origin, withKeybindings));

// for non-nested non-iterable commands,
// check if this is a legacy-style command block so we can inform the loader that fixups are needed
if (jsonBlock.isMember(JsonKey("command")) && !jsonBlock.isMember(JsonKey("iterateOn")))
{
if (jsonBlock.isMember(JsonKey("keys")))
{
// there are keys in this command block - its the legacy style
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
_fixUpsAppliedDuringLoad = true;
}

if (origin == OriginTag::User && !jsonBlock.isMember(JsonKey("id")))
{
// there's no ID in this command block - we will generate one for the user
// inform the loader that the ID needs to be written into the json
_fixUpsAppliedDuringLoad = true;
}
}
}
else
{
// this is not a command block, so it is a keybinding block
_AddKeyBindingHelper(jsonBlock, warnings);
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
}
}

return warnings;
Expand All @@ -60,23 +96,12 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{
Json::Value actionList{ Json::ValueType::arrayValue };

// Command serializes to an array of JSON objects.
// This is because a Command may have multiple key chords associated with it.
// The name and icon are only serialized in the first object.
// Example:
// { "name": "Custom Copy", "command": "copy", "keys": "ctrl+c" }
// { "command": "copy", "keys": "ctrl+shift+c" }
// { "command": "copy", "keys": "ctrl+ins" }
auto toJson = [&actionList](const Model::Command& cmd) {
const auto cmdImpl{ winrt::get_self<implementation::Command>(cmd) };
const auto& cmdJsonArray{ cmdImpl->ToJson() };
for (const auto& cmdJson : cmdJsonArray)
{
actionList.append(cmdJson);
}
const auto& cmdJson{ cmdImpl->ToJson() };
actionList.append(cmdJson);
};

// Serialize all standard Command objects in the current layer
for (const auto& [_, cmd] : _ActionMap)
{
toJson(cmd);
Expand All @@ -96,4 +121,74 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation

return actionList;
}

Json::Value ActionMap::KeyBindingsToJson() const
{
Json::Value keybindingsList{ Json::ValueType::arrayValue };

auto toJson = [&keybindingsList](const KeyChord kc, const winrt::hstring cmdID) {
Json::Value keyIDPair{ Json::ValueType::objectValue };
JsonUtils::SetValueForKey(keyIDPair, "keys", kc);
JsonUtils::SetValueForKey(keyIDPair, "id", cmdID);
keybindingsList.append(keyIDPair);
};

// Serialize all standard keybinding objects in the current layer
for (const auto& [keys, cmdID] : _KeyMap)
{
toJson(keys, cmdID);
}

return keybindingsList;
}

void ActionMap::_AddKeyBindingHelper(const Json::Value& json, std::vector<SettingsLoadWarnings>& warnings)
{
// There should always be a "keys" field
// - If there is also an "id" field - we add the pair to our _KeyMap
// - If there is no "id" field - this is an explicit unbinding, still add it to the _KeyMap,
// when this key chord is queried for we will know it is an explicit unbinding
// todo: use the KeysKey and IDKey static strings from Command.cpp
const auto keysJson{ json[JsonKey("keys")] };
if (keysJson.isArray() && keysJson.size() > 1)
{
warnings.push_back(SettingsLoadWarnings::TooManyKeysForChord);
}
else
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
{
Control::KeyChord keys{ nullptr };
winrt::hstring idJson;
if (JsonUtils::GetValueForKey(json, "keys", keys))
{
// if these keys are already bound to some command,
// we need to update that command to erase these keys as we are about to overwrite them
if (const auto foundCommand = _GetActionByKeyChordInternal(keys); foundCommand && *foundCommand)
{
const auto foundCommandImpl{ get_self<implementation::Command>(*foundCommand) };
foundCommandImpl->EraseKey(keys);
}

// if the "id" field doesn't exist in the json, then idJson will be an empty string which is fine
JsonUtils::GetValueForKey(json, "id", idJson);

// any existing keybinding with the same keychord in this layer will get overwritten
_KeyMap.insert_or_assign(keys, idJson);

// make sure the command registers these keys
if (!idJson.empty())
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
{
// TODO GH#17160
// if the command with this id is only going to appear later during settings load
// then this will return null, meaning that the command created later on will not register this keybinding
// the keybinding will still work fine within the app, its just that the Command object itself won't know about this key mapping
// we are going to move away from Command needing to know its key mappings in a followup, so this shouldn't matter for very long
if (const auto cmd = _GetActionByID(idJson))
{
cmd.RegisterKey(keys);
}
}
}
}
return;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ bool SettingsLoader::FixupUserSettings()
};

auto fixedUp = userSettings.fixupsAppliedDuringLoad;
fixedUp = userSettings.globals->FixUpsAppliedDuringLoad() || fixedUp;

fixedUp = RemapColorSchemeForProfile(userSettings.baseLayerProfile) || fixedUp;
for (const auto& profile : userSettings.profiles)
Expand Down Expand Up @@ -504,10 +505,6 @@ bool SettingsLoader::FixupUserSettings()
fixedUp = true;
}

// we need to generate an ID for a command in the user settings if it doesn't already have one
auto actionMap{ winrt::get_self<ActionMap>(userSettings.globals->ActionMap()) };
actionMap->GenerateIDsForActions();

return fixedUp;
}

Expand Down