Dead keys with keyboard hook - how?

Just starting out? Need help? Post your questions and find answers here.
BarryG
Addict
Addict
Posts: 4293
Joined: Thu Apr 18, 2019 8:17 am

Dead keys with keyboard hook - how?

Post by BarryG »

Hi all. Hope you have a Merry Christmas. :)

I'm using a modified version of the keyboard hook code by Michael (viewtopic.php?p=600684#p600684), and a user has emailed me saying that my app doesn't let him type in his native language anymore, because the "dead keys" of a Portuguese layout aren't being recognized. I'm using the keyboard layout shown in the screenshot below.

So here's a small test snippet where basically I'm using his keyboard language and trying to hold down ^ and then type a to get ä. It's not working, and quite frankly I'm not sure how to fix it. What makes it harder is that my app does auto-completion of typed text, so as you can see in the snippet I'm using the "text$" variable to track what's been typed, so this needs to be taken in consideration as well.

Note: The snippet doesn't take the Shift key into account, but it should (so Shift+A should show "A" and not "a" like it does now).

The end goal is for "text$" to be Hi ä there when I type Hi {shiftdown}^{shiftup}a there.

PS: The snippet works perfectly fine with an English keyboard layout.

Image

Code: Select all

Structure KeyboardState
  b.b[256]
EndStructure

Global kbs.KeyboardState, Hook, text$

Procedure.l myKeyboardHook(nCode, wParam, *p.KBDLLHOOKSTRUCT)
  
  If nCode = #HC_ACTION
    If wParam = #WM_KEYUP Or wParam = #WM_SYSKEYUP
    
      key = *p\vkcode
      
      k$=Space(9)
      ToAscii_(key,MapVirtualKey_(key,#MAPVK_VK_TO_CHAR),@kbs,@k$,0)
      text$ + Trim(k$)
      
      SetGadgetText(1, text$)
      
    EndIf
  EndIf
  
  ProcedureReturn CallNextHookEx_(0, nCode, wParam, *p)
  
EndProcedure

OpenWindow(0,0,0,500,180,"Hook Test",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
StringGadget(0,10,10,480,130,"")
TextGadget(1,10,150,480,20,"")

SetActiveGadget(0)

SetWindowsHookEx_(#WH_KEYBOARD_LL,@myKeyboardHook(),GetModuleHandle_(0),0)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      quit=1
  EndSelect
Until quit
breeze4me
Enthusiast
Enthusiast
Posts: 648
Joined: Thu Mar 09, 2006 9:24 am
Location: S. Kor

Re: Dead keys with keyboard hook - how?

Post by breeze4me »

There is a way to track character input rather than individual key presses, as shown in the code below. If necessary, use it with a keyboard hook.
There's also a WM_DEADCHAR message, so check it out if needed.
https://learn.microsoft.com/en-us/windo ... m-deadchar

Code: Select all

Structure KeyboardState
  b.b[256]
EndStructure

Global kbs.KeyboardState, Hook, text$

Procedure.l myGetMsgProc(nCode, wParam, *p.MSG)
  
  If nCode = #HC_ACTION
    
    If *p\message = #WM_CHAR
      
      text$ + Chr(*p\wParam)
      
      SetGadgetText(1, text$)
      
    EndIf
  EndIf
  
  ProcedureReturn CallNextHookEx_(0, nCode, wParam, *p)
  
EndProcedure

OpenWindow(0,0,0,500,180,"Hook Test",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
StringGadget(0,10,10,480,130,"")
TextGadget(1,10,150,480,20,"")

SetActiveGadget(0)

Hook = SetWindowsHookEx_(#WH_GETMESSAGE,@myGetMsgProc(),GetModuleHandle_(0),GetCurrentThreadId_())

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      quit=1
  EndSelect
Until quit

UnhookWindowsHookEx_(Hook)

BarryG
Addict
Addict
Posts: 4293
Joined: Thu Apr 18, 2019 8:17 am

Re: Dead keys with keyboard hook - how?

Post by BarryG »

Thanks for the example, breeze4me. :) Works perfectly like that, but I can't seem to make it work globally outside my app (for example with Notepad so that the typed chars are correct in Notepad and also correctly shown in the TextGadget). I will try again tomorrow, as it's Christmas morning here in Australia (8am). Thanks for the present! :mrgreen:
breeze4me
Enthusiast
Enthusiast
Posts: 648
Joined: Thu Mar 09, 2006 9:24 am
Location: S. Kor

Re: Dead keys with keyboard hook - how?

Post by breeze4me »

BarryG wrote: Wed Dec 24, 2025 11:01 pm (for example with Notepad so that the typed chars are correct in Notepad and also correctly shown in the TextGadget).
Merry Christmas! :mrgreen:

Tested on Windows 10.
If the handles for Notepad are not found, please fix it yourself. :wink:


Hook.dll code:

Code: Select all

EnableExplicit

#APP_HookInput = #WM_APP + 246
#GUID_FileMap$ = "MyAppFM_bd9b51f3-9905-4b7a-a63b-7ea7353e2c42"

Global g_hMod, g_hFileMap, *g_MapView

ProcedureDLL.l myGetMsgProc(nCode, wParam, *p.MSG)
  Protected hWnd
  
  If nCode = #HC_ACTION
    
    If *p\message = #WM_CHAR
      If *g_MapView
        hWnd = PeekI(*g_MapView)
        If hWnd
          SendMessage_(hWnd, #APP_HookInput, *p\hwnd, *p\wParam)
        EndIf
      EndIf
    EndIf
    
  EndIf
  
  ProcedureReturn CallNextHookEx_(0, nCode, wParam, *p)
EndProcedure

ProcedureDLL SetHook(hWndTarget)
  Protected hHook, tid.l
  
  If hWndTarget
    tid = GetWindowThreadProcessId_(hWndTarget, 0)
    If tid
      hHook = SetWindowsHookEx_(#WH_GETMESSAGE, @myGetMsgProc(), g_hMod, tid)
    EndIf
  EndIf
  
  ProcedureReturn hHook
EndProcedure

ProcedureDLL UnHook(hHook)
  ProcedureReturn UnhookWindowsHookEx_(hHook)
EndProcedure

ProcedureDLL AttachProcess(Instance)
  g_hMod = Instance
  g_hFileMap = OpenFileMapping_(#FILE_MAP_READ, 0, #GUID_FileMap$)
  If g_hFileMap
    *g_MapView = MapViewOfFile_(g_hFileMap, #FILE_MAP_READ, 0, 0, 64)
  EndIf
EndProcedure

ProcedureDLL DetachProcess(Instance)
  
  If *g_MapView
    UnmapViewOfFile_(*g_MapView)
  EndIf
  If g_hFileMap
    CloseHandle_(g_hFileMap)
  EndIf
  
EndProcedure
Main code:

Code: Select all

#APP_HookInput = #WM_APP + 246

#GUID_FileMap$ = "MyAppFM_bd9b51f3-9905-4b7a-a63b-7ea7353e2c42"

Prototype ptSetHook(hWndTarget)
Prototype ptUnHook(hHook)

Global SetHook.ptSetHook
Global UnHook.ptUnHook


Global NewList g_hHook()
Global NewMap g_Text$()

Global g_hFileMap, *g_MapView


If OpenLibrary(0, "Hook.dll")
  SetHook = GetFunction(0, "SetHook")
  UnHook = GetFunction(0, "UnHook")
  
  If SetHook And UnHook
    Debug "Open."
  Else
    Debug "Cannot open the hook Dll."
    End
  EndIf
EndIf

Procedure WndProc_Main(hWnd, uMsg, wParam, lParam)
  If uMsg = #APP_HookInput
    
    g_Text$(Str(wParam)) + Chr(lParam)
    Debug "Target hWnd: " + wParam + " " + g_Text$()
    
    ProcedureReturn 1
  EndIf
  
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure


;-----------------------------------------------------------
;- Test
;-----------------------------------------------------------

; Open two Notepad windows.
RunProgram("notepad.exe")
RunProgram("notepad.exe")

Sleep_(1500)

Global NewList g_HwndNotepad()

; Save the handles of two Notepad windows.
Procedure EnumWindowsProc(hWnd, lParam)
  Protected s.s{64}
  
  If GetClassName_(hWnd, @s, 60)
    If s = "Notepad"
      If AddElement(g_HwndNotepad())
        g_HwndNotepad() = hWnd
      EndIf
    EndIf
  EndIf
  
  ProcedureReturn #True
EndProcedure

EnumWindows_(@EnumWindowsProc(), 0)

If ListSize(g_HwndNotepad()) <> 2
  Debug "Notepad instances <> 2. Quit."
  End
EndIf


If OpenWindow(0, 0, 0, 270, 80, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ButtonGadget(1, 10, 20, 120, 30, "Set Hook")
  ButtonGadget(2, 140, 20, 120, 30, "UnHook")
  
  SetWindowCallback(@WndProc_Main(), 0)
  
  
  ; After creating shared memory, store the window handle value that will receive messages.
  g_hFileMap = CreateFileMapping_(#INVALID_HANDLE_VALUE, 0, #PAGE_READWRITE | #SEC_COMMIT, 0, 64, #GUID_FileMap$)
  If g_hFileMap
    *g_MapView = MapViewOfFile_(g_hFileMap, #FILE_MAP_ALL_ACCESS, 0, 0, 64)
    If *g_MapView
      PokeI(*g_MapView, WindowID(0))
    EndIf
  EndIf
  
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        Quit = 1
        
      Case #PB_Event_Gadget
        Select EventGadget()
          Case 1
            
            ForEach g_HwndNotepad()
              hHook = SetHook(g_HwndNotepad())
              If hHook
                If AddElement(g_hHook())
                  g_hHook() = hHook
                EndIf
                Debug "hHook : " + hHook
              EndIf
            Next
            
          Case 2
            ForEach g_hHook()
              If g_hHook()
                Result = UnhookWindowsHookEx_(g_hHook())
                Debug "UnHook: " + g_hHook() + " " + Result
                g_hHook() = 0
              EndIf
            Next
            
            ClearList(g_hHook())
            
        EndSelect
    EndSelect
  Until Quit
  
EndIf

If *g_MapView
  UnmapViewOfFile_(*g_MapView)
EndIf

If g_hFileMap
  CloseHandle_(g_hFileMap)
EndIf
BarryG
Addict
Addict
Posts: 4293
Joined: Thu Apr 18, 2019 8:17 am

Re: Dead keys with keyboard hook - how?

Post by BarryG »

Thanks for trying, but this line doesn't output anything on Win 11:

Code: Select all

Debug "Target hWnd: " + wParam + " " + g_Text$()
Don't know if it's an easy fix? I don't know what to fix anyway. :(
breeze4me
Enthusiast
Enthusiast
Posts: 648
Joined: Thu Mar 09, 2006 9:24 am
Location: S. Kor

Re: Dead keys with keyboard hook - how?

Post by breeze4me »

The issue seems to be that the hook is only installed on a single thread associated with a specific window. The code below installs a global hook without specifying a thread, so it should work.

Hook.dll code:

Code: Select all

EnableExplicit

#APP_HookInput = #WM_APP + 246
#GUID_FileMap$ = "MyAppFM_bd9b51f3-9905-4b7a-a63b-7ea7353e2c42"

Global g_hMod, g_hFileMap, *g_MapView

ProcedureDLL.l myGetMsgProc(nCode, wParam, *p.MSG)
  Protected hWnd
  
  If nCode = #HC_ACTION
    
    If *p\message = #WM_CHAR
      If *g_MapView
        hWnd = PeekI(*g_MapView)
        If hWnd
          SendMessage_(hWnd, #APP_HookInput, *p\hwnd, *p\wParam)
        EndIf
      EndIf
    EndIf
    
  EndIf
  
  ProcedureReturn CallNextHookEx_(0, nCode, wParam, *p)
EndProcedure

ProcedureDLL SetHook()
  ProcedureReturn SetWindowsHookEx_(#WH_GETMESSAGE, @myGetMsgProc(), g_hMod, 0)
EndProcedure

ProcedureDLL UnHook(hHook)
  ProcedureReturn UnhookWindowsHookEx_(hHook)
EndProcedure

ProcedureDLL AttachProcess(Instance)
  g_hMod = Instance
  g_hFileMap = OpenFileMapping_(#FILE_MAP_READ, 0, #GUID_FileMap$)
  If g_hFileMap
    *g_MapView = MapViewOfFile_(g_hFileMap, #FILE_MAP_READ, 0, 0, 64)
  EndIf
EndProcedure

ProcedureDLL DetachProcess(Instance)
  
  If *g_MapView
    UnmapViewOfFile_(*g_MapView)
  EndIf
  If g_hFileMap
    CloseHandle_(g_hFileMap)
  EndIf
  
EndProcedure
Main code:

Code: Select all

#APP_HookInput = #WM_APP + 246
#GUID_FileMap$ = "MyAppFM_bd9b51f3-9905-4b7a-a63b-7ea7353e2c42"

Prototype ptSetHook()
Prototype ptUnHook(hHook)

Global SetHook.ptSetHook
Global UnHook.ptUnHook


Global NewMap g_Text$()

Global g_hFileMap, *g_MapView


If OpenLibrary(0, "Hook.dll")
  SetHook = GetFunction(0, "SetHook")
  UnHook = GetFunction(0, "UnHook")
EndIf

If SetHook And UnHook
  Debug "Open."
Else
  Debug "Cannot open the hook Dll."
  End
EndIf

Procedure WndProc_Main(hWnd, uMsg, wParam, lParam)
  If uMsg = #APP_HookInput
    
    g_Text$(Str(wParam)) + Chr(lParam)
    Debug "Target hWnd: " + wParam + " " + g_Text$()
    
    ProcedureReturn 1
  EndIf
  
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure



RunProgram("notepad.exe")
RunProgram("notepad.exe")

Sleep_(1500)


If OpenWindow(0, 0, 0, 270, 80, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ButtonGadget(1, 10, 20, 120, 30, "Set Hook")
  ButtonGadget(2, 140, 20, 120, 30, "UnHook")
  
  SetWindowCallback(@WndProc_Main(), 0)
  
  
  ; After creating shared memory, store the window handle value that will receive messages.
  g_hFileMap = CreateFileMapping_(#INVALID_HANDLE_VALUE, 0, #PAGE_READWRITE | #SEC_COMMIT, 0, 64, #GUID_FileMap$)
  If g_hFileMap
    *g_MapView = MapViewOfFile_(g_hFileMap, #FILE_MAP_ALL_ACCESS, 0, 0, 64)
    If *g_MapView
      PokeI(*g_MapView, WindowID(0))
    EndIf
  EndIf
  
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        Quit = 1
        
      Case #PB_Event_Gadget
        Select EventGadget()
          Case 1
            If hHook = 0
              hHook = SetHook()
              If hHook
                Debug "hHook : " + hHook
              EndIf
            EndIf
            
          Case 2
            If hHook
              ;Result = UnhookWindowsHookEx_(hHook)
              Result = UnHook(hHook)
              Debug "UnHook: " + hHook + " " + Result
              hHook = 0
            EndIf
            
        EndSelect
    EndSelect
  Until Quit
  
EndIf

If *g_MapView
  UnmapViewOfFile_(*g_MapView)
EndIf

If g_hFileMap
  CloseHandle_(g_hFileMap)
EndIf
BarryG
Addict
Addict
Posts: 4293
Joined: Thu Apr 18, 2019 8:17 am

Re: Dead keys with keyboard hook - how?

Post by BarryG »

Almost there... keys like Esc and Enter aren't detected on some apps that don't recognise them. Is there a way to make them always get detected, no matter which window or app has the focus? BTW, I appreciate your help.
breeze4me
Enthusiast
Enthusiast
Posts: 648
Joined: Thu Mar 09, 2006 9:24 am
Location: S. Kor

Re: Dead keys with keyboard hook - how?

Post by breeze4me »

If necessary, use it with a keyboard hook.
As mentioned in the first answer, you can use a keyboard(low level) hook together.
Where to ignore and where to allow specific key inputs depends on the situation, so decide based on your needs.

Hook.dll code:

Code: Select all

EnableExplicit

#APP_HookInput = #WM_APP + 246
#GUID_FileMap$ = "MyAppFM_bd9b51f3-9905-4b7a-a63b-7ea7353e2c42"

Global g_hMod, g_hFileMap, *g_MapView

ProcedureDLL.l myGetMsgProc(nCode, wParam, *p.MSG)
  Protected hWnd
  
  If nCode = #HC_ACTION
    
    ; Whether to ignore the press of specific keys here is up to you.
    
    ;If *p\message = #WM_CHAR
    If *p\message = #WM_CHAR And (*p\wParam <> #VK_ESCAPE And *p\wParam <> #VK_RETURN)
      If *g_MapView
        hWnd = PeekI(*g_MapView)
        If hWnd
          SendMessage_(hWnd, #APP_HookInput, *p\hwnd, *p\wParam)
        EndIf
      EndIf
    EndIf
    
  EndIf
  
  ProcedureReturn CallNextHookEx_(0, nCode, wParam, *p)
EndProcedure

ProcedureDLL SetHook()
  ProcedureReturn SetWindowsHookEx_(#WH_GETMESSAGE, @myGetMsgProc(), g_hMod, 0)
EndProcedure

ProcedureDLL UnHook(hHook)
  ProcedureReturn UnhookWindowsHookEx_(hHook)
EndProcedure

ProcedureDLL AttachProcess(Instance)
  g_hMod = Instance
  g_hFileMap = OpenFileMapping_(#FILE_MAP_READ, 0, #GUID_FileMap$)
  If g_hFileMap
    *g_MapView = MapViewOfFile_(g_hFileMap, #FILE_MAP_READ, 0, 0, 64)
  EndIf
EndProcedure

ProcedureDLL DetachProcess(Instance)
  
  If *g_MapView
    UnmapViewOfFile_(*g_MapView)
  EndIf
  If g_hFileMap
    CloseHandle_(g_hFileMap)
  EndIf
  
EndProcedure
Main code:

Code: Select all

#APP_HookInput = #WM_APP + 246
#APP_HookKBD = #WM_APP + 247

#GUID_FileMap$ = "MyAppFM_bd9b51f3-9905-4b7a-a63b-7ea7353e2c42"

Prototype ptSetHook()
Prototype ptUnHook(hHook)

Global SetHook.ptSetHook
Global UnHook.ptUnHook


Global NewMap g_Text$()

Global g_hFileMap, *g_MapView


Procedure.l myKeyboardHook(nCode, wParam, *p.KBDLLHOOKSTRUCT)
  
  If nCode = #HC_ACTION
    
    If (wParam = #WM_KEYUP Or wParam = #WM_SYSKEYUP) And (*p\vkcode = #VK_ESCAPE Or *p\vkcode = #VK_RETURN)
      SendMessage_(WindowID(0), #APP_HookKBD, 0, *p\vkcode)
      
      ; Or you can send it using the same event code. Choose as needed.
      ;SendMessage_(WindowID(0), #APP_HookInput, 0, *p\vkcode)
    EndIf
    
  EndIf
  
  ProcedureReturn CallNextHookEx_(0, nCode, wParam, *p)
EndProcedure

If OpenLibrary(0, "Hook.dll")
  SetHook = GetFunction(0, "SetHook")
  UnHook = GetFunction(0, "UnHook")
EndIf

If SetHook And UnHook
  Debug "Open."
Else
  Debug "Cannot open the hook Dll."
  End
EndIf

Procedure WndProc_Main(hWnd, uMsg, wParam, lParam)
  
  If uMsg = #APP_HookKBD
    Debug "Key pressed: " + lParam
  EndIf
  
  If uMsg = #APP_HookInput
    
    g_Text$(Str(wParam)) + Chr(lParam)
    Debug "Target hWnd: " + wParam + " " + g_Text$()
    
    ProcedureReturn 1
  EndIf
  
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure



RunProgram("notepad.exe")
RunProgram("notepad.exe")

Sleep_(1500)


If OpenWindow(0, 0, 0, 270, 80, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ButtonGadget(1, 10, 20, 120, 30, "Set Hook")
  ButtonGadget(2, 140, 20, 120, 30, "UnHook")
  
  SetWindowCallback(@WndProc_Main(), 0)
  
  
  ; After creating shared memory, store the window handle value that will receive messages.
  g_hFileMap = CreateFileMapping_(#INVALID_HANDLE_VALUE, 0, #PAGE_READWRITE | #SEC_COMMIT, 0, 64, #GUID_FileMap$)
  If g_hFileMap
    *g_MapView = MapViewOfFile_(g_hFileMap, #FILE_MAP_ALL_ACCESS, 0, 0, 64)
    If *g_MapView
      PokeI(*g_MapView, WindowID(0))
    EndIf
  EndIf
  
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        Quit = 1
        
      Case #PB_Event_Gadget
        Select EventGadget()
          Case 1
            If hHook = 0
              hHook = SetHook()
              If hHook
                Debug "hHook : " + hHook
              EndIf
            EndIf
            
            If hHookKBD = 0
              hHookKBD = SetWindowsHookEx_(#WH_KEYBOARD_LL, @myKeyboardHook(), GetModuleHandle_(0), 0)
              If hHookKBD
                Debug "hHookKBD : " + hHookKBD
              EndIf
            EndIf
            
          Case 2
            If hHook
              Result = UnHook(hHook)
              ;Result = UnhookWindowsHookEx_(hHook)
              Debug "UnHook(hHook): " + hHook + " " + Result
              hHook = 0
            EndIf
            
            If hHookKBD
              Result = UnhookWindowsHookEx_(hHookKBD)
              Debug "UnHook(hHookKBD): " + hHookKBD + " " + Result
              hHookKBD = 0
            EndIf
            
        EndSelect
    EndSelect
  Until Quit
  
EndIf

If *g_MapView
  UnmapViewOfFile_(*g_MapView)
EndIf

If g_hFileMap
  CloseHandle_(g_hFileMap)
EndIf
Last edited by breeze4me on Fri Dec 26, 2025 10:20 am, edited 1 time in total.
BarryG
Addict
Addict
Posts: 4293
Joined: Thu Apr 18, 2019 8:17 am

Re: Dead keys with keyboard hook - how?

Post by BarryG »

Thank you, kind sir. It now fully works as I need. :) Can you PM me, please?

BTW, this GUID can be anything, right? Just something unique to my app?

Code: Select all

#GUID_FileMap$ = "MyAppFM_bd9b51f3-9905-4b7a-a63b-7ea7353e2c42"
breeze4me
Enthusiast
Enthusiast
Posts: 648
Joined: Thu Mar 09, 2006 9:24 am
Location: S. Kor

Re: Dead keys with keyboard hook - how?

Post by breeze4me »

BarryG wrote: Fri Dec 26, 2025 10:20 am BTW, this GUID can be anything, right? Just something unique to my app?

Code: Select all

#GUID_FileMap$ = "MyAppFM_bd9b51f3-9905-4b7a-a63b-7ea7353e2c42"
Yes, if the string is unique worldwide. :mrgreen:
Rinzwind
Enthusiast
Enthusiast
Posts: 708
Joined: Wed Mar 11, 2009 4:06 pm
Location: NL

Re: Dead keys with keyboard hook - how?

Post by Rinzwind »

FYI: won't catch all keys... ie anywhere in MS word or in start menu. The application itself prevents passing messages on?
breeze4me
Enthusiast
Enthusiast
Posts: 648
Joined: Thu Mar 09, 2006 9:24 am
Location: S. Kor

Re: Dead keys with keyboard hook - how?

Post by breeze4me »

Rinzwind wrote: Sat Dec 27, 2025 9:41 am FYI: won't catch all keys... ie anywhere in MS word or in start menu. The application itself prevents passing messages on?
For applications that are not traditional Win32 applications(such as some modern apps like Universal Windows Platform (UWP) apps), the WM_CHAR message may not be hooked.
Depending on the frameworks used by apps, even low level keyboard hooks may or may not be possible.
Even so, for the Windows Start menu (at least in Windows 10), key input can be monitored using the WH_KEYBOARD_LL hook.

The AI's explanation is more detailed, so take a look.
Why standard WH_KEYBOARD_LL hooks are problematic for UWP

App Container Sandbox: UWP apps run within a secure, isolated app container that limits their access to system-wide functions, including cross-process hooking mechanisms.

DLL Injection Restrictions: Global hooks typically require a DLL to be injected into the address space of other processes. For UWP and Windows Store app processes, hook DLLs are not loaded in-process unless installed by UIAccess processes (like accessibility tools).

API Limitations: Access to certain traditional Win32 APIs may be restricted or behave differently within the UWP environment.
Post Reply