diff --git a/BakNRet/BakNRet.psd1 b/BakNRet/BakNRet.psd1 index b2aeeb0..a2d8408 100644 --- a/BakNRet/BakNRet.psd1 +++ b/BakNRet/BakNRet.psd1 @@ -19,6 +19,7 @@ CompatiblePSEditions = @('Desktop', 'Core') FunctionsToExport = @( + 'Read-BakNRetLine', 'Get-BakNRetConfigSetting', 'Set-BakNRetConfigSetting', 'Invoke-BakNRetEntryScript', diff --git a/BakNRet/BakNRet.psm1 b/BakNRet/BakNRet.psm1 index 52567d7..c24962c 100644 --- a/BakNRet/BakNRet.psm1 +++ b/BakNRet/BakNRet.psm1 @@ -171,7 +171,10 @@ . (Join-Path $PSScriptRoot 'Public\Get-BakNRetConfigSetting.ps1') . (Join-Path $PSScriptRoot 'Public\Set-BakNRetConfigSetting.ps1') +. (Join-Path $PSScriptRoot 'Public\Read-BakNRetLine.ps1') + Export-ModuleMember -Function @( + 'Read-BakNRetLine', 'Get-BakNRetConfigSetting', 'Set-BakNRetConfigSetting', 'Invoke-BakNRetEntryScript', diff --git a/BakNRet/Public/Read-BakNRetLine.ps1 b/BakNRet/Public/Read-BakNRetLine.ps1 new file mode 100644 index 0000000..1e6f69a --- /dev/null +++ b/BakNRet/Public/Read-BakNRetLine.ps1 @@ -0,0 +1,38 @@ +function Read-BakNRetLine { + <# + .SYNOPSIS + 读一行文本:字符追加、Backspace 删一个、Enter 确认、Esc 取消。 + + .DESCRIPTION + 为什么需要它、而不用 `Read-Host`:TUI 里所有输入都走同一个 `-Driver`,门禁才能用 + `-InputScript` 把"输入一个值"这一步也驱动起来 —— `Read-Host` 无法脚本驱动,它会在门禁里 + **挂住**,而挂起比变红糟得多。 + + 为什么 Esc 返回 `$null` 而不是空串:空串是"把值改成空"这个**合法意图**,取消是另一个意思, + 两者必须能区分 —— 否则调用方会把"用户取消"当成"用户要清空这个值"。 + + 其它键(方向键、空格等)一律忽略:在输入行里按方向键不该有副作用。 + #> + param( + [Parameter(Mandatory = $true)]$Driver, + [AllowEmptyString()][string]$Initial = '' + ) + + $buffer = $Initial + + while ($true) { + $key = Read-BakNRetKey -Driver $Driver + + if ($key -eq 'Enter') { return $buffer } + if ($key -eq 'Esc') { return $null } + + if ($key -eq 'Backspace') { + if ($buffer.Length -gt 0) { $buffer = $buffer.Substring(0, $buffer.Length - 1) } + continue + } + + if ($key.StartsWith('Char:')) { + $buffer += $key.Substring(5) + } + } +} diff --git a/tests/Run-Tests.ps1 b/tests/Run-Tests.ps1 index 966cd36..0017dd8 100644 --- a/tests/Run-Tests.ps1 +++ b/tests/Run-Tests.ps1 @@ -1774,6 +1774,18 @@ Test-Case '配置标量:只认单行标量;改一个值只动那一行;设 Assert-True $threw2 '非标量(行内哈希)也必须抛错' } +Test-Case '输入行:字符追加、Backspace 删除、Esc 取消返回 $null(与空串区分)' { + # 全部用按键序列驱动 —— 这也是它不用 Read-Host 的原因:Read-Host 在门禁里会挂住。 + Assert-Equal 'ab' (Read-BakNRetLine -Driver (New-BakNRetInputDriver -Script @('Char:a', 'Char:b', 'Enter'))) '逐字符输入' + Assert-Equal 'a' (Read-BakNRetLine -Driver (New-BakNRetInputDriver -Script @('Char:a', 'Char:b', 'Backspace', 'Enter'))) 'Backspace 删一个' + Assert-Equal '' (Read-BakNRetLine -Driver (New-BakNRetInputDriver -Script @('Backspace', 'Enter'))) '空缓冲按 Backspace 不抛错' + Assert-True ($null -eq (Read-BakNRetLine -Driver (New-BakNRetInputDriver -Script @('Char:a', 'Esc')))) 'Esc 应当返回 $null 表示取消' + Assert-Equal '' (Read-BakNRetLine -Driver (New-BakNRetInputDriver -Script @('Enter'))) '直接回车给空串(空串是合法意图)' + Assert-Equal 'xy' (Read-BakNRetLine -Driver (New-BakNRetInputDriver -Script @('Char:y', 'Enter')) -Initial 'x') '初始值之后继续追加' + Assert-Equal 'ab' (Read-BakNRetLine -Driver (New-BakNRetInputDriver -Script @('Char:a', 'Down', 'Char:b', 'Enter'))) '方向键在输入行里被忽略(无副作用)' + Assert-Equal 'k' (Read-BakNRetLine -Driver (New-BakNRetInputDriver -Script @('Char:K', 'Enter'))) '字母按小写存(与键名归一化一致)' +} + # ============================================================================ Remove-Item -LiteralPath $sandbox -Recurse -Force -ErrorAction SilentlyContinue Remove-Item -LiteralPath $itemSandbox -Recurse -Force -ErrorAction SilentlyContinue