Mensajes de carácter

Si usamos la función TranslateMessage, cada mensaje WM_KEYDOWN se traduce en un mensaje WM_CHAR o WM_DEADCHAR; y cada mensaje WM_SYSKEYDOWN a un mensaje WM_SYSCHAR o WM_SYSDEADCHAR.

Generalmente ignoraremos todos estos mensajes, salvo WM_CHAR. Los mensajes WM_SYSCHAR y WM_SYSDEADCHAR se usan por Windows para acceder de forma rápida a menús, y no necesitamos procesarlos. En cuanto al mensaje WM_DEADCHAR, notifica sobre caracteres de teclas muertas, y generalmente, tampoco resultará interesante procesarlos.

Teclas muertas

Veamos qué es este curioso concepto de tecla muerta. Las teclas muertas son aquellas que no generan un carácter por sí mismas, y necesitan combinarse con otras para formarlos. Por ejemplo, la tecla del acento (´), cuando se pulsa, no crea un carácter, es necesario pulsar otra tecla después para que eso ocurra. Si la tecla que se pulsa en segundo lugar genera un carácter que se puede combinar con la tecla muerta, se generará un único carácter, por ejemplo 'á'. Si no es así, se generan dos caracteres, el primero combinando la tecla muerta con un espacio, y el segundo con el carácter, por ejemplo "´b".

Cuando se pulse una tecla muerta, el mensaje que se genera por TanslateMessage puede ser WM_DEADCHAR o WM_SYSDEADCHAR, pero en cualquier caso, estos mensajes se puede ignorar, ya que el sistema los almacena internamente para generar los caracteres imprimibles.

        case WM_CHAR:
           switch((TCHAR) wParam) {
              case 13:
                 // Procesar retorno de línea
                 break;
              case 0x08:
                 // Procesar carácter de retroceso (borrar)
                 break;
              default:
                 // Cualquier otro carácter
                 break;
           }
           InvalidateRect(hwnd, NULL, TRUE);
           break;

Estado de teclas

A veces nos interesa conocer el estado de alguna tecla concreto en el momento en que estamos procesando un mensaje procedente de otra pulsación de tecla. Por ejemplo, para tratar combinaciones de teclas como ALT+Fin o ALT+Inicio. Tenemos dos funciones para hacer esto.

Por una parte, la función GetAsyncKeyState nos dice el estado de una tecla virtual en el mismo momento en que la llamamos. Y la función GetKeyState nos da la misma información, pero en el momento en que se generó el mensaje que estamos tratando.

        case WM_KEYDOWN: // CONTROL+Inicio = Borra todo
           if(VK_HOME == (int)wParam) { // Tecla de inicio
              if(GetKeyState(VK_CONTROL) && 0x1000) {
                 nLinea=0;
                 nColumna=0;
                 lista[0][0] = 0;
                 InvalidateRect(hwnd, NULL, TRUE);
              }
           }
           break;

En este ejemplo, usamos la combinación CTRL+Inicio para borrar el texto que estamos escribiendo. Procesamos el mensaje WM_KEYDOWN, para detectar la tecla de [Inicio], y si cuando eso sucede, verificamos si también está pulsada la tecla de [CTRL], para ello usamos la función GetKeyState y comprobamos si el valor de retorno tiene el bit de mayor peso activo, comparando con 0x1000.

Ejemplo 38


  Nombre Fichero Fecha Tamaño Contador Descarga
D Ejemplo 38 win038.zip 2004-07-11 2952 bytes 235

Hot keys

He preferido no traducir el término "hot key", ya que me parece que es mucho más familiar que la traducción literal "tecla caliente". Una hot key es una tecla, o combinación de teclas, que tiene asignada una función especial y directa.

En Windows hay muchas hot keys predefinidas, por ejemplo, Ctrl+Alt+Supr sirve para activar el administrador de tareas, o la tecla de Windows izquierda en combinación con la tecla 'E', para abrir el explorador de archivos. Dentro de cada ventana o aplicación exiten más, por ejemplo, Alt+F4 cierra la ventana, etc.

Hay dos tipos de hot keys, uno es el de las asociadas a ventanas. Es posible asociar una tecla o combinación de teclas a una ventana, de modo que al pulsarla se activa esa ventana, estemos donde estemos, estas son las hot keys globales.

El otro tipo, que es el que vamos a ver ahora, son las hot keys de proceso, lo locales. Nuestra aplicación puede crear tantas de ellas como creamos necesario, procesarlas y, si es necesario, destruirlas.

Crear, o mejor dicho, registrar una hot key es sencillo, basta con usar la función RegisterHotKey. Esta función necesita cuatro parámetros. El primero es la ventana a la que estárá asociada la hot key. El segundo parámetro es el identificador. El tercero son los modificadores de tecla, indica si deben estar presionadas las teclas de Control, Alt, Mayúsculas o Windows. Y el cuarto es el código de tecla virtual asociado a la hot key. Recordemos que los códigos de teclas virtuales de teclas correspondientes a caracteres son los propios caracteres, en el caso de letras, las mayúsculas.

        case WM_CREATE:
           hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
           color = GetSysColor(COLOR_BACKGROUND);
           RegisterHotKey(hwnd, ID_VERDE, 0, 'V');
           RegisterHotKey(hwnd, ID_ROJO, MOD_ALT, 'R');
           RegisterHotKey(hwnd, ID_AZUL, MOD_CONTROL, 'A');
           break;

Cada vez que se pulse la tecla o combinación de teclas correspondiente a una hot key, el sistema la busca entre las registradas, y envía un mensaje WM_HOTKEY a la ventana que la registró. Aunque esa ventana no esté activa, el mensaje será enviado, siempre que sea la única ventana que ha registrar esa combinación de teclas. En el parámetro wParam se recibe el identificador de la hot key.

        case WM_HOTKEY:
           switch((int)wParam) {
              case ID_VERDE:
                 color = RGB(0,255,0);
                 break;
              case ID_ROJO:
                 color = RGB(255,0,0);
                 break;
              case ID_AZUL:
                 color = RGB(0,0,255);
                 break;
           }
           InvalidateRect(hwnd, NULL, FALSE);
           break;

Finalmente, se puede desregistrar una hot key usando la función UnregisterHotKey, indicando la ventana para la que se registró, y el identificador.

        case WM_DESTROY:
           UnregisterHotKey(hwnd, ID_VERDE);
           UnregisterHotKey(hwnd, ID_ROJO);
           UnregisterHotKey(hwnd, ID_AZUL);
           PostQuitMessage(0);    /* envía un mensaje WM_QUIT a la cola de mensajes */
           break;

Ejemplo 39


  Nombre Fichero Fecha Tamaño Contador Descarga
D Ejemplo 39 win039.zip 2004-07-11 2959 bytes 232

Códigos de teclas virtuales

Los códigos virtuales de las teclas que generan caracteres son los códigos ASCII de esos caracteres, por ejemplo, el código virtual de la tecla [A] es el 'A', o en número, el 65. Para el resto de las teclas existen constantes definidas en el fichero "winuser.h". Las constantes definidas son:

Constante Tecla Constante Tecla
VK_LBUTTON Botón izquierdo de ratón VK_RBUTTON Botón derecho de ratón
VK_CANCEL   VK_MBUTTON Botón central de ratón
VK_BACK   VK_TAB Tabulador
VK_CLEAR   VK_RETURN Retorno
VK_KANA   VK_SHIFT Mayúsculas
VK_CONTROL Control VK_MENU  
VK_PAUSE Pausa VK_CAPITAL Bloqueo mayúsculas
VK_ESCAPE Escape VK_SPACE Espacio
VK_PRIOR Página anterior VK_NEXT Página siguiente
VK_END Fin VK_HOME Inicio
VK_LEFT Flecha izquierda VK_UP Flecha arriba
VK_RIGHT Flecha derecha VK_DOWN Flecha abajo
VK_SELECT   VK_PRINT Imprimir pantalla
VK_EXECUTE   VK_SNAPSHOT  
VK_INSERT Insertar VK_DELETE Suprimir
VK_HELP Ayuda VK_LWIN Windows izquierda
VK_RWIN Windows derecha VK_APPS Menú de aplicación
VK_NUMPAD0 '0' numérico VK_NUMPAD1 '1' numérico
VK_NUMPAD2 '2' numérico VK_NUMPAD3 '3' numérico
VK_NUMPAD4 '4' numérico VK_NUMPAD5 '5' numérico
VK_NUMPAD6 '6' numérico VK_NUMPAD7 '7' numérico
VK_NUMPAD8 '8' numérico VK_NUMPAD9 '9' numérico
VK_MULTIPLY Multiplicar VK_ADD Sumar
VK_SEPARATOR   VK_SUBTRACT Restar
VK_DECIMAL Punto decimal VK_DIVIDE Dividir
VK_F1 F1 VK_F2 F2
VK_F3 F3 VK_F4 F4
VK_F5 F5 VK_F6 F6
VK_F7 F7 VK_F8 F8
VK_F9 F9 VK_F10 F10
VK_F11 F11 VK_F12 F12
VK_F13 F13 VK_F14 F14
VK_F15 F15 VK_F16 F16
VK_F17 F17 VK_F18 F18
VK_F19 F19 VK_F20 F20
VK_F21 F21 VK_F22 F22
VK_F23 F23 VK_F24 F24
VK_NUMLOCK Bloqueo numérico VK_SCROLL Bloqueo desplazamiento
VK_LSHIFT Mayúsculas izquierdo VK_RSHIFT Mayúsculas derecho
VK_LCONTROL Control izquierdo VK_RCONTROL Control derecho
VK_LMENU   VK_RMENU  
VK_PROCESSKEY   VK_ATTN  
VK_CRSEL   VK_EXSEL  
VK_EREOF   VK_PLAY  
VK_ZOOM   VK_NONAME  
VK_PA1   VK_OEM_CLEAR  

Las teclas sin descripción no están en mi teclado, de modo que no he podido averiguar a qué corresponden.

Comentarios de los usuarios (5)

Neil Adams
2011-10-23 22:17:13

El tutorial es genial, pero ¿y la tecla Alt Gr?

Steven R. Davidson
2011-10-23 23:54:19

Hola Neil,

La tecla "Alt Gr" realmente genera una combinación de dos teclas: CTRL+ALT y así es como recibe esta tecla MS-Windows. Así que si quieres enviar la tecla AltGr+6, para el carácter '¬', puedes usar tanto esta combinación, si tu teclado la tiene, como usar CTRL+ALT+6.

Espero haber aclarado la duda.

Steven

Neil Adams
2011-10-24 18:25:35

Buenas Steve,

Primero, muchas gracias por molestarte en responder esto.

Estoy diseñando un programa en FreeConsole;. En este hay una declaración de una función que debe devolver 1 si AltGr está pulsada, en caso contrario debe devolver 0. He aquí el código:

bool IfAltGr () {
if (GetAsyncKeyState(/*Aquí es donde dudo que poner*/) {  
return 1;
} else {
return 0;
}
}

¿Podrías ayudarme? Muchísimas gracias por adelantado.

Steven R. Davidson
2011-10-24 19:27:21

Hola Neil,

Las constantes de los códigos de las teclas virtuales que requieres son 'VK_CONTROL' (tecla CTRL) y 'VK_MENU' (tecla ALT). Ahora bien, al usar la función 'GetAsyncKeyState()', sólo recibirás el estado de una sola tecla virtual. Por lo tanto, deberías consultar ambas teclas para ver si están siendo presionadas a la vez. Por ejemplo,

BOOL bCTRL_Pulsado = 0x8000 & GetAsyncKeyState( VK_CONTROL );
BOOL bALT_Pulsado  = 0x8000 & GetAsyncKeyState( VK_MENU );

if( bCTRL_Pulsado && bALT_Pulsado )
{
  // Combinación: CTRL+ALT
  ...
}

(Nota: No lo he probado, pero creo que debería funcionar bien).

También podrías usar 'GetKeyboardState()' para obtener el estado de las 256 teclas, ya que 'GetAsyncKeyState()' es asíncrona así que dos invocaciones puede implicar un cambio de estado entre una invocación y la otra. Para más información consulta el siguiente enlace: http://winapi.conclase.net/curso/?winfun=GetKeyboardState#inicio

Espero que esto te ayude.

Steven

Arturo Olmedo
2019-07-01 03:18:02

Que tal.

Tengo una pregunta.

Como puedo hacer que en el título de la ventana me acepten acentos?

Si pongo una vocal acentuada, se observan otros caracteres.

No he encontrado como hacerlo.

Gracias de antemano !

Saludos