1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-04 15:39:42 +00:00

fix(windows): support arrow key escape sequences in interactive menus

Some terminals send escape sequences (ESC [ A/B) instead of VirtualKeyCode
for arrow keys. Now handles both methods for better terminal compatibility.
This commit is contained in:
Bhadra
2026-01-08 22:49:43 +05:30
parent 800db2429d
commit 9b40c5acf4

View File

@@ -180,32 +180,59 @@ function Show-Menu {
Write-Host "" Write-Host ""
Write-Host " ${gray}Use arrows or j/k to navigate, Enter to select, q to quit${nc}" Write-Host " ${gray}Use arrows or j/k to navigate, Enter to select, q to quit${nc}"
# Read key # Read key - handle both VirtualKeyCode and escape sequences
$key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") $key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
switch ($key.VirtualKeyCode) { # Debug: uncomment to see key codes
38 { # Up arrow # Write-Host "VKey: $($key.VirtualKeyCode), Char: $([int]$key.Character)"
$selected = if ($selected -gt 0) { $selected - 1 } else { $maxIndex }
} # Handle escape sequences for arrow keys (some terminals send these)
40 { # Down arrow $moved = $false
$selected = if ($selected -lt $maxIndex) { $selected + 1 } else { 0 } if ($key.VirtualKeyCode -eq 0 -or $key.Character -eq [char]27) {
} # Escape sequence - read the next characters
13 { # Enter if ($Host.UI.RawUI.KeyAvailable) {
# Show cursor $key2 = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Write-Host -NoNewline "$([char]27)[?25h" if ($key2.Character -eq '[' -and $Host.UI.RawUI.KeyAvailable) {
$key3 = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
if ($AllowBack -and $selected -eq $maxIndex) { switch ($key3.Character) {
return $null # Back selected 'A' { # Up arrow escape sequence
$selected = if ($selected -gt 0) { $selected - 1 } else { $maxIndex }
$moved = $true
}
'B' { # Down arrow escape sequence
$selected = if ($selected -lt $maxIndex) { $selected + 1 } else { 0 }
$moved = $true
}
}
} }
return $Options[$selected]
} }
default { }
switch ($key.Character) {
'k' { $selected = if ($selected -gt 0) { $selected - 1 } else { $maxIndex } } if (-not $moved) {
'j' { $selected = if ($selected -lt $maxIndex) { $selected + 1 } else { 0 } } switch ($key.VirtualKeyCode) {
'q' { 38 { # Up arrow
Write-Host -NoNewline "$([char]27)[?25h" $selected = if ($selected -gt 0) { $selected - 1 } else { $maxIndex }
return $null }
40 { # Down arrow
$selected = if ($selected -lt $maxIndex) { $selected + 1 } else { 0 }
}
13 { # Enter
# Show cursor
Write-Host -NoNewline "$([char]27)[?25h"
if ($AllowBack -and $selected -eq $maxIndex) {
return $null # Back selected
}
return $Options[$selected]
}
default {
switch ($key.Character) {
'k' { $selected = if ($selected -gt 0) { $selected - 1 } else { $maxIndex } }
'j' { $selected = if ($selected -lt $maxIndex) { $selected + 1 } else { 0 } }
'q' {
Write-Host -NoNewline "$([char]27)[?25h"
return $null
}
} }
} }
} }
@@ -274,42 +301,66 @@ function Show-SelectionList {
$key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") $key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
switch ($key.VirtualKeyCode) { # Handle escape sequences for arrow keys (some terminals send these)
38 { $cursor = if ($cursor -gt 0) { $cursor - 1 } else { $maxIndex } } $moved = $false
40 { $cursor = if ($cursor -lt $maxIndex) { $cursor + 1 } else { 0 } } if ($key.VirtualKeyCode -eq 0 -or $key.Character -eq [char]27) {
32 { # Space # Escape sequence - read the next characters
if ($MultiSelect) { if ($Host.UI.RawUI.KeyAvailable) {
$selected[$cursor] = -not $selected[$cursor] $key2 = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
} if ($key2.Character -eq '[' -and $Host.UI.RawUI.KeyAvailable) {
else { $key3 = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
$selected = @{ $cursor = $true } switch ($key3.Character) {
} 'A' { # Up arrow escape sequence
} $cursor = if ($cursor -gt 0) { $cursor - 1 } else { $maxIndex }
13 { # Enter $moved = $true
Write-Host -NoNewline "$([char]27)[?25h"
$result = @()
foreach ($key in $selected.Keys) {
if ($selected[$key]) {
$result += $Items[$key]
}
}
return $result
}
default {
switch ($key.Character) {
'k' { $cursor = if ($cursor -gt 0) { $cursor - 1 } else { $maxIndex } }
'j' { $cursor = if ($cursor -lt $maxIndex) { $cursor + 1 } else { 0 } }
' ' {
if ($MultiSelect) {
$selected[$cursor] = -not $selected[$cursor]
} }
else { 'B' { # Down arrow escape sequence
$selected = @{ $cursor = $true } $cursor = if ($cursor -lt $maxIndex) { $cursor + 1 } else { 0 }
$moved = $true
} }
} }
'q' { }
Write-Host -NoNewline "$([char]27)[?25h" }
return @() }
if (-not $moved) {
switch ($key.VirtualKeyCode) {
38 { $cursor = if ($cursor -gt 0) { $cursor - 1 } else { $maxIndex } }
40 { $cursor = if ($cursor -lt $maxIndex) { $cursor + 1 } else { 0 } }
32 { # Space
if ($MultiSelect) {
$selected[$cursor] = -not $selected[$cursor]
}
else {
$selected = @{ $cursor = $true }
}
}
13 { # Enter
Write-Host -NoNewline "$([char]27)[?25h"
$result = @()
foreach ($selKey in $selected.Keys) {
if ($selected[$selKey]) {
$result += $Items[$selKey]
}
}
return $result
}
default {
switch ($key.Character) {
'k' { $cursor = if ($cursor -gt 0) { $cursor - 1 } else { $maxIndex } }
'j' { $cursor = if ($cursor -lt $maxIndex) { $cursor + 1 } else { 0 } }
' ' {
if ($MultiSelect) {
$selected[$cursor] = -not $selected[$cursor]
}
else {
$selected = @{ $cursor = $true }
}
}
'q' {
Write-Host -NoNewline "$([char]27)[?25h"
return @()
}
} }
} }
} }