2008-11-25 17 views
20

Estoy tratando de asignar un código clave virtual a un char.C# ¿Cómo traducir el código clave virtual a char?

Mi código usa ProcessCmdKey para escuchar WM_KEYDOWN que me da acceso a la tecla presionada. Por ejemplo, cuando presiono una comilla simple obtengo una clave de 222 que quiero que se asigne a keychar 39, que representa ... lo adivinaste ... comilla simple.

Mi contexto dev es: - NET Framework 2.0 - control de usuario se coloca en un montón de lugares

¿Sabe usted la respuesta a la pregunta?

+1

[MapVirtualKey] (http://msdn.microsoft .com/en-us/library/ms646306 (VS.85) .aspx)()? – plinth

Respuesta

20

Sí, utilicé el método MapVirtualKey. Pero esperaba más detalles sobre cómo usarlo: qué directiva DllImport usar, qué enum es específico para mapear caracteres, etc.

No me gustan estas respuestas en las que hace google como 5 segundos y luego solo sugiera una solución: el verdadero desafío es juntar todas las piezas y no perder el tiempo con toneladas de páginas MSDN sin muestra u otros foros de codificación para obtener su respuesta. Sin fundamento ofensivo, pero tu respuesta (incluso buena) no tuvo problemas ya que tenía esta respuesta incluso antes de publicar mi pregunta en el foro.

Y esto es todo, voy a publicar lo que estaba buscando - una solución out-of-the-box C#:

1- Coloque esta directiva dentro de su clase:

[DllImport("user32.dll")] 
static extern int MapVirtualKey(uint uCode, uint uMapType); 

2- Recuperar a tu personaje como este:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)  
    { 
    const int WM_KEYDOWN = 0x100; 

    if (msg.Msg == WM_KEYDOWN) 
    {    
     // 2 is used to translate into an unshifted character value 
     int nonVirtualKey = MapVirtualKey((uint)keyData, 2); 

     char mappedChar = Convert.ToChar(nonVirtualKey); 
    } 

    return base.ProcessCmdKey(ref msg, keyData); 
    } 

Gracias por cuidar ... y disfrutar!

+0

Gracias por dar seguimiento. Si ya había examinado MapVirtualKey() quizás debería haber incluido eso en su pregunta (es decir, "He examinado MapVirtualKey() pero no sé cómo llamarlo desde C#). Para sus necesidades futuras, usted podría encontrar útil http://www.pinvoke.net – plinth

+1

Y en el caso de MapVirtualKey, aquí está la entrada de pinvoke.net:. http://www.pinvoke.net/default.aspx/user32/MapVirtualKey.html – plinth

+1

menor corrección: MapVirtualKey realidad devuelve un uint, no un int Pero gracias por ese trozo de código, que era exactamente lo que necesitaba para mi propio proyecto –

39

¿No es eso para lo que es la clase System.Windows.Form.KeysConverter?

KeysConverter kc = new KeysConverter(); 
string keyChar = kc.ConvertToString(keyData); 
+0

se olvidó de..... mencionar el contexto de mi pregunta: - .net Framework 2.0 - UserControl Así que la respuesta a su respuesta es no – Horas

+2

Me acabo de dar cuenta que nunca respondí t o que ... [KeysConverter existe en .NET 2.0] (http://msdn.microsoft.com/en-us/library/system.windows.forms.keysconverter%28v=vs.80%29.aspx). – Powerlord

+2

Hm, pero eso funciona solo parcialmente. Como un ejemplo donde no funcionará: '(new KeysConverter()). ConvertToString (Keys.OemQuestion)' * (** Spoiler: ** devolvería 'OemQuestion' en lugar de'? ') *. Además, no está claro cómo manejar la tecla * Shift *. ¿Hay una solución de trabajo? –

1

KeysConverter recibe el nombre de clave no las teclas de "texto" ex: "Num2" en lugar de "2" MapVirtualKey funcionarán para Inglés, pero para no ingleses estados de documentación caracteres utilizando MapVirtualKeyEx pero que requiere un local identificador ese identificador es cargado por LoadKeyboardLayout que requiere una identificación de la cultura constante pero luego después de encontrar los valores de id correctas no funcionó como lo intenté así que finalmente me deshice de todo el asunto

+0

MapVirtualKey funciona también para diseños no ingleses. usa el diseño del teclado real. – X181

7

después de leer y probar algunas de las respuestas proporcionadas, pensé que sugeriría una alternativa.

Como se menciona en MM, System.Windows.KeysConverter no proporciona una representación de caracteres de la clave sino el nombre de la enumeración, p. "Ingresar" en lugar de "\ n".

El método MapVirtualKey sugerido por Horas, en respuesta a su propia pregunta, es un buen punto de partida, pero aún no admite capslo o los caracteres ingresados ​​con la tecla Mayús, p. '!', '$' y '>'.

Una alternativa al método MapVirtualKey, que estoy usando, es un método de extensión para la clase Teclas:

public static char ToChar(this Keys key) 
{ 
    char c = '\0'; 
    if((key >= Keys.A) && (key <= Keys.Z)) 
    { 
     c = (char)((int)'a' + (int)(key - Keys.A)); 
    } 

    else if((key >= Keys.D0) && (key <= Keys.D9)) 
    { 
     c = (char)((int)'0' + (int)(key - Keys.D0)); 
    } 

    return c; 
} 

el método mostrado anteriormente proporcionará soporte para caracteres alfanuméricos. El soporte para caracteres adicionales podría implementarse con una instrucción switch o una tabla de búsqueda.

+0

¿Esto usa 'System.Windows.Forms' o' System.Windows.Input'? 'Key' es una enumeración en' System.Windows.Input', pero no se usa aquí, y no está claro de dónde viene 'Keys'. –

6

que estaba buscando algo similar pero que necesitaba el personaje asignado a la disposición del teclado actual. Como ninguna de las respuestas anteriores cumplió con mis requisitos, esto es lo que se me ocurrió.


     public string KeyCodeToUnicode(Keys key) 
     { 
      byte[] keyboardState = new byte[255]; 
      bool keyboardStateStatus = GetKeyboardState(keyboardState); 

      if (!keyboardStateStatus) 
      { 
       return ""; 
      } 

      uint virtualKeyCode = (uint)key; 
      uint scanCode = MapVirtualKey(virtualKeyCode, 0); 
      IntPtr inputLocaleIdentifier = GetKeyboardLayout(0); 

      StringBuilder result = new StringBuilder(); 
      ToUnicodeEx(virtualKeyCode, scanCode, keyboardState, result, (int)5, (uint)0, inputLocaleIdentifier); 

      return result.ToString(); 
     } 

     [DllImport("user32.dll")] 
     static extern bool GetKeyboardState(byte[] lpKeyState); 

     [DllImport("user32.dll")] 
     static extern uint MapVirtualKey(uint uCode, uint uMapType); 

     [DllImport("user32.dll")] 
     static extern IntPtr GetKeyboardLayout(uint idThread); 

     [DllImport("user32.dll")] 
     static extern int ToUnicodeEx(uint wVirtKey, uint wScanCode, byte[] lpKeyState, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszBuff, int cchBuff, uint wFlags, IntPtr dwhkl); 

+0

Excelente. Funciona perfectamente con caracteres no ingleses. Lo uso desde el evento KeyDown y lo llamo con e.Keycode o e.KeyData y ambos funcionan. Gracias –

+1

¡El héroe que necesitamos, pero no el héroe que merecemos! –

+0

Esto es genial. Funciona como se esperaba Por otro lado, una tarea tan obvia requiere mucho código. Bien hecho. –

1

acabo de escribir una mejora de Ivan Petrov answer para mostrar una representación de cadena de combinaciones de teclas pulsadas en WPF, vea mi código de abajo:

public static string GetKeyString(Key key, ModifierKeys modifiers) 
{ 
    string result = ""; 
    if (key != Key.None) 
    { 
     // Setup modifiers 
     if (modifiers.HasFlag(ModifierKeys.Control)) 
      result += "Ctrl + "; 
     if (modifiers.HasFlag(ModifierKeys.Alt)) 
      result += "Alt + "; 
     if (modifiers.HasFlag(ModifierKeys.Shift)) 
      result += "Shift + "; 
     // Get string representation 
     string keyStr = key.ToString(); 
     int keyInt = (int)key; 
     // Numeric keys are returned without the 'D' 
     if (key >= Key.D0 && key <= Key.D9) 
      keyStr = char.ToString((char)(key - Key.D0 + '0')); 
     // Char keys are returned directly 
     else if (key >= Key.A && key <= Key.Z) 
      keyStr = char.ToString((char)(key - Key.A + 'A')); 
     // If the key is a keypad operation (Add, Multiply, ...) or an 'Oem' key, P/Invoke 
     else if ((keyInt >= 84 && keyInt <= 89) || keyInt >= 140) 
      keyStr = KeyCodeToUnicode(key); 
     result += keyStr; 
    } 
    return result; 
} 

private static string KeyCodeToUnicode(Key key) 
{ 
    byte[] keyboardState = new byte[255]; 
    bool keyboardStateStatus = GetKeyboardState(keyboardState); 

    if (!keyboardStateStatus) 
    { 
     return ""; 
    } 

    uint virtualKeyCode = (uint)KeyInterop.VirtualKeyFromKey(key); 
    uint scanCode = MapVirtualKey(virtualKeyCode, 0); 
    IntPtr inputLocaleIdentifier = GetKeyboardLayout(0); 

    StringBuilder result = new StringBuilder(); 
    ToUnicodeEx(virtualKeyCode, scanCode, new byte[255], result, (int)5, (uint)0, inputLocaleIdentifier); 

    return result.ToString(); 
} 

[DllImport("user32.dll")] 
static extern bool GetKeyboardState(byte[] lpKeyState); 

[DllImport("user32.dll")] 
static extern uint MapVirtualKey(uint uCode, uint uMapType); 

[DllImport("user32.dll")] 
static extern IntPtr GetKeyboardLayout(uint idThread); 

[DllImport("user32.dll")] 
static extern int ToUnicodeEx(uint wVirtKey, uint wScanCode, byte[] lpKeyState, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszBuff, int cchBuff, uint wFlags, IntPtr dwhkl); 
Cuestiones relacionadas