I've been updating my codebase all weekend for @lexikos' most excellent recent updates to the language. They are fantastic! If you haven't tried the new build, you definitely should. Anyhow, as I was refactoring things...
It dawned on me that it might be more efficient if there were a built-in way to use Shift+Space to expand hotstrings. The keys are extremely easily reached and logical for an expansion, and very often unused/underused, at least by me. Inadvertent hotstring expansion happens often when I'm using hotstrings as intended (e.g. without solely obscure end characters), and might it be a pain point that could be fixed?
I am writing this not as much as an "ask for help" but more as a feature discussion. I've noticed
earlier posts on the topic in "ask for help", but these seem to be pretty ugly workarounds for something that seems like it might be a good idea. It might even be something that could be highlighted in the docs as a core example of how to avoid unwanted expansion, if there were a built-in way to handle it.
Would adding an option that would enable SendKeys-style key notation be hard to do, or would it conflict with other features? If there's an easy way already included in the options, I'd be interested in knowing. Many thanks.
Random feature? Shift+Space to expand hotstrings?
Re: Random feature? Shift+Space to expand hotstrings?
Hotstrings are formed by text (character strings), and Shift+Space does not imply any text different to Space.
If you want a hotstring to be triggered only by Shift+Space, I think the easiest method is this:
This only works because Shift+Space still produces a space.
A more general workaround is to send an end char. For example (save as UTF-8):
If you want to allow other end chars and not omit them, you can just leave out the O option and simulate one of those end chars instead.
There are at least two drawbacks:
But this won't be 100% reliable, and may cause further complications.
Of course, you don't need a workaround if you want +Space to always produce the end char (for example, if you want +Space to produce a non-breaking space, you can use that as the end char).
More generally, the end key-combo might have some effect which you want to avoid when triggering a hotstring, but otherwise keep. Perhaps each context where the key-combo is used could be detected with #HotIf and excluded from firing the end char hotkey, but that might be difficult or impossible, or maybe there's some context where you want to use the key-combo for both purposes.
There have been requests for allowing Send syntax within the hotstring's trigger, so a hotstring can be triggered by a sequence of key combos that don't normally produce text. This cannot be done, because hotstring recognition is based on a single buffer containing text produced by keypresses, relying on the premise that these keypresses can be allowed to have their normal effect, then be undone by backspacing.
However, the hotstring end char is blocked (not backspaced) when backspacing is to be done or the O option was used. This can only be done by the hotstring recognizer, because only it knows that the keypress just triggered a hotstring. It's just a keypress at this stage and hasn't yet produced text, so recognizing other key combos for hotstring ending would certainly be feasible. Input and InputHook already use the concept of end keys, using Send syntax.
There might be cases where one wants to trigger hotstring expansion without pressing any keyboard keys. Adding something like Hotstring("End") for this purpose should be feasible. (There is already Hotstring("Reset") to reset the hotstring recognizer.) This would avoid the complications of #InputLevel vs. SendLevel or unintended effects of sending the end char or attempting to backspace it, but not the issues of hotkey (non)suppression.
In theory, giving it a return value indicating whether a hotstring was recognized might also solve the issue of whether to suppress the hotkey:
However, I don't think the hook would handle this kind of reentry well. Also, this is noncompliant with an important recommendation:
Perhaps a couple of extra functions would allow the most flexibility (and I'm starting to think Hotstring() shouldn't have more than one "mode"):
... but I can't yet imagine how HotstringPending could be used on its own.
If you want a hotstring to be triggered only by Shift+Space, I think the easiest method is this:
Code: Select all
#HotIf GetKeyState("Shift")
:*:x1 ::Example #1 ; Space is included in the hotstring.
A more general workaround is to send an end char. For example (save as UTF-8):
Code: Select all
#Hotstring EndChars ⌨
#Hotstring O
$+Space::{
SendLevel 1
Send "⌨"
}
::x1::Example #1
There are at least two drawbacks:
- Shift+Space will always be blocked and can't be used for some other purpose (even when it is not preceded by a legitimate hotstring).
- If no hotstring is triggered, or if the end char is not omitted, Shift+Space will produce a character that might be unwanted.
Code: Select all
$+Space::{
SendLevel 1
Send "⌨"
Sleep 50
if !(A_ThisHotkey ~= "^:.*:" && A_PriorKey = "Space")
Send "{BS}"
}
Of course, you don't need a workaround if you want +Space to always produce the end char (for example, if you want +Space to produce a non-breaking space, you can use that as the end char).
More generally, the end key-combo might have some effect which you want to avoid when triggering a hotstring, but otherwise keep. Perhaps each context where the key-combo is used could be detected with #HotIf and excluded from firing the end char hotkey, but that might be difficult or impossible, or maybe there's some context where you want to use the key-combo for both purposes.
There have been requests for allowing Send syntax within the hotstring's trigger, so a hotstring can be triggered by a sequence of key combos that don't normally produce text. This cannot be done, because hotstring recognition is based on a single buffer containing text produced by keypresses, relying on the premise that these keypresses can be allowed to have their normal effect, then be undone by backspacing.
However, the hotstring end char is blocked (not backspaced) when backspacing is to be done or the O option was used. This can only be done by the hotstring recognizer, because only it knows that the keypress just triggered a hotstring. It's just a keypress at this stage and hasn't yet produced text, so recognizing other key combos for hotstring ending would certainly be feasible. Input and InputHook already use the concept of end keys, using Send syntax.
There might be cases where one wants to trigger hotstring expansion without pressing any keyboard keys. Adding something like Hotstring("End") for this purpose should be feasible. (There is already Hotstring("Reset") to reset the hotstring recognizer.) This would avoid the complications of #InputLevel vs. SendLevel or unintended effects of sending the end char or attempting to backspace it, but not the issues of hotkey (non)suppression.
Code: Select all
#Requires ???
^Space::Hotstring "End"
Code: Select all
#Requires ???
#HotIf Hotstring("End")
^Space::return
Specifically, pressing just Space in the following example would end hotstrings (search for a & b:: in the #HotIf documentation for details):Note: Scripts should not assume that the expression is only evaluated when the key is pressed (see below).
Code: Select all
#Requires ???
Space::Send " "
#HotIf Hotstring("End")
Space & b::return
Code: Select all
#Requires ???
Space::Send " "
#HotIf HotstringPending()
Space & b::HotstringEnd()