Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Intellisense-like autoreplacement with multiple suggestions


  • Please log in to reply
123 replies to this topic
jordis
  • Members
  • 81 posts
  • Last active: Aug 22 2014 01:56 PM
  • Joined: 30 Jul 2004
[PLEASE READ FIRST: This script is really old (2004!) and unmaintained. If you like the intended functionality, you might want to have a look at TypingAid, a much evolved, improved and revamped take of my initial script: http://www.autohotke...pic.php?t=53630 This can save you from reading pages and pages of posts. jordis]

Hi all
Since I have a couple of problems in my script, I though I shouldn't post it in the Script&Utilities forum, but it's almost doing its job :)
The script concept is based on Rajat's Intellisense for AHK commands script.
Basically, it needs a file called wordlist.txt in the same path as the script containing a list of words (or sentences) to look for. When the user types 3 characters (can be changed in the script) that match the beginning of a word included in wordlist.txt, then the scripts offers it as a suggestion tooltip. If the 3 typed characters match multiple words, then the script sugests them all as a choice.
To trigger the replacement, I though about pressing control something, or alt something, but then I thought I would avoid such key combinations because 1) the apllication in which i want to use it, already uses these key combinations for other purposes and 2) I dont think it's fast or convenient enough having to press an extra key during normal typing. Therefore, I though to use the 0-9 number keys (regular ones, not numpad) to trigger the replacement. So, when a suggestion is presented to the user, he/she simply has to "double-press" the corresponding number (kind of double-click, but with the number key). I think this is faster than having to press a combination of another key plus the number... There is a timeout of 0.5 seconds for the second key press. That is, if the user presses 1 upon a suggestion, the script will wait for half a second to check whether the 1 key is pressed again. Otherwise, a literal 1 is send.
The script is still in a development stage... for example I didn't event implement the new Caret recognition functions to show the tooltip near the caret... YET :oops: but first I wanted it to work as I expect...
At this point, I'm stuck with 2 problems for which I can't seem to spot the faulty portion of code:
[EDIT]
1) All diacritics seem to work perfectly, EXCEPT fort the " ` ", as in òèìù. I'm running the latest .18 version, and I don't think it's related to the bug identified in previous versions (see keyboard malfunctioning when using HotStrings), because I do not have any problems with other scripts... Also, the word variable (the variable which stores the word the user is typing) picks the "ò" perfectly, but only an "o" is sent to the application... could it probaly be something related to the escape char being " ` "? dunno...
2) The auto-replacement does not seem to work the FIRST time the users triggers a replacement... For example, if wordlist.txt includes the word "system", when the user types "sys" he is provided with a suggestion "1. system". He double-presses the 1 key, but instead of replacing the word, it only sends "1". Funnily enough, it works perfectly well in all the subsequent times! Some testing led to the conclusion that, the first time, the 2nd key input's errorlevel is always Timeout instead of the actual key pressed... To test it, you can uncomment line 243, which will show the errorlevel of the 2nd key input... You'll see that the first time (and ONLY the first time) , the errorlevel is Timeout. The subsequent times, the errorlevel is detected correctly. Any ideas on why does this happen?

Well, enough talking. Here goes the script.
I guess a lot of ironing can be done to it and don't be scared about my logic of doing things :roll:
[EDIT]
SetKeyDelay, 0
CoordMode, ToolTip, Relative
AutoTrim, Off

;_______________________________________

;    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) 
;_______________________________________

;reads list of words from file
Loop, Read,  %A_ScriptDir%\Wordlist.txt   
{
   tosend = %a_loopreadline%
   cmd%a_index% = %toSend%
}

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}
   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
   }
   
   ;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  -- this was causing problem number 1
   ifequal, EndKey, Endkey:], Gosub,clearallvars
   ifequal, EndKey, Endkey:{, Gosub,clearallvars
   ifequal, EndKey, Endkey:}, Gosub,clearallvars
   
   ;Backspace clears last letter
   ifequal, EndKey, Endkey:BackSpace, StringTrimRight, Word, Word, 1
   ifnotequal, EndKey, Endkey:BackSpace, Setenv, Word, %word%%chr%
   
   ;Wait till minimum letters
   StringLen, len, Word
   IfLess, len, %wlen%
   {
      ToolTip
      Continue
   }
   
   ;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
   }
   
   ;Show matched command
   StringTrimRight, match, match, 1        ; Get rid of the last linefeed
   IfNotEqual, Word,,ToolTip, %match%, 388, 24
} 

; 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
         Send,%key%
         Gosub,clearallvars
         Suspend, off
         Return
      }

   if word=        ; only continue if word is not empty
      {
         if key =10
            key = 0
         Send,%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
         Send,%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
      Send, %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
      Send, %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
      Send, %key%%keyagain%
      Setenv, Word, %word%%key%%keyagain%
      clearword=0
      Gosub,clearallvars
      Suspend, off
      Return
   }

   ; SEND THE WORD!
   if key =0
      key = 10
   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
   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
      Return
jordi

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
Thanks for reporting this.

The first problem is a bug and has been fixed in the installer at http://www.autohotkey.com : "Fixed commands that turn on the keyboard hook (such as Input) so that they will not re-enable suspended hotkeys. [thanks jordi]"

The second issue has to do with the fact that the end-keys of an Input command are handled by virtual key code rather than their ASCII value (this is done so that non-ascii keys such as {WIN} and {Down} can be supported). Since I believe the virtual key for '[' is the same as for accent-grave, the accent in effect becomes an end-key. I think you can work around this by removing '[' from the list of end-keys. You might also remove '{' though that is probably not necessary.

Some further improvements in this area are probably needed, but for now, hopefully it's enough.

jordis
  • Members
  • 81 posts
  • Last active: Aug 22 2014 01:56 PM
  • Joined: 30 Jul 2004
Thanks Chris
you are always so right :)
the new installer fixed the Timeout problem
and getting rid of [ as endkey also did the trick for the diacritic problem

I think the main functionality of the script has been achieved... I'll move on polishing and adding in some improvements

I edited my previous post to notify readers that both problems were solved. Also, I modified the script to fix problem with diacritic.

Rajat
  • Members
  • 1904 posts
  • Last active: Jul 17 2015 07:45 AM
  • Joined: 28 Mar 2004
way to go Jordi! i've checked it and it works great.
i'm sure u'll improve the original script a lot... by the way i've already updated my script to use caret functions so u can use that in yours readily.

MIA

CleanNews.in : Bite sized latest news headlines from India with zero bloat


  • Guests
  • Last active:
  • Joined: --
This his a great script.
Personally I use it in a slightly adapted way to make it work with multipleline items.

E.g.:
She frowned and called him Mr.
Because in sport he kr.
And so in spite
That very nite
This Mr. kr. sr.

In the Wordlist.txt this limerick is transcripted to one line: She frowned and called him Mr.- -Because in sport he kr.- -And so in spite- -That very nite- -This Mr. kr. sr.

- - means hard return (can be replaced by any other delimiter)


The adaptations of the script are marked with <---

(near line 110)

; Create list of matches
StringTrimLeft, singlematch, cmd%num%, 0
StringLeft, singlematch, singlematch, 100 ;<--- no multipleline display in tooltip
match = %match%%number%. %singlematch%`n

(100 can be replaced by any other number)

(near line 285)

; SEND THE WORD!
   if key =0
      key = 10
   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 <--- replaced by next 2
   StringReplace, sendingReturn, sending, -     -, `n, All ;<--- set hard return back
   SendRaw, %sendingReturn%  ; <---
   Gosub,clearallvars
   Suspend, off
   Return

I think there are other uses possible (eg: 100 euro displayed in tooltip as corresponding amount of lires or marks; automatic sending of abbrevitions etc..). Since I am not a programmer this may take a while, if it is possible at all! Any ideas are wellcome. Thanks.

Dirk

BAbdulBaki
  • Guests
  • Last active:
  • Joined: --
In line 51, remove {space} from the Input line so that spaces can be used in the autoreplacement string.

Maniac
  • Members
  • 445 posts
  • Last active: Jan 06 2016 12:02 PM
  • Joined: 28 Aug 2009
Thanks for this script! I made a few fixes, never used AHK before so review would be nice..

I don't think } was working as an end character... need to use {}} not {}
Line 51:
Input, chr, L1 V,{enter}{space}.;`,:¿?¡!'"()]{}{bs}{esc}
should be:
Input, chr, L1 V,{enter}{space}.;`,:¿?¡!'"()]{}[color=red]}[/color]{bs}{esc}

Backspacing didn't seem to work right, this seems to fix it:
Line 85-87:
old:
;Backspace clears last letter
   ifequal, EndKey, Endkey:BackSpace, StringTrimRight, Word, Word, 1
   ifnotequal, EndKey, Endkey:BackSpace, Setenv, Word, %word%%chr%
new:
;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 {
            
           Setenv, Word, %word%%chr%
           }

When a lot of words would pop up I ran into issues where if I typed fast my next key wouldn't be recognized... this limits the list to 10 lines

old:

   ;Match part-word with command
   Num =
   Match =
   singlematch = 0
   number = 0
   Loop
   {
      IfEqual, cmd%a_index%,, Break
      StringLen, chars, Word

new:
;Match part-word with command 
   Num = 
   Match = 
   singlematch = 0 
   number = 0 
   Loop
   { 
      IfEqual, cmd%a_index%,, Break 
[color=red]      ifequal, number, 10
           Break[/color]
      StringLen, chars, Word 

I also modified the script to only need the key to be hit once, my words don't have numbers in them, to do this comment out lines 208, 248-292

Thanks for your work!

Endre
  • Members
  • 10 posts
  • Last active: Feb 19 2013 05:05 PM
  • Joined: 14 Jan 2008
Hello maniac,

Would you mind posting the entire script so it's easier to try out?

Thanks,
Endre

Morpheus
  • Members
  • 475 posts
  • Last active: Oct 21 2014 11:08 AM
  • Joined: 31 Jul 2008
I was working on combining Intellisense with this script, until I found Isense: http://www.autohotke...pic.php?t=12985

The code that I had so far, combined the list in in Jordis' script with Rajats' intellisense. Completed so far:
added support for the 5 loop commands.
autocomplete for A_ variables
{Ctrl}F1 for help file
plus some of maniacs ideas.

#SingleInstance Force
#MaxThreadsPerHotkey 1
SetKeyDelay, 0
CoordMode, ToolTip, Relative
AutoTrim, Off
SetBatchLines, -1

I_HelpHotkey = ^F1
Editor = PSPad ; Editor Recognition
CmdLen = 3 ;Minimum word length to make a guess
VarLen = 2

I_FullLoop1 := "Loop [, Count]`n{`n	ID := A_Index`n	If var%A_Index% =`n	break`n}"
I_FullLoop2 := "Loop, FilePattern [, IncludeFolders?, Recurse?]`n{`n	FileName := A_LoopFileName`n	FileFullPath := A_LoopFileLongPath`n	FileRelativeDir := A_LoopFileDir`n	command2`n}"
I_FullLoop3 := "Loop, Parse, InputVar [, Delimiters|CSV, OmitChars]`n{`n	Line := A_LoopField`n	command2`n}"
I_FullLoop4 := "Loop, Read, InputFile [, OutputFile]`n{`n	Line := A_LoopReadLine`n	command2`n}"
I_FullLoop5 := "Loop, HKLM|HKU|HKCU|HKCR|HKCC [, Key, IncludeSubkeys?, Recurse?]`n{`n	RegName := A_LoopRegName`n	RegType := A_LoopRegType`n	command2`n}"
I_CurrLoop1 := "Loop"
I_CurrLoop2 := "Loop, FilePattern"
I_CurrLoop3 := "Loop, Parse a string"
I_CurrLoop4 := "Loop, Read file contents"
I_CurrLoop5 := "Loop (registry)"

IfNotEqual, A_IsCompiled, 1
	SplitPath, A_AhkPath,, Ahk_Dir
IfNotExist %Ahk_Dir%\Extras\Editors\Syntax\Commands.txt
{
	MsgBox, Could not find the AutoHotKey folder.
	ExitApp
}

Ahk_Help_File = %Ahk_Dir%\AutoHotKey.chm

; Read command syntaxes:
Index = -1
Loop, Read, %Ahk_Dir%\Extras\Editors\Syntax\Commands.txt
{
	I_FullCmd = %A_LoopReadLine%
  StringLeft, TempVar, I_FullCmd, 4
  If TempVar <> Loop
  {
	 ; Directives have a first space instead of a first comma.
	 ; So use whichever comes first as the end of the command name:
	 StringGetPos, I_cPos, I_FullCmd, `,
	 StringGetPos, I_sPos, I_FullCmd, %A_Space%
	 DeLim := " "
   IfInString, I_FullCmd, `,
     DeLim := ", "
	 If (I_cPos = -1 or (I_cPos > I_sPos and I_sPos <> -1))
  		I_EndPos := I_sPos
 	 Else
  		I_EndPos := I_cPos

	 If I_EndPos <> -1
  		StringLeft, I_CurrCmd, I_FullCmd, %I_EndPos%
	 Else  ; This is a directive/command with no parameters.
	  	I_CurrCmd = %A_LoopReadLine%

	 StringReplace, I_CurrCmd, I_CurrCmd, [,, All
	 StringReplace, I_CurrCmd, I_CurrCmd, %A_Space%,, All
	 StringReplace, I_FullCmd, I_FullCmd, ``n, `n, All
	 StringReplace, I_FullCmd, I_FullCmd, ``t, `t, All
	 I_HelpCmd := I_FullCmd
  }
  Else
  {
   LoopCount++
 	 I_CurrCmd := I_CurrLoop%LoopCount%
   I_FullCmd := I_FullLoop%LoopCount%
   I_HelpCmd := "Loop"
  }
	; Make arrays of command names, part commands and full cmd syntaxes:
	Index++
	I_Cmd%Index% = %I_CurrCmd%
	I_FullCmd%Index% = %I_FullCmd%
	I_Delim%Index% = %Delim%
}
Index = -1
Loop, Read,  %Ahk_Dir%\Extras\Editors\Syntax\Variables.txt
{
 Index++
   I_Var%Index% = %a_loopreadline%
}

Key=
RetFlag = 1

TempVar := "0!1!2!3!4!5!6!7!8!9"
Loop, Parse, TempVar, !
 Hotkey, %A_LoopField%, CheckWord

If I_HelpHotkey <>
	Hotkey, %I_HelpHotkey%, I_HelpHotkey

SetTimer, Winchanged, 100

Loop
{
 WinGetActiveTitle, ATitle
 WinGet, A_id, ID, %ATitle%
 IfNotInString, ATitle, %Editor%   ;Editor check
 {
  ToolTip
  Word =
  Sleep, 500
  Continue
 }

 ;Get one key at a time
 Input, Chr, L1 V,{enter}{space}.;`,:¿?¡!'"()]{}{bs}{esc}
 EndKey = %errorlevel%
 WinGetActiveTitle, ATitle
 WinGet, A_id2, ID, %ATitle%
 If  A_id <> %A_id2%
 {
  Gosub,ClearAllVars
  Word := Chr
  Continue
 }

 ;Blanks word reserve
 ifequal, EndKey, Endkey:Enter
 {
  Gosub,ClearAllVars
  I_ThisFullCmd =
 }
 ifequal, EndKey, Endkey:Escape
 {
  Gosub,ClearAllVars
  Tooltip, %I_ThisFullCmd%, A_CaretX, A_CaretY + 20
 }
 ifequal, EndKey, Endkey:Space
 {
  Gosub, ClearMostVars
  Word =
;  retFlag = 0
 }
 ifequal, EndKey, Endkey:`,, Gosub,ClearMostVars
 ifequal, EndKey, Endkey:`, Gosub,ClearMostVars
 ifequal, EndKey, Endkey:., Gosub,ClearMostVars
 ifequal, EndKey, Endkey:`:, Gosub,ClearMostVars
 ifequal, EndKey, Endkey:`;, Gosub,ClearMostVars
 ifequal, EndKey, Endkey:!, Gosub,ClearMostVars
 ifequal, EndKey, Endkey:¡, Gosub,ClearMostVars
 ifequal, EndKey, Endkey:?, Gosub,ClearMostVars
 ifequal, EndKey, Endkey:¿, Gosub,ClearMostVars
 ifequal, EndKey, Endkey:", Gosub,ClearMostVars
 ifequal, EndKey, Endkey:', Gosub,ClearMostVars
 ifequal, EndKey, Endkey:(, Gosub,ClearMostVars
 ifequal, EndKey, Endkey:), Gosub,ClearMostVars
;   ifequal, EndKey, Endkey:[, Gosub,ClearMostVars  -- this was causing problem number 1
 ifequal, EndKey, Endkey:], Gosub,ClearMostVars
 ifequal, EndKey, Endkey:{, Gosub,ClearMostVars
 ifequal, EndKey, Endkey:}, Gosub,ClearMostVars
  ;Backspace clears last letter
 ifequal,  EndKey, Endkey:BackSpace
 {
  StringLen, Len, Word
  If Len <> 0
  {
   If Len = 1
      Gosub,ClearAllVars
   Else
      StringTrimRight, Word, Word, 1
  }
 }
 Word .= Chr
;  msgbox, *%word%*
 Match =
 Number = -1
 StringLen, Len, Word
 If RetFlag = 1
 {
  If Len < %CmdLen%   ;Wait till minimum letters
     goto, VarCheck
  Loop
  {
   Num := A_Index - 1
   If I_Cmd%Num% =
      Break
   StringLen, Chars, Word
   StringLeft, StrippedCmd, I_Cmd%Num%, %Chars%
   StringLeft, StrippedWord, Word, %Chars%
   If StrippedCmd = %StrippedWord%
   {
    Number ++
    ; Create list of matches
    StringTrimLeft, SingleMatch, I_Cmd%Num%, 0
    Match .= Number . "." . SingleMatch . "`n"
    ; Map SingleMatch with corresponding cmd
    SingleMatch%Number%=I_Cmd%Num%
    SingleDelim%Number% := I_Delim%Num%
    Continue
   }
  }
 }
 VarCheck:
 If Len >= 2 ;%VarLen%
 {
  Loop
  {
   Num := A_Index - 1
   If I_Var%Num% =
      Break
   StringLen, Chars, Word
   StringLeft, StrippedCmd, I_Var%Num%, %Chars%
   StringLeft, StrippedWord, Word, %Chars%
   If StrippedCmd = %StrippedWord%
   {
    Number ++
    ; Create list of matches
    StringTrimLeft, SingleMatch, I_Var%Num%, 0
    Match .= Number . "." . SingleMatch . "`n"
    ; Map SingleMatch with corresponding cmd
    SingleMatch%Number%=I_Var%Num%
    Continue
   }
  }
 }
 ;If no match then clear Tip
 If Match =
 {
  Gosub,ClearMostVars
  Continue
 }
 ;Show matched command
 StringTrimRight, Match, Match, 1        ; Get rid of the last linefeed
 If Word <>
    ToolTip, %Match%, 388, 24
}

; This is to blank all vars related to matches, tooltip and (optionally) word
ClearAllVars:
 Tooltip
 RetFlag = 1
 Word =
ClearMostVars:
 ; Clear all SingleMatches
 Loop, 10
 {
  TempVar := A_Index - 1
  SingleMatch%TempVar% =
  SingleDelim%TempVar% =
 }
 I_Word =
 Key=
 Match=
 Return
 
; 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


; If hotkey was pressed, check wether there's a match going on and send it, otherwise send the number(s) typed
CheckWord:
 Key := A_ThisHotkey
 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%
 {
  Send,%Key%
  Gosub,ClearAllVars
  Suspend, off
  Return
 }

 If word=        ; only continue if word is not empty
 {
  Send,%Key%
  Gosub, ClearMostVars
  Word := Key
  Suspend, off
  Return
 }

 If SingleMatch%Key% =   ; only continue SingleMatch is not empty
 {
  Send,%Key%
  Word .= Key
  Gosub, ClearMostVars
  Suspend, off
  Return
 }

 ; SEND THE WORD!

 StringTrimLeft, TempVar, SingleMatch%Key%, 0 ; This is because i can't get %SingleMatch%%Key%
 StringTrimLeft, I_Word, %TempVar%, 0        ; to work in this line
 StringLen, Len, Word
 Send, {BS %Len%}    ; First do the backpaces
 StringLeft, TempVar, I_Word, 4
 ThisWord := I_Word
 If TempVar = Loop
 {
  ThisWord = Loop
  SingleDelim%Number% := ", "
  IfInString, I_Word, Loop`, Read
    ThisWord := "Loop, Read"
  IfInString, I_Word, Loop`, Parse
    ThisWord := "Loop, Parse"
 }
 ThisDelim := SingleDelim%Number%
 SendRaw, %ThisWord%%ThisDelim%  ; Then send word (Raw because we want the string exactly as in wordlist.txt)
 I_Index =

 Loop
 {
	I_ThisCmd := I_Cmd%A_Index%
	If I_ThisCmd =
  		break
	If (I_Word = I_ThisCmd)
	{
  	I_Index := A_Index
		I_HelpOn = %I_ThisCmd%
		break
	}
 }

	; If no match then resume watching user input:
 If I_Index <>
 {
	; Show matched command to guide the user:
	I_ThisFullCmd := I_FullCmd%I_Index%
	ToolTip, %I_ThisFullCmd%, A_CaretX, A_CaretY + 20
	I_FullHelpOn = Y
 }
 Else
   Tooltip, %I_ThisFullCmd%, A_CaretX, A_CaretY + 20
Gosub, ClearMostVars
RetFlag = 0
Suspend, off
Return

I_HelpHotkey:
	WinGetTitle, ActiveTitle, A
	IfNotInString, ActiveTitle, %I_Editor%, Return

	ToolTip  ; Turn off syntax helper since there is no need for it now.

	SetTitleMatchMode, 1  ; In case it's 3. This setting is in effect only for this thread.
	IfWinNotExist, AutoHotkey Help
	{
		IfNotExist, %ahk_help_file%
		{
			MsgBox, Could not find the help file: %ahk_help_file%.
			return
		}
		Run, %ahk_help_file%
		WinWait, AutoHotkey Help
	}

	if I_ThisCmd =  ; Instead, use what was most recently typed.
		I_ThisCmd := I_Word

	; The above has set the "last found" window which we use below:
	WinActivate
	WinWaitActive
	StringReplace, I_ThisCmd, I_ThisCmd, #, {#}  ; Replace leading #, if any.
	Send, !n{home}+{end}%I_HelpOn%{enter}
return

^Q::ExitApp
[/url]

Asaptrad
  • Members
  • 4 posts
  • Last active: Sep 03 2009 11:55 AM
  • Joined: 29 Apr 2009

In line 51, remove {space} from the Input line so that spaces can be used in the autoreplacement string.


That would be useful but for some reason it seems to stop the script from working properly. Can anyone see why?
David

Maniac
  • Members
  • 445 posts
  • Last active: Jan 06 2016 12:02 PM
  • Joined: 28 Aug 2009
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
;  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
;  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:
SetKeyDelay, 0

Change all
Send, %key%
to
SendInput, %key%
(and the ones where %keyagain% is at the end)

in SEND THE WORD
changed
   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
   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:
   ;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
   ;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):
      ;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:
   WinGetActiveTitle, ATitle
   WinGet, A_id2, ID, %ATitle%
   IfNotEqual, A_id, %A_id2%
   {
      Gosub,clearallvars
      Setenv, Word, %chr%
      Continue
   }
to
   WinGetActiveTitle, ATitle 
   WinGet, A_id2, ID, %ATitle% 
   IfNotEqual, A_id, %A_id2% 
   { 
      Gosub,clearallvars 
      Setenv, Word, %chr% 
      Continue 
   } [color=red]
   
   ifequal, OldCaretY,
        OldCaretY = %A_CaretY%
   ifnotequal, OldCaretY, %A_CaretY%
   {
         Gosub,clearallvars
         Setenv, Word, %chr%
         Continue
         
   } 
   
   OldCaretY=%A_CaretY%[/color]

from:
   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
   WinGetActiveTitle, ATitle
   WinGet, A_id2, ID, %ATitle%
   IfNotEqual, A_id, %A_id2%
      {
         if key =10
            key = 0
         Send,%key%
         Gosub,clearallvars
         Suspend, off
         Return
      }[color=red]
   IfNotEqual, OldCaretY, %A_CaretY%
      { 
         if key =10 
            key = 0 
         SendInput,%key% 
         Gosub,clearallvars 
         Return 
      } [/color]

in clearallvars:
add:
      clearword=1 [color=red]
      OldCaretY=[/color]

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:
   ;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:
   ;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:
Loop, Read,  %A_ScriptDir%\Wordlist.txt   
{
   tosend = %a_loopreadline%
   cmd%a_index% = %toSend%
}

to:
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:
   ;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
   ;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:
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
}


Maniac
  • Members
  • 445 posts
  • Last active: Jan 06 2016 12:02 PM
  • Joined: 28 Aug 2009
changed winchanged: so the tooltip clears (word is not cleared til you start typing again) if the Y position of the caret has changed.

Be warned, I had some issues with this regarding double clicks, I think they are now fixed.

Colored code = new code:

; 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 ,
   } [color=red]else {
            ; If we are in the correct window, and OldCaretY is set, clear the tooltip if not in the same line
            IfInString, ATitle, %ETitle%
            {
               IfNotEqual, OldCaretY,
               {
                  IfNotEqual, OldCaretY, %A_CaretY%    
                  {
                     ToolTip,
                  }
               }
            }
         }[/color]
   Return


  • Guests
  • Last active:
  • Joined: --
manic please post the entire code so I don't make the changes but just load your new code. thanks.

  • Guests
  • Last active:
  • Joined: --
I can't find this part in the code

Winchanged:

in the first code you post

SetKeyDelay, 0
CoordMode, ToolTip, Relative
AutoTrim, Off

;_______________________________________

;    CONFIGURATIONS

; Editor Window Recognition
; (make it blank to make the script seek all windows)

ETitle =


  • Guests
  • Last active:
  • Joined: --
Hi. I have this as wordlist.
http://www.sil.org/l... ... ordsEn.txt

As it's a long list it sorts of lag when I type in the pop up has to catch up. It's behind some 3, 4 words I think.

Please try to see what I mean. Thanks.

http://www.sil.org/l... ... ordsEn.txt