How to catch and change EVERY(!) key

Just starting out? Need help? Post your questions and find answers here.
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by GPI.

Is it possible to get the pressed key of every programm and check and modified it, that the active applikation thinks, that an other key is pressed?

For example, i press F1 and the Programm think, i pressed F2.

Why do i need this?

I had bought a keyboard with special keys. One problem is, that the f-keys are also used for special command (open e-mail, etc). The problem is, that this f-key are default with the special commands. I say, that the special-commands are ignored, but not for f5-f8. So i want to write a programm, that can redefinied the keys.

PII 333, 256MB, Asus TNT2Ultra 32MB, AWE Gold 64 4MB
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by DemonHell.
Originally posted by GPI

Is it possible to get the pressed key of every programm and check and modified it, that the active applikation thinks, that an other key is pressed?
Yup, I did something similar a while back...wrote my own keyboard handler to take care of the "multimedia keys" on the keyboard to control winamp instead of the stupid media player built into the keyboard driver !

To catch keypresses you have to create a callback procedure within a separate DLL. Otherwise you`ll only get keypresses when your apps window has focus :(

I`ll have a root about for the source code later (must remember to label my backup CD`s !)
But simply put, you get the keycode as a parameter in the callback function, examine it..change it if needed, then pass that on to the default window callback procedure so other apps can access it.
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by GPI.

Please send you code, i don't understand, what do you have done.

GPI

PII 333, 256MB, Asus TNT2Ultra 32MB, AWE Gold 64 4MB
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by DemonHell.


OK.. the first code is the DLL keysnooping code.
(compiled as "dnkbd.dll")

Code: Select all

Global hHook.l,msgwnd.l
hHook.l=0
msgwnd.l=0

Procedure.l Keylog(idHook.l,wParam.l,lParam.l)
Shared msgwnd.l
 If msgwnd=0
  msgwnd=findwindowex_(0,0,"STATIC","DnKBD")
 EndIf

 If (idHook>=0)And (wParam=255)
   kc.l=(lparam & $00FF0000)>>16
   kw.l=((lparam & $FF000000)>>24)
   postmessage_(msgwnd,#WM_USER+28,kw,kc)
   ProcedureReturn 0
 EndIf

 ProcedureReturn CallNextHookEx_(hHook,idHook,wParam,lParam)
EndProcedure 

ProcedureDLL.l Init(DLLMod.l,hwnd.l)
 msgwnd.l=hwnd.l
 If hHook0
  messagebox_(0,"Hook already installed","ERROR",#MB_OK)
  unhookwindowshookex_(hHook)
 EndIf
 
 hHook.l=SetWindowsHookEx_(#WH_KEYBOARD,@Keylog(),DLLMod,0)
 If hHook=0
  messagebox_(0,"HOOK INIT ERROR","ERROR",#MB_OK)
 EndIf
 ProcedureReturn hHook
EndProcedure

ProcedureDLL Unhook(hHook)
 If hHook0
  UnHookWindowsHookEx_(hHook)
 EndIf
EndProcedure
The next bit is snipped from a very long source, but should give you
a good idea of what I was doing..

Code: Select all

Procedure.l TRAYPROC(hwnd.l,message.l,wParam.l,lParam.l)
 If (message=#WM_USER+28)
  ;## Just to see what keycodes were pressed
  ;## Just do a Select/Case/EndSelect loop to filter and change
  Debug str(wParam)+" "+str(lParam) 

 Endif
 ProcedureReturn CallWindowProc_(oldProc,hwnd,message,wParam,lParam)
EndProcedure

ol.l= OpenLibrary(0,"dnkbd.dll")

If ol=0
 messagebox_(0,"Couldnt find dnkbd.dll","ERROR",#MB_OK)
 End
EndIf

If (IsFunction(0,"_Init")=0)
 messagebox_(0,"Bad dnkbd.dll","ERROR",#MB_OK)
 Closelibrary(0)
 End 
EndIf

MyHwnd.l=createwindowex_(0,"STATIC",appname$,0,0,0,0,0,0,0,0,0)
oldProc.l=GetWindowLong_(MyHwnd,#GWL_WNDPROC)
SetWindowLong_(MyHwnd,#GWL_WNDPROC,@TRAYPROC())
KBD_Hook.l=CallFunction(0,"_Init",ol,MyHwnd)

Repeat
 waitmessage_()
Forever
Maybe the entire filtering/code changing code could be moved inside the DLL ..I just used sendmessage_() so I could debug more easily!
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by GPI.

Dont work right. I get only message, when the programm-window is active, not global for all programms.

my prg:

Code: Select all

Global scan 
Global hookid 

ProcedureDLL hook(w1,w2,w3) 
 scan=w3>>16&$ff 
 
 ProcedureReturn CallNextHookEx_(hookid,w1,w2,w3) 
EndProcedure 

ProcedureDLL sethookid(x) 
 hookid=x 
EndProcedure 
ProcedureDLL doit() 
 ss=scan:scan=0 
 ProcedureReturn ss 
EndProcedure 

ProcedureDLL AttachProcess(Instance) 
EndProcedure 

ProcedureDLL DetachProcess(Instance) 
EndProcedure 

ProcedureDLL AttachThread(Instance) 
EndProcedure 

ProcedureDLL DetachThread(Instance) 
EndProcedure
main-prg

Code: Select all

Global hookid 
Global hook_hmod 
hook_hmod=OpenLibrary(0, "C:\Programme\PureBasic\Compilers\purebasic.dll") 


Procedure dehook() 
 If hookid 
  UnhookWindowsHookEx_(hookid) 
 EndIf 
EndProcedure 
Procedure inithook(ins,thr) 
 dehook() 
 ;hookid=SetWindowsHookEx_(#WH_GETMESSAGE,IsFunction(0,"hook"),ins,thr) 
 hookid=SetWindowsHookEx_(#WH_Keyboard,IsFunction(0,"hook"),ins,thr) 
 CallFunction(0,"sethookid",hookid) 
 ProcedureReturn hookid 
EndProcedure 

 
If hook_hmod 
 hook=inithook(hook_hmod,0) 

 OpenWindow(0,0,400,320,240,#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget| #PB_Window_SizeGadget,"Test") 
 CreateGadgetList(WindowID(0)) 
 ListViewGadget(0,0,0,320,240) 

 If hookid 
  AddGadgetItem(0,0,"Hook install"+Hex(hookid)) 
 Else 
  AddGadgetItem(0,0,"Hook error") 
 EndIf  

 Repeat 
  scan=CallFunction(0,"doit") 
  ;Debug scan  
  If scan0 
   AddGadgetItem(0,0,"#down: " +Str(scan)) 
  EndIf 
 Until WindowEvent()=#pb_event_closewindow 
 
 dehook() 
 CloseLibrary(0) 
 CloseWindow(0) 
EndIf 


PII 333, 256MB, Asus TNT2Ultra 32MB, AWE Gold 64 4MB
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by DemonHell.
Originally posted by GPI

Dont work right. I get only message, when the programm-window is active, not global for all programms.
Oops, looking back at the source I scrapped together..I didn`t even call the Init function in the DLL ! But, looking at your source, I see you figured that for yourself :wink:

I`m not 100% sure about this, but it could be down the the way windows does its event handling. In my example, I sent a message to another procedure in the main program code.. that gets sent regardless of if the window has focus or not.
In your code, you don`t do the message, and rely on the CallNextHookEx_() to pass on the keypress to your program.
Maybe windows doesn`t bother to pass keypress events on to windows that aren`t active??
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by GPI.

I also test your solution with send message.

It make no diffrent.

Under what OS do you run your programm. Maybe this is the error.

PII 333, 256MB, Asus TNT2Ultra 32MB, AWE Gold 64 4MB
Post Reply