Re: AutoCorrect for v2
Posted: 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.
Let's help each other out
https://www.autohotkey.com/boards/
https://www.autohotkey.com/boards/viewtopic.php?f=83&t=120220
Unfortunately, no. There's no table that indicates each original 'whole-word' item, and the 'multi-match' items that were derived from them.
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::.someguyinKC wrote: ↑22 Apr 2024, 17:291) 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.
Same question: Do you mean like hotstrings that are sent with the f() function, or is it more like:someguyinKC wrote: ↑22 Apr 2024, 17:292) 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.
Code: Select all
!+s::
{
Send "Some text."
}
Code: Select all
:B0X*?:zx::f("lllllllllllllllllllllllllllllllllllllllllllllllll")
:B0X*?:cv::f("ooooooooooooooooooooooooooooooooooooooooooooooooo")
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.
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: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")
Duplicate String Extractor for v2.ahk
AutoCorrect2.ahk
AutoCorrect2_OLD.ahk
@kunkel321:kunkel321 wrote: ↑23 Apr 2024, 14:34EDIT:
@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.
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
; }
Code: Select all
:B0X*?:po::f("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
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:04the 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.
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.
Code: Select all
:B0X*C:smith::f("Smith")
Code: Select all
::smith::Smith
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:someguyinKC wrote: ↑30 Apr 2024, 16:03I'm still not sure what the windows specific hotkeys do, but I probably don't need them.
When the AutoCorrect.ahk script is running, hold down the Shift key and the Alt key, then press F3 (?)someguyinKC wrote: ↑30 Apr 2024, 16:03I don't see how to use the (shift+Alt+F3) to see the last trigger.
Code: Select all
!+F3:: MsgBox(lastTrigger, "Trigger", 0) ; Shift+Alt+F3: Peek at last trigger. (Disabled because I never use it.)
Code: Select all
:B0X*:ty::f("Thank you")
Code: Select all
SendInput("{BS " . (TrigLen - ignorLen) . "}" replace endchar) ; Type replacemement and endchar.
Code: Select all
SendInput("{BS " . (TrigLen - ignorLen) . "}" replace StrReplace(endchar, "!", "{!}")) ; Type replacemement and endchar.
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...SpoilerAs 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:to this:Code: Select all
SendInput("{BS " . (TrigLen - ignorLen) . "}" replace endchar) ; Type replacemement and endchar.
I think that's right....Code: Select all
SendInput("{BS " . (TrigLen - ignorLen) . "}" replace StrReplace(endchar, "!", "{!}")) ; Type replacemement and endchar.
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.
Very nice. I was also thinking about doing a regex...Jasonosaj wrote: ↑02 May 2024, 14:08Code: Select all
If (RegExMatch(endchar , "[!.,;:?!-]")) SendInput("{" endChar "} ") else SendInput(endChar)