AutoCorrect for v2

Post your working scripts, libraries and tools.
d_romeo
Posts: 28
Joined: 23 Dec 2020, 12:18

Re: AutoCorrect for v2

Post by d_romeo » 16 Apr 2024, 08:45

Here you have converted single words for multiple matching, I assumed you had an updated list of single words that you then convert to multiple matching.

User avatar
kunkel321
Posts: 1113
Joined: 30 Nov 2015, 21:19

Re: AutoCorrect for v2

Post by kunkel321 » 16 Apr 2024, 10:00

d_romeo wrote:
16 Apr 2024, 08:45
.... I assumed you had an updated list of single words that you then convert to multiple matching.
Unfortunately, no. There's no table that indicates each original 'whole-word' item, and the 'multi-match' items that were derived from them.

It occurred to me after converting the list, that I should have added the original item to the ; In-line comment for each converted item. I wish I had done that, but did not.

It's noteworthy that the original 2007 list had around 5k items, and the current list has around 5k, but there is not a "one-to-one" correspondence with those 5k items... When converting the original list, many many items were redundant. For example the typo might have been in the root word, but there were multiple items because of prefixes (un-, re-, anti-, etc) and suffixes (-ing, -ed, -ation, etc). The conversion process typically would "winnow-down" the item to its root (or a subpart of its root). As such, the redundancies were removed. I'd say more than 1k items were culled out that way.

However... Several hundred items from the Wikipedia grammar list were added.
viewtopic.php?f=6&t=118965&p=528053

Also, I've added probably a couple of hundred items from google searches, ChatGPT, my own typing experiences, and the recent "manual correct logger" tool (which is also based on my own typing experiences.)

Those items have all been converted (when converting was warranted) and put in the same list. I guess it would technically be possible to programmatically figure out which of the current AutoCorrect2 items correspond to the whole word items in the original 2007 AutoCorrect. IDK.

Extra note: The functionality of the "WAG" tool posted here
viewtopic.php?f=83&t=120377#p534275
got integrated into the "HotString Helper 2.0" tool. It is accessed via the [Exam] pane button.
ste(phen|ve) kunkel

User avatar
kunkel321
Posts: 1113
Joined: 30 Nov 2015, 21:19

Re: AutoCorrect for v2

Post by kunkel321 » 22 Apr 2024, 16:46

I think @Jasonosaj is the one who suggested scanning the entire code when doing validity checks (rather that just stopping after the first identified duplicate/conflict.) That has been added in the GitHub repo.

Interestingly, this created a dilemma... If a user puts a really short 'word-middle' multi-match string, then checks the validity (see img), then there can be thousands of conflicts found... So many, that the script crashes when the edit control of the gui is created. To address this: When more than 5 problems are found, everything after the fifth one is truncated, and a message ## Too many conflicts to show in form ## is added at the bottom (again see image).
Spoiler
It will only report a max of one conflict per hotstring in the code.

The PDF manual is updated to explain the extra scripts that are in the repo.
ste(phen|ve) kunkel

someguyinKC
Posts: 66
Joined: 25 Oct 2018, 11:33

Re: AutoCorrect for v2

Post by someguyinKC » 22 Apr 2024, 17:29

@kunkel321
I've noticed two things that the autocorrect script does that might be able to be improved, in my humble opinion:

1) when I type something into a box and then tab to the next box, if the thing that I put into the first box is a hotkey then the translation mostly gets put into the second box.

2) if I type the same hotkey twice in a row quickly, the second one doesn't get translated for some reason. if I wait a second or so, it does get translated.

if these are not fixable, then no worries. I appreciate the script so much as is!
thank you,

Someguy

User avatar
kunkel321
Posts: 1113
Joined: 30 Nov 2015, 21:19

Re: AutoCorrect for v2

Post by kunkel321 » 22 Apr 2024, 20:34

someguyinKC wrote:
22 Apr 2024, 17:29
1) when I type something into a box and then tab to the next box, if the thing that I put into the first box is a hotkey then the translation mostly gets put into the second box.
I'm not sure I understand what you mean... First I want to make sure you mean "hotkey" such as #h::, rather than "hotstring" such as ::mytrigger::.
Also, when you say, "box," do you mean like the edit fields in a webform, where you type something, then press tab to go to the next field?
someguyinKC wrote:
22 Apr 2024, 17:29
2) if I type the same hotkey twice in a row quickly, the second one doesn't get translated for some reason. if I wait a second or so, it does get translated.
Same question: Do you mean like hotstrings that are sent with the f() function, or is it more like:

Code: Select all

!+s::
{
   Send "Some text."
}
If you are doing Send, then you might try using SendInput instead. (Though I think Send is supposed to work like SendInput by default anyway).

Also... Make sure that you are not accidentally running two instances of AutoCorrect2. The #SingleInstance directive at the top of the script is supposed to make that impossible, but I find that it still happens. In my experience, if one instance is running because I clicked the link in my Start Menu, then I open the script for editing in VSCode, and THEN I press Ctrl+F9 to run the script from there, I will often get two instances. It causes the script to do weird things and is super-annoying. You can usually tell by looking for the icons in the Windows SysTray.
ste(phen|ve) kunkel

someguyinKC
Posts: 66
Joined: 25 Oct 2018, 11:33

Re: AutoCorrect for v2

Post by someguyinKC » 23 Apr 2024, 12:32

@kunkel321 I apologize for the confusion. I did mean hotstring instead of hotkey.

I'll restate my questions with corrections and more info:

I've noticed two things that the autocorrect script does that might be able to be improved, in my humble opinion:

1) when I type something into an edit field in a webform and then I press tab to the move to the next edit field, if the thing that I put into the first box is a hotstring then the translation mostly gets put into the second edit field.

2) if I type the same hotstring twice in a row quickly, the second one doesn't get translated for some reason. if I wait a second or so, it does get translated.

if these are not fixable, then no worries. I appreciate the script so much as is!
thank you,

Someguy

User avatar
kunkel321
Posts: 1113
Joined: 30 Nov 2015, 21:19

Re: AutoCorrect for v2

Post by kunkel321 » 23 Apr 2024, 14:34

Thank you for reporting this, and for the extra information. I'm not sure how I never noticed this! LOL.

I did not see the webform effect that you described in #1. Can you post the hotstring you are using? How long is the replacement text?

I did see the effect you describe in #2 though. I made these two test items:

Code: Select all

:B0X*?:zx::f("lllllllllllllllllllllllllllllllllllllllllllllllll")
:B0X*?:cv::f("ooooooooooooooooooooooooooooooooooooooooooooooooo")
If I quickly press zxzx, then only the first zx gets expanded. Interstingly, if I press zxcvzxcv, then the first two (zx and cv) get expanded, but the second two do not.

I experimented, and I think it is the logger function causing the problem... Near the bottom of the f(replace := "") function is the GoLogger(addToLog) function call. If you comment-out that, it seems to fix it. No doubt it is the one second wait in the GoLogger() function that causes this. There is an inputHook that starts when it is called. The inputHook lih := InputHook("B V I1 E T1", EndKeys) waits to see if you press the BackSpace key, then uses that info when logging the autocorrection in the log. I hadn't even thought about this when I made the script, but it makes sense that it would cause a delay.

IDK. Maybe I can have something in f() interrupt the inputHook... Will experiment. :D

EDIT:
@someguyinKC I think I may have fixed the second problem... Replace the relevant part of your script with this, and try:

Code: Select all

;========= LOGGER OPTIONS ====================================================== 
saveIntervalMinutes := 20     ; Collect the log items in RAM, then save to disc this often. 
IntervalsBeforeStopping := 2  ; Stop collecting, if no new pattern matches for this many intervals.
; (Script will automatically restart the log intervals next time there's a match.)

!+F3:: MsgBox(lastTrigger, "Trigger", 0) ; Shift+Alt+F3: Peek at last trigger. (Disabled because I never use it.)
;!+l::Run("AutoCorrectsLog.ahk") ; Shift+Alt+L: View/Run log of all autocorrections. (Disabled hotkey because I never use it.) 

; Mikeyww's idea to use a one-line function call. Cool.
; www.autohotkey.com/boards/viewtopic.php?f=76&t=120745
lastTrigger := "none yet" ; in case no autocorrects have been made
f(replace := "") ; All the one-line "f" autocorrects call this f(unction).
{	static HSInputBuffer := InputBuffer()
	HSInputBuffer.Start()
	trigger := A_ThisHotkey, endchar := A_EndChar
	Global lastTrigger := StrReplace(trigger, "B0X", "") "::" replace ; set 'lastTrigger' before removing options and colons.
	trigger := SubStr(trigger, inStr(trigger, ":",,,2)+1) ; use everything to right of 2nd colon. 
	TrigLen := StrLen(trigger) + StrLen(endchar) ; determine number of backspaces needed.
	; Rarify: Only remove and replace rightmost necessary chars.  
	trigL := StrSplit(trigger)
	replL := StrSplit(replace)
	Global ignorLen := 0
	Loop Min(trigL.Length, replL.Length) ; find matching left substring.
	{	If (trigL[A_Index] == replL[A_Index]) ; The double equal (==) makes it case-sensitive. 
			ignorLen++
		else break
	}
	replace := SubStr(replace, (ignorLen+1))
	SendInput("{BS " . (TrigLen - ignorLen) . "}" replace endchar) ; Type replacemement and endchar. 
	replace := "" ; Reset to blank string.
	HSInputBuffer.Stop()
	SoundBeep(900, 60) ; Notification of replacement.
	Global KeepForLog := LastTrigger  "`n"
	SetTimer(keepText, -1)
}

logIsRunning := 0
savedUpText := ''
intervalCounter := 0 ; Initialize the counter
saveIntervalMinutes := saveIntervalMinutes*60*1000 ; convert to miliseconds.

#MaxThreadsPerHotkey 5 ; Allow up to 5 instances of the function.
; There's no point running the logger if no text has been saved up...  
; So don't run timer when script starts.  Run it when logging starts. 
keepText(*) ; Automatically logs if an autocorrect happens, and if I press Backspace within X seconds. 
{ 	EndKeys := "{Backspace}"
	global lih := InputHook("B V I1 E T1", EndKeys) ; "logger input hook." T is time-out. T1 = 1 second.
	lih.Start(), lih.Wait()
	;msgbox lih.EndKey
	hyphen := (lih.EndKey = "Backspace")?  " << " : " -- "
	global savedUpText .= A_YYYY "-" A_MM "-" A_DD hyphen KeepForLog
	global intervalCounter := 0  	; Reset the counter since we're adding new text
	If logIsRunning = 0  			; only start the timer it it is not already running.
		setTimer Appender, saveIntervalMinutes  	; call function every X minutes.
}
#MaxThreadsPerHotkey 1

; Gets called by timer, or by onExit.
Appender(*) 
{	FileAppend(savedUpText, "AutoCorrectsLog.ahk")
	global savedUpText := ''  		; clear each time, since text has been logged.
	global logIsRunning := 1  		; set to 1 so we don't keep resetting the timer.
	global intervalCounter += 1 	; Increments here, but resets in other locations. 
	If (intervalCounter >= IntervalsBeforeStopping) ; Check if no text has been kept for X intervals
	{   setTimer Appender, 0  		; Turn off the timer
		global logIsRunning := 0  	; Indicate that the timer is no longer running
		global intervalCounter := 0 ; Reset the counter for safety
	}
	;soundBeep 800, 800 ; <----------------------------------- Announcement to ensure the log is logging.  Remove later. 
	;soundBeep 600, 800
}

OnExit Appender 					; Also append one more time on exit. 
Note also, that earlier today, I changed the log mechanism so that is saves-up the log items in a cache, then appends them periodically, inbulk to the log file. Most of the new parts of the code is actually for that.

For what it's worth... In my own AutoCorrect scritpt, I don't use the f() for hotstrings that are boilerplate text entry items. The whole reason for the f() is to log items, and the whole reason to log items is to see which autocorrections triggered at unwanted times (I determine this by whether backspace was pressed within one second). I never "accidentally" enter a boilerplate text entry, so there really no point in logging them.
ste(phen|ve) kunkel

User avatar
kunkel321
Posts: 1113
Joined: 30 Nov 2015, 21:19

Re: AutoCorrect for v2

Post by kunkel321 » 24 Apr 2024, 15:17

I updated the "Duplicate String Extractor" script. (Which might also be called the "Updating to a newer version of AutoCorrect2" script).
Location:
https://github.com/kunkel321/AutoCorrect2/blob/main/Duplicate%20String%20ExtracterFor%20v2.ahk

Image

The functionality is probably best explained by this sample output:
Search took 0 minutes and 4 seconds.

We Found 2 items unique to AutoCorrect2_OLD.ahk. These might be custom items that you added via HotString Helper. Please copy and keep any that you want to keep, then you can optionally delete AutoCorrect2_OLD.ahk.

We also found 7 items unique to AutoCorrect2.ahk. These are either newly added ones, or ones that you manually removed from your own version of ac2. Search for and remove any unwanted items from AutoCorrect2.ahk.
=================================
AutoCorrect2_OLD.ahk items you may wish to keep:
::sample::sample
::Example::Example

=================================
AutoCorrect2.ahk items that you may have removed from you AutoCorrect2 file, or items that were recently added:
:B0X*:is ran by::f("is run by") ; Fixes 1 word
:B0X*:itwas::f("it was") ; Fixes 1 word
:B0X*:lays near::f("lies near") ; Fixes 1 word
:B0X*:life time::f("lifetime") ; Fixes 1 word
:B0X*:liftime::f("lifetime") ; Fixes 1 word
:B0X*:lighter then::f("lighter than") ; Fixes 1 word
:B0X:I thing::f("I think")
Please note that the paths for the two files have to be manually pasted into the script.... Haven't automated, or added that to the gui yet. As mentioned in a previous reply, if/when updating to a newer version of AutoCorrect2 I recommend renaming your existing file to something like "AutoCorrect_OLD.ahk" then put in the same folder:
Duplicate String Extractor for v2.ahk
AutoCorrect2.ahk
AutoCorrect2_OLD.ahk
ste(phen|ve) kunkel

someguyinKC
Posts: 66
Joined: 25 Oct 2018, 11:33

Re: AutoCorrect for v2

Post by someguyinKC » 25 Apr 2024, 17:53

kunkel321 wrote:
23 Apr 2024, 14:34
EDIT:
@someguyinKC I think I may have fixed the second problem... Replace the relevant part of your script with this, and try:

Code: Select all

;========= LOGGER OPTIONS ====================================================== 
saveIntervalMinutes := 20     ; Collect the log items in RAM, then save to disc this often. 
IntervalsBeforeStopping := 2  ; Stop collecting, if no new pattern matches for this many intervals.
; (Script will automatically restart the log intervals next time there's a match.)

!+F3:: MsgBox(lastTrigger, "Trigger", 0) ; Shift+Alt+F3: Peek at last trigger. (Disabled because I never use it.)
;!+l::Run("AutoCorrectsLog.ahk") ; Shift+Alt+L: View/Run log of all autocorrections. (Disabled hotkey because I never use it.) 

; Mikeyww's idea to use a one-line function call. Cool.
; www.autohotkey.com/boards/viewtopic.php?f=76&t=120745
lastTrigger := "none yet" ; in case no autocorrects have been made
f(replace := "") ; All the one-line "f" autocorrects call this f(unction).
{	static HSInputBuffer := InputBuffer()
	HSInputBuffer.Start()
	trigger := A_ThisHotkey, endchar := A_EndChar
	Global lastTrigger := StrReplace(trigger, "B0X", "") "::" replace ; set 'lastTrigger' before removing options and colons.
	trigger := SubStr(trigger, inStr(trigger, ":",,,2)+1) ; use everything to right of 2nd colon. 
	TrigLen := StrLen(trigger) + StrLen(endchar) ; determine number of backspaces needed.
	; Rarify: Only remove and replace rightmost necessary chars.  
	trigL := StrSplit(trigger)
	replL := StrSplit(replace)
	Global ignorLen := 0
	Loop Min(trigL.Length, replL.Length) ; find matching left substring.
	{	If (trigL[A_Index] == replL[A_Index]) ; The double equal (==) makes it case-sensitive. 
			ignorLen++
		else break
	}
	replace := SubStr(replace, (ignorLen+1))
	SendInput("{BS " . (TrigLen - ignorLen) . "}" replace endchar) ; Type replacemement and endchar. 
	replace := "" ; Reset to blank string.
	HSInputBuffer.Stop()
	SoundBeep(900, 60) ; Notification of replacement.
	Global KeepForLog := LastTrigger  "`n"
	SetTimer(keepText, -1)
}

logIsRunning := 0
savedUpText := ''
intervalCounter := 0 ; Initialize the counter
saveIntervalMinutes := saveIntervalMinutes*60*1000 ; convert to miliseconds.

#MaxThreadsPerHotkey 5 ; Allow up to 5 instances of the function.
; There's no point running the logger if no text has been saved up...  
; So don't run timer when script starts.  Run it when logging starts. 
keepText(*) ; Automatically logs if an autocorrect happens, and if I press Backspace within X seconds. 
{ 	EndKeys := "{Backspace}"
	global lih := InputHook("B V I1 E T1", EndKeys) ; "logger input hook." T is time-out. T1 = 1 second.
	lih.Start(), lih.Wait()
	;msgbox lih.EndKey
	hyphen := (lih.EndKey = "Backspace")?  " << " : " -- "
	global savedUpText .= A_YYYY "-" A_MM "-" A_DD hyphen KeepForLog
	global intervalCounter := 0  	; Reset the counter since we're adding new text
	If logIsRunning = 0  			; only start the timer it it is not already running.
		setTimer Appender, saveIntervalMinutes  	; call function every X minutes.
}
#MaxThreadsPerHotkey 1

; Gets called by timer, or by onExit.
Appender(*) 
{	FileAppend(savedUpText, "AutoCorrectsLog.ahk")
	global savedUpText := ''  		; clear each time, since text has been logged.
	global logIsRunning := 1  		; set to 1 so we don't keep resetting the timer.
	global intervalCounter += 1 	; Increments here, but resets in other locations. 
	If (intervalCounter >= IntervalsBeforeStopping) ; Check if no text has been kept for X intervals
	{   setTimer Appender, 0  		; Turn off the timer
		global logIsRunning := 0  	; Indicate that the timer is no longer running
		global intervalCounter := 0 ; Reset the counter for safety
	}
	;soundBeep 800, 800 ; <----------------------------------- Announcement to ensure the log is logging.  Remove later. 
	;soundBeep 600, 800
}

OnExit Appender 					; Also append one more time on exit. 
@kunkel321:
in the above coding, does this only fix the autologging part or does it do something else also? I don't use the autlogging feature, so I don't need to fix this unless swapping this scripting also fixes something else.

as far as the part where pressing tab on a webform doesn't work as it should (as I described above), here is a website where it gives me trouble:

https://www.supplyhouse.com/sh/control/contactUs

if it works just fine, then what part of my (very long) script should I share with you?
thank you,

Someguy

User avatar
kunkel321
Posts: 1113
Joined: 30 Nov 2015, 21:19

Re: AutoCorrect for v2

Post by kunkel321 » 30 Apr 2024, 08:00

@someguyinKC Sorry about the delay. I was one of the people who hasn't been able to log on. It seems like Tank has the forums fixed for now though.

Regarding the logging feature: You are correct. All of the changes to that last code I posted were for the logging parts. If you have no need for that, you can remove all of the parts that you see commented-out in this version:

Code: Select all

;========= LOGGER OPTIONS ====================================================== 
; saveIntervalMinutes := 20     ; Collect the log items in RAM, then save to disc this often. 
; IntervalsBeforeStopping := 2  ; Stop collecting, if no new pattern matches for this many intervals.
; (Script will automatically restart the log intervals next time there's a match.)

!+F3:: MsgBox(lastTrigger, "Trigger", 0) ; Shift+Alt+F3: Peek at last trigger. (Disabled because I never use it.)
;!+l::Run("AutoCorrectsLog.ahk") ; Shift+Alt+L: View/Run log of all autocorrections. (Disabled hotkey because I never use it.) 

; Mikeyww's idea to use a one-line function call. Cool.
; www.autohotkey.com/boards/viewtopic.php?f=76&t=120745
lastTrigger := "none yet" ; in case no autocorrects have been made
f(replace := "") ; All the one-line "f" autocorrects call this f(unction).
{	static HSInputBuffer := InputBuffer()
	HSInputBuffer.Start()
	trigger := A_ThisHotkey, endchar := A_EndChar
	Global lastTrigger := StrReplace(trigger, "B0X", "") "::" replace ; set 'lastTrigger' before removing options and colons.
	trigger := SubStr(trigger, inStr(trigger, ":",,,2)+1) ; use everything to right of 2nd colon. 
	TrigLen := StrLen(trigger) + StrLen(endchar) ; determine number of backspaces needed.
	; Rarify: Only remove and replace rightmost necessary chars.  
	trigL := StrSplit(trigger)
	replL := StrSplit(replace)
	Global ignorLen := 0
	Loop Min(trigL.Length, replL.Length) ; find matching left substring.
	{	If (trigL[A_Index] == replL[A_Index]) ; The double equal (==) makes it case-sensitive. 
			ignorLen++
		else break
	}
	replace := SubStr(replace, (ignorLen+1))
	SendInput("{BS " . (TrigLen - ignorLen) . "}" replace endchar) ; Type replacemement and endchar. 
	replace := "" ; Reset to blank string.
	HSInputBuffer.Stop()
	SoundBeep(900, 60) ; Notification of replacement.
	; Global KeepForLog := LastTrigger  "`n"
	; SetTimer(keepText, -1)
}

; logIsRunning := 0, savedUpText := '', intervalCounter := 0 ; Initialize the counter
; saveIntervalMinutes := saveIntervalMinutes*60*1000 ; convert to miliseconds.

; #MaxThreadsPerHotkey 5 ; Allow up to 5 instances of the function.
; ; There's no point running the logger if no text has been saved up...  
; ; So don't run timer when script starts.  Run it when logging starts. 
; keepText(*) ; Automatically logs if an autocorrect happens, and if I press Backspace within X seconds. 
; { 	EndKeys := "{Backspace}"
; 	global lih := InputHook("B V I1 E T1", EndKeys) ; "logger input hook." T is time-out. T1 = 1 second.
; 	lih.Start(), lih.Wait()
; 	;msgbox lih.EndKey
; 	hyphen := (lih.EndKey = "Backspace")?  " << " : " -- "
; 	global savedUpText .= A_YYYY "-" A_MM "-" A_DD hyphen KeepForLog
; 	global intervalCounter := 0  	; Reset the counter since we're adding new text
; 	If logIsRunning = 0  			; only start the timer it it is not already running.
; 		setTimer Appender, saveIntervalMinutes  	; call function every X minutes.
; }
; #MaxThreadsPerHotkey 1

; ; Gets called by timer, or by onExit.
; Appender(*) 
; {	FileAppend(savedUpText, "AutoCorrectsLog.ahk")
; 	global savedUpText := ''  		; clear each time, since text has been logged.
; 	global logIsRunning := 1  		; set to 1 so we don't keep resetting the timer.
; 	global intervalCounter += 1 	; Increments here, but resets in other locations. 
; 	If (intervalCounter >= IntervalsBeforeStopping) ; Check if no text has been kept for X intervals
; 	{   setTimer Appender, 0  		; Turn off the timer
; 		global logIsRunning := 0  	; Indicate that the timer is no longer running
; 		global intervalCounter := 0 ; Reset the counter for safety
; 	}
; 	;soundBeep 800, 800 ; <----------------------------------- Announcement to ensure the log is logging.  Remove later. 
; 	;soundBeep 600, 800
; }
Also, if you never care to peek at the last-used trigger, you could get rid of a couple of more things. I do have to point out, that the main purpose of the f() is to enable logging, so if you don't need that feature, it might be better to just use normal vanilla ahk hotstrings.

Regarding the thing about navigating webforms: I didn't mean for you to share your entire script, just one of the hotstrings that are giving you trouble. Here is a test one that I made:

Code: Select all

:B0X*?:po::f("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
I went to the building supply store that you linked, then went to the login page, because it was the only page I could find that had two edit boxes next to each other. Then it clicked in the first box, pressed "po" and IMMEDIATELY pressed the Tab key, to see if some of the xxxs would get sent to the second edit box. They did not. The xs all got put in the first edit box, then the focus changed to the second one.

Am I testing the right thing, or were your describing something different?
ste(phen|ve) kunkel

someguyinKC
Posts: 66
Joined: 25 Oct 2018, 11:33

Re: AutoCorrect for v2

Post by someguyinKC » 30 Apr 2024, 10:04

@kunkel321 again, I appreciate any and all help!

the reason that I use the f() feature is the delay it adds so that I don't get subsequent typing mixed in with the hotstring translation.

how do I peek at the last-used trigger? just look in the log file? I could use this to figure out which part of my script is causing unintended consequences.

the coding that I am using that doesn't work as I intend is this:

:B0XC:smith::f("Smith")

also: I noticed in your script the "window specific hotkeys". I looked in your instruction manual and couldn't find the explanation/instructions for those. :)
thank you,

Someguy

User avatar
kunkel321
Posts: 1113
Joined: 30 Nov 2015, 21:19

Re: AutoCorrect for v2

Post by kunkel321 » 30 Apr 2024, 14:53

someguyinKC wrote:
30 Apr 2024, 10:04
the reason that I use the f() feature is the delay it adds so that I don't get subsequent typing mixed in with the hotstring translation.
Do you mean the "inputBuffering" mechanism? That is definitely and important part. In theory, default vanilla ahk hotstrings should work the same, but sometimes they don't. All hail to Descolada's inputBuffer class for fixing this issue! LOL.
someguyinKC wrote:
30 Apr 2024, 10:04
I noticed in your script the "window specific hotkeys".
Yep - Those hotkeys are all for doing things to the hh2 gui, so we only want them to be active when the hh2 form is open and active.

It's noteworthy that hotstrings can be embedded between #HotIf directives as well, to make them window-specific. I don't really use any of those, so there are none in the ac2 script.

As for peeking at the last trigger, it's Shift+Alt+F3. And for the :B0XC:smith::f("Smith") item, I can't image why the Tab key would get interspersed in there... Double check that you don't have multiple instances of your AutoCorrect2 script running. In theory there shouldn't be multiple instances, because of the #SingleInstance directive--but it can still happen. Check your WinSysTray for duplicate icons, and also check TaskManager for duplicate processes.

EDIT: Oh wow, I just tried the :B0XC:smith::f("Smith") item and it does the same for me! An asterisk fixes it... :B0X*C:smith::f("Smith"). The other comments about multiple instances of the script are also true, but, apparently not the cause here.

I don't know why it does this... I guess maybe Chrome browser "sees" the Tab key before the ahk script key recognizer sees it(??)
@Descolada, have you run into this? Typing this: :B0XC:smith::f("Smith") into a webform (where you navigate via Tab, which is also an endkey) leaves the trigger smith in the first edit field, and puts the replacement Smith in the second edit field.

EDIT 2: The error does not happen with vanilla hotstrings :C:smith::Smith.

EDIT 3: The _HS() function has the same error. I ruled-out the inputBuffer as the problem though... I think it must just be the calling of a function. Default vanilla hotstrings must work at a "lower system level" then function calls do (??) IDK.
ste(phen|ve) kunkel

someguyinKC
Posts: 66
Joined: 25 Oct 2018, 11:33

Re: AutoCorrect for v2

Post by someguyinKC » 30 Apr 2024, 16:03

@kunkel321:

I'm still not sure what the windows specific hotkeys do, but I probably don't need them.

I don't see how to use the (shift+Alt+F3) to see the last trigger.

I checked for multiple instances in the systray and the TaskManager and I have neither... but the * in

Code: Select all

:B0X*C:smith::f("Smith")
fixes it. and a simple

Code: Select all

::smith::Smith
fixes it also.
thank you,

Someguy

User avatar
kunkel321
Posts: 1113
Joined: 30 Nov 2015, 21:19

Re: AutoCorrect for v2

Post by kunkel321 » 30 Apr 2024, 17:01

someguyinKC wrote:
30 Apr 2024, 16:03
I'm still not sure what the windows specific hotkeys do, but I probably don't need them.
It's not like "specific to the Windows OS," it's like "Only active under certain conditions." Usually the conditions are a particular window being open, but not always. See here:
https://www.autohotkey.com/docs/v2/lib/HotIf.htm
someguyinKC wrote:
30 Apr 2024, 16:03
I don't see how to use the (shift+Alt+F3) to see the last trigger.
When the AutoCorrect.ahk script is running, hold down the Shift key and the Alt key, then press F3 (?)

It's defined in this line of code just above the f() function:

Code: Select all

!+F3:: MsgBox(lastTrigger, "Trigger", 0) ; Shift+Alt+F3: Peek at last trigger. (Disabled because I never use it.)
I had it commented-out for a while... It might be commented out in your code too.
ste(phen|ve) kunkel

Descolada
Posts: 1163
Joined: 23 Dec 2021, 02:30

Re: AutoCorrect for v2

Post by Descolada » 30 Apr 2024, 22:43

@kunkel321 :C:smith::Smith works because normal hotstrings suppress the end character and resend it with the replacement. However, the X option doesn't cause the end character to be suppressed, which you can demonstrate with this: :B0X:smith::MsgBox "Hello". To fix this, add the O option and correct backspacing length in f/_HS function. In the case of _HS the line #Hotstring ZXB0 needs to be modified to #Hotstring ZXB0O and MaxBS := StrLen(RegExReplace(Trigger, "s)((?>\P{M}(\p{M}|\x{200D}))+\P{M})|\X", "_")) + !Omit to MaxBS := StrLen(RegExReplace(Trigger, "s)((?>\P{M}(\p{M}|\x{200D}))+\P{M})|\X", "_")).

Edit: this leads to a new bug... :B0*OX:smith::MsgBox "Hello" will omit the last "h" for some reason, so that will need to be adjusted for as well.

someguyinKC
Posts: 66
Joined: 25 Oct 2018, 11:33

Re: AutoCorrect for v2

Post by someguyinKC » 01 May 2024, 17:09

I looked through my code and it was commented out. I removed the semicolon and it works great. this will be very helpful for me to use this feature. Thank you!

I just noticed something else that doesn't work as intended, as I was typing that message above: when the ending character is an exclamation point, it doesn't come through.

Code: Select all

:B0X*:ty::f("Thank you")
when I press ty! the ! doesn't come through. interestingly, but ty? works.
thank you,

Someguy

User avatar
kunkel321
Posts: 1113
Joined: 30 Nov 2015, 21:19

Re: AutoCorrect for v2

Post by kunkel321 » 02 May 2024, 10:08

@Descolada Thanks for analyzing this and for posting the bug report!

I think this :B0X:smith::MsgBox "Hello" and this :OB0X:smith::MsgBox "Hello" might be acting as expected for me. (Unless I'm not understanding the issue.) If I type a pipechar | then press left, so that the cursor is "pushing" the pipechar forward, then I try the first one, I get smith | (space was used for the endchar). Then if I add the letter O like the second one, and do the same, I get smith|. The endchar is not there (as expected).

I do get the bug effect with :B0*OX:smith::MsgBox "Hello" though... It leaves smit|.

@someguyinKC, Thank you for posting these things you are finding! I confirmed the same thing you describe, with
:B0X:ty::f("Thank you"). Of course the asterisk fixes the situation, but without the asterisk * I can't even image why the exclamation point doesn't work! Descolada, do you think this is caused by the same issue as above? (See SomeGuy's post right above this one). I will experiment more and post if I learn anything.

EDIT: Well... I embedded a msgbox inside the f() function, but I didn't really learn anything from it...
Spoiler
As I was working on it, it did occur to me that exclamation points have a special meaning in AHK code.... They mean "Not". I wonder if having the X in the hotstring options somehow causes .... Wait a minute... Mid-post idea... LOL. The "Send" command might be sending an Alt key, since ! = Alt. Will experiment more...

EDIT (two minutes later) BINGO!
@someguyinKC: Find this line of code near the top of the f() function:
trigger := A_ThisHotkey, endchar := A_EndChar
and replace it with this:
trigger := A_ThisHotkey, endchar := StrReplace(A_EndChar, "!", "{!}")
SORRY!! You can't change it there, or the number of backspaces gets messed up...
Further down the f() function, change this:

Code: Select all

SendInput("{BS " . (TrigLen - ignorLen) . "}" replace endchar) ; Type replacemement and endchar. 
to this:

Code: Select all

SendInput("{BS " . (TrigLen - ignorLen) . "}" replace StrReplace(endchar, "!", "{!}")) ; Type replacemement and endchar.
I think that's right....

One more edit: I forgot to mention, SomeGuy, don't keep the asterisk in :*:ty::Thank You, or you'll never be able to type "Tylenol" or "typo." LOL.
ste(phen|ve) kunkel

Jasonosaj
Posts: 53
Joined: 02 Feb 2022, 15:02
Location: California

Re: AutoCorrect for v2

Post by Jasonosaj » 02 May 2024, 14:08

Not sure why but I ended up having problems integrating the revised code. The following seems to work, however.



f(replace)
{
Global lastTrigger := ""
Global KeepForLog
Global ignorLen := 0
Static HSInputBuffer := InputBuffer()

HSInputBuffer.Start()

endchar := A_EndChar
trigger := A_ThisHotkey
lastTrigger := StrReplace(trigger, "B0X", "") . "::" . replace

trigger := SubStr(trigger, inStr(trigger, ":", , , 2) + 1)

TrigLen := StrLen(trigger) + StrLen(endchar)

trigL := StrSplit(trigger)
replL := StrSplit(replace)

Loop Min(trigL.Length , replL.Length)
{
If (trigL[A_Index] == replL[A_Index])
ignorLen++
else
break
}

replace := SubStr(replace, (ignorLen + 1))

SendInput("{BS " . (TrigLen - ignorLen - 1) . "}" replace)

If (RegExMatch(endchar , "[!.,;:?!-]"))
SendInput("{" endChar "} ")
else
SendInput(endChar)

HSInputBuffer.Stop()
SoundBeep(900 , 60)

KeepForLog := LastTrigger . "`n"
SetTimer(keepText , -1)
}



kunkel321 wrote:
02 May 2024, 10:08
@Descolada Thanks for analyzing this and for posting the bug report!

I think this :B0X:smith::MsgBox "Hello" and this :OB0X:smith::MsgBox "Hello" might be acting as expected for me. (Unless I'm not understanding the issue.) If I type a pipechar | then press left, so that the cursor is "pushing" the pipechar forward, then I try the first one, I get smith | (space was used for the endchar). Then if I add the letter O like the second one, and do the same, I get smith|. The endchar is not there (as expected).

I do get the bug effect with :B0*OX:smith::MsgBox "Hello" though... It leaves smit|.

@someguyinKC, Thank you for posting these things you are finding! I confirmed the same thing you describe, with
:B0X:ty::f("Thank you"). Of course the asterisk fixes the situation, but without the asterisk * I can't even image why the exclamation point doesn't work! Descolada, do you think this is caused by the same issue as above? (See SomeGuy's post right above this one). I will experiment more and post if I learn anything.

EDIT: Well... I embedded a msgbox inside the f() function, but I didn't really learn anything from it...
Spoiler
As I was working on it, it did occur to me that exclamation points have a special meaning in AHK code.... They mean "Not". I wonder if having the X in the hotstring options somehow causes .... Wait a minute... Mid-post idea... LOL. The "Send" command might be sending an Alt key, since ! = Alt. Will experiment more...

EDIT (two minutes later) BINGO!
@someguyinKC: Find this line of code near the top of the f() function:
trigger := A_ThisHotkey, endchar := A_EndChar
and replace it with this:
trigger := A_ThisHotkey, endchar := StrReplace(A_EndChar, "!", "{!}")
SORRY!! You can't change it there, or the number of backspaces gets messed up...
Further down the f() function, change this:

Code: Select all

SendInput("{BS " . (TrigLen - ignorLen) . "}" replace endchar) ; Type replacemement and endchar.
to this:

Code: Select all

SendInput("{BS " . (TrigLen - ignorLen) . "}" replace StrReplace(endchar, "!", "{!}")) ; Type replacemement and endchar.
I think that's right....

One more edit: I forgot to mention, SomeGuy, don't keep the asterisk in :*:ty::Thank You, or you'll never be able to type "Tylenol" or "typo." LOL.

User avatar
kunkel321
Posts: 1113
Joined: 30 Nov 2015, 21:19

Re: AutoCorrect for v2

Post by kunkel321 » 02 May 2024, 15:06

Jasonosaj wrote:
02 May 2024, 14:08

Code: Select all

	If (RegExMatch(endchar , "[!.,;:?!-]"))
		SendInput("{" endChar "} ")
	else
		SendInput(endChar)
Very nice. I was also thinking about doing a regex...

I think mostly the problematic characters will be !#^+ as discussed here
https://www.autohotkey.com/docs/v2/lib/Send.htm#Parameters

Edit... Actually, I guess ! is the only one from that list that is also an EndChar
https://www.autohotkey.com/docs/v2/lib/Hotstring.htm#EndChars
Unless you've manually added the others as EndChars too.
ste(phen|ve) kunkel

someguyinKC
Posts: 66
Joined: 25 Oct 2018, 11:33

Re: AutoCorrect for v2

Post by someguyinKC » 03 May 2024, 11:52

@kunkel321 OKAY! I made that change and it work! Thank you again for your help. your script makes my work much easier.
thank you,

Someguy

Post Reply

Return to “Scripts and Functions (v2)”