PDA

Ver la Versión Completa : Hook de teclado con filtro de pulsaciones


aguml
21-11-2014, 15:15:00
Hola amigos, me gustaria crear un hook el cual me permita capturar las pulsaciones de teclado y poder anular pulsaciones como el Ctrl+C y otras que interfieran con el buen funcionamiento de mi aplicacion. Tengo este codigo:

dll.cpp:
#include <windows.h>
#include "dll.h"

#pragma data_seg("SharedBlock")
#pragma data_seg()

#define OK -32767 //Necesario para el keylogger

enum {LCtrl,RCtrl,HacerClic,Cerrar,Activar,Desactivar,Mostrar,Ocultar,Maximizar,Restaurar,Minimizar,Siemp reEncima,NoEncima,Enviar};

HHOOK gancho;

/**********************************************/
/*FUNCION PARA FILTRAR LOS RESULTADOS DEL HOOK*/
/**********************************************/
LRESULT CALLBACK Filtro(int nCode, WORD wParam, DWORD lParam)
{
int retval=0;

if(nCode<0){
return(CallNextHookEx(gancho,nCode,wParam,lParam));
}

//si hay datos, los guardamos
if (lParam & (1 << 31)) {
BYTE KeyboardState[256];
GetKeyboardState(KeyboardState);
WORD CharValue;

//Aqui el codigo de filtrado de pulsaciones
if(GetAsyncKeyState(VK_LCONTROL)==OK){ //si está pulsada [Ctrl(Izq)]
retval = LCtrl;
}else if(GetAsyncKeyState(VK_RCONTROL)==OK){ //si está pulsada [Ctrl(Dcha)]
retval = RCtrl;
}else if((GetKeyState(76) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+L]
retval = HacerClic;
}else if((GetKeyState(67) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+C]
retval = Cerrar;
}else if((GetKeyState(65) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+A]
retval = Activar;
}else if((GetKeyState(68) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+D]
retval = Desactivar;
}else if((GetKeyState(77) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+M]
retval = Mostrar;
}else if((GetKeyState(79) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+O]
retval = Ocultar;
}else if((GetKeyState(88) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+X]
retval = Maximizar;
}else if((GetKeyState(82) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+R]
retval = Restaurar;
}else if((GetKeyState(73) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+I]
retval = Minimizar;
}else if((GetKeyState(83) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+S]
retval = SiempreEncima;
}else if((GetKeyState(78) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+N]
retval = NoEncima;
}else if((GetKeyState(69) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+E]
retval = Enviar;
}
}
return CallNextHookEx(gancho,nCode,wParam,lParam);
}

/*******************************************************/
/*FUNCIÓN PARA INSTALAR/DESINSTALAR EL HOOK DEL TECLADO*/
/*******************************************************/
extern "C" __declspec(dllexport)int CreaHook(BOOL Instala, HINSTANCE DLLInst)
{
int retval;

if(Instala==TRUE) {
gancho=SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)Filtro,DLLInst,0);
if(gancho==NULL){
retval = 0;
}else{
retval = 1;
}
}else{
retval = UnhookWindowsHookEx(gancho);
}
return retval;
}

/*************************/
/*PROCEDIMIENTO PRINCIPAL*/
/*************************/
BOOL WINAPI DllMain(HANDLE hModule, DWORD dwFunction, LPVOID lpNot)
{
return TRUE;
}

dll.h:
#ifndef _DLL_H_
#define _DLL_H_

#if BUILDING_DLL
# define DLLIMPORT extern "C" __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define DLLIMPORT extern "C" __declspec (dllimport)
#endif /* Not BUILDING_DLL */

LRESULT CALLBACK Filtro(int nCode, WORD wParam, DWORD lParam);
extern "C" __declspec(dllexport)int CreaHook(BOOL Instala,HINSTANCE DLLInst);

#endif /* _DLL_H_ */

Unit1.cpp:
#include <vcl.h>
#pragma hdrstop
#include <windows.h>

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

HMODULE Dll;

typedef void (*LPFuncion)(BOOL,HINSTANCE/*Redefiní la funcion*/);
LPFuncion Funcion=NULL;

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
//cargamos la Dll
Dll=LoadLibrary("HookKeyboard.dll");
if(!Dll){
ShowMessage("No se encontró la Dll: RBT_KLogger.dll");
return;
}

//buscamos la funcion en la dll
Funcion = (LPFuncion)GetProcAddress(Dll, "_CreaHook");
if(!Funcion){
ShowMessage("ERROR");
FreeLibrary(Dll);
return;
}

//ejecutamos la función
Funcion(TRUE,Dll);//instalamos el hook
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
//desinstalamos el hook
Funcion(FALSE,NULL);

//liberamos la memoria
FreeLibrary(Dll);
}
//---------------------------------------------------------------------------


De momento no se como aplicar el filtro. El hook funciona pero no se que hacer para filtrar esas pulsaciones.
Otra cosa, ¿por que me exporta CreaHook como _CreaHook?¿No se supone que el extern "C" evita eso?

aguml
21-11-2014, 16:59:40
Este me funciona fenomenal pero no me evita que se ejecute el atajo de teclas en la ventana en que esté en ese momento:

Trozo de codigo de Unit1.h:

//Comprobamos si se pulsó algún atajos de teclado
switch(Combinacion)
{
case HacerClic:
ButtonClic->Click();
Sleep(150);
break;

case Cerrar:
ButtonClose->Click();
break;

case Activar:
ButtonEnable->Click();
break;

case Desactivar:
ButtonDisable->Click();
break;

case Mostrar:
ButtonShow->Click();
break;

case Ocultar:
ButtonHide->Click();
break;

case Maximizar:
ButtonMaximize->Click();
break;

case Restaurar:
ButtonRestore->Click();
break;

case Minimizar:
ButtonMinimize->Click();
break;

case SiempreEncima:
ButtonTopmost->Click();
break;

case NoEncima:
ButtonNonTop->Click();
break;

case Enviar:
ButtonSendCaption->Click();
break;
}


Funcion que controla las pulsaciones:

/*==============================================================
ESTA FUNCIÓN ES LA QUE CAPTURA LAS TECLAS DE CONTROL
==============================================================*/
bool KeyLogger(int *combinacion)
{
bool retval = false;
*combinacion = 0;

if(GetAsyncKeyState(VK_LCONTROL)==OK){ //si está pulsada [Ctrl(Izq)]
retval = true;
}else if(GetAsyncKeyState(VK_RCONTROL)==OK){ //si está pulsada [Ctrl(Dcha)]
retval = true;
}else if((GetKeyState(76) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+L]
*combinacion = HacerClic;
}else if((GetKeyState(67) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+C]
*combinacion = Cerrar;
}else if((GetKeyState(65) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+A]
*combinacion = Activar;
}else if((GetKeyState(68) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+D]
*combinacion = Desactivar;
}else if((GetKeyState(77) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+M]
*combinacion = Mostrar;
}else if((GetKeyState(79) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+O]
*combinacion = Ocultar;
}else if((GetKeyState(88) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+X]
*combinacion = Maximizar;
}else if((GetKeyState(82) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+R]
*combinacion = Restaurar;
}else if((GetKeyState(73) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+I]
*combinacion = Minimizar;
}else if((GetKeyState(83) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+S]
*combinacion = SiempreEncima;
}else if((GetKeyState(78) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+N]
*combinacion = NoEncima;
}else if((GetKeyState(69) < 0) && ((GetKeyState(VK_LCONTROL) < 0) || (GetKeyState(VK_RCONTROL) < 0))){ //si pulsamos [Alt+E]
*combinacion = Enviar;
}

return retval;
}
//---------------------------------------------------------------------------


Si por ejemplo estoy seleccionando un texto del notepad y doy a Ctrl+C me funciona mi codigo perfectamente pero tambien me copia el texto que estaba seleccionado al portapapeles. Eso es lo que me gustaria evitar que, por ejemplo en este caso, no se entere de que tiene que copiar al portapapeles.

aguml
22-11-2014, 02:02:21
me han comentado que lo que quiero hacer se hace con RegisterHotKey y UnregisterHotKey. He encontrado algun ejemplo incluso aqui y quiero probar pero mi duda es ¿Que pasa si el HotKey global ya existe? Por ejemplo Ctrl+C si yo creo la mia supongo que la mia sobreescribe la que hay y al eliminar la mia ¿Vuelve a estar operativa la anterior o me la he cargado? Evidentemente el Id seria diferente.

escafandra
22-11-2014, 13:05:02
Puedes hacerlo como quieras. El Hook engancha antes de procesar la pulsación. HotKey te envía un mensaje.
El problema es actuar en el ClipBoard, tienes que trampearlo.

No es necesaria una dll para un hook de teclado, hazlo a bajo nivel.

Te muestro un ejemplo simple para evitar la copia al ClipBoard con un Hook LL al teclado:


HHOOK hKeybHook;

LRESULT WINAPI KeybEvent(int nCode, WPARAM wParam, LPARAM lParam)
{
if( (nCode == HC_ACTION) && ((wParam == WM_SYSKEYDOWN) || (wParam == WM_KEYDOWN)) ){

bool Ctl_C = GetAsyncKeyState(VK_CONTROL) && (*(PDWORD)lParam == 0x43); //VK_C;
bool Ctl_V = GetAsyncKeyState(VK_CONTROL) && (*(PDWORD)lParam == 0x56); //VK_V;

if(Ctl_C){
CloseClipboard();
OpenClipboard(0);
EmptyClipboard();
}
else if(Ctl_V)
CloseClipboard();
}

return CallNextHookEx(hKeybHook, nCode, wParam, lParam);
}

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
hKeybHook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeybEvent, GetModuleHandle(NULL), 0);
Beep(1000, 100);
}

//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
UnhookWindowsHookEx(hKeybHook);
CloseClipboard();
}
Saludos.

aguml
22-11-2014, 17:06:55
mmm ¿pero eso tendria que hacer trampeos con todas las combinaciones? Segun me dijeron, con RegisterHotKey se ejecuta la que yo quiero y yo me encargo de que se ejecute lo demas que se deba ejecutar para esa combinacion. Creo que si es asi me quedo con ese metodo.

escafandra
22-11-2014, 20:41:03
Mi respuesta responde al título del hilo: "Hook de teclado con filtro de pulsaciones"

Para conseguir tu objetivo con el ClipBoard, el método por hotkeys es más fácil y directo en este caso, pero no es un hook, de forma tendrás que registrar cada combinación de teclas que quieras manejar para otras cuestiones. Tu eliges que técnica usar.


Saludos.

aguml
23-11-2014, 09:18:32
¿Y por que no me funcionaba usando la dll? Me interesa saber como seria para que funcione con la dll.

escafandra
23-11-2014, 11:15:11
¿No te funciona el Hook?, entendí que si, que lo que no funciobaba era el bloqueo del clipboard.

Si es así, revisa como lbloqueo el clipboard en el ejemplo que puse. Básicamente cuando una app usa Ctl-C para copiar, abro el clipboard, lo vacío y lo dejo abierto para evitar que la app lo use hasta que se pulse Ctl-V monento en que lo cierro y dejo libre. Al deshacer el hook también cierro el clipboard para liberarlo. Es por eso que digo "trampear el clipboard".

Revisa el código.


Saludos.

aguml
23-11-2014, 13:14:38
en mi hook no capturaba las teclas especiales como las Fx, flechas, ctrl, shift,... El tuyo no he podido probarlo aun. A lo que me refiero es que ¿como hago para que me capture esas teclas?

aguml
23-11-2014, 17:08:02
Bueno, me he decidido por usar el registrado de los atajos y tengo esto:
private: // User declarations
bool AtajosGlobales;
TMessageEvent OldApplicationOnMessage;

protected:
virtual void __fastcall AppMessage(tagMSG &Msg, bool &Handled);

void __fastcall TForm1::AppMessage(tagMSG &Msg, bool &Handled)
{
if(Msg.message == WM_HOTKEY)
{
//Comprobamos si se pulsó algún atajo de teclado

if((LOWORD(Msg.lParam) == MOD_CONTROL) && (HIWORD(Msg.lParam) == 'L'))
{
ButtonClic->Click();
Sleep(150);
}else if((LOWORD(Msg.lParam) == MOD_CONTROL) && (HIWORD(Msg.lParam) == 'C'))
{
ButtonClose->Click();
}else if((LOWORD(Msg.lParam) == MOD_CONTROL) && (HIWORD(Msg.lParam) == 'D'))
{
ButtonDisable->Click();
}else if((LOWORD(Msg.lParam) == MOD_CONTROL) && (HIWORD(Msg.lParam) == 'A'))
{
ButtonEnable->Click();
}else if((LOWORD(Msg.lParam) == MOD_CONTROL) && (HIWORD(Msg.lParam) == 'M'))
{
ButtonShow->Click();
}else if((LOWORD(Msg.lParam) == MOD_CONTROL) && (HIWORD(Msg.lParam) == 'O'))
{
ButtonHide->Click();
}else if((LOWORD(Msg.lParam) == MOD_CONTROL) && (HIWORD(Msg.lParam) == 'X'))
{
ButtonMaximize->Click();
}else if((LOWORD(Msg.lParam) == MOD_CONTROL) && (HIWORD(Msg.lParam) == 'R'))
{
ButtonRestore->Click();
}else if((LOWORD(Msg.lParam) == MOD_CONTROL) && (HIWORD(Msg.lParam) == 'I'))
{
ButtonMinimize->Click();
}else if((LOWORD(Msg.lParam) == MOD_CONTROL) && (HIWORD(Msg.lParam) == 'S'))
{
ButtonTopmost->Click();
}else if((LOWORD(Msg.lParam) == MOD_CONTROL) && (HIWORD(Msg.lParam) == 'N'))
{
ButtonNonTop->Click();
}else if((LOWORD(Msg.lParam) == MOD_CONTROL) && (HIWORD(Msg.lParam) == 'E'))
{
ButtonSendCaption->Click();
}else{
OldApplicationOnMessage(Msg,Handled);
}
}else{
OldApplicationOnMessage(Msg,Handled);
}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
if(AtajosGlobales == true)
{
UnregisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey1"));
UnregisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey2"));
UnregisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey3"));
UnregisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey4"));
UnregisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey5"));
UnregisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey6"));
UnregisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey7"));
UnregisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey8"));
UnregisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey9"));
UnregisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey10"));
UnregisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey11"));
UnregisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey12"));
}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{
OldApplicationOnMessage = Application->OnMessage;
Application->OnMessage = AppMessage;

RegisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey1"), MOD_CONTROL,'L');
RegisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey2"), MOD_CONTROL,'C');
RegisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey3"), MOD_CONTROL,'D');
RegisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey4"), MOD_CONTROL,'A');
RegisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey5"), MOD_CONTROL,'M');
RegisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey6"), MOD_CONTROL,'O');
RegisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey7"), MOD_CONTROL,'X');
RegisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey8"), MOD_CONTROL,'R');
RegisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey9"), MOD_CONTROL,'I');
RegisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey10"), MOD_CONTROL,'S');
RegisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey11"), MOD_CONTROL,'N');
RegisterHotKey(Application->Handle, GlobalAddAtomA("MiHotKey12"), MOD_CONTROL,'E');
}

Lo que quiero es que cuando no sea uno de los atajos que yo he registrado el programa el resto funcione perfectamente pero no consigo ni que compile. ¿alguna ayuda para hacerlo bien?

escafandra
25-11-2014, 01:23:56
en mi hook no capturaba las teclas especiales como las Fx, flechas, ctrl, shift,... El tuyo no he podido probarlo aun. A lo que me refiero es que ¿como hago para que me capture esas teclas?

Con el Hook


LRESULT CALLBACK Filtro(int nCode, WORD wParam, DWORD lParam)
{
if(nCode == HC_ACTION){
if((GetKeyState(0x43) < 0) && GetAsyncKeyState(VK_CONTROL) == OK){ //si pulsamos [Ctl+C]
CloseClipboard();
OpenClipboard(0);
EmptyClipboard();
}
else if((GetKeyState(0x56) < 0) && GetAsyncKeyState(VK_CONTROL) == OK){ //si pulsamos [Ctl+V]
CloseClipboard();
}
}
return CallNextHookEx(gancho,nCode,wParam,lParam);
}

/*******************************************************/
/*FUNCIÓN PARA INSTALAR/DESINSTALAR EL HOOK DEL TECLADO*/
/*******************************************************/
extern "C" __declspec(dllexport) __stdcall int CreaHook(BOOL Instala, HINSTANCE DLLInst)
{
int retval;

if(Instala==TRUE) {
gancho=SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)Filtro,DLLInst,0);
if(gancho==NULL){
retval = 0;
}else{
retval = 1;
}
}else{
CloseClipboard();
retval = UnhookWindowsHookEx(gancho);
}
return retval;
}


void __fastcall TForm1::Button1Click(TObject *Sender)
{
//cargamos la Dll
Dll=LoadLibrary("HookKeyboard.dll");
if(!Dll){
ShowMessage("No se encontró la Dll: RBT_KLogger.dll");
return;
}

//buscamos la funcion en la dll
Funcion = (LPFuncion)GetProcAddress(Dll, "CreaHook");
if(!Funcion){
ShowMessage("ERROR");
//FreeLibrary(Dll);
return;
}

//ejecutamos la función
Funcion(TRUE,Dll);//instalamos el hook
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
//desinstalamos el hook
Funcion(FALSE,NULL);

//liberamos la memoria
// FreeLibrary(Dll);
}
//---------------------------------------------------------------------------

Observa que he declarado como __stdcallla función CreaHook. Esto es porque en un momentode este hilo preguntabas porqué el compilador "decoraba" la función con un guión delante. De esta manera el nombre de la función no se altera. No deber descargar la dll porque perderás el valor de la variable gancho.


Saludos.

escafandra
25-11-2014, 01:31:14
Registrando HotKeys:


//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include <vcl\Clipbrd.hpp>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{
RegisterHotKey(Handle, 67, MOD_CONTROL, 67);
}
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// Procesamos los mensajes a bajo nivel
void __fastcall TForm1::WndProc(Messages::TMessage &Message)
{
if(Message.Msg == WM_HOTKEY)
if(Message.WParam == 67) Clipboard()->Clear();

TForm::WndProc(Message);
}
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
UnregisterHotKey(Handle, 67);
}
//---------------------------------------------------------------------------


Saludos.

aguml
25-11-2014, 12:47:08
Amigo el hook va fantastico, lo he modificado un poquitin y quedó así:

App:
#include <vcl.h>
#pragma hdrstop

#include "Main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"

typedef void (*LPFuncion)(BOOL,HINSTANCE/*Redefiní la funcion*/);

TForm1 *Form1;
HMODULE Dll;
bool errorFunc=true, errorDll=true;
LPFuncion Funcion=NULL;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ButtonColocarHookClick(TObject *Sender)
{
ColocarHook();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ButtonQuitarHookClick(TObject *Sender)
{
//desinstalamos el hook
Funcion(FALSE,NULL);

ButtonColocarHook->Enabled = true;
ButtonQuitarHook->Enabled = false;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{
ColocarHook();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
//desinstalamos el hook
if(!errorFunc)
Funcion(FALSE,NULL);

//liberamos la memoria
if(!errorDll)
FreeLibrary(Dll);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ColocarHook()
{
//cargamos la Dll
Dll=LoadLibrary("DllHookKeyboard.dll");
if(!Dll){
ShowMessage("No se encontró la Dll: DllHookKeyboard.dll");
errorDll = true;
}else{
errorDll = false;
//buscamos la funcion en la dll
Funcion = (LPFuncion)GetProcAddress(Dll, "CreaHook");
if(!Funcion){
ShowMessage("ERROR, no se encontró la función: Crck");
errorFunc = true;
}else{
//ejecutamos la función
Funcion(TRUE,Dll);//instalamos el hook
ButtonColocarHook->Enabled = false;
ButtonQuitarHook->Enabled = true;
errorFunc = false;
}
}
}

Dll:
#include <windows.h>

#define OK -32767 //Necesario para el keylogger

HHOOK gancho;

#pragma argsused

LRESULT CALLBACK Filtro(int nCode, WORD wParam, DWORD lParam)
{
if(nCode == HC_ACTION){
if((GetKeyState(0x43) < 0) && GetAsyncKeyState(VK_CONTROL) == OK){ //si pulsamos [Ctl+C]
CloseClipboard();
OpenClipboard(0);
EmptyClipboard();
MessageBox(NULL,"Has intentado copiar al portapapeles con Ctrl+C","Atención", MB_OK | MB_ICONINFORMATION);
}
else if((GetKeyState(0x56) < 0) && GetAsyncKeyState(VK_CONTROL) == OK){ //si pulsamos [Ctl+V]
CloseClipboard();
MessageBox(NULL,"Has intentado pegar desde el portapapeles con Ctrl+V","Atención",MB_OK | MB_ICONINFORMATION);
}
}
return CallNextHookEx(gancho,nCode,wParam,lParam);
}

/*******************************************************/
/*FUNCIÓN PARA INSTALAR/DESINSTALAR EL HOOK DEL TECLADO*/
/*******************************************************/
extern "C" __declspec(dllexport) __stdcall int CreaHook(BOOL Instala, HINSTANCE DLLInst)
{
int retval;

if(Instala==TRUE) {
gancho=SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)Filtro,DLLInst,0);
if(gancho==NULL){
retval = 0;
}else{
retval = 1;
}
}else{
CloseClipboard();
retval = UnhookWindowsHookEx(gancho);
}
return retval;
}
//---------------------------------------------------------------------------

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
return 1;
}

Ahora bien, lo que pones de los HotKeys a mi no me ha funcionado pero si me funciona usando esto:
http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/Forms_TApplication_OnMessage.html

Por lo que puedo entender en el comentario del final del codigo dice que si no lo pongo yo handled a true será gestionado por otros manejadores y no veo que el haga nada al respecto si no lo maneja el y así lo dejé yo:

App.h:
private: // User declarations
TMessageEvent OldApplicationOnMessage;
void __fastcall AppMessage(tagMSG &Msg, bool &Handled);

App.cpp:
void __fastcall TForm1::FormCreate(TObject *Sender)
{
OldApplicationOnMessage = Application->OnMessage;
Application->OnMessage = AppMessage;
RegistrarHotKeys();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormDestroy(TObject *Sender)
{
Application->OnMessage = OldApplicationOnMessage;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::AppMessage(tagMSG &Msg, bool &Handled)
{
if(Msg.message == WM_HOTKEY)
{
//Comprobamos si se pulsó algún atajo de teclado

if( LOWORD(Msg.lParam) == MOD_CONTROL )
{
switch( HIWORD(Msg.lParam) )
{
case 'L':
ButtonClic->Click();
Sleep(150);
Handled = true;
break;

case 'C':
ButtonClose->Click();
Handled = true;
break;

case 'D':
ButtonDisable->Click();
Handled = true;
break;

case 'A':
ButtonEnable->Click();
Handled = true;
break;

case 'M':
ButtonShow->Click();
Handled = true;
break;

case 'O':
ButtonHide->Click();
Handled = true;
break;

case 'X':
ButtonMaximize->Click();
Handled = true;
break;

case 'R':
ButtonRestore->Click();
Handled = true;
break;

case 'I':
ButtonMinimize->Click();
Handled = true;
break;

case 'S':
ButtonTopmost->Click();
Handled = true;
break;

case 'N':
ButtonNonTop->Click();
Handled = true;
break;

case 'E':
ButtonSendCaption->Click();
Handled = true;
break;

case 'F':
if(ButtonIntroHandle->Enabled == true)
ButtonIntroHandle->Click();
Handled = true;
break;
}
}
}
}

Así va perfecto pero no se si es lo mas correcto o no :confused:

escafandra
25-11-2014, 15:00:38
La mejor forma de hacer un hook al teclado es el de bajo nivel, WH_KEYBOARD_LL (http://msdn.microsoft.com/en-us/library/windows/desktop/ms644985%28v=vs.85%29.aspx) sin dll. Es el primer hook que te mostré.

Las HotKeys funcionan tanto si los mensajes los tratas a nivel de formulario (a bajo nivel, con sobreescritura de la función WndProc, o capturando mensajes estilo delphi, como capturando los mensajes en TApplication (Application->OnMessage)

Los mensajes WM_HOTKEY reciben en wParam el id usado para registrar la tecla. con dicho id conoces la tecla regictrada. Yo uso como dato de ese id le VK_ de la tecla que registro, así no tengo pérdidas.
Lo siguiente registra Ctl-C:

RegisterHotKey(Handle, 67, MOD_CONTROL, 67);


Y tratamos de esta manera el mensaje, usando Application->OnMessage, que parece que te gusta más:

void __fastcall TForm1::AppMessage(tagMSG &Msg, bool &Handled)
{
if(Msg.message == WM_HOTKEY){
if(Msg.wParam == 67)
Beep();
// else if ......
}
}


Al terminar la APP siempre debes usar UnregisterHotKey para liberar las HotKeys.


Saludos.

aguml
25-11-2014, 17:18:05
Yo uso MAKEINTATOM para obtener el id con lo que para poder hacerlo como indicas tendria que almacenar todos los ids de los atoms y luego usar estos en los cases. La verdad es que asi ya funciona perfectamente y el codigo lo saque de codegear.