Page 1 of 1

How to test for hotkey of Alt+LMB?

Posted: Sun Feb 09, 2020 4:29 am
by BarryG
I was wondering if there's a way to detect a "hotkey" combo of the Alt key and left mouse button down, no matter which app has the focus at the time? I know #WM_HOTKEY is for keys and not mouse, and below is a start, but it only works if the left mouse button is held down BEFORE you press the Alt key. It doesn't work if Alt is held down FIRST. From what I can see, the #WM_HOTKEY message isn't received until after the key is released? That's what I need to overcome: when it's down, as opposed to up.

Note: I ideally want this to work with all keys, not just Alt. Reason is that the user specifies which hotkey combo to use with my app, which is triggered by #WM_HOTKEY in my callback. So I can't do a poll of all key states or use GetAsyncKeyState_() for their specified keys. I just need a way, either before or after #WM_HOTKEY is received, to detect the left mouse button state at that moment. Thanks!

Code: Select all

Procedure WinCallback(hWnd,uMsg,WParam,LParam)
  Result=#PB_ProcessPureBasicEvents
  If uMsg=#WM_HOTKEY
    If GetAsyncKeyState_(#VK_LBUTTON) & $8000
      Debug "Alt+LMB down"
    EndIf
  EndIf
  ProcedureReturn Result
EndProcedure

OpenWindow(0,300,300,320,160,"Alt+LMB",#PB_Window_SystemMenu)
RegisterHotKey_(WindowID(0),0,#MOD_ALT,0)
SetWindowCallback(@WinCallback())

Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow

Re: How to test for hotkey of Alt+LMB?

Posted: Sun Feb 09, 2020 8:02 am
by RASHAD
Hi

Code: Select all

Global Keyhook

Procedure HookProc(nCode,wParam,lParam)
  Select nCode
      Case #HC_ACTION
        If GetAsyncKeyState_(#VK_MENU) = -$8000 And GetAsyncKeyState_(#VK_LBUTTON) = -$8000
          If GetActiveGadget() = 1
            Debug "Editor"
          Else
            Debug "String"
          EndIf
        EndIf
        UnhookWindowsHookEx_(Keyhook)
       EndSelect

   ProcedureReturn CallNextHookEx_(0,nCode,wParam,lParam)   
EndProcedure

If OpenWindow(0, 0, 0, 600, 300, "WebGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered|#PB_Window_SizeGadget)
  EditorGadget(1, 0, 0, 600, 150)
  StringGadget(2, 10, 270, 300, 20 ,"")
  
Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
        Quit = 1                 
       
    Case #PB_Event_Gadget
        Select EventGadget()
          Case 1
            Keyhook = SetWindowsHookEx_(#WH_KEYBOARD,@HookProc(),0, GetCurrentThreadId_())
              
          Case 2
            Keyhook = SetWindowsHookEx_(#WH_KEYBOARD,@HookProc(),0, GetCurrentThreadId_())
          EndSelect
  EndSelect
 Until Quit = 1
EndIf
UnhookWindowsHookEx_(Keyhook)

Re: How to test for hotkey of Alt+LMB?

Posted: Sun Feb 09, 2020 9:48 am
by BarryG
Hi Rashad, thanks, but it doesn't work when third-party apps have the focus (as mentioned). It also seems weirdly hit-and-miss: sometimes I get a debug output once or twice, and other times I get lots of debug outputs in a row. Strange.

Also is the issue of #VK_MENU being hard-coded. In my app, the key can be any hotkey mod combo, so #VK_MENU|#VK_CONTROL, or #VK_MENU|#VK_CONTROL|#VK_SHIFT, etc. I can't code for all these possibilities, so it's best just to check for #WM_HOTKEY in a callback and try to go from there. Unfortunately it seems there's no way to know when a hotkey has been pushed down; Windows only reports when it's been released. I'll keep researching, and I do appreciate your willingness to help. You're a good guy.

Re: How to test for hotkey of Alt+LMB?

Posted: Sun Feb 09, 2020 12:30 pm
by chi
BarryG wrote:but it doesn't work when third-party apps have the focus
You need a global hook if you want to catch all apps...

mhook_app

Code: Select all

#MHOOK_DLL = 0

OpenWindow(0, 0, 0, 320, 200, "MHook Example", #PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)

If OpenLibrary(#MHOOK_DLL, "mhook.dll")
  MHOOK_DLL = SetWindowsHookEx_(#WH_MOUSE, GetFunction(#MHOOK_DLL, "MHook"), LibraryID(#MHOOK_DLL), #Null)
  MHOOK_Message = RegisterWindowMessage_("MHOOK")
  ChangeWindowMessageFilter_(MHOOK_Message, #MSGFLT_ADD)
Else
  MessageRequester("", "mhook.dll not found...")
  End
EndIf

Repeat
  event = WaitWindowEvent()
  Select event
      
    Case MHOOK_Message
      Debug "hWnd: " + Hex(EventwParam())
      Debug "rMsg: " + EventlParam()
      Debug "-------------"
      
  EndSelect
Until event = #PB_Event_CloseWindow

If MHOOK_DLL
  UnhookWindowsHookEx_(MHOOK_DLL)
EndIf

If IsLibrary(#MHOOK_DLL)
  CloseLibrary(#MHOOK_DLL)
EndIf
mhook_dll

Code: Select all

ProcedureDLL AttachProcess(Instance)
  DisableThreadLibraryCalls_(Instance)
  Global MHOOK_Window  = FindWindow_(0, "MHook Example")
  Global MHOOK_Message = RegisterWindowMessage_("MHOOK")
EndProcedure

ProcedureDLL MHook(nCode, wParam, *lParam.MOUSEHOOKSTRUCT)
  If nCode < #HC_ACTION : ProcedureReturn CallNextHookEx_(@MHook(), nCode, wParam, *lParam) : EndIf
  Select wParam 
      
    Case #WM_LBUTTONDOWN, #WM_NCLBUTTONDOWN
      If GetAsyncKeyState_(#VK_MENU) & $8000
        PostMessage_(MHOOK_Window, MHOOK_Message, GetAncestor_(*lParam\hwnd, #GA_ROOT), Random(999))
      EndIf 
      
  EndSelect
  ProcedureReturn CallNextHookEx_(@MHook(), nCode, wParam, *lParam)
EndProcedure
[/size]
BarryG wrote:Also is the issue of #VK_MENU being hard-coded...
You'll figure it out :wink:

Re: How to test for hotkey of Alt+LMB?

Posted: Sun Feb 09, 2020 1:15 pm
by BarryG
Thanks for the code, chi. A shame I have to use an external DLL, but it may be the only way.

Re: How to test for hotkey of Alt+LMB?

Posted: Sun Feb 09, 2020 2:59 pm
by chi
BarryG wrote:Thanks for the code, chi.
You're welcome :)
BarryG wrote:A shame I have to use an external DLL, but it may be the only way.
Yeah, it's the only way... Since the dll gets injected into every process, make sure to exclude processes you don't want to trigger (e.g. Taskbar, StartButton, ...)