Page 1 of 1
Modify pointer hook directly
Posted: Fri Jan 27, 2023 9:43 pm
by Kwai chang caine
Hello at all
In a keyboard hook, when i use SendInput_() this API call a new time the hook
For not have this behavior, is it possible to modify the directly the CallNextHookEx_() in the hook rather using SendInput_()
I have try, but the character writing is not modified by a "R"
Code: Select all
#WH_KEYBOARD_LL = 13
Global Hook
Procedure KeyboardHook(nCode, wParam,lParam)
*keyInput.KBDLLHOOKSTRUCT = lParam
If wParam = #WM_KEYDOWN
*keyInput\vkCode = 82
*keyInput\scanCode = 13
Result = CallNextHookEx_(hook, nCode, wParam, *keyInput)
EndIf
ProcedureReturn Result
EndProcedure
OpenWindow(0, 0, 0, 350, 100, "")
hook = SetWindowsHookEx_(#WH_KEYBOARD_LL, @KeyboardHook(), GetModuleHandle_(0), 0)
Repeat : WaitWindowEvent(100) :Until GetAsyncKeyState_(#VK_ESCAPE)
Have a good day
Re: Modify pointer hook directly
Posted: Sat Jan 28, 2023 4:12 pm
by bgeraghty
I don't know the answer to the question about modifying the pointer specifically, but here is a basic little example that might help. What should happen, is the [Up] And [Down] Arrow Keys will be reversed! (Up=Down, Down=Up, etc.)
The key to it I found was to return a non-zero (1) when you need to disrupt the regular flow of that particular key and replace the action, see the comment in the callback.
Code: Select all
Global _KeyBd_Hook,Message.MSG
; Quickly Set All Modifier Keys To Up/Released
Macro ReleaseAllModifiers()
Dim ModKeys.INPUT(0)
Define R.i
ReDim ModKeys(12)
For R=0 To 11
ModKeys(R)\type=#INPUT_KEYBOARD
ModKeys(R)\ki\dwFlags=#KEYEVENTF_KEYUP
Select R
Case 00:ModKeys(R)\ki\wVk=#VK_SHIFT : Case 01:ModKeys(R)\ki\wVk=#VK_LSHIFT
Case 02:ModKeys(R)\ki\wVk=#VK_RSHIFT : Case 03:ModKeys(R)\ki\wVk=#VK_MENU
Case 04:ModKeys(R)\ki\wVk=#VK_LMENU : Case 05:ModKeys(R)\ki\wVk=#VK_RMENU
Case 06:ModKeys(R)\ki\wVk=#VK_CONTROL : Case 07:ModKeys(R)\ki\wVk=#VK_RCONTROL
Case 08:ModKeys(R)\ki\wVk=#VK_LCONTROL: Case 09:ModKeys(R)\ki\wVk=#VK_WIN
Case 10:ModKeys(R)\ki\wVk=#VK_LWIN : Case 11:ModKeys(R)\ki\wVk=#VK_RWIN
EndSelect
SendInput_(1,@ModKeys(R),SizeOf(INPUT))
Next
EndMacro
; Flag #KEYEVENTF_EXTENDEDKEY Required To Combine
; These Keys With Modifiers like CTRL,Shift,ALT,WIN:
;
; VK_PRIOR 0x21 PAGE UP key (vk 33)
; VK_NEXT 0x22 PAGE DOWN key (vk 34)
; VK_END 0x23 END key (vk 35)
; VK_HOME 0x24 HOME key (vk 36)
; VK_LEFT 0x25 LEFT ARROW key (vk 37)
; VK_UP 0x26 UP ARROW key (vk 38)
; VK_RIGHT 0x27 RIGHT ARROW key(vk 39)
; VK_DOWN 0x28 DOWN ARROW key (vk 40)
; VK_INSERT 0x2D INSERT key (vk 45)
; VK_DELETE 0x2E DELETE key (vk 46)
Macro setKeyUp(VKey)
Dim In_Key.INPUT(0):Dim In_Key(1):In_Key(0)\type=#INPUT_KEYBOARD : In_Key(0)\ki\wVk=vKey
Select vKey
Case #VK_PRIOR To #VK_DOWN, #VK_INSERT, #VK_DELETE:In_Key(0)\ki\dwFlags=#KEYEVENTF_KEYUP|#KEYEVENTF_EXTENDEDKEY
Default:In_Key(0)\ki\dwFlags=#KEYEVENTF_KEYUP
EndSelect
SendInput_(1,@In_Key(0),SizeOf(INPUT))
EndMacro
Macro setKeyDown(VKey)
Dim In_Key.INPUT(0):Dim In_Key(1):In_Key(0)\type=#INPUT_KEYBOARD : In_Key(0)\ki\wVk=vKey
Select vKey
Case #VK_PRIOR To #VK_DOWN, #VK_INSERT, #VK_DELETE:In_Key(0)\ki\dwFlags=#KEYEVENTF_EXTENDEDKEY
Default:In_Key(0)\ki\dwFlags=0
EndSelect
SendInput_(1,@In_Key(0),SizeOf(INPUT))
EndMacro
Macro doKeyPress(VKey)
setKeyDown(VKey):setKeyUp(VKey)
EndMacro
Procedure _HookCallBack(iCode, wParam, *hk.KBDLLHOOKSTRUCT)
Protected vKey=*hk\vkCode
Select wParam
Case #WM_KEYDOWN;:Debug Str(vKey)+" ▼"
Select vKey
Case #VK_UP
setKeyDown(#VK_DOWN); <- Replacement Action
ProcedureReturn 1 ; <- This prevents original key being passed on
Case #VK_DOWN
setKeyDown(#VK_UP)
ProcedureReturn 1
Default:
EndSelect
Case #WM_KEYUP;:Debug Str(vKey)+" ▲"
Select vKey
Case #VK_DOWN
setKeyUp(#VK_UP)
ProcedureReturn 1
Case #VK_UP
setKeyUp(#VK_DOWN)
ProcedureReturn 1
Default:
EndSelect
EndSelect
ProcedureReturn CallNextHookEx_(0,iCode,wParam,*hk)
EndProcedure
_KeyBd_Hook=SetWindowsHookEx_(#WH_KEYBOARD_LL, @_HookCallBack(), GetModuleHandle_(0), 0)
While GetMessage_(@Message, #Null, 0, 0)
TranslateMessage_(@Message) : DispatchMessage_(@Message)
Delay(1)
Wend
UnhookWindowsHookEx_(_Keybd_Hook)
Re: Modify pointer hook directly
Posted: Sat Jan 28, 2023 4:44 pm
by bgeraghty
P.S. Since this is swapping 2 keys back and fourth in a mirror, there is an issue of somewhat of a 'feedback loop' effect even if up or down are only pressed for a split-second:
Code: Select all
37 ▼
37 ▲
39 ▼
39 ▲
37 ▼
37 ▲
40 ▼
38 ▼
40 ▼
38 ▼
40 ▼
38 ▼
40 ▼
38 ▼
40 ▼
38 ▼
40 ▼
38 ▼
40 ▼
38 ▼
40 ▼
38 ▼
40 ▼
38 ▼
40 ▼
38 ▼
40 ▼
38 ▼
40 ▼
38 ▼
40 ▼
38 ▼
40 ▼
38 ▼
40 ▼
38 ▼
40 ▼
40 ▲
38 ▲
40 ▲
38 ▲
40 ▲
38 ▲
40 ▲
38 ▲
40 ▲
38 ▲
40 ▲
38 ▲
40 ▲
38 ▲
40 ▲
38 ▲
40 ▲
38 ▲
40 ▲
38 ▲
40 ▲
38 ▲
40 ▲
38 ▲
40 ▲
38 ▲
40 ▲
38 ▲
40 ▲
38 ▲
40 ▲
It still resolves to the correct keypress, but probably taxes the CPU. Needs mutex or something else to lock/unlock the state.
If you only want to replace one thing for something else, and not also the other way, this shouldn't happen.
Re: Modify pointer hook directly
Posted: Sat Jan 28, 2023 5:18 pm
by bgeraghty
Quick and Dirty fix to prevent the hook from calling the second time while swapping a key, could be better:
Code: Select all
Global SkipHook.b=#False
Procedure _HookCallBack(iCode, wParam, *hk.KBDLLHOOKSTRUCT)
If Not SkipHook
Protected vKey=*hk\vkCode
Select wParam
Case #WM_KEYDOWN:Debug Str(vKey)+" ▼"
Select vKey
Case #VK_UP:SkipHook=#True
setKeyDown(#VK_DOWN); <- Replacement Action
SkipHook=#False
ProcedureReturn 1 ; <- This prevents original key being passed on
Case #VK_DOWN:SkipHook=#True
setKeyDown(#VK_UP)
SkipHook=#False
ProcedureReturn 1
Default:
EndSelect
Case #WM_KEYUP:Debug Str(vKey)+" ▲"
Select vKey
Case #VK_DOWN
SkipHook=#True
setKeyUp(#VK_UP)
SkipHook=#False
ProcedureReturn 1
Case #VK_UP
SkipHook=#True
setKeyUp(#VK_DOWN)
SkipHook=#False
ProcedureReturn 1
Default:
EndSelect
EndSelect
EndIf
ProcedureReturn CallNextHookEx_(0,iCode,wParam,*hk)
EndProcedure
Re: Modify pointer hook directly
Posted: Sat Jan 28, 2023 5:43 pm
by Kwai chang caine
Hello bgeraghty
Thanks a lot for your great code, looks like an airplane cockpit

A little bit hard to understand for the neuronal KCC level

But it works...i see my down/up inversing
Apparently that answer at my first question about the keyboard, at the begining of the history
viewtopic.php?t=80597
The goal ?
Simply (i believed at the moment

) replace a key by another
Then i create in a file txt, an array of characters i want replace and just beside, the character for replacing ..it's all
For example :
I want replace
f by G
S by q
; by §
etc ....
in the file txt i write
fG
Sq
;§
etc ...
But the more difficult to do, it's the Lcase()/Ucase() management
I cannot replacing a lcase character by a ucase other character and the opposite
For the moment, all my codes give the same behavior
If the character for replacing is lcase, the replacer writing is Lcase too
And If the character for replacing is Ucase, the replacer writing is Ucase too
A real hell this apparently "Simple"
code i want to do 
Re: Modify pointer hook directly
Posted: Sat Jan 28, 2023 8:18 pm
by Mijikai
Hello Kwai chang caine & bgeraghty.
If you press lowercase
f the StringGadget will show a uppercase
G.
Code:
Code: Select all
EnableExplicit
Structure INPUT_STRUCT
type.i
StructureUnion
mi.MOUSEINPUT
ki.KEYBDINPUT
hi.HARDWAREINPUT
EndStructureUnion
EndStructure
Global hook_keyboard.i
Procedure.i hookKeyboardInject(Code.i,Flags.i,Shift.i)
Protected Dim in.INPUT_STRUCT(3)
in(1)\type = #INPUT_KEYBOARD
in(1)\ki\wVk = Code
in(1)\ki\wScan = MapVirtualKey_(Code,#MAPVK_VK_TO_VSC)
in(1)\ki\dwFlags = Flags
If Shift
in(0)\type = #INPUT_KEYBOARD
in(0)\ki\wVk = #VK_SHIFT
in(0)\ki\wScan = MapVirtualKey_(#VK_SHIFT,#MAPVK_VK_TO_VSC)
in(0)\ki\dwFlags = #Null
in(2) = in(0)
in(2)\ki\dwFlags = #KEYEVENTF_KEYUP
ProcedureReturn SendInput_(3,@in(0),SizeOf(INPUT_STRUCT))
EndIf
ProcedureReturn SendInput_(1,@in(1),SizeOf(INPUT_STRUCT))
EndProcedure
Procedure.i hookKeyboardProc(Code.i,Word.i,*Long.KBDLLHOOKSTRUCT)
Protected shift.i
Protected state.i
If Code = #HC_ACTION
shift = Bool(GetKeyState_(#VK_SHIFT) & $8000);<- is the shift key down?
state = Bool(Word = #WM_KEYUP Or Word = #WM_SYSKEYUP) * #KEYEVENTF_KEYUP;<- is it a keyup event (if so set state to #KEYEVENTF_KEYUP)
If *Long\flags & #LLKHF_INJECTED = 0;<- dont interfere with already injected keys
Select *Long\vkCode
Case #VK_F;<- check if 'f' was pressed
If Not shift;<- is it the lower case 'f' (aka. not shifted)
hookKeyboardInject(#VK_G,state,#True);<- inject a shifted 'G'
ProcedureReturn 1;<- dont process the intercepted key
EndIf
EndSelect
EndIf
EndIf
ProcedureReturn CallNextHookEx_(hook_keyboard,Code,Word,*Long)
EndProcedure
Procedure.i hookKeyboardInstall()
If hook_keyboard = #Null
hook_keyboard = SetWindowsHookEx_(#WH_KEYBOARD_LL,@hookKeyboardProc(),GetModuleHandle_(#Null),#Null)
EndIf
ProcedureReturn Bool(hook_keyboard <> #Null)
EndProcedure
Procedure.i hookKeyboardUninstall()
If hook_keyboard
UnhookWindowsHookEx_(hook_keyboard)
hook_keyboard = #Null
EndIf
ProcedureReturn #Null
EndProcedure
Procedure.i Main()
If hookKeyboardInstall()
If OpenWindow(0,0,0,320,200,#Null$,#PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_MinimizeGadget)
StringGadget(0,10,10,120,20,#Null$)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
EndSelect
ForEver
CloseWindow(0)
EndIf
hookKeyboardUninstall()
EndIf
ProcedureReturn #Null
EndProcedure
Main()
End
Re: Modify pointer hook directly
Posted: Sat Jan 28, 2023 8:35 pm
by Kwai chang caine
Waoouuuh !!!!
That's work very well !!!!
One thousand of thanks MIJIKAI for your amazing code
With all the works you already do for me, i dare not ask, how you would do to give the letter or the punctuation to replace and the one that replaces it in two variables

Because the more difficult for me, it's manage the SHIFT in the HOOK procedure
Like
Code: Select all
Procedure.i Main()
If hookKeyboardInstall()
SearchCharacter = "F"
ReplaceCharacter = "g"
If OpenWindow(0,0,0,320,200,#Null$,#PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_MinimizeGadget)
......
....
Re: Modify pointer hook directly
Posted: Sat Jan 28, 2023 9:08 pm
by Mijikai
Give this a try
Code: Select all
EnableExplicit
Structure INPUT_STRUCT
type.i
StructureUnion
mi.MOUSEINPUT
ki.KEYBDINPUT
hi.HARDWAREINPUT
EndStructureUnion
EndStructure
Structure KEYSHORT_STRUCT
vk.a
shift.a
EndStructure
Structure KEYSCAN_STRUCT
StructureUnion
code.u
short.KEYSHORT_STRUCT
EndStructureUnion
EndStructure
Structure KEYMAP_STRUCT
scan.KEYSCAN_STRUCT[2]
EndStructure
Global NewList hook_map.KEYMAP_STRUCT()
Global hook_keyboard.i
Procedure.i hookKeyboardInject(Code.i,Flags.i,Shift.i)
Protected Dim in.INPUT_STRUCT(3)
in(0)\type = #INPUT_KEYBOARD
in(0)\ki\wVk = #VK_SHIFT
in(0)\ki\wScan = MapVirtualKey_(#VK_SHIFT,#MAPVK_VK_TO_VSC)
in(0)\ki\dwFlags = #Null
in(1)\type = #INPUT_KEYBOARD
in(1)\ki\wVk = Code
in(1)\ki\wScan = MapVirtualKey_(Code,#MAPVK_VK_TO_VSC)
in(1)\ki\dwFlags = Flags
in(2) = in(0)
in(2)\ki\dwFlags = #KEYEVENTF_KEYUP
If Shift = #False
Swap in(0)\ki\dwFlags,in(2)\ki\dwFlags
EndIf
ProcedureReturn SendInput_(3,@in(0),SizeOf(INPUT_STRUCT))
EndProcedure
Procedure.i hookKeyboardProc(Code.i,Word.i,*Long.KBDLLHOOKSTRUCT)
Protected shift.i
Protected state.i
If Code = #HC_ACTION
If *Long\flags & #LLKHF_INJECTED = 0;<- dont interfere with already injected keys
shift = Bool(GetAsyncKeyState_(#VK_SHIFT));<- is the shift key down?
state = Bool(Word = #WM_KEYUP Or Word = #WM_SYSKEYUP) * #KEYEVENTF_KEYUP;<- is it a keyup event (if so set state to #KEYEVENTF_KEYUP)
ForEach hook_map()
If *Long\vkCode = hook_map()\scan[0]\short\vk And shift = hook_map()\scan[0]\short\shift
hookKeyboardInject(hook_map()\scan[1]\short\vk,state,hook_map()\scan[1]\short\shift)
ProcedureReturn #True
EndIf
Next
EndIf
EndIf
ProcedureReturn CallNextHookEx_(hook_keyboard,Code,Word,*Long)
EndProcedure
Procedure.i hookKeyboardMapKey(Old.s,New.s)
If AddElement(hook_map())
hook_map()\scan[0]\code = VkKeyScan_(PeekA(@Old))
hook_map()\scan[1]\code = VkKeyScan_(PeekA(@New))
ProcedureReturn #True
EndIf
ProcedureReturn #False
EndProcedure
Procedure.i hookKeyboardInstall()
If hook_keyboard = #Null
hook_keyboard = SetWindowsHookEx_(#WH_KEYBOARD_LL,@hookKeyboardProc(),GetModuleHandle_(#Null),#Null)
EndIf
ProcedureReturn Bool(hook_keyboard <> #Null)
EndProcedure
Procedure.i hookKeyboardUninstall()
If hook_keyboard
UnhookWindowsHookEx_(hook_keyboard)
hook_keyboard = #Null
EndIf
ProcedureReturn #Null
EndProcedure
Procedure.i Main()
hookKeyboardMapKey("f","G")
If hookKeyboardInstall()
If OpenWindow(0,0,0,320,200,#Null$,#PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_MinimizeGadget)
StringGadget(0,10,10,120,20,#Null$)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
EndSelect
ForEver
CloseWindow(0)
EndIf
hookKeyboardUninstall()
EndIf
ProcedureReturn #Null
EndProcedure
Main()
End
Re: Modify pointer hook directly
Posted: Sat Jan 28, 2023 9:26 pm
by Kwai chang caine
You are really an angel
I have tested your jewel code, il all the case
Lcase / Ucase Characters (Works)
hookKeyboardMapKey("f","G")
Ucase / Lcase Characters (Works)
hookKeyboardMapKey("G","f")
Low / Up Characters on two differents key (Works)
hookKeyboardMapKey(";","§")
Up / Low Characters on two differents key (
Problem 
)
hookKeyboardMapKey("§",";")
In this case, the first character is UP on the french key (Low = ! Up =§)

But the result "point" is also UP on the french key (Low = ; Up = .)
This history of SHIFT is a real hell

Re: Modify pointer hook directly
Posted: Sat Jan 28, 2023 9:37 pm
by Mijikai
Hi Kwai chang caine,
i changed the code it should fix the problem.
btw. i cant see your images/gifs
Re: Modify pointer hook directly
Posted: Sat Jan 28, 2023 9:52 pm
by Kwai chang caine
The image his snapshot of french keys
Works on the two size
hookKeyboardMapKey("?","§") Works
hookKeyboardMapKey("§","?") Works
And i don't know why the comma resists
hookKeyboardMapKey(",","§") Works
hookKeyboardMapKey("§",",") Not works (I have top ? at the place of the low comma)
EDIT: I have see another problem, this time it's with the ALTGR
hookKeyboardMapKey(":","¤")
The french key is (Low = $ Top = £ AltGr = ¤)
And when i press : on the key i have the SHIFT £ rather the AltGR ¤
But it's surely normal you not have managed the ALTGR i suppose

Re: Modify pointer hook directly
Posted: Sat Jan 28, 2023 10:24 pm
by Mijikai
Not sure for what to do, maybe there is another way without using SendInput_().
Re: Modify pointer hook directly
Posted: Sun Jan 29, 2023 1:38 am
by bgeraghty
Mijikai wrote: Sat Jan 28, 2023 9:08 pm
Give this a try
Code: Select all
EnableExplicit
Structure INPUT_STRUCT
type.i
StructureUnion
mi.MOUSEINPUT
ki.KEYBDINPUT
hi.HARDWAREINPUT
EndStructureUnion
EndStructure
Structure KEYSHORT_STRUCT
vk.a
shift.a
EndStructure
Structure KEYSCAN_STRUCT
StructureUnion
code.u
short.KEYSHORT_STRUCT
EndStructureUnion
EndStructure
Structure KEYMAP_STRUCT
scan.KEYSCAN_STRUCT[2]
EndStructure
Global NewList hook_map.KEYMAP_STRUCT()
Global hook_keyboard.i
Procedure.i hookKeyboardInject(Code.i,Flags.i,Shift.i)
Protected Dim in.INPUT_STRUCT(3)
in(0)\type = #INPUT_KEYBOARD
in(0)\ki\wVk = #VK_SHIFT
in(0)\ki\wScan = MapVirtualKey_(#VK_SHIFT,#MAPVK_VK_TO_VSC)
in(0)\ki\dwFlags = #Null
in(1)\type = #INPUT_KEYBOARD
in(1)\ki\wVk = Code
in(1)\ki\wScan = MapVirtualKey_(Code,#MAPVK_VK_TO_VSC)
in(1)\ki\dwFlags = Flags
in(2) = in(0)
in(2)\ki\dwFlags = #KEYEVENTF_KEYUP
If Shift = #False
Swap in(0)\ki\dwFlags,in(2)\ki\dwFlags
EndIf
ProcedureReturn SendInput_(3,@in(0),SizeOf(INPUT_STRUCT))
EndProcedure
Procedure.i hookKeyboardProc(Code.i,Word.i,*Long.KBDLLHOOKSTRUCT)
Protected shift.i
Protected state.i
If Code = #HC_ACTION
If *Long\flags & #LLKHF_INJECTED = 0;<- dont interfere with already injected keys
shift = Bool(GetAsyncKeyState_(#VK_SHIFT));<- is the shift key down?
state = Bool(Word = #WM_KEYUP Or Word = #WM_SYSKEYUP) * #KEYEVENTF_KEYUP;<- is it a keyup event (if so set state to #KEYEVENTF_KEYUP)
ForEach hook_map()
If *Long\vkCode = hook_map()\scan[0]\short\vk And shift = hook_map()\scan[0]\short\shift
hookKeyboardInject(hook_map()\scan[1]\short\vk,state,hook_map()\scan[1]\short\shift)
ProcedureReturn #True
EndIf
Next
EndIf
EndIf
ProcedureReturn CallNextHookEx_(hook_keyboard,Code,Word,*Long)
EndProcedure
Procedure.i hookKeyboardMapKey(Old.s,New.s)
If AddElement(hook_map())
hook_map()\scan[0]\code = VkKeyScan_(PeekA(@Old))
hook_map()\scan[1]\code = VkKeyScan_(PeekA(@New))
ProcedureReturn #True
EndIf
ProcedureReturn #False
EndProcedure
Procedure.i hookKeyboardInstall()
If hook_keyboard = #Null
hook_keyboard = SetWindowsHookEx_(#WH_KEYBOARD_LL,@hookKeyboardProc(),GetModuleHandle_(#Null),#Null)
EndIf
ProcedureReturn Bool(hook_keyboard <> #Null)
EndProcedure
Procedure.i hookKeyboardUninstall()
If hook_keyboard
UnhookWindowsHookEx_(hook_keyboard)
hook_keyboard = #Null
EndIf
ProcedureReturn #Null
EndProcedure
Procedure.i Main()
hookKeyboardMapKey("f","G")
If hookKeyboardInstall()
If OpenWindow(0,0,0,320,200,#Null$,#PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_MinimizeGadget)
StringGadget(0,10,10,120,20,#Null$)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
EndSelect
ForEver
CloseWindow(0)
EndIf
hookKeyboardUninstall()
EndIf
ProcedureReturn #Null
EndProcedure
Main()
End
Very cool, wasn't aware of some of this capacity with hooking before now.