2014-02-26 58 views
4

我想創建一個PowerShell會話中輸入的任何開括號的匹配的結束括號的ConsoleKeyInfo實例(我使用PSReadline做重點處理)。爲了您的方便,這裏有所有鍵的屬性涉及如何知道只有ConsoleKey枚舉和修飾符的按鍵字符?

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和控制

我可以通過它轉換成一得到正確的ConsoleKeyint並向上移動兩個...

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

我可以從被按下的按鍵的Modifiers通過測試它按位地圖...

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

但是,我不知道如何得到這個控制檯鍵值的文本char。控制檯如何從鍵盤鍵獲取字符?這隻能用現場控制檯/鍵盤完成嗎?

我寧願不保持地圖的密鑰對,也不拆分處理,每一個「和絃」,並進行硬編碼匹配的關鍵字符。 :(

+2

看我的例子爲「InsertPairedBraces」這裏https://github.com /lzybkr/PSReadLine/blob/master/PSReadLine/SamplePSReadlineProfile.ps1 –

回答

3

不幸的是,你不能真正做到這一點。鍵盤輸入是不是鍵盤鍵+改性劑=字符一樣簡單。相反,它更是鍵盤的鍵+修正值=字符的序列。在英文鍵盤這個序列的長度往往是1,但在其他語言中,序列可能更長,這意味着一般來說這不是一個可解決的問題,因爲一個鍵不能確定產生給定的字符

Michael Kaplan有一個神話般的博客系列,詳細探討了這一點

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

+1

PSReadline在沒有任何抱怨的情況下忽略此問題 - 無法爲無法由ConsoleKeyInfo表示的密鑰提供自定義綁定。 –

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,但我猜你只是有興趣讓你的鍵盤上工作。 :-)

5

你也許並不需要創建一個ConsoleKeyInfo只是PSReadline。

偶爾,您可能需要將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; 
} 
+0

嘿,我承認代碼:) – x0n

相關問題