Deshabilitar Alt+Tab en Windows XP
|
Como sabrás, sobre todo si lo has intentado, en Windows NT/2000/XP no se puede deshabilitar la combinación de teclas Ctrl+Alt+Supr, esto es por razones de seguridad, ya que es el propio sistema operativo el que se encarga de que esa combinación de teclas no sea interceptable. La razón principal es que esa es la combinación de teclas que se utiliza antes de iniciar una sesión, al menos en los servidores Windows siempre es así, ya que tanto en Windows XP como en Windows 2000 Pro, podemos indicar que no nos pregunte por el usuario que inicia el equipo y por tanto no se mostraría la pantalla que nos indica que pulsemos esa combinación antes de indicar nuestro nombre y contraseña.
Por eso, salvo que alguien encuentre un código de cómo hacerlo, y si lo encuentra es posible que no lo difunda... no es ese mi caso, pero... para que no salte el listillo de siempre y diga: "yo se cómo evitar que se pulsen esas teclas".
Antes de que alguien lo diga, voy a decirlo... en Windows 9x sí es posible deshabilitar esa combinación de teclas, la forma de hacerlo la tienes en este link: ¿Cómo evitar el uso de CTRL+ALT+SUPR y ALT+TAB?
Un poco de historia para alargar el artículo:
Ayer estaba revisando las consultas de los grupos de noticias, como suelo hacer casi todos los días, y me encontré con un mensaje que preguntaba precisamente cómo evitar esa triple combinación de teclas en los Windows tipo NT, la respuesta que le dieron fue de que buscara en Google (indicando el grupo de noticias microsoft.public.vb.es) ya que en muchas ocasiones se había dado respuesta a esa pregunta. Como un servidor no se las sabe todas, pues seguí el susodicho link y busqué en Google y uno de los mensajes que encontré fue precisamente mío, con fecha de Enero del 2000, (del que yo, ni me acordaba), el link a ese "hilo" es este: Re- aclaración sobre inhabilitar CTRL+ALT+SUPR y ALT+TAB. Aunque no daba la solución, pero si mostraba un código creado en C++ que "casi" hacía eso... realmente sólo evitaba las tres combinaciones que indico en el título de este artículo. Así que, me puse a convertirlo a Visual Basic (clásico, para que el personal no se me queje de que ahora sólo publico cosas sobre punto NET) y el resultado es el que te presento aquí.Espero que te sea de utilidad, que de eso es de lo que al fin y al cabo se trata y también te invito a que hagas pruebas con otras combinaciones de teclas, para que practiques.
Una cosa muy importante es que en el código que te muestro se hace un "gancho" (hook) al teclado, por tanto no te recomiendo que hagas las pruebas en el IDE de Visual Basic, ya que si por casualidad se produjera un error mientras el gancho está activo, es posible que se te quede colgado el sistema... o al menos el IDE y pierdas lo que no hayas guardado. Avisado estás.
Funciones del API usadas en este artículo:
Te resumo las funciones del API y técnicas que se utilizan en este artículo para que tengas un visión general de lo que el código te va a mostrar.
Función Comentario SetWindowsHookEx para crear un gancho UnhookWindowsHookEx para quitar el gancho creado con SetWindowsHookEx CallNextHookEx para llamar al siguiente gancho GetAsyncKeyState para saber el estado de pulsación de una tecla CopyMemory para copiar una estructura a partir de un puntero Constante Valor Comentario WH_KEYBOARD_LL 13& para indicar a SetWindowsHookEx que el gancho será para el teclado VK_TAB 9& la tecla TAB VK_CONTROL &H11 la tecla Control (CTRL) VK_ESCAPE &H1B la tecla Esc (Escape) LLKHF_ALTDOWN &H20 usada para indicar si también está pulsada la tecla ALT HC_ACTION 0& si la función del gancho recibe este código es cuando hay que actuar... También se utiliza la siguiente estructura, que es la que recibe la información de la tecla pulsada, te muestro la información indicada en la documentación que acompaña al Visual Basic 6.0:
typedef struct tagKBDLLHOOKSTRUCT {
DWORD vkCode; // virtual key code
DWORD scanCode; // scan code
DWORD flags; // flags
DWORD time; // time stamp for this message
DWORD dwExtraInfo; // extra info from the driver or keybd_event
}En esta misma documentación puedes encontrar información sobre el resto de las funciones del API, así como de la forma en que habrá que declarar la función que será llamada cada vez que se pulse una tecla, en esta ocasión, la función tiene este formato:
LRESULT CALLBACK LowLevelKeyboardProc(
int nCode, // hook code
WPARAM wParam, // message identifier
LPARAM lParam // pointer to structure with message data
);Ahora veremos cómo declararla y usarla desde una aplicación de VB6 o VB5, pero no anteriores, ya que se utiliza AddressOf y esa instrucción no existe en las versiones anteriores a Visual Basic 5.0
Vamos a crear un nuevo proyecto, al cual añadiremos un módulo BAS.
En el formulario que se incluye, añade dos botones que tendrán estos nombres: cmdHook y cmdUnHook, desde estos botones se activará y desactivará la intercepción de las teclas.
En el módulo BAS incluiremos las declaraciones del API y demás constantes y tipos, así como la función que será llamada por el sistema operativo cuando el gancho del teclado esté activo.
Según la documentación el código incluido en esa función no debería alargarse más de lo debido, por tanto, en esa función haz sólo lo que debas hacer y no lo alargues innecesariamente.Los pasos que daremos para activar/desactivar el gancho serán:
1- Iniciar el gancho del teclado (podemos hacerlo al iniciarse la aplicación, pero en este ejemplo se hará cuando pulsemos en el botón cmdHook.
2- Quitar el gancho del teclado cuando la aplicación se cierre. Aquí además de eso, vamos a quitar el mencionado gancho cuando pulsemos en el botón cmdUnHook.Una vez activado el gancho, cada vez que se pulse una tecla, se filtrará por la función gancho que tenemos en el módulo BAS a la que he llamado LLKeyBoardProc, en esa función se comprobarán las combinaciones de teclas y se devolverá un valor 1, si queremos que sean "obviadas" por el sistema, en caso de que no sea una de las teclas que queremos interceptar, la función debe devolver el valor indicado por CallNextHookEx, de forma que se pueda si hay otras aplicaciones que también han puesto un gancho, sean llamadas.
Todo esto lo verás en el código, así que, no me enrollo más y veamos ese código.
El código
Empezaremos por el código del formulario que es mucho más simple.'------------------------------------------------------------------------------ ' Formulario de prueba para desactivar algunas teclas especiales (08/Mar/03) ' en Windows NT/2000/XP ' ' ©Guillermo 'guille' Som, 2003 '------------------------------------------------------------------------------ Option Explicit Private Sub cmdCerrar_Click() Unload Me End Sub Private Sub cmdHook_Click() ' iniciar el gancho para el teclado HookKeyB App.hInstance End Sub Private Sub cmdUnHook_Click() ' quitar el gancho del teclado UnHookKeyB End Sub Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer) ' al cerrar el formulario, quitar el gancho del teclado UnHookKeyB End SubComo puedes comprobar, en la aplicación también he añadido un botón para cerrarla.
Ahora veamos el código a incluir en el módulo BAS:
'------------------------------------------------------------------------------ ' Para bloquear algunas teclas en Windows NT/2000/XP (08/Mar/03) ' Para NT debe tener el SP3 como mínimo ' ' ¡¡¡ NO FUNCIONA para Ctrl+Alt+Supr !!! ' ' En este ejemplo se bloquean las siguientes teclas: ' Ctrl+Esc, Alt+Tab y Alt+Esc ' ' ©Guillermo 'guille' Som, 2003 '------------------------------------------------------------------------------ Option Explicit ' para guardar el gancho creado con SetWindowsHookEx Private mHook As Long ' ' para indicar a SetWindowsHookEx que tipo de gancho queremos instalar Private Const WH_KEYBOARD_LL As Long = 13& ' este es para el ratón 'Private Const WH_MOUSE_LL As Long = 14& ' Private Type tagKBDLLHOOKSTRUCT vkCode As Long scanCode As Long flags As Long time As Long dwExtraInfo As Long End Type ' Private Const VK_TAB As Long = &H9 Private Const VK_CONTROL As Long = &H11 ' tecla Ctrl 'Private Const VK_MENU As Long = &H12 ' tecla Alt Private Const VK_ESCAPE As Long = &H1B 'Private Const VK_DELETE As Long = &H2E ' tecla Supr (Del) ' Private Const LLKHF_ALTDOWN As Long = &H20& ' ' códigos para los ganchos (la acción a tomar en el gancho del teclado) Private Const HC_ACTION As Long = 0& '----------------------------- ' Funciones del API de Windows '----------------------------- ' para asignar un gancho (hook) Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" _ (ByVal idHook As Long, ByVal lpfn As Long, _ ByVal hMod As Long, ByVal dwThreadId As Long) As Long ' para quitar el gancho creado con SetWindowsHookEx Private Declare Function UnhookWindowsHookEx Lib "user32" _ (ByVal hHook As Long) As Long ' para llamar al siguiente gancho Private Declare Function CallNextHookEx Lib "user32" _ (ByVal hHook As Long, ByVal nCode As Long, _ ByVal wParam As Long, ByVal lParam As Long) As Long ' para saber si se ha pulsado en una tecla Private Declare Function GetAsyncKeyState Lib "user32" _ (ByVal vKey As Long) As Integer ' para copiar la estructura en un long Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _ (Destination As Any, Source As Any, ByVal Length As Long) ' La función a usar para el gancho del teclado Public Function LLKeyBoardProc(ByVal nCode As Long, _ ByVal wParam As Long, _ ByVal lParam As Long _ ) As Long Dim pkbhs As tagKBDLLHOOKSTRUCT Dim ret As Long ' ret = 0 ' ' copiar el parámetro en la estructura CopyMemory pkbhs, ByVal lParam, Len(pkbhs) ' If nCode = HC_ACTION Then ' ' si se pulsa Ctrl+Esc If pkbhs.vkCode = VK_ESCAPE Then If (GetAsyncKeyState(VK_CONTROL) And &H8000) Then ret = 1 End If End If ' ' si se pulsa Alt+Tab If pkbhs.vkCode = VK_TAB Then If (pkbhs.flags And LLKHF_ALTDOWN) <> 0 Then ret = 1 End If End If ' ' si se pulsa Alt+Esc If pkbhs.vkCode = VK_ESCAPE Then If (pkbhs.flags And LLKHF_ALTDOWN) <> 0 Then ret = 1 End If End If ' End If ' If ret = 0 Then ret = CallNextHookEx(mHook, nCode, wParam, lParam) End If ' LLKeyBoardProc = ret ' ' ' El código C++ en el que he basado (o casi) el de VB 'LRESULT CALLBACK LowLevelKeyboardProc (INT nCode, WPARAM wParam, LPARAM lParam) '{ ' // By returning a non-zero value from the hook procedure, the ' // message does not get passed to the target window ' KBDLLHOOKSTRUCT *pkbhs = (KBDLLHOOKSTRUCT *) lParam; ' BOOL bControlKeyDown = 0; ' ' switch (nCode) ' { ' case HC_ACTION: ' { ' // Check to see if the CTRL key is pressed ' bControlKeyDown = GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1); ' ' // Disable CTRL+ESC ' if (pkbhs->vkCode == VK_ESCAPE && bControlKeyDown) ' return 1; ' ' // Disable ALT+TAB ' if (pkbhs->vkCode == VK_TAB && pkbhs->flags & LLKHF_ALTDOWN) ' return 1; ' ' // Disable ALT+ESC ' if (pkbhs->vkCode == VK_ESCAPE && pkbhs->flags & LLKHF_ALTDOWN) ' return 1; ' ' break; ' } ' 'default: ' break; ' } return CallNextHookEx (hHook, nCode, wParam, lParam); '} End Function Public Sub HookKeyB(ByVal hMod As Long) ' instalar el gancho para el teclado ' hMod será el valor de App.hInstance de la aplicación mHook = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf LLKeyBoardProc, hMod, 0&) End Sub Public Sub UnHookKeyB() ' desinstalar el gancho para el teclado ' Es importante hacerlo antes de finalizar la aplicación, ' normalmente en el evento Unload o QueryUnload If mHook <> 0 Then UnhookWindowsHookEx mHook End If End SubTe he dejado algunas declaraciones de constantes comentadas, para que sepas los valores y puedas intentar otras cosas.
También he dejado el código C/C++ en el que está basado el código de VB, el cual era el que puse en el mensaje ese que te comenté al principio, el cual a su vez estaba tomado de un artículo de la Knowledge Base titulado: HOWTO: Disable Task Switching on Win32 Platforms.Para terminar, decirte que si este código lo usas en Windows NT, debes tener como mínimo el SP3.
Espero que te sea de utilidad.
Nos vemos.
Guillermo