visual textbox1 studio evento .net windows winforms input keyboard

.net - textbox1 - onkeypress c# textbox



convertir un código clave al personaje de visualización relevante (3)

Mire KeysConverter y su método ConvertToString. Recuerde que no todo el mapa KeyDown a KeyPress.

En un proyecto C # Windows.Forms tengo un control que no proporciona el evento KeyPressed (es un control COM - mapa ESRI).

Solo proporciona los eventos KeyUp y KeyDown, que contienen la estructura KeyEventArgs .

¿Cómo puedo convertir la información en KeyEventArgs a un carácter Unicode que se puede visualizar, teniendo en cuenta el diseño actual del teclado activo, etc.?


El truco consiste en utilizar un conjunto de funciones user32.dll: GetWindowThreadProcessId , GetKeyboardLayout , GetKeyboardState y ToUnicodeEx .

  1. Use la función GetWindowThreadProcessId con su controlador para lograr la id. De hebra nativa relevante.
  2. Pase esa identificación de hilo a GetKeyboardLayout para obtener la disposición actual del teclado.
  3. Llame a GetKeyboardState para obtener el estado del teclado actual. Esto ayuda al siguiente método a decidir qué carácter generar según el estado de los modificadores.
  4. Finalmente, llame a la función ToUnicodeEx con el código de clave virtual deseado y el código de exploración (esos dos pueden ser iguales), el estado del teclado actual, un generador de cadenas como titular de cadena (para mantener el resultado), sin indicadores (0) y el puntero de diseño de teclado actual.

Si el resultado no es cero, simplemente devuelve el primer carácter devuelto.

public class KeyboardHelper { [DllImport("user32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] private static extern int ToUnicodeEx( uint wVirtKey, uint wScanCode, Keys[] lpKeyState, StringBuilder pwszBuff, int cchBuff, uint wFlags, IntPtr dwhkl); [DllImport("user32.dll", ExactSpelling = true)] internal static extern IntPtr GetKeyboardLayout(uint threadId); [DllImport("user32.dll", ExactSpelling = true)] internal static extern bool GetKeyboardState(Keys[] keyStates); [DllImport("user32.dll", ExactSpelling = true)] internal static extern uint GetWindowThreadProcessId(IntPtr hwindow, out uint processId); public static string CodeToString(int scanCode) { uint procId; uint thread = GetWindowThreadProcessId(Process.GetCurrentProcess().MainWindowHandle, out procId); IntPtr hkl = GetKeyboardLayout(thread); if (hkl == IntPtr.Zero) { Console.WriteLine("Sorry, that keyboard does not seem to be valid."); return string.Empty; } Keys[] keyStates = new Keys[256]; if (!GetKeyboardState(keyStates)) return string.Empty; StringBuilder sb = new StringBuilder(10); int rc = ToUnicodeEx((uint)scanCode, (uint)scanCode, keyStates, sb, sb.Capacity, 0, hkl); return sb.ToString(); } }


La solución de Itai Bar-Haim es agradable, pero tiene un problema con las teclas muertas.

La primera vez que llama a CodeToString (int scanCode) con el código de exploración de una clave muerta, el código de retorno de ToUnicodeEx () es -1 y su método devuelve el valor correcto.

Pero en la próxima llamada, ToUnicodeEx () devolverá 2. La cadena de resultados contendrá la clave muerta antes del resultado esperado, seguido de los datos de la memoria basura.

Por ejemplo, llamo a su método con ^ (tecla muerta) y luego con $. La primera llamada devuelve ^ (agradable), pero la segunda llamada devuelve ^ $ azertyui.

Debes hacer dos cosas para arreglar eso:

1) Debe usar el valor absoluto del código de retorno ToUnicodeEx () para establecer la longitud de su StringBuilder. Así que evitas obtener datos basura después de los personajes.

2) Cuando el código de retorno ToUnicodeEx () es -1, debe tomar el primer carácter de su StringBuilder como resultado de su método. Y luego debe eliminar la clave muerta del estado del teclado: recuperar ToUnicodeEx () con el código de exploración de la tecla Espacio.

Otro problema que podría tener: si el estado del teclado ha sido modificado por un usuario que tocó una tecla muerta antes de llamar a ToUnicodeEx (), la cadena devuelta contendrá el carácter de clave muerta antes del valor esperado. Una solución alternativa que encontré es llamar a ToUnicodeEx () con el código de exploración de la tecla Espacio antes de la llamada real.

¡Espero que esto ayude!