我想在PowerShell会话中创建任何打开大括号的匹配右括号的ConsoleKeyInfo
实例(我正在使用PSReadline来执行密钥处理)。为方便起见,以下是所涉及的所有密钥的属性
PS> while($true){ [System.Console]::ReadKey($true) }
KeyChar Key Modifiers
------- --- ---------
[ Oem4 0
] Oem6 0
{ Oem4 Shift
} Oem6 Shift
在密钥处理程序中,我被赋予ConsoleKeyInfo
用于被按下的“和弦”(PSReadline会进行过滤,所以我已经知道我只收到Oem4
或{{1 }})。我想生成匹配的Shift+Oem4
,以便我可以将对打印发送到控制台。
ConsoleKeyInfo
char
System.ConsoleKey
,分别用于Shift,Alt和Control 我可以通过将其投放到bool
并向上移动两个来获得正确的ConsoleKey
...
int
我可以按下按键PS> [System.ConsoleKey]([int]$key.Key + 2)
Oem6
进行映射,然后按位测试......
Modifiers
但是,我不知道如何获得此控制台密钥的文字PS> ($key.Modifiers -band [System.ConsoleModifiers]::Shift) -ne 0
False
。控制台如何从键盘键获取字符?这只能通过现场控制台/键盘来完成吗?
我宁愿不维护密钥对的映射,也不拆分处理程序,每个“和弦”一个,并硬编码匹配的密钥char。 :(
答案 0 :(得分:5)
您可能不需要为PSReadline创建一个ConsoleKeyInfo。
有时您可能需要将ConsoleKeyInfo传递给PSConsoleReadLine中的方法,但PSConsoleReadLine中接受ConsoleKeyInfo的大多数方法甚至都不会查看该参数。这就是参数为Nullable的原因。
这实际上并没有回答你的问题。 JaredPar绝对正确,一般来说,无法将ConsoleKey / ConsoleModifiers对转换为char。如果我们不关心完全的通用性(当前PSReadline没有),您可以使用类似于PSReadline使用的代码:
internal static char GetCharFromConsoleKey(ConsoleKey key, ConsoleModifiers modifiers)
{
// default for unprintables and unhandled
char keyChar = '\u0000';
// emulate GetKeyboardState bitmap - set high order bit for relevant modifier virtual keys
var state = new byte[256];
state[NativeMethods.VK_SHIFT] = (byte)(((modifiers & ConsoleModifiers.Shift) != 0) ? 0x80 : 0);
state[NativeMethods.VK_CONTROL] = (byte)(((modifiers & ConsoleModifiers.Control) != 0) ? 0x80 : 0);
state[NativeMethods.VK_ALT] = (byte)(((modifiers & ConsoleModifiers.Alt) != 0) ? 0x80 : 0);
// a ConsoleKey enum's value is a virtual key code
uint virtualKey = (uint)key;
// get corresponding scan code
uint scanCode = NativeMethods.MapVirtualKey(virtualKey, NativeMethods.MAPVK_VK_TO_VSC);
// get corresponding character - maybe be 0, 1 or 2 in length (diacriticals)
var chars = new char[2];
int charCount = NativeMethods.ToUnicode(
virtualKey, scanCode, state, chars, chars.Length, NativeMethods.MENU_IS_INACTIVE);
// TODO: support diacriticals (charCount == 2)
if (charCount == 1)
{
keyChar = chars[0];
}
return keyChar;
}
答案 1 :(得分:3)
不幸的是你无法真正做到这一点。键盘输入不像键盘键+修饰符=字符那么简单。相反,它更多的是一系列键盘键+修饰符值=一个字符。在英语键盘中,这个序列的长度往往是1,但在其他语言中,序列可以长得多。这意味着一般来说这不是一个可解决的问题,因为一个键不能肯定产生给定的字符
Michael Kaplan有一个精彩的博客系列,详细介绍了这一点
答案 2 :(得分:3)
如果您只是尝试插入右括号,那么您应该能够执行此处理程序所做的事情 - 它对单引号和双引号也是如此:
Set-PSReadlineKeyHandler -Chord "Ctrl+'","Ctrl+Shift+'" `
-BriefDescription SmartInsertQuote `
-Description "Insert paired quotes if not already on a quote" `
-ScriptBlock {
param($key, $arg)
$line = $null
$cursor = $null
[PSConsoleUtilities.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)
$keyChar = $key.KeyChar
if ($key.Key -eq 'Oem7') {
if ($key.Modifiers -eq 'Control') {
$keyChar = "`'"
}
elseif ($key.Modifiers -eq 'Shift','Control') {
$keyChar = '"'
}
}
if ($line[$cursor] -eq $keyChar) {
# Just move the cursor
[PSConsoleUtilities.PSConsoleReadLine]::SetCursorPosition($cursor + 1)
}
else {
# Insert matching quotes, move cursor to be in between the quotes
[PSConsoleUtilities.PSConsoleReadLine]::Insert("$keyChar" * 2)
[PSConsoleUtilities.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)
[PSConsoleUtilities.PSConsoleReadLine]::SetCursorPosition($cursor - 1)
}
}
它可能不适用于所有键盘AFAIK,但我猜你只是想让它在你的键盘上工作。 : - )