我很惊讶这个问题没有更受欢迎。Corben 的答案的问题是,在按下“j”之后,如果按下的下一个键是 return 或 ctrl 之类的修饰符,则会插入文字而不是您期望使用的键。
我已经重写了解决这两个问题的答案,并且还把它变成了一个函数,使它更容易重复使用(例如在绑定两个不同的字母时,比如 jk)。
Set-PSReadLineKeyHandler -vimode insert -Chord "k" -ScriptBlock { mapTwoLetterNormal 'k' 'j' }
Set-PSReadLineKeyHandler -vimode insert -Chord "j" -ScriptBlock { mapTwoLetterNormal 'j' 'k' }
function mapTwoLetterNormal($a, $b){
mapTwoLetterFunc $a $b -func $function:setViCommandMode
}
function setViCommandMode{
[Microsoft.PowerShell.PSConsoleReadLine]::ViCommandMode()
}
function mapTwoLetterFunc($a,$b,$func) {
if ([Microsoft.PowerShell.PSConsoleReadLine]::InViInsertMode()) {
$key = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
if ($key.Character -eq $b) {
&$func
} else {
[Microsoft.Powershell.PSConsoleReadLine]::Insert("$a")
# Representation of modifiers (like shift) when ReadKey uses IncludeKeyDown
if ($key.Character -eq 0x00) {
return
} else {
# Insert func above converts escape characters to their literals, e.g.
# converts return to ^M. This doesn't.
$wshell = New-Object -ComObject wscript.shell
$wshell.SendKeys("{$($key.Character)}")
}
}
}
}
# Bonus example
function replaceWithExit {
[Microsoft.PowerShell.PSConsoleReadLine]::BackwardKillLine()
[Microsoft.PowerShell.PSConsoleReadLine]::KillLine()
[Microsoft.PowerShell.PSConsoleReadLine]::Insert('exit')
}
Set-PSReadLineKeyHandler -Chord ";" -ScriptBlock { mapTwoLetterFunc ';' 'q' -func $function:replaceWithExit }