How to write Hotstrings that takes user input?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Kotte
Posts: 45
Joined: 03 May 2021, 08:33

How to write Hotstrings that takes user input?

Post by Kotte » 26 Jul 2021, 12:05

Hi,
I don't know the name of what I'm looking for, so I haven't had any luck searching or reading different forum posts. I'll try to give a clear picture of what output I'm after and then maybe you can point me in the right direction.

I would like to be able to trigger a hotstring, have it take multiple input variables and then get an output.
One example would be writing fractions in latex. Today I have the hotstring "frac" which outputs "\frac{}{}{left 3}", which works fine for simple expressions, but becomes useless for more complex ones (useless in the sense that it is faster to just manually write every character instead).

Let's say I wanted to write the fraction a/b. Today i would write "frac+Space" to get \frac{}{}, then type "a" and then get over to the next parenthesis and type "b". What I would like is to write something like "fr.a''b.,." and get the output \frac{a}{b}.

This is just the tip of the iceberg of what I'd like it to do, but I'm guessing it's best to start small.

What do you suggest I do/read?

User avatar
mikeyww
Posts: 26435
Joined: 09 Sep 2014, 18:38

Re: How to write Hotstrings that takes user input?

Post by mikeyww » 26 Jul 2021, 13:33

Here are some examples of hotstrings & hotkeys that can be used to parse input.

https://www.autohotkey.com/boards/viewtopic.php?f=76&t=93046

User avatar
flyingDman
Posts: 2776
Joined: 29 Sep 2013, 19:01

Re: How to write Hotstrings that takes user input?

Post by flyingDman » 26 Jul 2021, 14:03

In that thread referred to by @mikeyww , I mentioned the hotstrings() function (see this post: https://github.com/Paris/AutoHotkey-Scripts/blob/master/Hotstrings.ahk). It might be what you are looking for. Put the function in a library or include it in the script.

This accomplishes what you requested:

Code: Select all

hotstrings("fr.(\w)''(\w).,.", "label")           ; these are 2 single quotes between the \w
return

label:
send % "\frac{{}" $1 "{}}{{}" $2 "{}}"
return
Now type fr.a''b.,.
I would simplify it to

Code: Select all

hotstrings("fr.(\w)(\w)", "label")
return

label:
send % "\frac{{}" $1 "{}}{{}" $2 "{}}"
return
Now type fr.ab
14.3 & 1.3.7

Kotte
Posts: 45
Joined: 03 May 2021, 08:33

Re: How to write Hotstrings that takes user input?

Post by Kotte » 26 Jul 2021, 16:13

@mikeyww I didn't find what I was looking for when I searched the AHK help for parse. Is it mentioned in an other section?

Kotte
Posts: 45
Joined: 03 May 2021, 08:33

Re: How to write Hotstrings that takes user input?

Post by Kotte » 26 Jul 2021, 16:34

@flyingDman I couldn't get your code to work in heartstrings.ahk. "#Warn" gives me constant error messages until I close the script. That happened where ever I added the code. It starts by saying "z" is not assigned a value and continues with the other variables.

User avatar
flyingDman
Posts: 2776
Joined: 29 Sep 2013, 19:01

Re: How to write Hotstrings that takes user input?

Post by flyingDman » 26 Jul 2021, 16:48

Try deleting #Warn
14.3 & 1.3.7

Kotte
Posts: 45
Joined: 03 May 2021, 08:33

Re: How to write Hotstrings that takes user input?

Post by Kotte » 27 Jul 2021, 07:34

@flyingDman Haha, such an easy solution =) I saw #Warn in some video by Joe Glines and have just had it in all scripts since. It works now, but only for single inputs. What do I need for it to take any input.

It will differ a lot, but "a" might have the form "\int_{0}^{a^2} \frac{f''(x)}{\sin x} ,\ dx".

My thought was that I have to create variables for "a" and "b" so that any input, including hotstrings, can be used.

User avatar
flyingDman
Posts: 2776
Joined: 29 Sep 2013, 19:01

Re: How to write Hotstrings that takes user input?

Post by flyingDman » 27 Jul 2021, 09:45

Try something like:

Code: Select all

hotstrings("fr@(.*)@(.*)@", "label")
return

label:
send % "\frac{{}" $1 "{}}{{}" $2 "{}}"
return
start with fr@ then enter a and b separated by a @ and end with @. I do not know if it works with complex strings or if they can be adapted to work with this. Give it a try.
14.3 & 1.3.7

Kotte
Posts: 45
Joined: 03 May 2021, 08:33

Re: How to write Hotstrings that takes user input?

Post by Kotte » 27 Jul 2021, 13:01

@flyingDman It works for multiple numbers and letters, but it doesn't solve the problem. Numbers and letters are not the problem, it's the characters like: \()[]{}'*^_-!%/*-+´`<>|.

I use all of those regularly, and most of them daily. I tried SendRaw instead and it worked better, but it seems like its the input that's the problem then. It only registers keystrokes. Is there something similar to SendRaw but for input, so that it takes the characters between @ and @ instead of what keypresses are made?

User avatar
flyingDman
Posts: 2776
Joined: 29 Sep 2013, 19:01

Re: How to write Hotstrings that takes user input?

Post by flyingDman » 27 Jul 2021, 14:34

I had the same result. A soon as you use one of the other characters, the results are unpredictable. I've used hotstrings() for a number scripts but never ran into this before. Does not seem to be a good solution for this type of application. :cry: :cry:
14.3 & 1.3.7

sofista
Posts: 644
Joined: 24 Feb 2020, 13:59
Location: Buenos Aires

Re: How to write Hotstrings that takes user input?

Post by sofista » 27 Jul 2021, 16:24

@flyingDman, @Kotte I know nothing about Latex, so I could be wrong here, but if you avoid the label subroutine, the call to Hotstrings.ahk seems to work.

Two examples:

Code: Select all

#Include Hotstrings.ahk

hotstrings("fr,(.+)(.+)", "\frac{%$1%}{%$2%}")
return

/* Type (for both examples): fr,ab

Output:

\frac{a}{b}
 */
or

Code: Select all

#Include Hotstrings.ahk

hotstrings("fr,(.+)(.+)", "\int_{0}^{%$1%^2} \frac{f''(x)}{\sin x} ,\ dx")
return

/* Output:

\int_{0}^{a^2} \frac{f''(x9}{\sin x} ,\ dx
 */

User avatar
flyingDman
Posts: 2776
Joined: 29 Sep 2013, 19:01

Re: How to write Hotstrings that takes user input?

Post by flyingDman » 27 Jul 2021, 17:35

It seems @sofista is correct. Dropping the label seems to fix the issue. Or at least whatever I threw at it. Strange that it handles these two situations differently.
14.3 & 1.3.7

sofista
Posts: 644
Joined: 24 Feb 2020, 13:59
Location: Buenos Aires

Re: How to write Hotstrings that takes user input?

Post by sofista » 27 Jul 2021, 18:49

@flyingDman It is a quite old code, with lots of deprecated commands. Perhaps something not too important was broken with the successive updates of AutoHotkey.

Also, it wouldn't be easy to update the function either, since the code almost lacks comments and variables have no meaningful names. It is easy to get lost there :(

User avatar
flyingDman
Posts: 2776
Joined: 29 Sep 2013, 19:01

Re: How to write Hotstrings that takes user input?

Post by flyingDman » 27 Jul 2021, 19:01

@sofista, yes I agree. It is an older piece of code and needs some TLC from someone who fully understands it. And I think that it would be worth to bring it to current standards as it is quite powerful and a natural / logical extension of regular hotstrings.
14.3 & 1.3.7

Kotte
Posts: 45
Joined: 03 May 2021, 08:33

Re: How to write Hotstrings that takes user input?

Post by Kotte » 29 Jul 2021, 09:33

@sofista It didn't work. It seems I have not explained what was input and what was output in a clear manner.
I'd like to input two expressions (a and b) and get the output \frac{a}{b}. Both a and b might contain any combination of these characters.
\()[]{}'*^_-!%/*-+´`>|

If I wrote "fr.x^{2}''\alpha.,." I would want the output \frac{x^2}{\alpha} (here I use two ' as separators between expressions).
So here a=x^{2} and b=\alpha, using "fr." as a trigger "''" as separators and ".,." as the ending trigger.

To not confuse with latex code, I would describe it something like a text expander with words/symbols before, in the middle and after. Another, maybe a clearer example would be:
"Hi, a! You are good at b!"

If I'd use "hi." as a trigger, kept the rest the same and wrote:
hi.Mike''swimming.,.
I would expect the output:
Hi, Mike! You are good at swimming!

The problem seems to be with the inputs. Instead of letters/numbers they would be basically any character on the keyboard.

sofista
Posts: 644
Joined: 24 Feb 2020, 13:59
Location: Buenos Aires

Re: How to write Hotstrings that takes user input?

Post by sofista » 29 Jul 2021, 18:37

@Kotte Thanks for the examples, now the issue is clearer. As I see it — without having tested it thoroughly or systematically — some regex metacharacters, such as "\" and "^", are either ignored in the hotstring expansion or the expression is not expanded at all, without any error message.

At least for now, I ran out of ideas. Hopefully someone else can provide you a working solution.

User avatar
flyingDman
Posts: 2776
Joined: 29 Sep 2013, 19:01

Re: How to write Hotstrings that takes user input?

Post by flyingDman » 29 Jul 2021, 19:53

The issue appears to be even more complex as \ and * seem to work without problem on their own. Ie this was an output:

Code: Select all

\frac{*}{*}
\frac{\}{\}
using

Code: Select all

hotstrings("fr@(.+)@(.+)@", "\frac{%$1%}{%$2%}")
with * and \ inputs.
But in combination with other characters the results are strange and unpredictable.
14.3 & 1.3.7

sofista
Posts: 644
Joined: 24 Feb 2020, 13:59
Location: Buenos Aires

Re: How to write Hotstrings that takes user input?

Post by sofista » 30 Jul 2021, 22:25

@flyingDman Yes, I agree that the issue is quite complex. I wasn't very clear in my previous message, although I don't fully understand this issue anyway.

What I meant is that, among other issues, the escape symbol "\" does not work correctly for metacharacters, so metacharacters cannot be used in hotstrings as common characters, i.e. with their literal meaning. Some examples to better show the issue:

Code: Select all

With this
hotstrings("fr/(.+),(.+)\s", "%$1%-%$2%")

If I type in		Get this output

fr/i,o				i-o
fr/\i,\o			fri-o
fr/\\i,\\o			fr/\i-o
fr/\i,\\o			fr/i-o
fr/\\i,\\\o			fr/\\i-o
fr/\{\i\},\{\o\}	fr/\{\{i}-{o}
Another issue is that the first characters of the hotstring appear in the result —except in the first example, where I don't use the backslash —, which strictly speaking should have been removed. Looks as if the function miscounts the number of characters to reproduce.

That's all for now.

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

Re: How to write Hotstrings that takes user input?

Post by lexikos » 01 Aug 2021, 04:01

sofista wrote:
30 Jul 2021, 22:25
the escape symbol "\" does not work correctly for metacharacters, so metacharacters cannot be used in hotstrings as common characters, i.e. with their literal meaning.
Backslash has no special meaning in this context. It is just passed to SendInput, which sends it by translating it to one or more keystrokes, just as it does with most other characters. I couldn't reproduce your issue; my results were as follows:

Code: Select all

; With this
hotstrings("fr/(.+),(.+)\s", "%$1%-%$2%")
/*
If I type in		Get this output

fr/i,o				i-o
fr/\i,\o			\i-\o
fr/\\i,\\o			\\i-\\o
fr/\i,\\o			\i-\\o
fr/\\i,\\\o			\\i-\\\o
fr/\{\i\},\{\o\}	\-\
*/
The last one is because SendInput {\i\} is invalid, as \i\ is not a valid key name. If you want to send plain text (causing ^+!#{} to be interpreted literally), you can do it without changing hotstrings():

Code: Select all

hotstrings("fr/(.+),(.+)\s", "{Text}%$1%-%$2%")  ; v1.1.27+ (recommended - sends Unicode characters)
hotstrings("fr/(.+),(.+)\s", "{Raw}%$1%-%$2%")  ; v1.0.43+ (sends keystrokes)
With either, the last one outputs \{\i\}-\{\o\} for me.

That it doesn't use {Raw} or SendRaw internally might be intentional - allowing {key} and ^+!# modifiers in the replacement/action parameter increases flexibility - but it makes little sense for meta-characters to be interpreted within the replacement strings for %$1% and %$2%. There would be multiple ways to allow something like %$1%{Left}, where the value of $1 is sent as raw text but {Left} is interpreted as a single key, but if the whole thing is meant to be raw text, {Text} is more reliable as it sends the exact characters without translating them to keys.
Another issue is that the first characters of the hotstring appear in the result
Do you mean that you type fr/i,o and get... fr/i,o? fri,o? fi,o?

hotstrings.ahk measures the captured string with StringLen, l, $ and deletes what was typed with SendInput, {BS %l%}. If manually pressing Backspace once for each character works, perhaps you should try replacing SendInput (in hotstrings.ahk) with SendEvent and try different SetKeyDelay settings. You might also try using some method of logging or debug output to verify what was captured, and use KeyHistory to verify what was sent.

If you typed \ but it wasn't captured, that would mean too few backspaces and it would be missing from $, and therefore not sent by SendInput.



hotstrings.ahk uses straight hotkeys for input. For instance, it registers the equivalent of ":: to capture quote marks. AutoHotkey translates " according to the current keyboard layout (of AutoHotkey at the time the hotkey is registered) and registers the appropriate key combination either with RegisterHotkey (a system function) or within its own hotkey tables. This approach isn't perfect - for instance, it does not adapt to changes in keyboard layout. hotstrings.ahk only registers hotkeys corresponding to ASCII characters, so doesn't work well with some international layouts.

The built-in hotstrings also work by monitoring keyboard input, since there isn't really any other option, but it does the translation in the opposite direction. That is, when you press a key, the hotstring monitor translates it to a character according to the keyboard layout of the currently active window, and buffers it.

Character-based input is possible using InputHook, which acts just prior to the hotstring monitor. This could replace the use of hotkeys in hotstrings.ahk to improve reliability, and add support for non-ASCII characters.

sofista
Posts: 644
Joined: 24 Feb 2020, 13:59
Location: Buenos Aires

Re: How to write Hotstrings that takes user input?

Post by sofista » 01 Aug 2021, 23:31

@lexikos Thank you for your advice and explanations. After reading your post, I ran numerous tests, but none of your suggestions worked here. Finally, I ran an online search and realized that I was using an outdated version of Hotstrings.ahk (v2.54, Edd's version). After installing v2.59 (Paris' version), I got the same results as yours. Consequently, the problem I had pointed out in a previous message is solved.

In addition, it seems to me that this suggestion also solves the original problem of this thread and some other old ones of mine, but these will have to wait because I am short of time. So thank you again, and sorry for any inconveniences.


@Kotte Check if the following code works for you too. See details in lexikos' post. Don't make my mistake and use v2.59 (if needed, download it from https://github.com/Paris/AutoHotkey-Scripts/blob/master/Hotstrings.ahk )

Code: Select all

#Include Hotstrings.ahk

hotstrings("fr/(.+),(.+)\s", "{Text}\frac{%$1%}{%$2%}")   ; v1.1.27+ (recommended - sends Unicode characters)
return
type in

Code: Select all

fr/x^2,\alpha
to get

Code: Select all

\frac{x^2}{\alpha}
Hope it works for you too.

Edited: Also, as you requested, the following hotstring works fine:

Code: Select all

hotstrings("fr.(.+)''(.+).,.", "{Text}\frac{%$1%}{%$2%}")   ; v1.1.27+ (recommended - sends Unicode characters)

Post Reply

Return to “Ask for Help (v1)”