【问题标题】:How do I get the char for a keypress knowing only the ConsoleKey enum and Modifiers?如何仅知道 ConsoleKey 枚举和修饰符来获取按键的字符?
【发布时间】:2014-02-26 17:19:03
【问题描述】:

我想创建一个 ConsoleKeyInfo 实例,该实例与在 PowerShell 会话中键入的任何左大括号匹配(我正在使用 PSReadline 进行密钥处理)。为方便起见,这里是所有涉及的键的属性

PS> while($true){ [System.Console]::ReadKey($true) }

    KeyChar     Key    Modifiers
    -------     ---    ---------
          [    Oem4            0
          ]    Oem6            0  
          {    Oem4        Shift
          }    Oem6        Shift

在键处理程序中,我得到了被按下的“和弦”的ConsoleKeyInfo(PSReadline 会进行过滤,所以我已经知道我只收到了Oem4Shift+Oem4)。我想生成匹配的ConsoleKeyInfo,以便将打印对发送到控制台。

ConsoleKeyInfo constructor 带走

  • char
  • System.ConsoleKey
  • bool 分别用于 Shift、Alt 和 Control

我可以通过将 ConsoleKey 转换为 int 并向上移动两个来获得正确的 ConsoleKey...

PS> [System.ConsoleKey]([int]$key.Key + 2)
Oem6

我可以通过按位测试从按下的键的Modifiers 映射...

PS> ($key.Modifiers -band [System.ConsoleModifiers]::Shift) -ne 0
False

但是,我不知道如何获取此控制台键的文字 char。控制台如何从键盘键中获取字符?这只能通过现场控制台/键盘来完成吗?

我宁愿不维护密钥对的映射,也不拆分处理程序,每个“和弦”一个,并对匹配的密钥字符进行硬编码。 :(

【问题讨论】:

标签: c# powershell console keypress


【解决方案1】:

您可能不需要仅为 PSReadline 创建 ConsoleKeyInfo。

有时您可能需要将 ConsoleKeyInfo 传递给 PSConsoleReadLine 中的方法,但 PSConsoleReadLine 中接受 ConsoleKeyInfo 的大多数方法甚至都不查看参数。这就是参数为 Nullable 的原因。

不过,这实际上并不能回答您的问题。 JaredPar 是绝对正确的,一般来说,不可能将 ConsoleKey/ConsoleModifiers 对转换为字符。如果我们不关心完整的通用性(目前 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;
}

【讨论】:

    【解决方案2】:

    如果您只是尝试插入右大括号,那么您应该能够执行此处理程序所做的事情 - 它对单引号和双引号执行相同的操作:

    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,但我猜你只对让它在你的键盘上工作感兴趣。 :-)

    【讨论】:

      【解决方案3】:

      很遗憾,您不能真正做到这一点。键盘输入并不像键盘键+修饰符=字符那么简单。相反,它更像是一系列键盘键 + 修饰符值 = 一个字符。在英语键盘中,这个序列的长度往往为 1,但在其他语言中,这个序列可能更长。这意味着一般来说这不是一个可解决的问题,因为一个键不能绝对产生一个给定的字符

      Michael Kaplan 有一个精彩的博客系列,详细介绍了这一点

      http://www.siao2.com/2006/04/13/575500.aspx

      【讨论】:

      • PSReadline 忽略了这个问题,到目前为止没有任何投诉 - 无法为无法由 ConsoleKeyInfo 表示的键提供自定义绑定。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-10
      • 2012-03-03
      相关资源
      最近更新 更多