Modify pointer hook directly

Just starting out? Need help? Post your questions and find answers here.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Modify pointer hook directly

Post 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
ImageThe happiness is a road...
Not a destination
User avatar
bgeraghty
User
User
Posts: 52
Joined: Wed Apr 02, 2014 12:45 am
Location: irc.ibotched.it:+6697
Contact:

Re: Modify pointer hook directly

Post 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)
SolveMyIssue_() - No QuickHelp available.
User avatar
bgeraghty
User
User
Posts: 52
Joined: Wed Apr 02, 2014 12:45 am
Location: irc.ibotched.it:+6697
Contact:

Re: Modify pointer hook directly

Post 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.
SolveMyIssue_() - No QuickHelp available.
User avatar
bgeraghty
User
User
Posts: 52
Joined: Wed Apr 02, 2014 12:45 am
Location: irc.ibotched.it:+6697
Contact:

Re: Modify pointer hook directly

Post 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 
SolveMyIssue_() - No QuickHelp available.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Modify pointer hook directly

Post by Kwai chang caine »

Hello bgeraghty

Thanks a lot for your great code, looks like an airplane cockpit :shock:
A little bit hard to understand for the neuronal KCC level :oops:
But it works...i see my down/up inversing :shock: 8)

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 :oops:) replace a key by another :mrgreen:

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 :cry:
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 :evil:

A real hell this apparently "Simple" :lol: code i want to do :oops:
ImageThe happiness is a road...
Not a destination
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: Modify pointer hook directly

Post 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
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Modify pointer hook directly

Post by Kwai chang caine »

Waoouuuh !!!!
That's work very well !!!!

One thousand of thanks MIJIKAI for your amazing code :shock:

Image

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 :oops:
Because the more difficult for me, it's manage the SHIFT in the HOOK procedure :oops:
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)
......
....
ImageThe happiness is a road...
Not a destination
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: Modify pointer hook directly

Post 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
Last edited by Mijikai on Sat Jan 28, 2023 10:07 pm, edited 2 times in total.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Modify pointer hook directly

Post by Kwai chang caine »

You are really an angel 8)

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 =§)
Image
But the result "point" is also UP on the french key (Low = ; Up = .)
Image

This history of SHIFT is a real hell :evil:
ImageThe happiness is a road...
Not a destination
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: Modify pointer hook directly

Post by Mijikai »

Hi Kwai chang caine,
i changed the code it should fix the problem.
btw. i cant see your images/gifs
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Modify pointer hook directly

Post by Kwai chang caine »

The image his snapshot of french keys :wink:

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 :wink:
ImageThe happiness is a road...
Not a destination
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: Modify pointer hook directly

Post by Mijikai »

:?
Not sure for what to do, maybe there is another way without using SendInput_().
User avatar
bgeraghty
User
User
Posts: 52
Joined: Wed Apr 02, 2014 12:45 am
Location: irc.ibotched.it:+6697
Contact:

Re: Modify pointer hook directly

Post 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.
SolveMyIssue_() - No QuickHelp available.
Post Reply