Hey All,
I made several more changes in terms of speed improvements. My script has deviated a lot from the original due to what I'm using it for (a specific in-house programming language) but I'll point out the differences and try to recreate the original script. All these changes resulted in a lot less cpu usage when running the script. It makes for a lot more reliable autocompletion. The script only works with characters in the ASCII character set (though I don't know if that's any different from before).
First, the new script (I only quickly tested these, but they seemed to work, like I said mine is heavily modified so I had to patch a few things back in - I have modified endkeys and stuff, in fact I'm thinking of changing mine to use Match keys since I pretty much only want alpha characters)
2 key hits for hotkey
Code:
; Intellitype: typing aid
; Press 1 to 0 keys to autocomplete the word upon suggestion
; (0 will match suggestion 10)
; - Jordi S
; Heavily modified by:
; Maniac
;___________________________________________
; CONFIGURATIONS
; Editor Window Recognition
; (make it blank to make the script seek all windows)
ETitle =
;Minimum word length to make a guess
WLen = 3
keyagain=
key=
clearword=1
;Gosub,clearallvars ; clean vars from start
; Press 1 to 0 keys to autocomplete the word upon suggestion
; (0 will match suggestion 10)
;_______________________________________
CoordMode, ToolTip, Relative
AutoTrim, Off
;reads list of words from file
Loop, Read, %A_ScriptDir%\Wordlist.txt
{
StringLeft, Base, a_loopreadline, %wlen%
Base := ConvertWordToAscii(Base)
basenum%Base%++
pos := basenum%Base%
cmd%Base%%pos% = %a_loopreadline%
}
SetTimer, Winchanged, 100
Loop
{
;Editor window check
WinGetActiveTitle, ATitle
WinGet, A_id, ID, %ATitle%
IfNotInString, ATitle, %ETitle%
{
ToolTip
Setenv, Word,
sleep, 500
Continue
}
;Get one key at a time
Input, chr, L1 V,{enter}{space}.;`,:¿?¡!'"()]{}{}}{bs}{{}{esc}{tab}{Home}{End}{PgUp}{PdDn}{Up}{Dn}{Left}{Right}
EndKey = %errorlevel%
; If active window has different window ID from before the input, blank word
; (well, assign the number pressed to the word)
WinGetActiveTitle, ATitle
WinGet, A_id2, ID, %ATitle%
IfNotEqual, A_id, %A_id2%
{
Gosub,clearallvars
Setenv, Word, %chr%
Continue
}
ifequal, OldCaretY,
OldCaretY = %A_CaretY%
ifnotequal, OldCaretY, %A_CaretY%
{
Gosub,clearallvars
Setenv, Word, %chr%
Continue
}
OldCaretY=%A_CaretY%
;Backspace clears last letter
ifequal, EndKey, Endkey:BackSpace
{
StringLen, len, Word
IfNotEqual, len, 0
{ ifequal, len, 1
{
Gosub,clearallvars
} else {
StringTrimRight, Word, Word, 1
}
}
} else ifequal, EndKey, Max
{
ifequal, chr, @
{
Gosub,clearallvars
Setenv, Word, %chr%
Continue
} else {
Setenv, Word, %word%%chr%
}
} else Gosub,clearallvars
;Wait till minimum letters
StringLen, len, Word
IfLess, len, %wlen%
{
ToolTip
Continue
}
;Match part-word with command
Num =
Match =
singlematch = 0
number = 0
StringLeft, baseword, Word, %wlen%
baseword := ConvertWordToAscii(baseword)
Loop
{
IfEqual, cmd%baseword%%a_index%,, Break
IfEqual, number, 10
Break
StringLen, chars, Word
StringLeft, strippedcmd, cmd%baseword%%a_index%, %chars%
ifequal, strippedcmd, %Word%
{
number ++
singlematch := cmd%baseword%%a_index%
match = %match%%number%. %singlematch%`n
singlematch%number% = %singlematch%
Continue
}
}
;If no match then clear Tip
IfEqual, Match,
{
clearword=0
Gosub,clearallvars
Continue
}
;Show matched command
StringTrimRight, match, match, 1 ; Get rid of the last linefeed
WinGetActiveTitle, ATitle
WinGetPos, , PosY, , SizeY, %ATitle%
MaxY := PosY + SizeY
ToolTipSizeY := (number * 12)
ToolTipPosY := A_CaretY+14
if ((ToolTipSizeY + ToolTipPosY) > MaxY)
ToolTipPosY := (A_CaretY - 14 - ToolTipSizeY)
IfNotEqual, Word,,ToolTip, %match%, %A_CaretX%, %ToolTipPosY%
; +14 Move tooltip down a little so as not to hide the caret.
}
; Timed function to detect change of focus (and remove tooltip when changing active window)
Winchanged:
WinGetActiveTitle, ATitle
WinGet, A_id3, ID, %ATitle%
IfNotEqual, A_id, %A_id3%
{
ToolTip
}
Return
; Key definitions for autocomplete (0 to 9)
#MaxThreadsPerHotkey 1
$1::
key=1
Gosub, checkword
Return
$2::
key=2
Gosub, checkword
Return
$3::
key=3
Gosub, checkword
Return
$4::
key=4
Gosub, checkword
Return
$5::
key=5
Gosub, checkword
Return
$6::
key=6
Gosub, checkword
Return
$7::
key=7
Gosub, checkword
Return
$8::
key=8
Gosub, checkword
Return
$9::
key=9
Gosub, checkword
Return
$0::
key=10
Gosub, checkword
Return
; If hotkey was pressed, check wether there's a match going on and send it, otherwise send the number(s) typed
checkword:
clearword=1
Suspend, on ; Suspend hotkeys so that they don't interfere with the second press
; If active window has different window ID from before the input, blank word
; (well, assign the number pressed to the word)
WinGetActiveTitle, ATitle
WinGet, A_id2, ID, %ATitle%
IfNotEqual, A_id, %A_id2%
{
if key =10
key = 0
SendInput,%key%
Gosub,clearallvars
Suspend, off
Return
}
IfNotEqual, OldCaretY, %A_CaretY%
{
if key =10
key = 0
SendInput,%key%
Gosub,clearallvars
Suspend, off
Return
}
if word= ; only continue if word is not empty
{
if key =10
key = 0
SendInput,%key%
Setenv, Word, %key%
clearword=0
Gosub,clearallvars
Suspend, off
Return
}
ifequal, singlematch%key%, ; only continue singlematch is not empty
{
if key =10
key = 0
SendInput,%key%
Setenv, Word, %word%%key%
clearword=0
Gosub,clearallvars
Suspend, off
Return
}
; 2nd press to confirm replacement
Input, keyagain, L1 I T0.5, 1234567890
; msgbox, ErrorLevel=%ErrorLevel% ; UNCOMMENT FOR TESTING 2ND PROBLEM DISCUSSED IN POST
; If there is a timeout, abort replacement, send key and return
IfEqual, ErrorLevel, Timeout
{
if key =10
key = 0
SendInput, %key%
Setenv, Word, %word%%key%
clearword=0
Gosub,clearallvars
Suspend, off
Return
}
; Make sure it's an EndKey, otherwise abort replacement, send key and return
IfNotInString, ErrorLevel, EndKey:
{
if key =10
key = 0
SendInput, %key%%keyagain%
Setenv, Word, %word%%key%%keyagain%
clearword=0
Gosub,clearallvars
Suspend, off
Return
}
; If the 2nd key is NOT the same 1st trigger key, abort replacement and send keys
if key =10
key = 0
IfNotInString,ErrorLevel, %key%
{
StringTrimLeft, keyagain, ErrorLevel, 7
SendInput, %key%%keyagain%
Setenv, Word, %word%%key%%keyagain%
clearword=0
Gosub,clearallvars
Suspend, off
Return
}
; SEND THE WORD!
if key =0
key = 10
sending := singlematch%key%
StringLen, len, Word
SendInput, {BS %len%}{Raw}%sending% ; First do the backspaces, Then send word (Raw because we want the string exactly as in wordlist.txt)
Gosub,clearallvars
Suspend, off
Return
; This is to blank all vars related to matches, tooltip and (optionally) word
clearallvars:
Ifequal,clearword,1,Setenv,word,
ToolTip
; Clear all singlematches
Loop, 10
{
singlematch%a_index% =
}
sending =
key=
match=
clearword=1
OldCaretY=
Return
ConvertWordToAscii(Base)
{
StringUpper, Base, Base
StringLen, Len, Base
Loop, %Len%
{
Transform, Letter, Asc, %Base%
StringLen, LetterLen, Letter
IfLess, %LetterLen%, 3
{
Amt := 3-LetterLen
Loop, %Amt%
{
Letter = 0%Letter%
}
}
New = %New%%Letter%
StringTrimLeft, Base, Base, 1
}
Return New
}
1 key hit for hotkey
Code:
; Intellitype: typing aid
; Press 1 to 0 keys to autocomplete the word upon suggestion
; (0 will match suggestion 10)
; - Jordi S
; Heavily modified by:
; Maniac
;___________________________________________
; CONFIGURATIONS
; Editor Window Recognition
; (make it blank to make the script seek all windows)
ETitle =
;Minimum word length to make a guess
WLen = 3
keyagain=
key=
clearword=1
;Gosub,clearallvars ; clean vars from start
; Press 1 to 0 keys to autocomplete the word upon suggestion
; (0 will match suggestion 10)
;_______________________________________
CoordMode, ToolTip, Relative
AutoTrim, Off
;reads list of words from file
Loop, Read, %A_ScriptDir%\Wordlist.txt
{
StringLeft, Base, a_loopreadline, %wlen%
Base := ConvertWordToAscii(Base)
basenum%Base%++
pos := basenum%Base%
cmd%Base%%pos% = %a_loopreadline%
}
SetTimer, Winchanged, 100
Loop
{
;Editor window check
WinGetActiveTitle, ATitle
WinGet, A_id, ID, %ATitle%
IfNotInString, ATitle, %ETitle%
{
ToolTip
Setenv, Word,
sleep, 500
Continue
}
;Get one key at a time
Input, chr, L1 V,{enter}{space}.;`,:¿?¡!'"()]{}{}}{bs}{{}{esc}{tab}{Home}{End}{PgUp}{PdDn}{Up}{Dn}{Left}{Right}
EndKey = %errorlevel%
; If active window has different window ID from before the input, blank word
; (well, assign the number pressed to the word)
WinGetActiveTitle, ATitle
WinGet, A_id2, ID, %ATitle%
IfNotEqual, A_id, %A_id2%
{
Gosub,clearallvars
Setenv, Word, %chr%
Continue
}
ifequal, OldCaretY,
OldCaretY = %A_CaretY%
ifnotequal, OldCaretY, %A_CaretY%
{
Gosub,clearallvars
Setenv, Word, %chr%
Continue
}
OldCaretY=%A_CaretY%
;Backspace clears last letter
ifequal, EndKey, Endkey:BackSpace
{
StringLen, len, Word
IfNotEqual, len, 0
{ ifequal, len, 1
{
Gosub,clearallvars
} else {
StringTrimRight, Word, Word, 1
}
}
} else ifequal, EndKey, Max
{
ifequal, chr, @
{
Gosub,clearallvars
Setenv, Word, %chr%
Continue
} else {
Setenv, Word, %word%%chr%
}
} else Gosub,clearallvars
;Wait till minimum letters
StringLen, len, Word
IfLess, len, %wlen%
{
ToolTip
Continue
}
;Match part-word with command
Num =
Match =
singlematch = 0
number = 0
StringLeft, baseword, Word, %wlen%
baseword := ConvertWordToAscii(baseword)
Loop
{
IfEqual, cmd%baseword%%a_index%,, Break
IfEqual, number, 10
Break
StringLen, chars, Word
StringLeft, strippedcmd, cmd%baseword%%a_index%, %chars%
ifequal, strippedcmd, %Word%
{
number ++
singlematch := cmd%baseword%%a_index%
match = %match%%number%. %singlematch%`n
singlematch%number% = %singlematch%
Continue
}
}
;If no match then clear Tip
IfEqual, Match,
{
clearword=0
Gosub,clearallvars
Continue
}
;Show matched command
StringTrimRight, match, match, 1 ; Get rid of the last linefeed
WinGetActiveTitle, ATitle
WinGetPos, , PosY, , SizeY, %ATitle%
MaxY := PosY + SizeY
ToolTipSizeY := (number * 12)
ToolTipPosY := A_CaretY+14
if ((ToolTipSizeY + ToolTipPosY) > MaxY)
ToolTipPosY := (A_CaretY - 14 - ToolTipSizeY)
IfNotEqual, Word,,ToolTip, %match%, %A_CaretX%, %ToolTipPosY%
; +14 Move tooltip down a little so as not to hide the caret.
}
; Timed function to detect change of focus (and remove tooltip when changing active window)
Winchanged:
WinGetActiveTitle, ATitle
WinGet, A_id3, ID, %ATitle%
IfNotEqual, A_id, %A_id3%
{
ToolTip
}
Return
; Key definitions for autocomplete (0 to 9)
#MaxThreadsPerHotkey 1
$1::
key=1
Gosub, checkword
Return
$2::
key=2
Gosub, checkword
Return
$3::
key=3
Gosub, checkword
Return
$4::
key=4
Gosub, checkword
Return
$5::
key=5
Gosub, checkword
Return
$6::
key=6
Gosub, checkword
Return
$7::
key=7
Gosub, checkword
Return
$8::
key=8
Gosub, checkword
Return
$9::
key=9
Gosub, checkword
Return
$0::
key=10
Gosub, checkword
Return
; If hotkey was pressed, check wether there's a match going on and send it, otherwise send the number(s) typed
checkword:
clearword=1
; If active window has different window ID from before the input, blank word
; (well, assign the number pressed to the word)
WinGetActiveTitle, ATitle
WinGet, A_id2, ID, %ATitle%
IfNotEqual, A_id, %A_id2%
{
if key =10
key = 0
SendInput,%key%
Gosub,clearallvars
Return
}
IfNotEqual, OldCaretY, %A_CaretY%
{
if key =10
key = 0
SendInput,%key%
Gosub,clearallvars
Return
}
if word= ; only continue if word is not empty
{
if key =10
key = 0
SendInput,%key%
Setenv, Word, %key%
clearword=0
Gosub,clearallvars
Return
}
ifequal, singlematch%key%, ; only continue singlematch is not empty
{
if key =10
key = 0
SendInput,%key%
Setenv, Word, %word%%key%
clearword=0
Gosub,clearallvars
Return
}
; SEND THE WORD!
if key =0
key = 10
sending := singlematch%key%
StringLen, len, Word
SendInput, {BS %len%}{Raw}%sending% ; First do the backspaces, Then send word (Raw because we want the string exactly as in wordlist.txt)
Gosub,clearallvars
Return
; This is to blank all vars related to matches, tooltip and (optionally) word
clearallvars:
Ifequal,clearword,1,Setenv,word,
ToolTip
; Clear all singlematches
Loop, 10
{
singlematch%a_index% =
}
sending =
key=
match=
clearword=1
OldCaretY=
Return
ConvertWordToAscii(Base)
{
StringUpper, Base, Base
StringLen, Len, Base
Loop, %Len%
{
Transform, Letter, Asc, %Base%
StringLen, LetterLen, Letter
IfLess, %LetterLen%, 3
{
Amt := 3-LetterLen
Loop, %Amt%
{
Letter = 0%Letter%
}
}
New = %New%%Letter%
StringTrimLeft, Base, Base, 1
}
Return New
}
OK, I changed all the Send/SendRaw to SendInput, to do this I changed the following
Removed L25:
Code:
SetKeyDelay, 0
Change all
Code:
Send, %key%
to
Code:
SendInput, %key%
(and the ones where %keyagain% is at the end)
in SEND THE WORD
changed
Code:
StringTrimLeft, lastone, singlematch%key%, 0 ; This is because i can't get %singlematch%%key%
StringTrimLeft, sending, %lastone%, 0 ; to work in this line
StringLen, len, Word
Send, {BS %len%} ; First do the backpaces
SendRaw, %sending% ; Then send word (Raw because we want the string exactly as in wordlist.txt)
Gosub,clearallvars
to
Code:
sending := singlematch%key%
StringLen, len, Word
SendInput, {BS %len%}{Raw}%sending% ; First do the backspaces, Then send word (Raw because we want the string exactly as in wordlist.txt)
Gosub,clearallvars
I also changed how the code evaluates the input, we don't need to check EVERY endkey!:
Remove all these lines:
Code:
;Blanks word reserve
ifequal, EndKey, Endkey:Enter, Gosub,clearallvars
ifequal, EndKey, Endkey:Escape, Gosub,clearallvars
ifequal, EndKey, Endkey:Space, Gosub,clearallvars
ifequal, EndKey, Endkey:`,, Gosub,clearallvars
ifequal, EndKey, Endkey:., Gosub,clearallvars
ifequal, EndKey, Endkey:`:, Gosub,clearallvars
ifequal, EndKey, Endkey:`;, Gosub,clearallvars
ifequal, EndKey, Endkey:!, Gosub,clearallvars
ifequal, EndKey, Endkey:¡, Gosub,clearallvars
ifequal, EndKey, Endkey:?, Gosub,clearallvars
ifequal, EndKey, Endkey:¿, Gosub,clearallvars
ifequal, EndKey, Endkey:", Gosub,clearallvars
ifequal, EndKey, Endkey:', Gosub,clearallvars
ifequal, EndKey, Endkey:(, Gosub,clearallvars
ifequal, EndKey, Endkey:), Gosub,clearallvars
; ifequal, EndKey, Endkey:[, Gosub,clearallvars
ifequal, EndKey, Endkey:], Gosub,clearallvars
ifequal, EndKey, Endkey:{, Gosub,clearallvars
ifequal, EndKey, Endkey:}, Gosub,clearallvars
change these lines
Code:
;Backspace clears last letter
ifequal, EndKey, Endkey:BackSpace, StringTrimRight, Word, Word, 1
ifnotequal, EndKey, Endkey:BackSpace, Setenv, Word, %word%%chr%
to (includes my previous changes):
Code:
;Backspace clears last letter
ifequal, EndKey, Endkey:BackSpace
{
StringLen, len, Word
IfNotEqual, len, 0
{ ifequal, len, 1
{
Gosub,clearallvars
} else {
StringTrimRight, Word, Word, 1
}
}
} else ifequal, EndKey, Max
{
ifequal, chr, @
{
Gosub,clearallvars
Setenv, Word, %chr%
Continue
} else {
Setenv, Word, %word%%chr%
}
} else Gosub,clearallvars
Implemented some code to make sure we are on the Correct Vertical Line (I haven't quite figured out horizontal positioning yet):
from:
Code:
WinGetActiveTitle, ATitle
WinGet, A_id2, ID, %ATitle%
IfNotEqual, A_id, %A_id2%
{
Gosub,clearallvars
Setenv, Word, %chr%
Continue
}
to
Code:
WinGetActiveTitle, ATitle
WinGet, A_id2, ID, %ATitle%
IfNotEqual, A_id, %A_id2%
{
Gosub,clearallvars
Setenv, Word, %chr%
Continue
}
ifequal, OldCaretY,
OldCaretY = %A_CaretY%
ifnotequal, OldCaretY, %A_CaretY%
{
Gosub,clearallvars
Setenv, Word, %chr%
Continue
}
OldCaretY=%A_CaretY%
from:
Code:
WinGetActiveTitle, ATitle
WinGet, A_id2, ID, %ATitle%
IfNotEqual, A_id, %A_id2%
{
if key =10
key = 0
Send,%key%
Gosub,clearallvars
Suspend, off
Return
}
to
Code:
WinGetActiveTitle, ATitle
WinGet, A_id2, ID, %ATitle%
IfNotEqual, A_id, %A_id2%
{
if key =10
key = 0
Send,%key%
Gosub,clearallvars
Suspend, off
Return
}
IfNotEqual, OldCaretY, %A_CaretY%
{
if key =10
key = 0
SendInput,%key%
Gosub,clearallvars
Return
}
in clearallvars:
add:
Code:
clearword=1
OldCaretY=
I modified the tooltip display code so it would appear above the text when at the bottom of the screen (not going to work well with weird font sizes):
from:
Code:
;Show matched command
StringTrimRight, match, match, 1 ; Get rid of the last linefeed
; IfNotEqual, Word,,ToolTip, %match%, 388, 24
display_y = %A_CaretY%
display_y += 20 ; Move tooltip down a little so as not to hide the caret.
IfNotEqual, Word,,ToolTip, %match%, %A_CaretX%, %display_y%
}
to:
Code:
;Show matched command
StringTrimRight, match, match, 1 ; Get rid of the last linefeed
WinGetActiveTitle, ATitle
WinGetPos, , PosY, , SizeY, %ATitle%
MaxY := PosY + SizeY
ToolTipSizeY := (number * 12)
ToolTipPosY := A_CaretY+14
if ((ToolTipSizeY + ToolTipPosY) > MaxY)
ToolTipPosY := (A_CaretY - 14 - ToolTipSizeY)
IfNotEqual, Word,,ToolTip, %match%, %A_CaretX%, %ToolTipPosY%
; +14 Move tooltip down a little so as not to hide the caret.
}
and finally I changed the script to make it so not all words have to be searched when finding a match, only those beginning with your minimum length word by using a pseudo-hash via a multidimensional array (only works with characters in the ASCII Character set!):
from:
Code:
Loop, Read, %A_ScriptDir%\Wordlist.txt
{
tosend = %a_loopreadline%
cmd%a_index% = %toSend%
}
to:
Code:
Loop, Read, %A_ScriptDir%\Wordlist.txt
{
StringLeft, Base, a_loopreadline, %wlen%
Base := ConvertWordToAscii(Base)
basenum%Base%++
pos := basenum%Base%
cmd%Base%%pos% = %a_loopreadline%
}
from:
Code:
;Match part-word with command
Num =
Match =
singlematch = 0
number = 0
Loop
{
IfEqual, cmd%a_index%,, Break
StringLen, chars, Word
StringLeft, strippedcmd, cmd%a_index%, %chars%
StringLeft, strippedword, Word, %chars%
ifequal, strippedcmd, %strippedword%
{
num = %a_index%
number ++
; Create list of matches
StringTrimLeft, singlematch, cmd%num%, 0
match = %match%%number%. %singlematch%`n
; Map singlematch with corresponding cmd
singlematch%number%=cmd%num%
Continue
}
}
;If no match then clear Tip
IfEqual, Num,
{
clearword=0
Gosub,clearallvars
Continue
}
to
Code:
;Match part-word with command
Num =
Match =
singlematch = 0
number = 0
StringLeft, baseword, Word, %wlen%
baseword := ConvertWordToAscii(baseword)
Loop
{
IfEqual, cmd%baseword%%a_index%,, Break
IfEqual, number, 10
Break
StringLen, chars, Word
StringLeft, strippedcmd, cmd%baseword%%a_index%, %chars%
ifequal, strippedcmd, %Word%
{
number ++
singlematch := cmd%baseword%%a_index%
match = %match%%number%. %singlematch%`n
singlematch%number% = %singlematch%
Continue
}
}
;If no match then clear Tip
IfEqual, Match,
{
clearword=0
Gosub,clearallvars
Continue
}
added function:
Code:
ConvertWordToAscii(Base)
{
StringUpper, Base, Base
StringLen, Len, Base
Loop, %Len%
{
Transform, Letter, Asc, %Base%
StringLen, LetterLen, Letter
IfLess, %LetterLen%, 3
{
Amt := 3-LetterLen
Loop, %Amt%
{
Letter = 0%Letter%
}
}
New = %New%%Letter%
StringTrimLeft, Base, Base, 1
}
Return New
}