Question

I use thousands of AHK hotstrings. For example (simplified):

::btw::by the way

Unlike most AHK users, the only endkey I allow is \. So when I type btw\, I get by the way. Space or enter or other such keys do not set off the hotstrings. This ensures that hotstrings are never set off unintentionally.

Now, I also use chords. Here's a simplified version of one my chords:

~t & g::
~g & t::
    SendInput {Backspace}
    SendInput {Space}the{Space}
    Return

The way these chords work is that if I press my finger on the border between the t and g keys, AHK types the (Including a space before and after.) Very useful.

Now, I'd like to take this up a notch: I want chords to automatically set off hotstrings. For example, say I want to type by the way the. I could type btw\ and then t and g together. But, it would be nicer if I could skip the backslash, and instead have the chord automatically set off the hotstring. (Only in the case where the text immediately before a chord is a hotstring, of course.)

Now obviously, I want this to work not only for this specific combination of btw and t+g, but for any combination of hotstring and chord from my vast collection.

How can I do that?

(One idea that came to mind is that AHK probably has a function that it launches every time you hit an endkey, which does something to the effect of "Look at the text that the user typed so far. Is it a hotstring? If so execute it." If only I had a way to invoke that function from inside my chord script, that would solve my problem. However, I have no idea how to do that.)

Was it helpful?

Solution 2

After spending about 10 hours on it, I've decided to abandon this project. Besides all the usual AHK horribleness and bugs, there's the intractable problem that if I type I love the sun and then 7 and u at the same time, I'll get I love the Sunday and instead of I love the sun and, because AutoHotKey has no way of knowing I didn't mean it to expand the hotstring in that instance.

OTHER TIPS

Your question bothered me so much, I played around until I found a solution that seems to work pretty well:

#HotString *B0
SendMode, Input

endChars := "`n `t"
interruptChars := chr(8) ; 8 is BACKSPACE
counter := 33
while(counter <= 126)
{
    interruptChars .= chr(counter++)
}
Loop, Parse, endChars
{
    Hotkey, *~%A_LoopField%, FinishHotstring
}
Loop, Parse, interruptChars
{
    Hotkey, *~%A_LoopField%, InterruptHotString
}

; this is our pending hotstring replacement
pendingHS := ""
; this var will hold the number of BACKSPACEs needed
; to erase the input before replacing the hotstring
pendingBS := -1

Exit

::btw::
    pendingHS := "by the way"
    RegExMatch(A_ThisLabel, ":.*?:(.*)", abbr)
    pendingBS := StrLen(abbr1)
return

::bt::
    pendingHS := "Bluetooth"
    RegExMatch(A_ThisLabel, ":.*?:(.*)", abbr)
    pendingBS := StrLen(abbr1)
return

~t & g::
~g & t::
    if(pendingHS) {
        pendingBS++
        Send % "{BACKSPACE " pendingBS "}" pendingHS " the "
        pendingHS := ""
    } else {
        Send % "{BACKSPACE} the "
    }
Return

FinishHotstring:
    if(pendingHS) {
        pendingBS++
        Send, % "{BACKSPACE " pendingBS "}" pendingHS
        pendingHS := ""
    }
return

InterruptHotString:
    if(pendingHS) {
        pendingHS := ""
    }
return

Sadly, this solution removes itself very far from the AHK standard for hotstrings. At the beginning, you'll have to define your custom endChars, and also your custom interruptChars (they tell the script when your hotstring isn't actually one, since it is triggered immediately). I used BACKSPACE and ASCII chars 33 through 126.
The rest is quite self-explanatory: Every alleged hotstring is stored and not yet sent. If either an endChar or a chord or an interruptChar is triggered, the script either sends the usual hotstring replacement or adds the chord appendix or doesn't do anything.

Please discuss!

Using RegEx Powered Dynamic Hotstrings may be an option for you. The tricky part would be determining whether the text is a hotstring or not. Possibly keeping an array of everything? Below is some pseudo-code.

#Include DynamicHotstrings.ahk

hotstrings("(\w+)\\", "check")
Return

check:
    args := $1
    if (args = "btw") ; Ideally you would check an array to see if this was a hotstring
        msgbox % args ; SendInput
return

Getting the hotstrings into an array could be simply maintaining them manually, parsing your script, or even using a script like this.

I hope this points you in the right direction.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top