Pregunta

Si necesito generar un diseño de teclado para la personalización al usuario que se parece a su teclado, ¿cómo puedo hacerlo?

Por ejemplo, algo como esto:

enter image description here

Francés, sueco, inglés, canadiense, etc. tendrá diferentes diseños, correcto. ¿Es esto mucho trabajo o simplemente una cuestión de usar algún tipo de clases regionales incorporadas en .NET?

¿Fue útil?

Solución

Una tecla Press genera un evento de hardware que informa un "código de escaneo" al sistema operativo Windows. Este código de escaneo se convierte en un "código de clave virtual" basado en el código de escaneo junto con otros factores de estado del teclado (Bloq Mayús estado, Cambio/Alternativo/Control Keystate, y también cualquier trazo de llave muerta pendiente). El valor de VK convertido es lo que informa el KeyDown evento, etc.

La conversión del código de escaneo al código VK depende de la configuración regional de entrada actual, simplistamente, la configuración regional de entrada define una asignación entre los códigos de escaneo y los códigos de clave virtuales. Ver la documentación MSDN Para una descripción completa de la entrada del teclado.

Al revertir este proceso de búsqueda, es posible determinar el código de escaneo que corresponde a cada código de clave virtual (por supuesto, el mismo código de escaneo se asignará a múltiples códigos VK debido a Shift/Ctrl/Alt State, etc.). La API Win32 proporciona la MapVirtualKeyEx función para realizar esta asignación, utilizando el MAPVK_VK_TO_VSC_EX opción. Puede usar esto para determinar qué código de escaneo genera el código VK particular.

Desafortunadamente, esto es lo más lejos que puede llegar mediante programación: no hay forma de determinar el diseño físico del teclado o la ubicación de la tecla para cada código de escaneo. Sin embargo, la mayoría de los teclados físicos están conectados de la misma manera, por lo que (por ejemplo) la tecla superior izquierda tendrá el mismo código de escaneo en la mayoría de los diseños de teclado físico. Puede usar esta convención supuesta para inferir la ubicación física correspondiente a un código de escaneo, dependiendo del diseño básico de teclado físico (101 teclas, 102 teclas, etc.). No está garantizado, pero es una suposición bastante segura.

El siguiente código es un extracto de una biblioteca de manejo de teclado más grande que escribí (he tenido la intención de obtenerlo abierto pero no he tenido tiempo). El método inicializa una matriz (this._virtualKeyScanCodes) que está indexado por el código VK para un local de entrada determinado (almacenado en this._inputLanguage que se declara como un System.Windows.Forms.InputLanguage. Puede usar la matriz para determinar el código de escaneo que corresponde al código VK examinando EG this._virtualKeyScanCodes[VK_NUMPAD0] - Si el código de escaneo es cero, entonces que VK no está disponible en el teclado en la configuración regional de entrada actual; Si no es cero, es el código de escaneo del que puede inferir la clave física.

Desafortunadamente, los asuntos son un poco más complicados que esto cuando entras en los reinos de las claves muertas (múltiples combinaciones de claves que producen caracteres acentuados, por ejemplo). Eso es demasiado complicado para entrar en este momento, pero Michael S. Kaplan escribió una serie detallada de publicaciones de blog Si quieres explorar esto más a fondo. ¡Buena suerte!

private void Initialize()
{
    this._virtualKeyScanCodes = new uint[MaxVirtualKeys];

    // Scroll through the Scan Code (SC) values and get the Virtual Key (VK)
    // values in it. Then, store the SC in each valid VK so it can act as both a 
    // flag that the VK is valid, and it can store the SC value.
    for (uint scanCode = 0x01; scanCode <= 0xff; scanCode++)
    {
        uint virtualKeyCode = NativeMethods.MapVirtualKeyEx(
            scanCode, 
            NativeMethods.MAPVK_VSC_TO_VK, 
            this._inputLanguage.Handle);
        if (virtualKeyCode != 0)
        {
            this._virtualKeyScanCodes[virtualKeyCode] = scanCode;
        }
    }

    // Add the special keys that do not get added from the code above
    for (KeysEx ke = KeysEx.VK_NUMPAD0; ke <= KeysEx.VK_NUMPAD9; ke++)
    {
        this._virtualKeyScanCodes[(uint)ke] = NativeMethods.MapVirtualKeyEx(
            (uint)ke, 
            NativeMethods.MAPVK_VK_TO_VSC, 
            this._inputLanguage.Handle);
    }

    this._virtualKeyScanCodes[(uint)KeysEx.VK_DECIMAL] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_DECIMAL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_DIVIDE] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_DIVIDE, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_CANCEL] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_CANCEL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);

    this._virtualKeyScanCodes[(uint)KeysEx.VK_LSHIFT] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_LSHIFT, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_RSHIFT] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_RSHIFT, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_LCONTROL] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_LCONTROL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_RCONTROL] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_RCONTROL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_LMENU] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_LMENU, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_RMENU] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_RMENU, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_LWIN] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_LWIN, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_RWIN] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_RWIN, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_PAUSE] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_PAUSE, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_VOLUME_UP] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_VOLUME_UP, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_VOLUME_DOWN] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_VOLUME_DOWN, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_VOLUME_MUTE] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_VOLUME_MUTE, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);

    this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_NEXT_TRACK] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_MEDIA_NEXT_TRACK, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_PREV_TRACK] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_MEDIA_PREV_TRACK, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_PLAY_PAUSE] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_MEDIA_PLAY_PAUSE, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_STOP] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_MEDIA_STOP, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);

    this._stateController = new KeyboardStateController();
    this._baseVirtualKeyTable = new VirtualKeyTable(this);
}

Editar: ver también esta pregunta que es similar al tuyo.

Otros consejos

No hay una clase .NET incorporada que contenga los diseños de teclado. Los diseños de teclado son una función del sistema operativo, generalmente Windows. Para cuando .NET se involucra, la tecla presionada se ha convertido de un evento de hardware a uno de software. Si desea ver esto en acción, busque 2 diseños de teclado donde una tecla se haya movido entre ellos. Configurar una aplicación ficticia con un controlador de eventos en el Key_Down evento, y luego tenga en cuenta que el evento Args es idéntico; Si presionó el - clave presionó el - clave independientemente de dónde - Se encuentra la clave.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top