Get pressed modifier key(s) + mouse click + mouse movement?

Just starting out? Need help? Post your questions and find answers here.
jacky
User
User
Posts: 63
Joined: Mon Jan 21, 2019 1:41 pm

Get pressed modifier key(s) + mouse click + mouse movement?

Post by jacky »

Hello,

I bought PB a few days ago and I'm searching for some help now :oops:

What I want to do:
I need to detect which mouse button is clicked while the mouse is hovering over a window (which is NOT my own!).
That window can be e.g. the Windows inbuilt file manager (aka Windows Explorer). The window
can already be the active one but this isn't a necessity (so it must work while the mouse is
hovering over it as well).

Additionally I need the information if one of the mouse buttons is not only clicked but hold
as well. There would be a minimal timeout that needs to be reached until such a "hold" would
count as a "hold", e.g. 200 ms (but this value would be user configurable).

Additionally (sorry!), it matters if the mouse gets moved while the first click was initiated.
E.g. the right mouse button is pressed and the mouse is moved 50px to somewhere else in
e.g. 1500 ms would be different from just clicking it and releasing it immediately after.

And the last thing: I need to be able to detect if a modifier key (or a combination of them)
is pressed when an initial click is happening (it doesn't matter if the keys are still pressed
when a mouse button is released). Modifier keys are shift, ctrl + alt. Win would be nice
but isn't a necessity.

The whole thing isn't ultra complicated in AutoHotkey (which I can't use for this application)
but I struggle to find anything that gets this done in PureBasic...

This does not need be cross-platform, the only supported platform is Windows...

Can a forum member help me out please?

Thank you,
Jacky
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Get pressed modifier key(s) + mouse click + mouse moveme

Post by Dude »

jacky wrote:The whole thing isn't ultra complicated in AutoHotkey
Got an AutoHotKey source that does it? Post it here and someone will easily convert it to PureBasic, because both languages are so similar in syntax.

Welcome to PureBasic, too. :)
jacky
User
User
Posts: 63
Joined: Mon Jan 21, 2019 1:41 pm

Re: Get pressed modifier key(s) + mouse click + mouse moveme

Post by jacky »

In AHK I would use a timer, for example like this (note: It doesn't take into account
that it can be a window that the mouse is hovering over but it would just a simple
thing to include that):

Code: Select all

Timer_MouseButton() {
    static lastCallTime := 0
    static lastMouseButton, lastModifier

    ; Do not proceed if app is not the active window
    IfWinNotActive, % "ahk_class" C["OWN"]["Some_Window_Class_Name"]
        return

    ; If app is paused, do not process the timer at all
    if (G["INT"]["IsPaused"])
        return

    ; If a double click action is in progress, do not process the timer at all
    if (G["INT"]["DoubleClickInProgress"]) {
        return
    }

    G["INT"]["ClickType"] := 0

    ; Reset the mouse button hold state on enter
    mouseButtonState := 0

    ; =======================
    ; = GET MOUSE BUTTON(S) =
    ; =======================

    ; 1 = down, 0 = up
    mb1State := GetKeyState("LButton")
    mb2State := GetKeyState("RButton")
    mb3State := GetKeyState("MButton")

    if (G["INI"]["General"]["MouseButtonVK4"]) {
        vkState := "vk" G["INI"]["General"]["MouseButtonVK4"]
        mb4State := GetKeyState(vkState)
    } else {
        mb4State := GetKeyState("XButton1")
    }

    if (G["INI"]["General"]["MouseButtonVK5"]) {
        vkState := "vk" G["INI"]["General"]["MouseButtonVK5"]
        mb5State := GetKeyState(vkState)
    } else {
        mb5State := GetKeyState("XButton2")
    }

    ; No left + right mouse click
    if (mb1State && mb2State)
        return

    ; Set the click type correctly
    G["INT"]["ClickType"] := 1

    ; Swapped left & right button?
    if (mb1State || mb2State)
        SysGet, swappedMouseButtons, 23

    if (mb1State) {
        mouseButtonState := mb1State
        G["INT"]["MouseButton"] := "MB1"
        mouseButtonName := "LButton"
        if (swappedMouseButtons)
            mouseButtonName := "RButton"
    } else if (mb2State) {
        mouseButtonState := mb2State
        G["INT"]["MouseButton"] := "MB2"
        mouseButtonName := "RButton"
        if (swappedMouseButtons)
            mouseButtonName := "LButton"
    } else if (mb3State) {
        mouseButtonState := mb3State
        G["INT"]["MouseButton"] := "MB3"
        mouseButtonName := "MButton"
    } else if (mb4State) {
        mouseButtonState := mb4State
        G["INT"]["MouseButton"] := "MB4"
        mouseButtonName := "XButton1"
    } else if (mb5State) {
        mouseButtonState := mb5State
        G["INT"]["MouseButton"] := "MB5"
        mouseButtonName := "XButton2"
    }

    ; As long as one of the two mouse buttons isn't pressed
    ; get out of it again and reset the loop counter
    if !(mouseButtonState) {
        cntTimer := 0
        return
    }

    ; Now we passed the prechecks, now increase the timer
    cntTimer++

    ; Found an elevated app instance
    if !(CanWeCommunicate()) {
        cntTimer := 0
        SelfElevate(true)
    }

    ; =======================
    ; = GET MODIFIER KEY(S) =
    ; =======================

    ; ctrl = ^, shift = +, alt = !, win = #
    ; 0 = None, 1 = Shift, 2 = Ctrl, 3 = Shift + Ctrl, 4 = Alt
    ; 5 = Shift + Alt, 6 = Ctrl + Alt, 7 = Shift + Ctrl + Alt
    shiftState := GetKeyState("Shift", "P") ? 1 : 0
    ctrlState  := GetKeyState("Ctrl",  "P") ? 2 : 0
    altState   := GetKeyState("Alt",   "P") ? 4 : 0
    lWinState  := GetKeyState("LWin",  "P") ? 8 : 0
    state      := ctrlState + shiftState + altState + lWinState

    G["INT"]["PressedModifier"] := state

    ; Check for same hotkey (same mouse button + same modifier)
    sameMouseButton := false, sameModifier := false, sameHotkey := false
    if (mouseButtonName = lastMouseButton)
        sameMouseButton := true
    if (G["INT"]["PressedModifier"] = lastModifier)
        sameModifier := true
    if (sameMouseButton && sameModifier)
        sameHotkey := true
    lastMouseButton := mouseButtonName
    lastModifier    := G["INT"]["PressedModifier"]

    DllCall("QueryPerformanceCounter", "Int64*", curCallTime)
    DllCall("QueryPerformanceFrequency", "Int64*", frequencyQPC)

    passedTime := (curCallTime - lastCallTime) * (1000 / frequencyQPC)
    if (passedTime > (C["Timers"]["MouseButton"] * 1.5)) {
        lastCallTime := curCallTime
        ;OutputDebug, % "Mouse button wasn't hold long enough, returning..."
        return
    }

    ; Get mouse position and "save" it as the reference for movement detection
    if (cntTimer == 1)
        MouseGetPos, x1, y1

    mouseButtonHoldTime := G["INI"]["General"]["MouseButtonHoldTime"] / 10
    KeyWait, % mouseButtonName, % "T" mouseButtonHoldTime
    if (ErrorLevel) { ; Not released in T<number>
        MouseGetPos, x2, y2
        ; Only show the menu if mouse position didn't change beyond the ini value
        mouseMaxMovedDistance := G["INI"]["General"]["MouseMaxMovedDistance"]
        if !(x2 < (x1 - mouseMaxMovedDistance)
          || x2 > (x1 + mouseMaxMovedDistance)
          || y2 < (y1 - mouseMaxMovedDistance)
          || y2 > (y1 + mouseMaxMovedDistance)) {
            cntTimer := 0
            G["INT"]["AppHwnd"] := WinExist("A")
            ; Do something now...

            ; Stop the timer from firing again
            ; If we'd use this loop without the single item check we wouldn't be able
            ; to click from one item on another one because the loop prevents that...
            if (G["INT"]["SingleMenu"]) {
                Loop { ; Now loop until the mouse button is released
                    Sleep, 25
                    if !(GetKeyState(mouseButtonName))
                        break
                }
            }
        }
    }
    ; Reset button state
    mouseButtonState := 0

    return
}
Welcome to PureBasic, too
Thank you!
JHPJHP
Addict
Addict
Posts: 2129
Joined: Sat Oct 09, 2010 3:47 am
Contact:

Re: Get pressed modifier key(s) + mouse click + mouse moveme

Post by JHPJHP »

Hi jacky,

Most of your requirements can be found in my Video Snipping Tool; see the Procedure MouseHook.

If you have trouble with any of the code, just post back and I or another forum member should be able to help.

Welcome to PureBasic.
eJan
Enthusiast
Enthusiast
Posts: 365
Joined: Sun May 21, 2006 11:22 pm
Location: Sankt Veit am Flaum

Re: Get pressed modifier key(s) + mouse click + mouse moveme

Post by eJan »

Try theese MouseHook's

Code: Select all

; RASHAD: https://www.purebasic.fr/english/viewtopic.php?p=523064#p523064

Global oTime

Procedure MouseHook(nCode, wParam, lParam)
  Select wParam

    Case #WM_LBUTTONDOWN
      If GetTickCount_() < (oTime + GetDoubleClickTime_())
        SetGadgetText(0, "Left Mouse DblClicked")
        ;MoveWindow_(WindowID(0),100,100,240,140,1)
      Else
        SetGadgetText(0, "Left Mouse Clicked")
      EndIf
      oTime = GetTickCount_()

    Case  #WM_MBUTTONDOWN
      SetGadgetText(0, "Middle Mouse Clicked")

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

OpenWindow(0, 0, 0, 240, 140, "Mouse Hook", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
TextGadget(0, 10, 10, 180, 20, "")

hhkLLMouse = SetWindowsHookEx_(#WH_MOUSE_LL, @MouseHook(), GetModuleHandle_(0), 0)

Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow

UnhookWindowsHookEx_(hhkLLMouse)

Code: Select all

; idle: http://www.purebasic.fr/english/viewtopic.php?p=302739#p302739

#WH_MOUSE_LL = 14
#WM_MOUSEHWHEEL = 526

Structure MSLLHOOKSTRUCT
  pt.POINT;
  mouseData.l;
  flags.l;
  time.l;
  dwExtraInfo.l;
EndStructure

Global myKeyHook.l

Procedure.l MouseProc(ncode.l, wParam.l, lParam.l)

  Static lbStarttime.i, lbEndtime.i
  Static rbStarttime.i, rbEndtime.i
  Static sx, ex, sy, ey
  Protected px, py
  Static mMouseInput.MSLLHOOKSTRUCT
  CopyMemory(lparam, @mMouseInput, SizeOf(MSLLHOOKSTRUCT))
  Static mInput.MOUSEINPUT

  If ncode = #HC_ACTION
    If wParam

      Select wParam

        Case #WM_LBUTTONDOWN
          sx = mMouseInput\pt\x
          sy = mMouseInput\pt\y
          lbStartTime = mMouseInput\time
          AddGadgetItem(0, -1, "Left Button Down")
        Case #WM_LBUTTONUP
          ex = mMouseInput\pt\x
          ey = mMouseInput\pt\y
          lbEndtime = mMouseInput\time
          AddGadgetItem(0, -1, "Left Button Up (" + Str(lbEndTime - lbStartTime) + " ms elapsed)")
        Case #WM_MBUTTONDOWN
          sx = mMouseInput\pt\x
          sy = mMouseInput\pt\y
          lbStartTime = mMouseInput\time
          AddGadgetItem(0, -1, "Middle Button Down")
        Case #WM_MBUTTONUP
          ex = mMouseInput\pt\x
          ey = mMouseInput\pt\y
          lbEndtime = mMouseInput\time
          AddGadgetItem(0, -1, "Middle Button Up (" + Str(lbEndTime - lbStartTime) + " ms elapsed)")
        Case #WM_RBUTTONDOWN
          sx = mMouseInput\pt\x
          sx = mMouseInput\pt\y
          rbStartTime = mMouseInput\time
          AddGadgetItem(0, -1, "Right Button Down")
        Case #WM_RBUTTONUP
          ex = mMouseInput\pt\x
          ey = mMouseInput\pt\y
          rbEndtime = mMouseInput\time
          AddGadgetItem(0, -1, "Right Button Up (" + Str(rbEndTime - rbStartTime) + " ms elapsed)")
        Case #WM_MOUSEMOVE
          px = mMouseInput\pt\x
          py = mMouseInput\pt\y
        Case #WM_MOUSEWHEEL
          If mMouseInput\mouseData > 0
            Debug "up"
          Else
            Debug "down"
          EndIf
      EndSelect
    EndIf
  EndIf

  ProcedureReturn CallNextHookEx_(myMousehook, nCode, wParam, lParam)

EndProcedure

Procedure SetMouseHook()
  hInstance = GetModuleHandle_(0)

  If hInstance
    myMouseHook = SetWindowsHookEx_(#WH_MOUSE_LL, @MouseProc(), hInstance, 0)
  Else
    MessageRequester("hook", "can't get module handle")
  EndIf

EndProcedure

Procedure KillMouseHook()
  UnhookWindowsHookEx_(myMouseHook)
  MyMouseHook = 0
EndProcedure

If OpenWindow(0, 0, 0, 500, 300, "Mouse Test", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
  SetMouseHook()
  EditorGadget (0, 10, 10, 480, 260)
  TextGadget(1, 10,  280, 250, 20, "Click in this here area down here")
  Repeat
  Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf

KillMouseHook()
Image
jacky
User
User
Posts: 63
Joined: Mon Jan 21, 2019 1:41 pm

Re: Get pressed modifier key(s) + mouse click + mouse moveme

Post by jacky »

@JHPJHP & eJan

Thanks for your kind words and the examples!

@JHPJHP

I'm currently trying to understand how these hooks work, so...
does *lParam\vkCode only ever contain one pressed key at once or all keys?
If it does contain more than one key, how can I check if a combination of
them is pressed, e.g. shift+ctrl or shift+ctrl+alt, etc.?
JHPJHP
Addict
Addict
Posts: 2129
Joined: Sat Oct 09, 2010 3:47 am
Contact:

Re: Get pressed modifier key(s) + mouse click + mouse moveme

Post by JHPJHP »

Hi jacky,

Read the following acticles:
SetWindowsHookExA function
GetAsyncKeyState function
GetKeyState function

Here is a local example posted by RASHAD: viewtopic.php?p=530624#p530624
jacky wrote:does *lParam\vkCode only ever contain one pressed key at once or all keys?
Single key. With other keys such as CTRL, Shift, and ALT the following can be used:

Code: Select all

#SHIFTED = $8000

keyCTRL = GetAsyncKeyState_(#VK_CONTROL)

If keyCTRL & #SHIFTED
  ;...
EndIf
Alternately and including, the following can be used for Caps Lock, Num Lock, and Scroll Lock
- see Windows Services & Other Stuff\Other_Stuff\OtherStuff\GlobalKeyboardHook.pb

Code: Select all

#SHIFTED = $8000
CapsLock = GetKeyState_(#VK_CAPITAL) & #SHIFTED
NumLock = GetKeyState_(#VK_NUMLOCK) & #SHIFTED
ScrollLock = GetKeyState_(#VK_SCROLL) & #SHIFTED
Last edited by JHPJHP on Thu Jan 24, 2019 11:00 pm, edited 2 times in total.
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Get pressed modifier key(s) + mouse click + mouse moveme

Post by Dude »

Hi JHPJHP, in my apps I've had to use "& 1" with the LED keys, like so:

Code: Select all

CapsLock = GetKeyState_(#VK_CAPITAL) & 1
NumLock = GetKeyState_(#VK_NUMLOCK) & 1
ScrollLock = GetKeyState_(#VK_SCROLL) & 1
Otherwise getting the state is not reliable and can return unexpected values.
JHPJHP
Addict
Addict
Posts: 2129
Joined: Sat Oct 09, 2010 3:47 am
Contact:

Re: Get pressed modifier key(s) + mouse click + mouse moveme

Post by JHPJHP »

Hi Dude,

Thank you, it made me re-read the documentation.
- my previous post has been updated
Return Value
Type: SHORT
The return value specifies the status of the specified virtual key, as follows:
If the high-order bit is 1, the key is down; otherwise, it is up.
If the low-order bit is 1, the key is toggled. A key, such as the CAPS LOCK key, is toggled if it is turned on. The key is off and untoggled if the low-order bit is 0. A toggle key's indicator light (if any) on the keyboard will be on when the key is toggled, and off when the key is untoggled.
See the following MS example: https://docs.microsoft.com/en-ca/window ... oard-input
- same as the GetAsyncKeyState function (check for most significant bit)

Code: Select all

#SHIFTED = $8000
CapsLock = GetKeyState_(#VK_CAPITAL) & #SHIFTED
NumLock = GetKeyState_(#VK_NUMLOCK) & #SHIFTED
ScrollLock = GetKeyState_(#VK_SCROLL) & #SHIFTED
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Get pressed modifier key(s) + mouse click + mouse moveme

Post by Dude »

Hi JHPJHP,

I just tried it, and I see that $8000 indicates the toggle state. My tip was for determining the current state (on/off):

Code: Select all

Repeat
  Debug GetKeyState_(#VK_CAPITAL) & 1 ; Returns 1 if on, or 0 if off.
  Sleep_(100)
ForEver
Both methods have benefits. :)
jacky
User
User
Posts: 63
Joined: Mon Jan 21, 2019 1:41 pm

Re: Get pressed modifier key(s) + mouse click + mouse moveme

Post by jacky »

Thanks a lot, JHPJHP!

I'm currently using this:

Code: Select all

#SHIFTED = $8000

Global.i hKeyboardHook

Procedure KeyboardHook(nCode, wParam, *lParam.KBDLLHOOKSTRUCT)
  Protected.i shiftState, ctrlState, altState, keyState

  If nCode <> #HC_ACTION
    ProcedureReturn CallNextHookEx_(hKeyboardHook, nCode, wParam, *lParam)
  EndIf

  If GetAsyncKeyState_(#VK_SHIFT)   & #SHIFTED : shiftState = 1 : Else : shiftState = 0 : EndIf
  If GetAsyncKeyState_(#VK_CONTROL) & #SHIFTED : ctrlState  = 2 : Else : ctrlState  = 0 : EndIf
  If GetAsyncKeyState_(#VK_MENU)    & #SHIFTED : altState   = 4 : Else : altState   = 0 : EndIf
  keyState = shiftState + ctrlState + altState

  If     keyState = 7 : Debug "Shift+Ctrl+Alt"
  ElseIf keyState = 6 : Debug "Ctrl+Alt"
  ElseIf keyState = 5 : Debug "Shift+Alt"
  ElseIf keyState = 4 : Debug "Alt"
  ElseIf keyState = 3 : Debug "Shift+Ctrl"
  ElseIf keyState = 2 : Debug "Ctrl"
  ElseIf keyState = 1 : Debug "Shift" : EndIf

  ProcedureReturn CallNextHookEx_(hKeyboardHook, nCode, wParam, *lParam)
EndProcedure
I will probably just store the keyState in a global available structure and then
read it from the mouse hook (which I haven't looked at yet)

I left out wParam and the check for #WM_KEYUP / #WM_KEYDOWN because
it's possible that sometimes a #WM_KEYUP event isn't detected / ignored / whatever
leading to situations where the state isn't reset correctly and pressing ctrl is interpreted
as e.g. a shift instead.
jacky
User
User
Posts: 63
Joined: Mon Jan 21, 2019 1:41 pm

Re: Get pressed modifier key(s) + mouse click + mouse moveme

Post by jacky »

My previous version isn't 100% reliable, the 0 state isn't always returned correctly (depending on how short / long a combination of key modifiers are pressed)...

I'm trying to use this one instead now:

Code: Select all

    Procedure KeyboardHook(nCode, wParam, *lParam.KBDLLHOOKSTRUCT)
      Static.i shiftState, ctrlState, altState, winState, lastState

      If nCode <> #HC_ACTION
        ProcedureReturn CallNextHookEx_(hKeyboardHook, nCode, wParam, *lParam)
      EndIf

      ; #SHIFTED tests for "if a key is currently pressed"
      ; Using 1 instead would test for "on / off", e.g. for #VK_CAPITAL, #VK_NUMLOCK or #VK_SCROLL
      Select wParam
        Case #WM_KEYDOWN, #WM_SYSKEYDOWN
          If shiftState = #False And GetAsyncKeyState_(#VK_SHIFT)   & #SHIFTED : shiftState = #KM_S : EndIf                                            ; Shift down
          If ctrlState  = #False And GetAsyncKeyState_(#VK_CONTROL) & #SHIFTED : ctrlState  = #KM_C : EndIf                                            ; Ctrl down
          If altState   = #False And GetAsyncKeyState_(#VK_MENU)    & #SHIFTED : altState   = #KM_A : EndIf                                            ; Alt down
          If winState   = #False And ((GetAsyncKeyState_(#VK_LWIN) & #SHIFTED) Or (GetAsyncKeyState_(#VK_RWIN) & #SHIFTED)) : winState = #KM_W : EndIf ; Win down

        Case #WM_KEYUP
          If shiftState = #KM_S And GetAsyncKeyState_(#VK_SHIFT)   & #SHIFTED : shiftState = #False : EndIf                                            ; Shift up
          If ctrlState  = #KM_C And GetAsyncKeyState_(#VK_CONTROL) & #SHIFTED : ctrlState  = #False : EndIf                                            ; Ctrl up
          If altState   = #KM_A And GetAsyncKeyState_(#VK_MENU)    & #SHIFTED : altState   = #False : EndIf                                            ; Alt up
          If winState   = #KM_W And ((GetAsyncKeyState_(#VK_LWIN) & #SHIFTED) Or (GetAsyncKeyState_(#VK_RWIN) & #SHIFTED)) : winState = #False : EndIf ; Win up
      EndSelect

      ; Put the state into the structure
      kbd\kbdState = shiftState + ctrlState + altState + winState

      ; Logging
      ;CompilerIf #False
        With kbd
          If \kbdState <> lastState
            If     \kbdState = #KM_WSCA : Dbg::DebugString("kbd hook: Win+Shift+Ctrl+Alt") ; 15
            ElseIf \kbdState = #KM_WCA  : Dbg::DebugString("kbd hook: Win+Ctrl+Alt")       ; 14
            ElseIf \kbdState = #KM_WSA  : Dbg::DebugString("kbd hook: Win+Shift+Alt")      ; 13
            ElseIf \kbdState = #KM_WA   : Dbg::DebugString("kbd hook: Win+Alt")            ; 12
            ElseIf \kbdState = #KM_WSC  : Dbg::DebugString("kbd hook: Win+Shift+Ctrl")     ; 11
            ElseIf \kbdState = #KM_WC   : Dbg::DebugString("kbd hook: Win+Ctrl")           ; 10
            ElseIf \kbdState = #KM_WS   : Dbg::DebugString("kbd hook: Win+Shift")          ;  9
            ElseIf \kbdState = #KM_W    : Dbg::DebugString("kbd hook: Win")                ;  8
            ElseIf \kbdState = #KM_SCA  : Dbg::DebugString("kbd hook: Shift+Ctrl+Alt")     ;  7
            ElseIf \kbdState = #KM_CA   : Dbg::DebugString("kbd hook: Ctrl+Alt")           ;  6
            ElseIf \kbdState = #KM_SA   : Dbg::DebugString("kbd hook: Shift+Alt")          ;  5
            ElseIf \kbdState = #KM_A    : Dbg::DebugString("kbd hook: Alt")                ;  4
            ElseIf \kbdState = #KM_SC   : Dbg::DebugString("kbd hook: Shift+Ctrl")         ;  3
            ElseIf \kbdState = #KM_C    : Dbg::DebugString("kbd hook: Ctrl")               ;  2
            ElseIf \kbdState = #KM_S    : Dbg::DebugString("kbd hook: Shift")              ;  1
            ElseIf \kbdState = #False   : Dbg::DebugString("kbd hook: <None>")             ;  0
            EndIf
          EndIf
          lastState = \kbdState
        EndWith
      ;CompilerEndIf

      ProcedureReturn CallNextHookEx_(hKeyboardHook, nCode, wParam, *lParam)
    EndProcedure
But it isn't optimal as well. It works rather fine on my main mechanical keyboard, but this happens:

Code: Select all

[09:12:44] kbd hook: Alt
[09:12:44] kbd hook: Ctrl+Alt
[09:12:44] kbd hook: Win+Ctrl+Alt
<a small delay>
[09:12:45] kbd hook: Win+Shift+Ctrl+Alt
[09:12:45] kbd hook: <None>
So it returns the <None> state correctly but when pressing more than one modifier at the same time,
all of them (apart from the last) are logged instantly (in this case the first three) but there is always a small delay until
the last pressed modifier is recognized as well.
It's the same when I press just e.g. only two of them at the same time. For example Shift+Ctrl.
Then either of them appears instantly in the log while there is again a small delay before the log shows that both of them
are pressed.

On a second mechanical keyboard the <None> state isn't always reported correctly. E.g.:

Code: Select all

[09:20:19] kbd hook: Ctrl
[09:20:19] kbd hook: Ctrl+Alt
[09:20:19] kbd hook: Win+Ctrl+Alt
[09:20:19] kbd hook: Win+Ctrl
After releasing Win+Ctrl+Alt (they were pressed only for a very short amount of time), not <None> was logged
but Win+Ctrl instead (which is ofc BAD, because my mouse hook reads the kbd\kbdState variable and gets wrong
information).

Any guide how to make this hook 100% reliable and without the delay until all pressed keys are recognized correctly?
Post Reply