Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   C++ Builder (https://www.clubdelphi.com/foros/forumdisplay.php?f=13)
-   -   bloqueador de teclado antigatos (https://www.clubdelphi.com/foros/showthread.php?t=90044)

aguml 24-03-2016 17:17:22

bloqueador de teclado antigatos
 
Bueno, esto suena chistoso pero estoy cansado de que mis gatos masajeen mi teclado y he estado buscando soluciones para bloquear el teclado y que por mucho que pisen no hagan ningun estropicio. Todo lo que he encontrado por la red ha sido referente a una app que haga un hook del teclado y deseche las pulsaciones hasta que haya una combinacion de teclas deseadas o una palabra o algo asi. He escrito este codigo pero funciona a medias:
Código PHP:

#include <vcl.h>
#pragma hdrstop

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

#define OK -32767 //Necesario para el keylogger

LRESULT WINAPI KeyboardEvent(int nCodeWPARAM wParamLPARAM lParam);

TForm1 *Form1;
HHOOK  hKeyboardHook;
//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponentOwner)
   : 
TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ButtonColocarHookClick(TObject *Sender)
{
   
hKeyboardHook  SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyboardEventGetModuleHandle(NULL), 0);
   
ButtonColocarHook->Enabled false;
   
ButtonQuitarHook->Enabled true;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ButtonQuitarHookClick(TObject *Sender)
{
   
UnhookWindowsHookEx(hKeyboardHook);
   
ButtonColocarHook->Enabled true;
   
ButtonQuitarHook->Enabled false;
}
//---------------------------------------------------------------------------

LRESULT WINAPI KeyboardEvent(int nCodeWPARAM wParamLPARAM lParam)
{
   static 
count=0;

   if( (
nCode == HC_ACTION) && ((wParam == WM_SYSKEYDOWN) || (wParam == WM_KEYDOWN)) ){
      if(
GetAsyncKeyState(VK_CONTROL) && GetAsyncKeyState(VK_SHIFT))
      {

      }else if(
GetAsyncKeyState(VK_CONTROL) && GetAsyncKeyState(VK_MENU))
      {

      }else if(
GetAsyncKeyState(VK_CONTROL))
      {

      }else if(
GetAsyncKeyState(VK_MENU))
      {

      }else if(
GetAsyncKeyState(VK_SHIFT)){

      }else{
         if (
count == && tolower(*(PDWORD)lParam) == 'u') {        // 'u'
            
count 1;
         } else if (
count == && tolower(*(PDWORD)lParam) == 'n') { // 'n'
            
count 2;
         } else if (
count == && tolower(*(PDWORD)lParam) == 'l') { // 'l'
            
count 3;
         } else if (
count == && tolower(*(PDWORD)lParam) == 'o') { // 'o'
            
count 4;
         } else if (
count == && tolower(*(PDWORD)lParam) == 'c') { // 'c'
            
count 5;
         } else if (
count == && tolower(*(PDWORD)lParam) == 'k') { // 'k'
            
count 0;
            
Form1->ButtonQuitarHook->Click();
         } else {
            
count 0;
         }
      }
   }
   return 
CallNextHookEx(hKeyboardHooknCodewParamlParam);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{
   
hKeyboardHook  SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyboardEventGetModuleHandle(NULL), 0);
   
ButtonColocarHook->Enabled false;
   
ButtonQuitarHook->Enabled true;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormClose(TObject *SenderTCloseAction &Action)
{
   
UnhookWindowsHookEx(hKeyboardHook);
   
ButtonColocarHook->Enabled true;
   
ButtonQuitarHook->Enabled false;
}
//--------------------------------------------------------------------------- 

Realmente capturo todas las pulsaciones que desee pero lo que deseo es que esas pulsaciones sean todas desechadas hasta que se desbloquee el teclado pero aunque las capturo no consigo anularlas. ¿podeis ayudarme con esto?

j0seant 24-03-2016 18:31:07

Algo sencillo es usar la función del API "BlockInput" (hay que ejecutarla con privilegios de administrador), bloquea tanto el teclado como el ratón hasta que se cierra el proceso que la invoco o usando la combinación CTRL+ALT+SUPR (que si los gatos ya conocen esta combinación se fastidio la cosa) ;-)

jhonny 24-03-2016 18:43:13

Realmente no aportaré mucho con lo siguiente pero... Que genial idea, mis gatos se ven tan bonitos ahí estorbando que es imposible bajarlos, así que o los enseñamos a no subirse ahí (cosa posible pero con mucha paciencia) o esperaré con ansias tu app, pues suena genial.

aguml 24-03-2016 19:37:50

Bueno, el codigo funciona perfectamente y es este:
Código PHP:

#include <vcl.h>
#pragma hdrstop

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

#define OK -32767 //Necesario para el keylogger

LRESULT WINAPI KeyboardEvent(int nCodeWPARAM wParamLPARAM lParam);
bool CloseApp;

TForm1 *Form1;
HHOOK  hKeyboardHook;
//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponentOwner)
   : 
TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ButtonColocarHookClick(TObject *Sender)
{
   
hKeyboardHook  SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyboardEventGetModuleHandle(NULL), 0);
   
ButtonColocarHook->Enabled false;
   
ButtonQuitarHook->Enabled true;
   
Activarteclado1->Enabled=ButtonQuitarHook->Enabled;
   
Desactivarteclado1->Enabled=ButtonColocarHook->Enabled;
   
SysTrayIcon1->IconIndex=0;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ButtonQuitarHookClick(TObject *Sender)
{
   
UnhookWindowsHookEx(hKeyboardHook);
   
ButtonColocarHook->Enabled true;
   
ButtonQuitarHook->Enabled false;
   
Activarteclado1->Enabled=ButtonQuitarHook->Enabled;
   
Desactivarteclado1->Enabled=ButtonColocarHook->Enabled;
   
SysTrayIcon1->IconIndex=1;
}
//---------------------------------------------------------------------------

LRESULT WINAPI KeyboardEvent(int nCodeWPARAM wParamLPARAM lParam)
{
   static 
count=0;

   if( (
nCode == HC_ACTION) && ((wParam == WM_SYSKEYDOWN) || (wParam == WM_KEYDOWN)) ){
      if(!
GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT) && !GetAsyncKeyState(VK_MENU)){
         if (
count == && *(PDWORD)lParam == 'U') {        // 'u'
            
count 1;
         } else if (
count == && *(PDWORD)lParam == 'N') { // 'n'
            
count 2;
         } else if (
count == && *(PDWORD)lParam == 'L') { // 'l'
            
count 3;
         } else if (
count == && *(PDWORD)lParam == 'O') { // 'o'
            
count 4;
         } else if (
count == && *(PDWORD)lParam == 'C') { // 'c'
            
count 5;
         } else if (
count == && *(PDWORD)lParam == 'K') { // 'k'
            
count 0;
            
Form1->ButtonQuitarHook->Click();
         } else {
            
count 0;
         }
      }else{
         
count 0;
      }
      return 
1;
   }
   return 
CallNextHookEx(hKeyboardHooknCodewParamlParam);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{
   
hKeyboardHook  SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyboardEventGetModuleHandle(NULL), 0);
   
ButtonColocarHook->Enabled false;
   
ButtonQuitarHook->Enabled true;
   
Activarteclado1->Enabled=ButtonQuitarHook->Enabled;
   
Desactivarteclado1->Enabled=ButtonColocarHook->Enabled;
   
CloseApp=false;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormClose(TObject *SenderTCloseAction &Action)
{
   
UnhookWindowsHookEx(hKeyboardHook);
   
ButtonColocarHook->Enabled true;
   
ButtonQuitarHook->Enabled false;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Salir1Click(TObject *Sender)
{
   
CloseApp true;
   
Close();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Desactivarteclado1Click(TObject *Sender)
{
   
ButtonColocarHook->Click();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Activarteclado1Click(TObject *Sender)
{
   
ButtonQuitarHook->Click();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCloseQuery(TObject *Senderbool &CanClose)
{
   if(
CloseApp){
      
CanClose CloseApp;
   }else{
      
CanClose=CloseApp;
      
SysTrayCanClose CanClose;
      
SysTrayIcon1->Minimize();
   }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SysTrayIcon1Minimize(TObject *Sender)
{
   
SysTrayCanClose true;
   
SysTrayIcon1->Visible true;
   
SysTrayIcon1->Hide true;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SysTrayIcon1Restore(TObject *Sender)
{
   
SysTrayIcon1->Visible false;
   
SysTrayIcon1->Hide false;
}
//--------------------------------------------------------------------------- 

Ahora tengo un pequeño problema, se que se ha visto mas veces pero no doy con el post donde se trató, lo que deseo es que el form principal se inicie oculto ya que uso el componente SysTrayIcon que creó escafandra y quiero que arranque mostrando solo el trayicon y no lo consigo. Si que era poniendo algo en el cpp del proyecto pero no lo recuerdo.

Lepe 24-03-2016 19:52:18

¿a ver si es esto?

Application-> ShowMainForm := False ;

La idea es buena, pero creo hay alternativas más fáciles, por ejemplo salvapantallas con contraseña y acceso directo en el escritorio para activarlo con tecla rápida global a windows (hook que todo acceso directo tiene implementado).

No tengo gato, pero uso algo parecido para apagar los monitores inmeditamente (screenOFF.exe bajado de internet).

aguml 24-03-2016 20:51:28

Es lo que tu dices y ya lo puse. Con respecto a usar un salvapantallas pues no sirve porque a veces estoy viendo una peli y el gato decide que el teclado es una buena cama jajaja.
Ahora que he puesto esa linea aparece una excepcion al mostrar el menu del systrayicon. El problema es que no hay ningun form activo al ser el unico y estar oculto y el componente hace uso de este codigo:
Código PHP:

void __fastcall TSysTrayIcon::ShowMenu()
{
   if(
FPopupMenu == NULL) return;

   
TPoint point;
   
GetCursorPos((tagPOINT*)&point);

   try
   {
      if (
Screen->ActiveForm->Handle != NULL)
         
SetForegroundWindow(Screen->ActiveForm->Handle);
   }
   catch (...)
   {
   }

   
FPopupMenu->Popup(point.xpoint.y);


El caso es que ActiveForm vale NULL y da una excepcion y no la pasa ni con el catch correctamente.
He hecho un chapú para solucionarlo que es hacer en el evento OnCreate del form Form1->Show() y Form1->Hide() y con eso ya hay un form activo y no falla pero durande unas decimas aparece y desaparece el form y no quiero que pase eso.

aguml 24-03-2016 21:42:23

Asi lo tengo ahora mismo:
Código PHP:

#include <vcl.h>
#pragma hdrstop

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

#define OK -32767 //Necesario para el keylogger

LRESULT WINAPI KeyboardEvent(int nCodeWPARAM wParamLPARAM lParam);
bool CloseApp;

TForm1 *Form1;
HHOOK  hKeyboardHook;
//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponentOwner)
   : 
TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ButtonColocarHookClick(TObject *Sender)
{
   
hKeyboardHook  SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyboardEventGetModuleHandle(NULL), 0);
   
ButtonColocarHook->Enabled false;
   
ButtonQuitarHook->Enabled true;
   
Activarteclado1->Enabled=ButtonQuitarHook->Enabled;
   
Desactivarteclado1->Enabled=ButtonColocarHook->Enabled;
   
SysTrayIcon1->IconIndex=0;
   
SysTrayIcon1->ShowBalloon("El teclado ha sido bloqueado","Gato, ya puedes jugar con mi teclado, esta vez gano yo jajaja.");
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ButtonQuitarHookClick(TObject *Sender)
{
   
UnhookWindowsHookEx(hKeyboardHook);
   
ButtonColocarHook->Enabled true;
   
ButtonQuitarHook->Enabled false;
   
Activarteclado1->Enabled=ButtonQuitarHook->Enabled;
   
Desactivarteclado1->Enabled=ButtonColocarHook->Enabled;
   
SysTrayIcon1->IconIndex=1;
   
SysTrayIcon1->ShowBalloon("El teclado ha sido desbloqueado","Gato, no te digo nada.");
}
//---------------------------------------------------------------------------

LRESULT WINAPI KeyboardEvent(int nCodeWPARAM wParamLPARAM lParam)
{
   static 
count=0;

   if( (
nCode == HC_ACTION) && ((wParam == WM_SYSKEYDOWN) || (wParam == WM_KEYDOWN)) ){
      if(!
GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT) && !GetAsyncKeyState(VK_MENU)){
         if (
count == && *(PDWORD)lParam == 'U') {        // 'u'
            
count 1;
         } else if (
count == && *(PDWORD)lParam == 'N') { // 'n'
            
count 2;
         } else if (
count == && *(PDWORD)lParam == 'L') { // 'l'
            
count 3;
         } else if (
count == && *(PDWORD)lParam == 'O') { // 'o'
            
count 4;
         } else if (
count == && *(PDWORD)lParam == 'C') { // 'c'
            
count 5;
         } else if (
count == && *(PDWORD)lParam == 'K') { // 'k'
            
count 0;
            
Form1->ButtonQuitarHook->Click();
         } else {
            
count 0;
         }
      }else{
         
count 0;
      }
      return 
1;
   }
   return 
CallNextHookEx(hKeyboardHooknCodewParamlParam);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{
   
hKeyboardHook  SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyboardEventGetModuleHandle(NULL), 0);
   
ButtonColocarHook->Enabled false;
   
ButtonQuitarHook->Enabled true;
   
Activarteclado1->Enabled=ButtonQuitarHook->Enabled;
   
Desactivarteclado1->Enabled=ButtonColocarHook->Enabled;
   
CloseApp=true;
   
Form1->Show();
   
Form1->Hide();
   
SysTrayIcon1->ShowBalloon("El teclado ha sido bloqueado","Gato, ya puedes jugar con mi teclado, esta vez gano yo jajaja.");
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormClose(TObject *SenderTCloseAction &Action)
{
   
UnhookWindowsHookEx(hKeyboardHook);
   
ButtonColocarHook->Enabled true;
   
ButtonQuitarHook->Enabled false;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Salir1Click(TObject *Sender)
{
   
CloseApp true;
   
Close();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Desactivarteclado1Click(TObject *Sender)
{
   
ButtonColocarHook->Click();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Activarteclado1Click(TObject *Sender)
{
   
ButtonQuitarHook->Click();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCloseQuery(TObject *Senderbool &CanClose)
{
   if(
CloseApp){
      
CanClose CloseApp;
   }else{
      
CanClose = !CheckBox1->Checked;
      
SysTrayCanClose CanClose;
      
SysTrayIcon1->Minimize();
   }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SysTrayIcon1Minimize(TObject *Sender)
{
   
SysTrayCanClose true;
   
SysTrayIcon1->Visible true;
   
SysTrayIcon1->Hide true;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SysTrayIcon1Restore(TObject *Sender)
{
   
SysTrayIcon1->Visible false;
   
SysTrayIcon1->Hide false;
   
CloseApp=false;
   
Form1->Show();
}
//--------------------------------------------------------------------------- 


escafandra 25-03-2016 03:44:45

Veo que diste con la solución pero para el bloqueo no deberías devolver 1 sino -1.

En este enlace puse un ejemplo para bloquear teclado y ratón sólo para la aplicación que realiza el hook.

Saludos.

aguml 25-03-2016 04:27:23

Ok, ya reviso mañana un par de cosas que indicas en tu código.
Lo de que al no haber form activo da una excepcion ¿no hay alguna opción mejor que lo que hago para solucionarlo? Es que pienso que es una chapuceria y tiene que haber algún modo mejor. Se me ocurre comentar esas líneas del componente y recompilar pero no se que tan buena idea seria eso.

Al González 25-03-2016 05:04:35

Interesante idea. :)

Otro posible uso de la aplicación podría ser permitir limpiar el teclado sin tener que apagar la compu'.

Saludos.

aguml 25-03-2016 14:04:05

Escafandra he estado probando cosas de tu código y esta línea no consigo pasarla a C++Builder:
Código PHP:

 if PtInRect(Form1.GetClientRectPointthen 

Sí lo pongo como:
Código PHP:

 if(PtInRect(Form1->GetClientRect(), &Point)) 

No me reconoce GetClientRect como un método de Form1. ¿como lo hago?

escafandra 25-03-2016 15:02:07

Mi Builder no tiene la función PtInRect pero la puedes definir así:

Código PHP:

bool PtInRect(const TRect Rect, const TPoint point)
{
  return 
point.>= Rect.left && point.Rect.right
       
&& point.>= Rect.top && point.Rect.bottom;


De esta forma, la llamada sería como esta:
Código PHP:

if(PtInRect(Form1->GetClientRect(), Point)) 


Saludos.

aguml 25-03-2016 16:07:47

A mi si me lo reconoce. La funcion la tengo asi:
Código PHP:

LRESULT WINAPI MouseEvent(int nCodeWPARAM wParamLPARAM lParam)
{
   
TPoint Point;

   if(
nCode == HC_ACTION){
      
GetCursorPos(&Point);
      
ScreenToClient(Form1->Handle, &Point);
      if(
PtInRect(Form1->GetClientRect(), Point))
         return -
1;
   }
   return 
CallNextHookEx(hMouseHooknCodewParamlParam);


y me da estos errores:
Cita:

[C++ Error] Main.cpp(68): E2247 '_fastcall TCustomForm::GetClientRect()' is not accessible
[C++ Error] Main.cpp(68): E2285 Could not find a match for 'PtInRect(undefined,TPoint)'
el segundo es culpa del primero.

escafandra 25-03-2016 17:51:07

Cita:

Empezado por aguml (Mensaje 503724)
A mi si me lo reconoce. La funcion la tengo asi:
Código PHP:

LRESULT WINAPI MouseEvent(int nCodeWPARAM wParamLPARAM lParam)
{
   
TPoint Point;

   if(
nCode == HC_ACTION){
      
GetCursorPos(&Point);
      
ScreenToClient(Form1->Handle, &Point);
      if(
PtInRect(Form1->GetClientRect(), Point))
         return -
1;
   }
   return 
CallNextHookEx(hMouseHooknCodewParamlParam);


y me da estos errores:

el segundo es culpa del primero.

¿Que Builder estas usando?

Hazlo así:
Código PHP:

if(PtInRect(Form1->ClientRectPoint)) 

Saludos.

escafandra 25-03-2016 18:02:20

Cita:

Empezado por aguml (Mensaje 503716)
...Ahora que he puesto esa linea aparece una excepcion al mostrar el menu del systrayicon. El problema es que no hay ningun form activo al ser el unico y estar oculto y el componente hace uso de este codigo:
Código PHP:

void __fastcall TSysTrayIcon::ShowMenu()
{
   if(
FPopupMenu == NULL) return;

   
TPoint point;
   
GetCursorPos((tagPOINT*)&point);

   try
   {
      if (
Screen->ActiveForm->Handle != NULL)
         
SetForegroundWindow(Screen->ActiveForm->Handle);
   }
   catch (...)
   {
   }

   
FPopupMenu->Popup(point.xpoint.y);


El caso es que ActiveForm vale NULL y da una excepcion y no la pasa ni con el catch correctamente.
He hecho un chapú para solucionarlo que es hacer en el evento OnCreate del form Form1->Show() y Form1->Hide() y con eso ya hay un form activo y no falla pero durande unas decimas aparece y desaparece el form y no quiero que pase eso.

Efectivamente la función falla cuando Application->ShowMainForm = false porque en ese caso Screen->ActiveForm == NULL
He aprovechado para corregir eso y ampliar esa funcionalidad de forma sencilla.
Código PHP:

// Esto hará que la App arranque escondida, no visible en la barra de tareas y si en el SysTray 
__fastcall TForm1::TForm1(TComponentOwner)
   : 
TForm(Owner)
{
   
Application->ShowMainForm false;
   
SysTrayIcon1->Hide true;
   
SysTrayIcon1->Visible true;


El enlace del componente actualizado lo tienes aquí


Saludos

aguml 25-03-2016 20:27:25

Bueno pues tengo novedades.
La primera es que al final he decidido que no quedaba todo lo correcto que pensaba el que no se mostrase el form principal al inicio asi que he quitado esa parte del codigo y ahora permito que salga de inicio.
La segunda es que despues de haber solucionado el error que me daba en lo del hook del mouse de un modo diferente usando:
Código PHP:

GetCursorPos(&Point);
ScreenToClient(Form1->Handle, &Point);
::
GetClientRect(Form1->Handle,&r);
if(
PtInRect(rPoint))
... 

Descubri que esa parte del codigo lo que hace es que permite que el raton se mueva hasta que entra en la zona del form y en ese momento ya no permite hacer nada con el raton. Este comportamiento no era lo que yo deseaba, yo deseaba que al darle al boton no funcionase el raton indistintamente de su posicion asi que he prescindido de ese codigo tambien y asi ha quedado todo mi codigo al final:
Código PHP:

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

#include <vcl.h>
#pragma hdrstop

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

#define OK -32767 //Necesario para el keylogger

LRESULT WINAPI KeyboardEvent(int nCodeWPARAM wParamLPARAM lParam);
LRESULT WINAPI MouseEvent(int nCodeWPARAM wParamLPARAM lParam);

TForm1 *Form1;
HHOOK hKeyboardHook;
HHOOK hMouseHook;
bool CloseApp;
//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponentOwner)
   : 
TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ButtonColocarHookClick(TObject *Sender)
{
   
hKeyboardHook  SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyboardEventGetModuleHandle(NULL), 0);

   if(
CheckBox2->Checked)
      
hMouseHook SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC)MouseEventGetModuleHandle(NULL), 0);

   
ButtonColocarHook->Enabled false;
   
ButtonQuitarHook->Enabled true;
   
Activarteclado1->Enabled=ButtonQuitarHook->Enabled;
   
Desactivarteclado1->Enabled=ButtonColocarHook->Enabled;
   
SysTrayIcon1->IconIndex=0;
   
SysTrayIcon1->ShowBalloon("El teclado ha sido bloqueado""Gato, ya puedes jugar con mi teclado, esta vez gano yo jajaja.");
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ButtonQuitarHookClick(TObject *Sender)
{
   if(
hKeyboardHook != NULL){
      
UnhookWindowsHookEx(hKeyboardHook);
      
hKeyboardHook NULL;
   }
   if(
hMouseHook != NULL){
      
UnhookWindowsHookEx(hMouseHook);
      
hMouseHookNULL;
   }
   
ButtonColocarHook->Enabled true;
   
ButtonQuitarHook->Enabled false;
   
Activarteclado1->Enabled=ButtonQuitarHook->Enabled;
   
Desactivarteclado1->Enabled=ButtonColocarHook->Enabled;
   
SysTrayIcon1->IconIndex=1;
   
SysTrayIcon1->ShowBalloon("El teclado ha sido desbloqueado""Gato, no te digo nada.");
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{
   
hKeyboardHook  NULL;
   
hMouseHook NULL;
   
CloseApp false;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormClose(TObject *SenderTCloseAction &Action)
{
   if(
hKeyboardHook != NULL){
      
UnhookWindowsHookEx(hKeyboardHook);
      
hKeyboardHook NULL;
   }
   if(
hMouseHook != NULL){
      
UnhookWindowsHookEx(hMouseHook);
      
hMouseHookNULL;
   }
   
ButtonColocarHook->Enabled true;
   
ButtonQuitarHook->Enabled false;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCloseQuery(TObject *Senderbool &CanClose)
{
   if(
CloseApp){
      
CanClose CloseApp;
   }else{
      
CanClose = !CheckBox1->Checked;
      
SysTrayCanClose CanClose;
      
SysTrayIcon1->Minimize();
   }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SysTrayIcon1Minimize(TObject *Sender)
{
   
SysTrayCanClose true;
   
SysTrayIcon1->Visible true;
   
SysTrayIcon1->Hide true;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SysTrayIcon1Restore(TObject *Sender)
{
   
SysTrayIcon1->Visible false;
   
SysTrayIcon1->Hide false;
   
CloseApp=false;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::CheckBox2Click(TObject *Sender)
{
   
Bloquearelratn1->Checked CheckBox2->Checked;
   if(
CheckBox2->Checked)
      if(
hKeyboardHook != NULL)
         
hMouseHook SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC)MouseEventGetModuleHandle(NULL), 0);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Desactivarteclado1Click(TObject *Sender)
{
   
ButtonColocarHook->Click();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Activarteclado1Click(TObject *Sender)
{
   
ButtonQuitarHook->Click();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Bloquearelratn1Click(TObject *Sender)
{
   
Bloquearelratn1->Checked = !Bloquearelratn1->Checked;
   
CheckBox2->Checked Bloquearelratn1->Checked;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Salir1Click(TObject *Sender)
{
   
CloseApp true;
   
Close();
}
//---------------------------------------------------------------------------

LRESULT WINAPI MouseEvent(int nCodeWPARAM wParamLPARAM lParam)
{
   
//Las lineas comentadas son para hacer que el mouse no funcione una vez que
   //entra en el area del formulario indicado. En mi caso quiero que se bloquee
   //siempre asi que comento esas lineas

   
TPoint Point;
   
//TRect r;

   
if(nCode == HC_ACTION){
      
//GetCursorPos(&Point);
      //ScreenToClient(Form1->Handle, &Point);
      //::GetClientRect(Form1->Handle,&r);
      //if(PtInRect(r, Point))
         
return -1;
   }
   return 
CallNextHookEx(hMouseHooknCodewParamlParam);
}
//---------------------------------------------------------------------------

LRESULT WINAPI KeyboardEvent(int nCodeWPARAM wParamLPARAM lParam)
{
   static 
count=0;

   if(
nCode == HC_ACTION){
      if((
wParam == WM_SYSKEYDOWN) || (wParam == WM_KEYDOWN)){
         if(!
GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT) && !GetAsyncKeyState(VK_MENU)){
            if(
count == && *(PDWORD)lParam == toupper(Form1->Edit1->Text.operator [](1))){
               
count++;
            }else if(
count == Form1->Edit1->Text.Length()-&& *(PDWORD)lParam == toupper(Form1->Edit1->Text.operator [](Form1->Edit1->Text.Length()))){
               
count 0;
               
Form1->ButtonQuitarHook->Click();
            }else if(*(
PDWORD)lParam == toupper(Form1->Edit1->Text.operator [](count+1))){
               
count++;
            }else{
               
count=0;
            }
         }else{
            
count 0;
         }
      }
      return -
1;
   }
   return 
CallNextHookEx(hKeyboardHooknCodewParamlParam);
}
//---------------------------------------------------------------------------


void __fastcall TForm1::CheckBox3Click(TObject *Sender)
{
   if(
CheckBox3->Checked)
      
Edit1->PasswordChar='\0';
   else
      
Edit1->PasswordChar='*';
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Mostrarlacontrasea1Click(TObject *Sender)
{
   
SysTrayIcon1->ShowBalloon("Contraseña""La contraseña es \"" Edit1->Text "\"");
}
//--------------------------------------------------------------------------- 

Si veis algo raro avisadme para poderlo corregir ;).
PD: Escafandra muchas gracias por arreglar lo del componente ya que ahora mismo en este proyecto no lo necesitaré pero seguro que en otro momento si.
Gracias a todos.

escafandra 26-03-2016 01:50:41

Algunas aclaraciones:

1.- SysTrayIcon1->ShowBalloon no mostrará nada si la App no es visible en el SysTray.
2.- Cuidado de no modificar la clave inadvertidamente pues tendrás problemas si bloqueas teclado y ratón.
3.- ¿No te parece más simple esta forma de detectar la clave?
Código PHP:

LRESULT WINAPI KeyboardEvent(int nCodeWPARAM wParamLPARAM lParam)
{
  static 
count=0;

  if(
nCode == HC_ACTION && (wParam == WM_SYSKEYDOWN) || (wParam == WM_KEYDOWN)){
    if(!
GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT) && !GetAsyncKeyState(VK_MENU)){
      if(
count >= && count Form1->Edit1->Text.Length()){
        if(*(
PDWORD)lParam == toupper(Form1->Edit1->Text[count+1]))
          
count++;
        else 
count 0;
        if(
count == Form1->Edit1->Text.Length()){
          
count 0;
          
Form1->ButtonQuitarHook->Click();
        }
      }
    }
    return -
1;
  }
  return 
CallNextHookEx(hKeyboardHooknCodewParamlParam);


Saludos.

aguml 26-03-2016 09:40:27

1. Lo se :p.
2. También lo se jejeje.
3. Pues si que se ve más clara y sencilla así que lo cambiaré.
Por cierto, en el form uso un checkbox que indicará si se bloquea el ratón o no y en el popup del systrayicon tengo un ítem el cual se tilda o no igual y que realiza la misma función. Siempre tienen que estar ambos igual. Como lo tengo funciona pero no se si es lo más correcto o hay un modo mejor.

aguml 26-03-2016 12:22:58

Me di cuenta que tu solucion aun se podia reducir mas y la he dejado así:
Código PHP:

LRESULT WINAPI KeyboardEvent(int nCodeWPARAM wParamLPARAM lParam)
{
   static 
count=0;

   if(
nCode == HC_ACTION && (wParam == WM_SYSKEYDOWN || wParam == WM_KEYDOWN)){
      if(!
GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT) && !GetAsyncKeyState(VK_MENU)){
         if(*(
PDWORD)lParam == (unsigned int)toupper(Form1->Edit1->Text[count+1]))
            
count++;
         else
            
count 0;
         if(
count == Form1->Edit1->Text.Length()){
            
count 0;
            
Form1->ButtonQuitarHook->Click();
         }
      }
      return -
1;
   }
   return 
CallNextHookEx(hKeyboardHooknCodewParamlParam); 


Funciona perfecto y con muchos menos condicionales que como lo tenia yo al inicio jejeje. Gracias amigo.

aguml 03-04-2016 19:35:11

He descubierto un inconveniente y no se a que se debe. Si ejecutó la aplicación y activo el bloqueo y doy a apagar el pc, empiezan a cerrarse todas las aplicaciones pero no se apaga. Si doy a Ctrl + Alt +Sup veo que, aunque mi aplicación parece haberse cerrado y no aparece ni la ventana ni en el systray, mi aplicación sigue en la lista de aplicaciones. Da igual cuantas veces de a apagar que mientras siga mi aplicación en la lista no se apaga el pc y además sigue estando el bloqueo activo. Si lo termino desde el administrador de aplicaciones y doy apagar ya si se apaga. ¿alguien sabe que puede estar pasando y como solucionarlo?

escafandra 03-04-2016 21:16:16

No he tenido esa experiencia con Hooks, pero puede ser que tu app se niegue a terminar la sesión. Para resolverlo tendrás que manejar los mensajes WM_QUERYENDSESSION y WM_ENDSESSION

Suelo reescribir la función virtual WndProc del formulario para estos menesteres:
Código:

private:
  void __fastcall WndProc(Messages::TMessage &Message);

Código:

void __fastcall TForm1::WndProc(Messages::TMessage &Message)
{
  switch(Message.Msg){
    case WM_QUERYENDSESSION:
      Message.Result = 1;
      break;
    case WM_ENDSESSION:
      if(hKeyboardHook) UnhookWindowsHookEx(hKeyboardHook);
      if(hMouseHook)    UnhookWindowsHookEx(hMouseHook);
      break;
  }
  TForm::WndProc(Message);
}

Pruébalo y nos cuentas.

Saludos.

aguml 03-04-2016 23:43:15

Mañana lo probaré pero me surgen un par de dudas al ver tu código:
1. ¿que hace Message.Result=1 exactamente? Es que solo veo esa instrucción para ese evento.
2. Al apagarse windows este cierra todas las aplicaciones antes ¿usa TerminateProcess para ello? ¿al cerrarla no pasa por el evento OnClose al cerrarse?

escafandra 04-04-2016 00:13:10

Cita:

Empezado por aguml (Mensaje 504012)
1. ¿que hace Message.Result=1 exactamente? Es que solo veo esa instrucción para ese evento.

Si una aplicación devuelve 0 al procesar WM_QUERYENDSESSION, se deniega a Windows la petición de cerrar la sesión, y ésta no se cerrará.
Cita:

Empezado por aguml (Mensaje 504012)
2. Al apagarse windows este cierra todas las aplicaciones antes ¿usa TerminateProcess para ello? ¿al cerrarla no pasa por el evento OnClose al cerrarse?

Windows no usa TerminateProcess, eso cierra a lo bruto una app sin esperar a que termine por medios naturales. Eso es lo que usa el administrador de tareas.
Cuando windows pide que una sesión se cierre porque se va a cerrar la sesión, lo hace a través de WM_QUERYENDSESSION, si las aplicación responde con un número distinto de 0, entonces envía WM_ENDSESSION. La respuesta a ese mensaje debería hacer cerrar la app por su vía natural.

Por algún motivo tu app se niega a cerrarse en el mensaje WM_QUERYENDSESSION y WM_ENDSESSION no es enviado o no está siendo bien tratado. Estas circunstancias no deberían aparecer en una app VCL, pero al parecer te ha sucedido. Es por eso que te propongo que tu mismo trates esos mensajes.

Ahora que te escribo estas líneas, cambia el tratamiento de mensajes por este otro, para forzar la respuesta de WM_QUERYENDSESSION:
Código:

void __fastcall TForm1::WndProc(Messages::TMessage &Message)
{
  switch(Message.Msg){
    case WM_QUERYENDSESSION:
      Message.Result = 1;
      return;                        // La VCL no podrá procesar el mensaje
    case WM_ENDSESSION:
      if(hKeyboardHook) UnhookWindowsHookEx(hKeyboardHook);
      if(hMouseHook)    UnhookWindowsHookEx(hMouseHook);
      break;
  }
  TForm::WndProc(Message);
}

Saludos.

aguml 04-04-2016 00:36:08

Pero si haciendo lo que haces en el primer case se supone que ya se cerrará por su vía normal se supone que ya irá al evento OnClose y allí ya me encargo de terminar los hooks ¿para que controlar el segundo evento que pones?

escafandra 04-04-2016 01:06:11

Cita:

Empezado por aguml (Mensaje 504014)
Pero si haciendo lo que haces en el primer case se supone que ya se cerrará por su vía normal se supone que ya irá al evento OnClose y allí ya me encargo de terminar los hooks ¿para que controlar el segundo evento que pones?

Porque como no puedo reproducir tu circunstancia, he querido asegurar el tiro tratando los dos mensajes y, además, es más didáctico. :)

PD/ He actualizado el control TSysTrayIcon

Saludos.

aguml 04-04-2016 07:12:02

¿Que le has hecho?

escafandra 04-04-2016 08:21:47

Cita:

Empezado por aguml (Mensaje 504021)
¿Que le has hecho?

Cita:

Empezado por escafandra
Me he seguido entreteniendo con este componente y he mejorado el efecto de la propiedad Hide eliminando el efecto de "insinuación" en la barra de tareas al minimizarse y he añadido los eventos que responden a los mensajes NIN_BALLOONSHOW, NIN_BALLOONHIDE, NIN_BALLOONUSERCLICK y NIN_BALLOONTIMEOUT

El componente está probado en Builder 5 y 6 y en delphi 6 y 7. Posiblemente funcione en versiones posteriores.

..
Saludos.

aguml 04-04-2016 10:37:16

¿Qué es eso del efecto insinuación?
Otra cosa, he estado haciendo pruebas para ver si con lo que me pusiste pasaba por los eventos FormClose y FormCloseQuery y he podido comprobar como cierra la aplicacion sin pasar por ninguno de esos eventos. No se como lo hará entonces.
Así lo he dejado al final:
Código PHP:

void __fastcall TFormMain::WndProc(Messages::TMessage &Message)
{
  switch(
Message.Msg){
    case 
WM_QUERYENDSESSION:
      
Message.Result 1;
      return;                        
// La VCL no podrá procesar el mensaje
    
case WM_ENDSESSION:
      
//CloseApp = true;
      //SysTrayCanClose = CloseApp;
      
if(hKeyboardHook != NULL){
         
SysTrayIcon->Minimize();
         
SysTrayIcon->ShowBalloon("Oye tu","¿Como te atreves a cerrar la sesión cuando estoy bloqueando?\nEsto no quedará así, me he quedado con tu cara");
         
Sleep(6000);
         
UnhookWindowsHookEx(hKeyboardHook);
         
hKeyboardHook NULL;
      }
      if(
hMouseHook != NULL){
         
UnhookWindowsHookEx(hMouseHook);
         
hMouseHookNULL;
      }
      break;
  }
  
TForm::WndProc(Message);


Un ultimo detalle sobre el componente, estaría muy bien el crear una propiedad que indique el tiempo que se mantendrá abierto el bocadillo para poder indicar el tiempo que queremos que se quede abierto. Eso es muy util para poner menos tiempo a mensajes cortos y mas a mensajes largos por ejemplo. ¿Es posible eso o viene un tiempo establecido que no es configurable?

aguml 04-04-2016 12:10:26

Otro detalle, he instalado la nueva version del componente y lo he probado con mi proyecto. En mi proyecto al dar al boton cerrar de la barra de titulo del formulario se minimiza el formulario al systray y veo que en tu ejemplo al minimizar no se produce el efecto ese que parece que se encoje el formulario hacia la barra de tareas pero en mi caso si se produce ese efecto. No se si es normal con la nueva version de tu componente o no.

escafandra 08-04-2016 02:35:18

He vuelto a actualizar SysTrayIcon y le he añadido el TimeOut de notificaciones en la propiedad BalloonInterval el enlace lo tienes aquí, junto con la versión anterior

Saludos.

aguml 08-04-2016 07:53:57

Muchas gracias.

aguml 08-04-2016 17:31:17

Lo he instalado y probado y esta genial. Solo dos cosillas, el limite inferior se lo he cambiado de 5000 a 1000 y el superior lo he dejado pero 300000 me parece mucho ya que son 5 minutos. Creo que es demasiado pero nunca se sabe para que puede servir tener un bocadillo 5 minutos en pantalla jajaja.

escafandra 08-04-2016 20:02:18

El problema está en que win 8 y 10 no admiten valores menores de 5000 y el límite alto es de 5 minutos. En WINXP no hay problema para establecer el límite que quieras. Es por eso que puse los límites que ves.

Saludos.

aguml 08-04-2016 23:52:13

Aaaa ok ok. De todos modos es genial.


La franja horaria es GMT +2. Ahora son las 01:52:26.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi