Last active
May 1, 2026 14:36
-
-
Save sba923/5671d24e0ae533689490b504eb5d8401 to your computer and use it in GitHub Desktop.
PowerShell utilities to deal with keybindings
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # this is one of Stéphane BARIZIEN's public domain scripts | |
| # the most recent version can be found at: https://gist.github.com/sba923/5671d24e0ae533689490b504eb5d8401#file-get-powershellrunninginwindowsterminalkeybinding-ps1 | |
| #requires -version 7 | |
| <# | |
| .SYNOPSIS | |
| Returns effective PowerShell key bindings when running inside Windows Terminal. | |
| .DESCRIPTION | |
| Calls the sibling Get-WindowsTerminalKeyBinding.ps1 script to load Windows Terminal | |
| bindings, then combines them with PSReadLine bindings that do not conflict. | |
| When a key sequence is already handled by Windows Terminal, the matching PSReadLine | |
| binding is omitted so the output reflects what is effectively reachable in an | |
| interactive session hosted by Windows Terminal. | |
| .PARAMETER WindowsTerminalPackageName | |
| Appx package name forwarded to Get-WindowsTerminalKeyBinding.ps1. | |
| Common values are: | |
| - Microsoft.WindowsTerminal | |
| - Microsoft.WindowsTerminalPreview | |
| When omitted, the sibling script auto-detects the package name. | |
| .PARAMETER ExcludeUnresolved | |
| Forwarded switch for Get-WindowsTerminalKeyBinding.ps1 to exclude unresolved Windows | |
| Terminal commands before computing the effective merged list. | |
| .OUTPUTS | |
| System.Management.Automation.PSCustomObject | |
| Objects with the properties: | |
| - Command | |
| - Parameters | |
| - Keys | |
| - Source | |
| .NOTES | |
| Script dependencies/calls: | |
| - Calls sibling script Get-WindowsTerminalKeyBinding.ps1 to retrieve Windows | |
| Terminal bindings before merging with PSReadLine key handlers. | |
| - (Indirectly) calls Get-WindowsTerminalVersion.ps1 to auto-detect stable vs preview package | |
| when -WindowsTerminalPackageName is not provided. | |
| .EXAMPLE | |
| Shows effective key bindings from Windows Terminal plus non-conflicting PSReadLine | |
| bindings. | |
| Get-PowerShellRunningInWindowsTerminalKeyBinding.ps1 | |
| .EXAMPLE | |
| Shows effective key bindings while filtering unresolved Windows Terminal commands. | |
| Get-PowerShellRunningInWindowsTerminalKeyBinding.ps1 -ExcludeUnresolved | |
| #> | |
| param( | |
| [string] $WindowsTerminalPackageName, | |
| [switch] $ExcludeUnresolved | |
| ) | |
| # cSpell: ignore pgup pgdn Stéphane BARIZIEN | |
| function Get-NormalizedChord { | |
| param([string] $Chord) | |
| if ([string]::IsNullOrWhiteSpace($Chord)) | |
| { | |
| return $null | |
| } | |
| $alias = @{ | |
| 'control' = 'ctrl' | |
| 'ctl' = 'ctrl' | |
| 'windows' = 'win' | |
| 'escape' = 'esc' | |
| 'return' = 'enter' | |
| 'pageup' = 'pgup' | |
| 'pagedown' = 'pgdn' | |
| } | |
| $modOrder = @('ctrl', 'alt', 'shift', 'win') | |
| $mods = New-Object System.Collections.Generic.List[string] | |
| $keys = New-Object System.Collections.Generic.List[string] | |
| foreach ($part in ($Chord -split '\+')) | |
| { | |
| $token = $part.Trim().ToLowerInvariant() | |
| if ([string]::IsNullOrWhiteSpace($token)) | |
| { | |
| continue | |
| } | |
| if ($alias.ContainsKey($token)) | |
| { | |
| $token = $alias[$token] | |
| } | |
| if ($token -in $modOrder) | |
| { | |
| if (-not $mods.Contains($token)) | |
| { | |
| $mods.Add($token) | |
| } | |
| } | |
| else | |
| { | |
| $keys.Add($token) | |
| } | |
| } | |
| $orderedMods = foreach ($m in $modOrder) | |
| { | |
| if ($mods.Contains($m)) | |
| { | |
| $m | |
| } | |
| } | |
| @($orderedMods + $keys) -join '+' | |
| } | |
| function Get-NormalizedKeySequence { | |
| param([string] $KeySequence) | |
| if ([string]::IsNullOrWhiteSpace($KeySequence)) | |
| { | |
| return $null | |
| } | |
| (($KeySequence -split ',') | ForEach-Object { Get-NormalizedChord -Chord $_ }) -join ',' | |
| } | |
| function Get-CanonicalPSReadLineKeyDisplay { | |
| param([string] $KeySequence) | |
| if ([string]::IsNullOrWhiteSpace($KeySequence)) | |
| { | |
| return $KeySequence | |
| } | |
| $modifierAlias = @{ | |
| 'ctrl' = 'Ctrl' | |
| 'control' = 'Ctrl' | |
| 'ctl' = 'Ctrl' | |
| 'alt' = 'Alt' | |
| 'shift' = 'Shift' | |
| 'win' = 'Win' | |
| 'windows' = 'Win' | |
| } | |
| $modifierOrder = @('Ctrl', 'Alt', 'Shift', 'Win') | |
| $canonicalChords = foreach ($chord in ($KeySequence -split '(?<!\+),')) | |
| { | |
| $tokens = @($chord -split '\+' | ForEach-Object { $_.Trim() } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) | |
| if ($tokens.Count -eq 0) | |
| { | |
| continue | |
| } | |
| $mods = @{} | |
| $nonMods = New-Object System.Collections.Generic.List[string] | |
| foreach ($token in $tokens) | |
| { | |
| $lower = $token.ToLowerInvariant() | |
| if ($modifierAlias.ContainsKey($lower)) | |
| { | |
| $mods[$modifierAlias[$lower]] = $true | |
| continue | |
| } | |
| if ($token.Length -eq 1 -and $token -cmatch '[A-Z]') | |
| { | |
| # In PSReadLine notation, uppercase letters imply Shift. | |
| $mods['Shift'] = $true | |
| $nonMods.Add($token.ToLowerInvariant()) | |
| continue | |
| } | |
| if ($token.Length -eq 1 -and $token -match '[a-zA-Z]') | |
| { | |
| $nonMods.Add($token.ToLowerInvariant()) | |
| continue | |
| } | |
| $nonMods.Add($token) | |
| } | |
| $orderedMods = @( | |
| foreach ($m in $modifierOrder) | |
| { | |
| if ($mods.ContainsKey($m)) | |
| { | |
| $m | |
| } | |
| } | |
| ) | |
| @($orderedMods + @($nonMods.ToArray())) -join '+' | |
| } | |
| $canonicalChords -join ',' | |
| } | |
| $wtScript = Join-Path -Path $PSScriptRoot -ChildPath 'Get-WindowsTerminalKeyBinding.ps1' | |
| if (-not (Test-Path -LiteralPath $wtScript)) | |
| { | |
| throw "Cannot find sibling script: $wtScript" | |
| } | |
| $wtParams = @{} | |
| if ($PSBoundParameters.ContainsKey('WindowsTerminalPackageName')) | |
| { | |
| $wtParams['PackageName'] = $WindowsTerminalPackageName | |
| } | |
| if ($ExcludeUnresolved) | |
| { | |
| $wtParams['ExcludeUnresolved'] = $true | |
| } | |
| $windowsTerminalBindings = & $wtScript @wtParams | |
| $wtKeySet = @{} | |
| $effectiveBindings = @() | |
| foreach ($binding in $windowsTerminalBindings) | |
| { | |
| $normalized = Get-NormalizedKeySequence -KeySequence ([string]$binding.Keys) | |
| if ($null -eq $normalized) | |
| { | |
| continue | |
| } | |
| $wtKeySet[$normalized] = $true | |
| $effectiveBindings += [PSCustomObject][ordered]@{ | |
| Command = $binding.Command | |
| Parameters = $binding.Parameters | |
| Keys = $binding.Keys | |
| Source = 'WindowsTerminal' | |
| } | |
| } | |
| $psReadLineBindings = Get-PSReadLineKeyHandler | |
| foreach ($binding in $psReadLineBindings) | |
| { | |
| $normalized = Get-NormalizedKeySequence -KeySequence ([string]$binding.Key) | |
| if ($null -eq $normalized) | |
| { | |
| continue | |
| } | |
| if ($wtKeySet.ContainsKey($normalized)) | |
| { | |
| continue | |
| } | |
| $effectiveBindings += [PSCustomObject][ordered]@{ | |
| Command = $binding.Function | |
| Parameters = [PSCustomObject]@{ | |
| Description = $binding.Description | |
| Group = $binding.Group | |
| } | |
| Keys = Get-CanonicalPSReadLineKeyDisplay -KeySequence ([string]$binding.Key) | |
| Source = 'PSReadLine' | |
| } | |
| } | |
| $effectiveBindings | Sort-Object -Property 'Keys', 'Source' | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # this is one of Stéphane BARIZIEN's public domain scripts | |
| # the most recent version can be found at: https://gist.github.com/sba923/5671d24e0ae533689490b504eb5d8401#file-get-windowsterminalkeybinding-ps1 | |
| #requires -version 7 | |
| <# | |
| .SYNOPSIS | |
| Returns effective Windows Terminal key bindings from defaults and user settings. | |
| .DESCRIPTION | |
| Loads the Windows Terminal defaults.json and user settings.json files, resolves key | |
| bindings from both action syntaxes (actions/keybindings), merges user and default | |
| bindings, and reports whether a user binding overrides a default binding. | |
| If PackageName is not provided, the script auto-detects whether the current Windows | |
| Terminal flavor is stable or preview and uses the corresponding package name. | |
| .PARAMETER PackageName | |
| Appx package name to inspect. | |
| Common values are: | |
| - Microsoft.WindowsTerminal | |
| - Microsoft.WindowsTerminalPreview | |
| When omitted, the package name is auto-detected. | |
| .PARAMETER ExcludeUnresolved | |
| Excludes key bindings whose command cannot be resolved (for example keybindings that | |
| reference an action id not found in defaults/user actions). | |
| .OUTPUTS | |
| System.Management.Automation.PSCustomObject | |
| Objects with the properties: | |
| - Command | |
| - Parameters | |
| - Keys | |
| - Source | |
| - OverridesDefault | |
| .NOTES | |
| Script dependencies/calls: | |
| - Calls Get-WindowsTerminalVersion.ps1 to auto-detect stable vs preview package | |
| when -PackageName is not provided. | |
| .EXAMPLE | |
| Returns merged Windows Terminal key bindings for the detected running flavor. | |
| Get-WindowsTerminalKeyBinding.ps1 | |
| .EXAMPLE | |
| Returns bindings for Windows Terminal Preview while filtering unresolved commands. | |
| Get-WindowsTerminalKeyBinding.ps1 -PackageName Microsoft.WindowsTerminalPreview -ExcludeUnresolved | |
| #> | |
| param( | |
| [string] $PackageName, | |
| [switch] $ExcludeUnresolved | |
| ) | |
| # cSpell: ignore wekyb bbwe Scancode numpad pgdn pgup Stéphane BARIZIEN | |
| if (-not $PSBoundParameters.ContainsKey('PackageName')) | |
| { | |
| $wtVersion = Get-WindowsTerminalVersion.ps1 | |
| if ($null -eq $wtVersion) | |
| { | |
| throw("Cannot determine the version / flavor of the current Windows Terminal") | |
| } | |
| if ($wtVersion.IsPreview) | |
| { | |
| $PackageName = 'Microsoft.WindowsTerminalPreview' | |
| } | |
| else | |
| { | |
| $PackageName = 'Microsoft.WindowsTerminal' | |
| } | |
| } | |
| try | |
| { | |
| $version = (Get-AppxPackage $PackageName).Version | |
| } | |
| catch | |
| { | |
| # retry after explicitly importing the Appx module | |
| if ($PSVersionTable.PSVersion.Major -eq 5) | |
| { | |
| Import-Module Appx | |
| } | |
| else | |
| { | |
| Import-Module Appx -UseWindowsPowerShell | |
| } | |
| $version = (Get-AppxPackage $PackageName).Version | |
| } | |
| $defaultJSON = Join-Path -Path $env:ProgramFiles -ChildPath ('WindowsApps\{0}_{1}_x64__8wekyb3d8bbwe\defaults.json' -f $PackageName, $version) | |
| $userJSON = Join-Path -Path $env:LOCALAPPDATA -ChildPath ('Packages\{0}_8wekyb3d8bbwe\LocalState\settings.json' -f $PackageName) | |
| $defaultSettings = Get-Content -Path $defaultJSON -Raw | ConvertFrom-Json | |
| $userSettings = Get-Content -Path $userJSON -Raw | ConvertFrom-Json | |
| function Get-NormalizedWTKey { | |
| param([string] $Key) | |
| if ([string]::IsNullOrWhiteSpace($Key)) | |
| { | |
| return $null | |
| } | |
| # Split key sequences on commas that are not part of a key token like Ctrl+, | |
| (($Key -split '(?<!\+),') | ForEach-Object { $_.Trim().ToLowerInvariant() }) -join ',' | |
| } | |
| function Get-CanonicalWTKeyDisplay { | |
| param([string] $Key) | |
| if ([string]::IsNullOrWhiteSpace($Key)) | |
| { | |
| return $Key | |
| } | |
| $modifierMap = @{ | |
| 'ctrl' = 'Ctrl' | |
| 'control' = 'Ctrl' | |
| 'alt' = 'Alt' | |
| 'shift' = 'Shift' | |
| 'win' = 'Win' | |
| 'windows' = 'Win' | |
| } | |
| $modifierOrder = @('Ctrl', 'Alt', 'Shift', 'Win') | |
| function Convert-WTNonModifierToken { | |
| param([string] $Token) | |
| if ([string]::IsNullOrWhiteSpace($Token)) | |
| { | |
| return $Token | |
| } | |
| $lower = $Token.ToLowerInvariant() | |
| if ($lower -match '^f(\d{1,2})$') | |
| { | |
| return ('F' + $matches[1]) | |
| } | |
| if ($lower -match '^sc\((\d+)\)$') | |
| { | |
| return ('Scancode(' + $matches[1] + ')') | |
| } | |
| if ($lower -match '^numpad_(.+)$') | |
| { | |
| $suffix = $matches[1] | |
| if ($suffix -eq 'plus') | |
| { | |
| $suffix = 'Plus' | |
| } | |
| elseif ($suffix -eq 'minus') | |
| { | |
| $suffix = 'Minus' | |
| } | |
| return ('NumPad_' + $suffix) | |
| } | |
| switch ($lower) | |
| { | |
| 'enter' { return 'Enter' } | |
| 'plus' { return 'Plus' } | |
| 'minus' { return 'Minus' } | |
| 'insert' { return 'Insert' } | |
| 'delete' { return 'Delete' } | |
| 'del' { return 'Del' } | |
| 'numpad_plus' { return 'NumPad_Plus' } | |
| 'numpad_minus' { return 'NumPad_Minus' } | |
| 'period' { return '.' } | |
| 'menu' { return 'Menu' } | |
| 'tab' { return 'Tab' } | |
| 'pgdn' { return 'PgDn' } | |
| 'pgup' { return 'PgUp' } | |
| 'down' { return 'DownArrow' } | |
| 'up' { return 'UpArrow' } | |
| 'home' { return 'Home' } | |
| 'end' { return 'End' } | |
| 'left' { return 'LeftArrow' } | |
| 'right' { return 'RightArrow' } | |
| 'space' { return 'Space' } | |
| default { return $lower } | |
| } | |
| } | |
| # Split key sequences on commas that are not part of a key token like Ctrl+, | |
| $normalizedChords = foreach ($chord in ($Key -split '(?<!\+),')) | |
| { | |
| $tokens = @($chord -split '\+' | ForEach-Object { $_.Trim() } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) | |
| if ($tokens.Count -eq 0) | |
| { | |
| continue | |
| } | |
| $mods = @{} | |
| $nonMods = New-Object System.Collections.Generic.List[string] | |
| foreach ($token in $tokens) | |
| { | |
| $lowerToken = $token.ToLowerInvariant() | |
| if ($modifierMap.ContainsKey($lowerToken)) | |
| { | |
| $mods[$modifierMap[$lowerToken]] = $true | |
| } | |
| else | |
| { | |
| $nonMods.Add((Convert-WTNonModifierToken -Token $token)) | |
| } | |
| } | |
| $orderedMods = @( | |
| foreach ($m in $modifierOrder) | |
| { | |
| if ($mods.ContainsKey($m)) | |
| { | |
| $m | |
| } | |
| } | |
| ) | |
| $nonModifierTokens = @($nonMods.ToArray()) | |
| @($orderedMods + $nonModifierTokens) -join '+' | |
| } | |
| ($normalizedChords -join ',') | |
| } | |
| function Convert-WTActionToObject { | |
| param( | |
| [PSCustomObject] $Action, | |
| [ValidateSet('Default', 'User')] | |
| [string] $Source | |
| ) | |
| if ($null -eq $Action) | |
| { | |
| return @() | |
| } | |
| $keys = @() | |
| if ($Action.PSObject.Properties.Name -contains 'keys') | |
| { | |
| if ($Action.keys -is [array]) | |
| { | |
| $keys = @($Action.keys) | |
| } | |
| elseif (-not [string]::IsNullOrWhiteSpace([string]$Action.keys)) | |
| { | |
| $keys = @([string]$Action.keys) | |
| } | |
| } | |
| if ($keys.Count -eq 0) | |
| { | |
| return @() | |
| } | |
| $commandName = $null | |
| $parameters = $null | |
| if ($Action.PSObject.Properties.Name -contains 'command') | |
| { | |
| if ($Action.command -is [string]) | |
| { | |
| $commandName = $Action.command | |
| } | |
| elseif ($null -ne $Action.command) | |
| { | |
| $commandObj = $Action.command | |
| if ($commandObj.PSObject.Properties.Name -contains 'action') | |
| { | |
| $commandName = $commandObj.action | |
| } | |
| $parameterMap = [ordered]@{} | |
| foreach ($prop in $commandObj.PSObject.Properties) | |
| { | |
| if ($prop.Name -ne 'action') | |
| { | |
| $parameterMap[$prop.Name] = $prop.Value | |
| } | |
| } | |
| if ($parameterMap.Count -gt 0) | |
| { | |
| $parameters = [PSCustomObject]$parameterMap | |
| } | |
| } | |
| } | |
| elseif ($Action.PSObject.Properties.Name -contains 'action') | |
| { | |
| # Backward-compatible fallback for older objects. | |
| $commandName = $Action.action | |
| } | |
| $result = foreach ($key in $keys) | |
| { | |
| $normalizedKey = Get-NormalizedWTKey -Key ([string]$key) | |
| if ($null -ne $normalizedKey) | |
| { | |
| [PSCustomObject][ordered]@{ | |
| Command = $commandName | |
| Parameters = $parameters | |
| Keys = Get-CanonicalWTKeyDisplay -Key ([string]$key) | |
| Source = $Source | |
| OverridesDefault = $false | |
| _NormalizedKey = $normalizedKey | |
| } | |
| } | |
| } | |
| @($result) | |
| } | |
| function Get-WTCommandInfo { | |
| param([PSCustomObject] $Node) | |
| $commandName = $null | |
| $parameters = $null | |
| if ($null -eq $Node) | |
| { | |
| return [PSCustomObject]@{ Command = $null; Parameters = $null } | |
| } | |
| if ($Node.PSObject.Properties.Name -contains 'command') | |
| { | |
| if ($Node.command -is [string]) | |
| { | |
| $commandName = $Node.command | |
| } | |
| elseif ($null -ne $Node.command) | |
| { | |
| $commandObj = $Node.command | |
| if ($commandObj.PSObject.Properties.Name -contains 'action') | |
| { | |
| $commandName = $commandObj.action | |
| } | |
| $parameterMap = [ordered]@{} | |
| foreach ($prop in $commandObj.PSObject.Properties) | |
| { | |
| if ($prop.Name -ne 'action') | |
| { | |
| $parameterMap[$prop.Name] = $prop.Value | |
| } | |
| } | |
| if ($parameterMap.Count -gt 0) | |
| { | |
| $parameters = [PSCustomObject]$parameterMap | |
| } | |
| } | |
| } | |
| elseif ($Node.PSObject.Properties.Name -contains 'action') | |
| { | |
| $commandName = $Node.action | |
| } | |
| [PSCustomObject]@{ Command = $commandName; Parameters = $parameters } | |
| } | |
| function Get-WTActionMapById { | |
| param([PSCustomObject] $Settings) | |
| $actionById = @{} | |
| if ($null -eq $Settings) | |
| { | |
| return $actionById | |
| } | |
| $actionsArray = @() | |
| if ($Settings.PSObject.Properties.Name -contains 'actions') | |
| { | |
| $actionsArray = @($Settings.actions) | |
| } | |
| foreach ($action in $actionsArray) | |
| { | |
| if (($action.PSObject.Properties.Name -contains 'id') -and -not [string]::IsNullOrWhiteSpace([string]$action.id)) | |
| { | |
| $actionById[[string]$action.id] = Get-WTCommandInfo -Node $action | |
| } | |
| } | |
| $actionById | |
| } | |
| function Convert-WTSettingsToBindingObjects { | |
| param( | |
| [PSCustomObject] $Settings, | |
| [ValidateSet('Default', 'User')] | |
| [string] $Source, | |
| [hashtable] $FallbackActionById = @{} | |
| ) | |
| $result = @() | |
| $actionById = @{} | |
| $actionsArray = @() | |
| if ($Settings.PSObject.Properties.Name -contains 'actions') | |
| { | |
| $actionsArray = @($Settings.actions) | |
| } | |
| foreach ($action in $actionsArray) | |
| { | |
| $cmdInfo = Get-WTCommandInfo -Node $action | |
| if (($action.PSObject.Properties.Name -contains 'id') -and -not [string]::IsNullOrWhiteSpace([string]$action.id)) | |
| { | |
| $actionById[[string]$action.id] = $cmdInfo | |
| } | |
| if ($action.PSObject.Properties.Name -contains 'keys') | |
| { | |
| foreach ($binding in (Convert-WTActionToObject -Action $action -Source $Source)) | |
| { | |
| $result += $binding | |
| } | |
| } | |
| } | |
| $keyBindingsArray = @() | |
| if ($Settings.PSObject.Properties.Name -contains 'keybindings') | |
| { | |
| $keyBindingsArray = @($Settings.keybindings) | |
| } | |
| foreach ($keyBinding in $keyBindingsArray) | |
| { | |
| $keys = @() | |
| if ($keyBinding.keys -is [array]) | |
| { | |
| $keys = @($keyBinding.keys) | |
| } | |
| elseif (-not [string]::IsNullOrWhiteSpace([string]$keyBinding.keys)) | |
| { | |
| $keys = @([string]$keyBinding.keys) | |
| } | |
| if ($keys.Count -eq 0) | |
| { | |
| continue | |
| } | |
| $cmdInfo = $null | |
| if ($keyBinding.PSObject.Properties.Name -contains 'command') | |
| { | |
| $cmdInfo = Get-WTCommandInfo -Node $keyBinding | |
| } | |
| elseif (($keyBinding.PSObject.Properties.Name -contains 'id') -and $actionById.ContainsKey([string]$keyBinding.id)) | |
| { | |
| $cmdInfo = $actionById[[string]$keyBinding.id] | |
| } | |
| elseif (($keyBinding.PSObject.Properties.Name -contains 'id') -and $FallbackActionById.ContainsKey([string]$keyBinding.id)) | |
| { | |
| $cmdInfo = $FallbackActionById[[string]$keyBinding.id] | |
| } | |
| else | |
| { | |
| $unresolvedId = $null | |
| if ($keyBinding.PSObject.Properties.Name -contains 'id') | |
| { | |
| $unresolvedId = [string]$keyBinding.id | |
| } | |
| $unresolvedParameters = $null | |
| if (-not [string]::IsNullOrWhiteSpace($unresolvedId)) | |
| { | |
| $unresolvedParameters = [PSCustomObject]@{ Id = $unresolvedId } | |
| } | |
| $cmdInfo = [PSCustomObject]@{ | |
| Command = '(!!! Unresolved !!!)' | |
| Parameters = $unresolvedParameters | |
| } | |
| } | |
| foreach ($key in $keys) | |
| { | |
| $normalizedKey = Get-NormalizedWTKey -Key ([string]$key) | |
| if ($null -eq $normalizedKey) | |
| { | |
| continue | |
| } | |
| $result += [PSCustomObject][ordered]@{ | |
| Command = $cmdInfo.Command | |
| Parameters = $cmdInfo.Parameters | |
| Keys = Get-CanonicalWTKeyDisplay -Key ([string]$key) | |
| Source = $Source | |
| OverridesDefault = $false | |
| _NormalizedKey = $normalizedKey | |
| } | |
| } | |
| } | |
| @($result) | |
| } | |
| $defaultActionById = Get-WTActionMapById -Settings $defaultSettings | |
| $defaultActions = Convert-WTSettingsToBindingObjects -Settings $defaultSettings -Source 'Default' | |
| $userActions = Convert-WTSettingsToBindingObjects -Settings $userSettings -Source 'User' -FallbackActionById $defaultActionById | |
| $userKeys = @{} | |
| foreach ($ua in $userActions) | |
| { | |
| $userKeys[$ua._NormalizedKey] = $true | |
| } | |
| foreach ($ua in $userActions) | |
| { | |
| if ($ua._NormalizedKey -in @($defaultActions._NormalizedKey)) | |
| { | |
| $ua.OverridesDefault = $true | |
| } | |
| } | |
| $actions = @($userActions) | |
| foreach ($da in $defaultActions) | |
| { | |
| if (-not $userKeys.ContainsKey($da._NormalizedKey)) | |
| { | |
| $actions += $da | |
| } | |
| } | |
| $outputActions = $actions | |
| if ($ExcludeUnresolved) | |
| { | |
| $outputActions = $outputActions | Where-Object { $_.Command -ne '(!!! Unresolved !!!)' } | |
| } | |
| $outputActions | | |
| Sort-Object -Property 'Keys' | | |
| Select-Object Command, Parameters, Keys, Source, OverridesDefault |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment