Private/Subscriptions/ConvertFrom-ElmKeyString.ps1

function ConvertFrom-ElmKeyString {
    <#
    .SYNOPSIS
        Parses a canonical key string into a ConsoleKey and ConsoleModifiers value.

    .DESCRIPTION
        Converts human-readable key strings like 'Q', 'Ctrl+Q', 'UpArrow',
        'Ctrl+Shift+Home' into a PSCustomObject containing the equivalent
        System.ConsoleKey enum value and System.ConsoleModifiers flags.

        Modifier prefixes (case-insensitive):
          Ctrl, Control, Alt, Shift

        Common key aliases (case-insensitive):
          Esc -> Escape
          Return -> Enter
          Space -> Spacebar
          Del -> Delete
          Ins -> Insert
          Up -> UpArrow
          Down -> DownArrow
          Left -> LeftArrow
          Right -> RightArrow
          PgUp -> PageUp
          PgDn -> PageDown
          0-9 -> D0-D9 (top-row digit keys)

    .PARAMETER KeyString
        The key string to parse. Format: [Modifier+]Key
        Examples: 'Q', 'Ctrl+Q', 'Alt+F4', 'Ctrl+Shift+Home', 'UpArrow', 'F1'

    .OUTPUTS
        PSCustomObject with Key ([System.ConsoleKey]) and Modifiers ([System.ConsoleModifiers]).

    .EXAMPLE
        ConvertFrom-ElmKeyString -KeyString 'Q'
        # Key = [ConsoleKey]::Q, Modifiers = 0

    .EXAMPLE
        ConvertFrom-ElmKeyString -KeyString 'Ctrl+Shift+N'
        # Key = [ConsoleKey]::N, Modifiers = Control | Shift

    .NOTES
        Used internally by New-ElmKeySub to build typed subscription objects.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [string]$KeyString
    )
    process {
        $parts   = $KeyString.Trim() -split '\+'
        $keyName = $parts[-1].Trim()

        [int]$modFlags = 0

        if ($parts.Length -gt 1) {
            foreach ($part in $parts[0..($parts.Length - 2)]) {
                switch ($part.Trim().ToLower()) {
                    'ctrl'    { $modFlags = $modFlags -bor [int][System.ConsoleModifiers]::Control }
                    'control' { $modFlags = $modFlags -bor [int][System.ConsoleModifiers]::Control }
                    'alt'     { $modFlags = $modFlags -bor [int][System.ConsoleModifiers]::Alt }
                    'shift'   { $modFlags = $modFlags -bor [int][System.ConsoleModifiers]::Shift }
                    default {
                        $ex  = [System.ArgumentException]::new(
                            "Unknown modifier: '$($part.Trim())'. Valid modifiers: Ctrl, Alt, Shift."
                        )
                        $err = [System.Management.Automation.ErrorRecord]::new(
                            $ex, 'UnknownModifier',
                            [System.Management.Automation.ErrorCategory]::InvalidArgument,
                            $KeyString
                        )
                        $PSCmdlet.ThrowTerminatingError($err)
                    }
                }
            }
        }

        # Normalize common aliases to ConsoleKey enum names
        $normalised = switch ($keyName.ToLower()) {
            'esc'     { 'Escape' }
            'return'  { 'Enter' }
            'space'   { 'Spacebar' }
            'del'     { 'Delete' }
            'ins'     { 'Insert' }
            'up'      { 'UpArrow' }
            'down'    { 'DownArrow' }
            'left'    { 'LeftArrow' }
            'right'   { 'RightArrow' }
            'pgup'    { 'PageUp' }
            'pgdn'    { 'PageDown' }
            '0'       { 'D0' }
            '1'       { 'D1' }
            '2'       { 'D2' }
            '3'       { 'D3' }
            '4'       { 'D4' }
            '5'       { 'D5' }
            '6'       { 'D6' }
            '7'       { 'D7' }
            '8'       { 'D8' }
            '9'       { 'D9' }
            default   { $keyName }
        }

        # Try enum parse (case-insensitive via PowerShell cast)
        $consoleKey = $null
        try {
            $consoleKey = [System.ConsoleKey]$normalised
        } catch {
            $ex  = [System.ArgumentException]::new(
                "Unknown key: '$keyName'. Must be a valid System.ConsoleKey name (e.g. 'Q', 'Enter', 'UpArrow', 'F1')."
            )
            $err = [System.Management.Automation.ErrorRecord]::new(
                $ex, 'UnknownKey',
                [System.Management.Automation.ErrorCategory]::InvalidArgument,
                $KeyString
            )
            $PSCmdlet.ThrowTerminatingError($err)
        }

        return [PSCustomObject]@{
            Key       = $consoleKey
            Modifiers = [System.ConsoleModifiers]$modFlags
        }
    }
}