Jump to content

Hold down Hotkey without repeating assigned function


Go to solution Solved by Andreik,

Recommended Posts

When I hold a key down I need it to fire a function which will run until I release the key.

I tried using _IsPressed which works, but it continues sending the actual key I'm holding down which is no good.

To prevent the key being sent I used HotKeySet. However, when I hold down the key set as a hotkey, it triggers the function continuously until I let go. So back to square one.

Is there a way to achieve what I want?

 

#include <Misc.au3>
Local $hDLL = DllOpen("user32.dll")

HotKeySet("{F8}", "Terminate")
HotKeySet("=", "test")

Func Terminate()
    DllClose($hDLL)
    Exit 0
EndFunc

Func test()
    If _IsPressed("BB", $hDLL) Then
        ConsoleWrite("_IsPressed - '=' Key was pressed." & @CRLF)
        While _IsPressed("BB", $hDLL)
            ConsoleWrite("  '=' Key remains pressed." & @CRLF)
            Sleep(250)
        WEnd
        ConsoleWrite("_IsPressed - '=' Key was released." & @CRLF)
    EndIf
    Sleep(250)
EndFunc

While 1
    Sleep(250)
WEnd

DllClose($hDLL)

 

Link to comment
Share on other sites

What is it, that you are trying to achieve?

I changed to key 1 for testing.

 

#include <Misc.au3>
Local $hDLL = DllOpen("user32.dll")

HotKeySet("{F8}", "Terminate")

Func Terminate()
    DllClose($hDLL)
    Exit 0
EndFunc

Func test()
    If _IsPressed("31", $hDLL) Then
        ConsoleWrite("_IsPressed - '=' Key was pressed." & @CRLF)
        While _IsPressed("31", $hDLL)
            ConsoleWrite("  '=' Key remains pressed." & @CRLF)
            Sleep(250)
        WEnd
        ConsoleWrite("_IsPressed - '=' Key was released." & @CRLF)
    EndIf
EndFunc

While 1
    Sleep(250)
    test()
WEnd

DllClose($hDLL)

 

 

Edited by Xenobiologist

Scripts & functions Organize Includes Let Scite organize the include files

Yahtzee The game "Yahtzee" (Kniffel, DiceLion)

LoginWrapper Secure scripts by adding a query (authentication)

_RunOnlyOnThis UDF Make sure that a script can only be executed on ... (Windows / HD / ...)

Internet-Café Server/Client Application Open CD, Start Browser, Lock remote client, etc.

MultipleFuncsWithOneHotkey Start different funcs by hitting one hotkey different times

Link to comment
Share on other sites

16 minutes ago, Xenobiologist said:

What is it, that you are trying to achieve?

I changed to key 1 for testing.

 

#include <Misc.au3>
Local $hDLL = DllOpen("user32.dll")

HotKeySet("{F8}", "Terminate")

Func Terminate()
    DllClose($hDLL)
    Exit 0
EndFunc

Func test()
    If _IsPressed("31", $hDLL) Then
        ConsoleWrite("_IsPressed - '=' Key was pressed." & @CRLF)
        While _IsPressed("31", $hDLL)
            ConsoleWrite("  '=' Key remains pressed." & @CRLF)
            Sleep(250)
        WEnd
        ConsoleWrite("_IsPressed - '=' Key was released." & @CRLF)
    EndIf
EndFunc

While 1
    Sleep(250)
    test()
WEnd

DllClose($hDLL)

 

 

 

When you run the code, open up notepad, and press and hold 1, the cosole output is correct, but as you will see, AutoIt keeps sending 1 to the notepad. Which is no good, re my initial post:

25 minutes ago, Seminko said:

I tried using _IsPressed which works, but it continues sending the actual key I'm holding down which is no good.

 

Link to comment
Share on other sites

#include <Misc.au3>
Local $hDLL = DllOpen("user32.dll")

HotKeySet("{F8}", "Terminate")
HotKeySet("=", "test")

Func Terminate()
    DllClose($hDLL)
    Exit 0
EndFunc

Func test()
    HotKeySet('=')
    ConsoleWrite("_IsPressed - '=' Key was pressed." & @CRLF)
    Do
        ConsoleWrite("  '=' Key remains pressed." & @CRLF)
        Sleep(250)
    Until Not _IsPressed('BB', $hDLL)
    ConsoleWrite("_IsPressed - '=' Key was released." & @CRLF)
    Sleep(250)
    HotKeySet("=", "test")
EndFunc

While 1
    Sleep(250)
WEnd

DllClose($hDLL)

 

When the words fail... music speaks.

Link to comment
Share on other sites

18 minutes ago, Andreik said:
#include <Misc.au3>
Local $hDLL = DllOpen("user32.dll")

HotKeySet("{F8}", "Terminate")
HotKeySet("=", "test")

Func Terminate()
    DllClose($hDLL)
    Exit 0
EndFunc

Func test()
    HotKeySet('=')
    ConsoleWrite("_IsPressed - '=' Key was pressed." & @CRLF)
    Do
        ConsoleWrite("  '=' Key remains pressed." & @CRLF)
        Sleep(250)
    Until Not _IsPressed('BB', $hDLL)
    ConsoleWrite("_IsPressed - '=' Key was released." & @CRLF)
    Sleep(250)
    HotKeySet("=", "test")
EndFunc

While 1
    Sleep(250)
WEnd

DllClose($hDLL)

 

Thanks for the reply. I tried just that before posting the thread. It suffers from the same unwanted behavior as Xenobiologist's asnwer. Since you remove the hotkey in the function, '=' is being sent during the function execution.

Link to comment
Share on other sites

  • Solution
Posted (edited)

Well, if you want to suppress the key just use a keyboard hook:

#include <WindowsConstants.au3>
#include <WinAPISys.au3>
#include <WinAPIConstants.au3>

Global $bExit = False

$hKeyboardProc = DllCallbackRegister('KeyboardProc', 'long', 'int;wparam;lparam')
$hHook = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, DllCallbackGetPtr($hKeyboardProc), _WinAPI_GetModuleHandle(0))

Do
    Sleep(10)
Until $bExit

_WinAPI_UnhookWindowsHookEx($hHook)
DllCallbackFree($hKeyboardProc)

Func KeyboardProc($nCode, $wParam, $lParam)
    If $nCode < 0 Then Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    Local $tKEYHOOKS = DllStructCreate('dword vkCode;dword scanCode;dword flags;dword time;ulong_ptr dwExtraInfo', $lParam)
    Switch $wParam
        Case $WM_KEYDOWN
            If $tKEYHOOKS.vkCode = 0x1B Then $bExit = True
            If $tKEYHOOKS.vkCode = 0xBB Then
                ConsoleWrite('= is pressed down' & @CRLF)
                Return 1
            EndIf
        Case $WM_KEYUP
            If $tKEYHOOKS.vkCode = 0xBB Then
                ConsoleWrite('= is released' & @CRLF)
                Return 1
            EndIf
    EndSwitch
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
EndFunc

 

Edited by Andreik

When the words fail... music speaks.

Link to comment
Share on other sites

1 hour ago, Andreik said:

Well, if you want to suppress the key just use a keyboard hook:

#include <WindowsConstants.au3>
#include <WinAPISys.au3>
#include <WinAPIConstants.au3>

Global $bExit = False

$hKeyboardProc = DllCallbackRegister('KeyboardProc', 'long', 'int;wparam;lparam')
$hHook = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, DllCallbackGetPtr($hKeyboardProc), _WinAPI_GetModuleHandle(0))

Do
    Sleep(10)
Until $bExit

_WinAPI_UnhookWindowsHookEx($hHook)
DllCallbackFree($hKeyboardProc)

Func KeyboardProc($nCode, $wParam, $lParam)
    Local Static $LastKey = Null
    If $nCode < 0 Then Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    Local $tKEYHOOKS = DllStructCreate('dword vkCode;dword scanCode;dword flags;dword time;ulong_ptr dwExtraInfo', $lParam)
    Switch $wParam
        Case $WM_KEYDOWN
            If $tKEYHOOKS.vkCode = 0x1B Then $bExit = True
            If $tKEYHOOKS.vkCode = 0xBB Then
                ConsoleWrite('= is pressed down' & @CRLF)
                Return 1
            EndIf
        Case $WM_KEYUP
            If $tKEYHOOKS.vkCode = 0xBB Then
                ConsoleWrite('= is released' & @CRLF)
                Return 1
            EndIf
    EndSwitch
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
EndFunc

 

Great stuff! Thank you very much.

I'm totally lost when it comes to DLL stuff, though. Would you be willing to comment the code a bit?

Link to comment
Share on other sites

#include <WindowsConstants.au3>
#include <WinAPISys.au3>
#include <WinAPIConstants.au3>

Global $KeyDown = False

; Register a hotkey to exit the program
HotKeySet('{ESC}', 'Quit')

; Set a low level keyboard hook
; KeyboardProc it's a callback function that it's called when keyboard events occurs
$hKeyboardProc = DllCallbackRegister('KeyboardProc', 'long', 'int;wparam;lparam')
$hHook = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, DllCallbackGetPtr($hKeyboardProc), _WinAPI_GetModuleHandle(0))

Do
    ; We process the messsage here because it's a good practice to return from 
    ; the callback function as soon as possible and without using any blocking functions
    If $KeyDown Then
        ConsoleWrite('= was pressed' & @CRLF)
        Do
            ConsoleWrite('= is still pressed' & @CRLF)
            Sleep(10)
        Until Not $KeyDown
        ConsoleWrite('= was released' & @CRLF)
    EndIf
    Sleep(10)
Until $bExit

; Unset the keyboard hook
_WinAPI_UnhookWindowsHookEx($hHook)
DllCallbackFree($hKeyboardProc)

Func KeyboardProc($nCode, $wParam, $lParam)
    ; If nCode is less than zero just call the next hook procedure in the current hook chain
    If $nCode < 0 Then Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    ; Create a structure that will contain info about the keyboard event
    ; (lParam it's the pointer to the KBDLLHOOKSTRUCT structure)
    Local $tKEYHOOKS = DllStructCreate('dword vkCode;dword scanCode;dword flags;dword time;ulong_ptr dwExtraInfo', $lParam)
    ; wParam contains the identifier of the keyboard message
    Switch $wParam
        Case $WM_KEYDOWN
            ; When = key it's pressed
            ; set $KeyDown to true, so you don't have to process anything else in the callback function
            If $tKEYHOOKS.vkCode = 0xBB Then
                $KeyDown = True
                ; Return nonzero value to prevent the system from passing the 
                ; message to the rest of the hook chain or the target window procedure
                Return 1
            EndIf
        Case $WM_KEYUP
            ; When = key it's released
            ; set $KeyDown to false, so you don't have to process anything else in the callback function
            If $tKEYHOOKS.vkCode = 0xBB Then
                $KeyDown = False
                ; Return nonzero value to prevent the system from passing the 
                ; message to the rest of the hook chain or the target window procedure
                Return 1
            EndIf
    EndSwitch
    ; Call the next hook procedure in the current hook chain
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
EndFunc

Func Quit()
    $bExit = True
EndFunc

You can read all this stuff in more details here, here and here.

Edited by Andreik

When the words fail... music speaks.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...