InputHook lags when triggering Hotstring Topic is solved

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
8LWXpg
Posts: 40
Joined: 26 May 2022, 03:55

InputHook lags when triggering Hotstring

Post by 8LWXpg » 26 May 2022, 04:11

I have a code working with InputHook(), but I found that it receives input that Hotstring sends, and is somehow makes the script consumes 25% of CPU and makes everything lagging. Is there any way preventing it?

here's my code:

Code: Select all

#SingleInstance Force

Esc:: ExitApp()

SacHook := InputHook("V")
SacHook.KeyOpt("{Tab}{Space}{Enter}", "+N")
SacHook.OnKeyDown := SacChar
SacHook.Start()
Hs := RegExHs()

SacChar(ih, vk, sc) {
    ; match when pressed
    if (vk = 0x09 || vk = 0x0d || vk = 0x20) {
        ; loop through
        input := ih.Input
        ih.Stop()
        loop Hs.Len() {
            str := Hs.str_arr[A_Index]
            call := Hs.call_arr[A_Index]
            if (RegExMatch(input, str, &match)) {
                ; delete matched string
                Send("{BS " match.Len[0] + 1 "}")
                if (call is String) {
                    Send(RegExReplace(input, str, call))
                } else if (call is Func) {
                    call(match)
                } else
                    throw 'callback type error:`ninput should be "Func" or "String"'
                ih.Start()
                return
            }
        }
        ih.Start()
    }
}

RegExHotstring(str, Callback) {
    Hs.Append(str, Callback)
}

Class RegExHs {

    str_arr := Array()
    call_arr := Array()

    ; append new RegExHotstring
    Append(str, callback) {
        this.str_arr.Push(str)
        this.call_arr.Push(callback)
    }

    Len() {
        return this.str_arr.Length
    }
}

; ###################### test #########################

RegExHotstring("(\w)abc", call)
RegExHotstring("(\w)dbc", "dbc$1")
::asdf::qwer
It lags when triggering hotstring.

lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: InputHook lags when triggering Hotstring  Topic is solved

Post by lexikos » 27 May 2022, 23:46

This is a bug. You can work around it by calling the following after ih.Stop():

Code: Select all

Critical false ; Enable immediate thread interruption.
Sleep -1 ; Process any pending messages.

it receives input that Hotstring sends
If you don't want that, you need to use the I option or set SacHook.MinSendLevel.

InputHook has first chance at keyboard events, but since you have not set it to suppress the trigger keys, the keyboard hook may notify you of the keypress and then also trigger a hotstring. If it triggers a hotstring, generally the AHK_HOTSTRING message will be in the message queue until the first check for messages after your function is called. This can be detected with the following function:

Code: Select all

HotstringIsQueued() {
    static AHK_HOTSTRING := 1025
    msg := Buffer(4*A_PtrSize+16)
    return DllCall("PeekMessage", "ptr", msg, "ptr", A_ScriptHwnd
        , "uint", AHK_HOTSTRING, "uint", AHK_HOTSTRING, "uint", 0)
}
So another workaround is to avoid stopping/starting the InputHook if a hotstring is queued:

Code: Select all

if HotstringIsQueued()
    return
If you leave MinSendLevel at its default value, SacHook.Input should update according to the keys sent by the hotstring. However, you probably want to instead reset SacHook when a normal hotstring is triggered, and currently I think the only way to do that is to Stop and Start it.

Post Reply

Return to “Ask for Help (v2)”