AutoHotkey Community

It is currently May 27th, 2012, 1:16 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 150 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6, 7, 8 ... 10  Next
Author Message
 Post subject:
PostPosted: January 11th, 2010, 4:11 pm 
Offline

Joined: August 28th, 2009, 3:00 pm
Posts: 275
hugov wrote:
maniac wrote:
The clipboard thing did not work right. It only seemed to sometimes paste in the value, other times it just left the text blank. I have left the clipboard code commented in case anyone wants to try playing with it. I changed it from ^v to {Ctrl Down}v{Ctrl Up} as I couldn't get ^v to work at all.
Try adding clipwait, 0 above the paste command. my guess is that it takes a short while before the clipboard gets the content so it pastes to fast.

Re speed: I think you will really start to notice the difference for very long lists e.g. 25000 lines but there is probably no difference when you have 100 words/lines in wordslist.txt


OK, I found the issue, or part of it... apparently BlockInput keeps SendInput from working. Commenting out BlockInput let SendInput work, but it seems the old clipboard data is getting back into the Clipboard before SendInput has actually put the text to the document. If I comment out the code that restores the old clipboard data it types the values correctly. Any ideas?

Right, the list I was checking has over 100,000 lines, but it still didn't seem like much of a performance increase (I think there was a small one). I expected there to be more of a boost, the efficiency issues must be somewhere else.

Thanks!

Edit:
Changing SendInput to Send or SendPlay seems to work... should I just use one of those?


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 11th, 2010, 4:16 pm 
Offline

Joined: May 27th, 2007, 9:41 am
Posts: 4999
Fiddle with clipwait or if that fails sleep 100, 250 etc
Code:
; below doesn't seem to work right, it randomly sends blank values to SendInput
;   ClipboardSave:=ClipboardAll
;   Clipboard =
;   Clipwait, 0
;   Clipboard = %sending%
;   SendInput, {BS %len%}{Ctrl Down}v{Ctrl Up} ; First do the backspaces, Then send word (Raw because we want the string exactly as in wordlist.txt)
;   Clipboard =
;   Clipwait, 0
;   Clipboard = %ClipboardSave%
;   Clipwait, 0


Re speed: it should help with start up/exit script not while running.

_________________
AHK FAQ
TF : Text files & strings lib, TF Forum


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 11th, 2010, 4:33 pm 
Offline

Joined: August 28th, 2009, 3:00 pm
Posts: 275
Sleeping doesn't appeal to me as the number needed will vary per PC it's running on (and I don't want to make it sleep too long). I messed some with clipwait but I couldn't get it to fix it. The issue seems to be SendInput just simply isn't being sent early enough so the Clipboard is clearing first - it does have data in it. I don't see how ClipWait could address that.

I think I'm just going to forego the clipboard entirely as I realized that will mess with programs which track Clipboard History... I know several people who use those.

It seems SendPlay fixes the issues I've been having with keystrokes being interspersed (see http://www.autohotkey.com/forum/viewtopic.php?t=49398), so I think I'm going to change from SendInput to SendPlay for the time being (unless there is some reason I'm missing besides the performance that I shouldn't do that).

Yeah, I realize it will help with startup/exit, but it still takes minutes to start/exit. Some of the processing it has to do is expensive (ie converting strings to ascii, sort, strip sort characters). It's mainly exiting that kills it, it takes about 8x as long as starting the script (see last post pg 1 for the wordlist I'm testing).

Thanks!

new version (using SendPlay):
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)

OnExit, SaveScript
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

WordListDone = 0
;reads list of words from file
FileRead, ParseWords, %A_ScriptDir%\Wordlist.txt
Loop, Parse, ParseWords, `n, `r
{
   AddWordToList(A_LoopField)
}
ParseWords =
SetTimer, Winchanged, 100
GoSub, ReverseWordNums
WordlistDone = 1

Loop
{
   ;Editor window check
    WinGetActiveTitle, ATitle
    WinGet, A_id, ID, %ATitle%
    IfNotInString, ATitle, %ETitle%
    {
      ToolTip
      Setenv, Word,
      WinWaitActive, %ETitle%
      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%
   {
      ; add the word if switching lines
      AddWordToList(Word)
         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
         {
            Setenv, Word, %word%%chr%
         } else {
                  ;addword = %Word%
                  ;Gosub, addwordtolist
                  AddWordToList(Word)
                  Gosub, clearallvars     
                }
   
   ;Wait till minimum letters
   IF ( StrLen(Word) < wlen )
   {
      ToolTip,
      Continue
   }
   
   ;Match part-word with command
   Num =
   Match =
   singlematch = 0
   number = 0
   StringLeft, baseword, Word, %wlen%
   baseword := ConvertWordToAscii(baseword,1)
   Loop
   {
      IfEqual, zword%baseword%%a_index%,, Break
      IfEqual, number, 10
         Break
      if ( SubStr(zword%baseword%%a_index%, 1, StrLen(Word)) = Word )
      {
         number ++
         singlematch := zword%baseword%%a_index%
         match := match . Mod(number,10) . ". " . 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%
   ToolTipSizeY := (number * 12)
   ToolTipPosY := A_CaretY+14
   if ((ToolTipSizeY + ToolTipPosY) > (PosY + SizeY))
       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 ,
   } 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,
                  }
               }
            }
         }
   Return
   
; Key definitions for autocomplete (0 to 9)
#MaxThreadsPerHotkey 1
$1::
$2::
$3::
$4::
$5::
$6::
$7::
$8::
$9::
$0::
CheckWord(A_ThisHotkey)
Return

; If hotkey was pressed, check wether there's a match going on and send it, otherwise send the number(s) typed
CheckWord(Key)
{
   global
   Local ATitle
   Local A_id2
   Local WordIndex
   
   StringRight, Key, Key, 1
   
   IfEqual, Key, 0
   {
      WordIndex = 10
   } else {
            WordIndex = %Key%
         } 
   
   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%
   {
         SendPlay,%key%
      Gosub,clearallvars
      Return
   }
     
   IfNotEqual, OldCaretY, %A_CaretY% ;Make sure we are still on the same line
      {
         SendPlay,%key%
         Gosub,clearallvars
         Return
      }

   ifequal, Word,        ; only continue if word is not empty
   {
      SendPlay,%key%
      Setenv, Word, %key%
      clearword=0
      Gosub,clearallvars
      Return
   }
   
   ifequal, singlematch%WordIndex%,   ; only continue singlematch is not empty
      {
         SendPlay,%key%
         Setenv, Word, %word%%key%
         clearword=0
         Gosub,clearallvars
         Return
      }

   Local sending
   Local len
   Local ClipboardSave
   ; SEND THE WORD!
   if key =0
      key = 10
   sending := singlematch%WordIndex%
   StringLen, len, Word
   ; Update Typed Count
   UpdateWordCount(sending)   
   SendPlay, {BS %len%}{Raw}%sending% ; First do the backspaces, Then send word (Raw because we want the string exactly as in wordlist.txt)
   ; below works but uses clipboard
   ;ClipboardSave:=ClipboardAll
   ;Clipboard = %sending%
   ;SendPlay, {BS %len%}^v ; First do the backspaces, Then send word (Raw because we want the string exactly as in wordlist.txt)
   ;Clipboard = %ClipboardSave%
   Gosub,clearallvars
   Return
}


; This is to blank all vars related to matches, tooltip and (optionally) word
clearallvars:
      Ifequal,clearword,1
      {
         Setenv,word,   
         OldCaretY=
      }
      ToolTip
      ; Clear all singlematches
      Loop, 10
      {
         singlematch%a_index% =
      }
      sending =
      key=
      match=
      clearword=1
      Return

AddWordToList(AddWord)
{
   global
   Local CharTerminateList
   Local Base
   Local AddWordInList
   Local CountWord
   Local pos
   
   Ifequal, Addword,  ;If we have no word to add, skip out.
      Return
   if ( Substr(addword,1,1) = ";" ) ;If first char is ";", clear word and skip out.
   {
      IfEqual, wordlistdone, 0 ;If we are still reading the wordlist file and we come across ;LEARNEDWORDS; set the LearnedWordsCount flag
      {
         IfEqual, AddWord, `;LEARNEDWORDS`;
            LearnedWordsCount=0
      }
      addword =
      Return
   }
   ifequal, wordlistdone, 1 ;if we are not reading the wordlist file, use the following characters in the terminate list
         CharTerminateList = 1,2,3,4,5,6,7,8,9,0
   else CharTerminateList =
   if addword contains %CharTerminateList% ;if one of the chars in the word is in the terminate list, don't add it
   {
      addword =
      CharTerminateList =
      Return
   }
   CharTerminateList =
   IF ( StrLen(addword) <= wlen ) ; don't add the word if it's not longer than the minimum length
   {
      addword =
      Return
   }

   Base := ConvertWordToAscii(SubStr(addword,1,wlen),1)
   AddWordInList =
   Loop ;Check to see if the word is already in the list, case sensitive
   {
      IfEqual, zword%base%%a_index%,, Break
      if ( zword%base%%a_index% == AddWord )
      {
         AddWordInList = 1
         Break
      }           
      Continue           
   }
     
   ifequal, AddWordInList,   ; if the word is not in the list
   {
      IfEqual, WordListDone, 0 ;if this is read from the wordlist
      {
         IfNotEqual,LearnedWordsCount,  ;if this is a stored learned word
         {
            CountWord := ConvertWordToAscii(addword,0)
            IfEqual, LearnedWords,     ;if we haven't learned any words yet, set the LearnedWords list to the new word
            {
               LearnedWords = %addword% 
            } else {   ;otherwise append the learned word to the list
                     LearnedWords = %LearnedWords%,%addword%
                  }
            zCount%CountWord% := LearnedWordsCount++    ;increment the count and store the Weight of the LearnedWord in reverse order (will be inverted later)
         }
      } else {    ; If this is an on-the-fly learned word
               CountWord := ConvertWordToAscii(addWord,0)
               zCount%CountWord% = 1   ;set the count to one as it's the first time we typed it
               IfEqual, LearnedWords,    ;if we haven't learned any words yet, set the LearnedWords list to the new word
               {
                  LearnedWords = %addword% 
               } else {   ;otherwise append the learned word to the list
                        LearnedWords = %LearnedWords%,%addword%
                     }
            }
      ; Increment the counter for each hash
      zbasenum%Base%++       
      pos := zbasenum%Base%
      ; Set the hashed value to the word
      zword%Base%%pos% = %addword%
      pos =
   } Else {
            IfEqual, WordListDone, 1   ;if we've already typed the word and we've loaded the wordlist increment the count
            {
               UpdateWordCount(addword)
            }
         }
   
   Return
}
   
; This sub will reverse the read numbers since now we know the total number of words
ReverseWordNums:
LearnedWordsCount+=4
Loop,parse,LearnedWords, `,
{
   AsciiWord := ConvertWordToAscii(A_LoopField,0)
   zCount%AsciiWord% := LearnedWordsCount - zCount%AsciiWord%
}

AsciiWord =
LearnedWordsCount =

Return

UpdateWordCount(word)
{
; If the Count for the word already exists - ie if it's a learned word, increment it, else don't.
   local CountWord := ConvertWordToAscii(word,0)
   IfNotEqual, zCount%CountWord%,
   {
      zCount%CountWord%++ 
      local WordBase
      StringLeft, WordBase, word, %wlen% ;find the pseudohash for the word
      WordBase := ConvertWordToAscii(WordBase,1)
      Local ConvertWord =
      Local LowIndex =
      Local WordList =
      Loop
      {
         ifequal, zword%WordBase%%A_Index%, ;Break the loop if no more words to read for the hash
            Break
         CountWord := zword%WordBase%%A_Index% ;Set CountWord to the current Word position
         ConvertWord := ConvertWordToAscii(CountWord,0) ; Find the Ascii equivalent of the word
         IfNotEqual, zCount%ConvertWord%,  ;If there's no count for this word do nothing
         {
            IfEqual, LowIndex,
               LowIndex = %A_Index% ;If this is the first word we've found with a count set this as our starting position
           
            IfEqual, WordList,  ;if we have no words in our wordlist, start it - prefix all words with (Count"z")
            {
               WordList := zCount%ConvertWord% . "z" . CountWord
            } Else {  ;else append to the wordlist
                     WordList := WordList . "," . zCount%ConvertWord% . "z" . CountWord
                  }
         }
      }
     
      ifnotequal, Wordlist, ;If we have no words to process, don't
      {
         Sort, WordList, N R D, ;Sort the wordlist by order of
         
         LowIndex-- ;A_Index starts at 1 so this value needs to be decremented
         Local IndexPos =
         Loop, Parse, WordList, `,
         {
            IndexPos := LowIndex + A_Index ;Set the current word we are processing to the starting pos plus word position
            StringTrimLeft, CountWord, A_LoopField, InStr(A_LoopField,"z") ;Strip (Number,"z") from beginning
            zword%WordBase%%IndexPos% = %CountWord% ; update the word in the list
           
         }
      }
   }
   Return
}
     
ConvertWordToAscii(Base,Caps)
{
; Return the word in Ascii numbers padded to length 3 per character
; Capitalize the string if NoCaps is not set
   IfEqual, Caps, 1
      StringUpper, Base, Base
   Loop, % StrLen(Base)
   {
      New := New . PadZeros(Asc(Base),3)
      StringTrimLeft, Base, Base, 1
   }
Return New
}

PadZeros(Word,Length)
{
; Pad a string out to Length numbers of 0's
   StringLen, WordLen, Word
   IfLess, WordLen, Length
   {
      Loop, % (Length - WordLen)
      {
         Word := "0" . Word
      }
   }
Return Word
}     
   
SaveScript:
; Add all the standard words to the tempwordlist
FileRead, ParseWords, %A_ScriptDir%\Wordlist.txt
Loop, Parse, ParseWords, `n, `r
{
   IfEqual, A_LoopField, `;LEARNEDWORDS`;
      SkipRest = 1
   IfEqual, SkipRest,
      TempWordList .= A_LoopField "`n"
}
ParseWords =
; Parse the learned words and store them in a new list by count if their total count is greater than 5.
; Prefix the word with the count and "z" for sorting
Loop, Parse, LearnedWords, `,
{
   SortWord := ConvertWordToAscii(A_LoopField,0)
   
   IfGreaterOrEqual, zCount%SortWord%, 5
   {
      IfEqual, SortWordList,
      {
         SortWordList := zCount%SortWord% . "z" . A_LoopField
      } else {
               SortWordList := SortWordList . "," . zCount%SortWord% . "z" . A_LoopField
            }
   }
}

Sort, SortWordList, N R D, ; Sort numerically, comma delimiter

IfNotEqual, SortWordList, ; If SortWordList exists write to the file, otherwise don't.
{
   TempWordList .= "`;LEARNEDWORDS`;`n"

   FirstTimeLoop = 1
   Loop, Parse, SortWordList, `,
   {
      StringTrimLeft, AppendWord, A_LoopField, InStr(A_LoopField,"z") ;Strip (Number,"z") from beginning
      IfEqual, FirstTimeLoop,  ;If we are not in our first time through the loop append a new line before the word
      {
         AppendWord = `n%AppendWord%
      } else {
               FirstTimeLoop =
         }
      TempWordList .= AppendWord
   }
   FileDelete, %A_ScriptDir%\Temp_Wordlist.txt
   FileAppend, %TempWordList%, %A_ScriptDir%\Temp_Wordlist.txt ;Only update the file if we have learned words
   FileCopy, %A_ScriptDir%\Temp_Wordlist.txt, %A_ScriptDir%\Wordlist.txt, 1
   FileDelete, %A_ScriptDir%\Temp_Wordlist.txt

}
ExitApp


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 11th, 2010, 5:09 pm 
Offline

Joined: May 27th, 2007, 9:41 am
Posts: 4999
There might be some ways to strip a few functions here and there, for example you don't need PadZeros as far as I can see and you could replace that with a SubStr in ConvertWordToAscii would save a function call but...

Other then changing the way you store/retrieve the words list data I don't see a way to speed it up as it has to loop each entry. But that would need an import/export routine and a predefined format for the wordlist making it harder to maintain (e.g. not simply editing wordlist.txt in your editor)

For example if I read your large wordlist 1.3 mb first page and use stringsplit to create an array it is done within a second, hows that for speed :-)

So rethinking the format of the list is worth the effort.

_________________
AHK FAQ
TF : Text files & strings lib, TF Forum


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 11th, 2010, 5:57 pm 
Offline

Joined: August 28th, 2009, 3:00 pm
Posts: 275
PadZeros is necessary so each character is padded out to 3 characters long when converted to ascii codes... otherwise some will only take 2 characters. 3 chars makes it easy when forming the variable name. I couldn't figure out how to do this with built in functions.

I'll have to reconsider how I store the list, but I'd have to maintain some other structure to keep track of where values are stored which may slow the script down when it's running.

Was having some issues when I put SendPlay everywhere, so I put SendInput back in some places.
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)

OnExit, SaveScript
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

WordListDone = 0
;reads list of words from file
FileRead, ParseWords, %A_ScriptDir%\Wordlist.txt
Loop, Parse, ParseWords, `n, `r
{
   AddWordToList(A_LoopField)
}
ParseWords =
SetTimer, Winchanged, 100
GoSub, ReverseWordNums
WordlistDone = 1

Loop
{
   ;Editor window check
    WinGetActiveTitle, ATitle
    WinGet, A_id, ID, %ATitle%
    IfNotInString, ATitle, %ETitle%
    {
      ToolTip
      Setenv, Word,
      WinWaitActive, %ETitle%
      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%
   {
      ; add the word if switching lines
      AddWordToList(Word)
         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
         {
            Setenv, Word, %word%%chr%
         } else {
                  ;addword = %Word%
                  ;Gosub, addwordtolist
                  AddWordToList(Word)
                  Gosub, clearallvars     
                }
   
   ;Wait till minimum letters
   IF ( StrLen(Word) < wlen )
   {
      ToolTip,
      Continue
   }
   
   ;Match part-word with command
   Num =
   Match =
   singlematch = 0
   number = 0
   StringLeft, baseword, Word, %wlen%
   baseword := ConvertWordToAscii(baseword,1)
   Loop
   {
      IfEqual, zword%baseword%%a_index%,, Break
      IfEqual, number, 10
         Break
      if ( SubStr(zword%baseword%%a_index%, 1, StrLen(Word)) = Word )
      {
         number ++
         singlematch := zword%baseword%%a_index%
         match := match . Mod(number,10) . ". " . 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%
   ToolTipSizeY := (number * 12)
   ToolTipPosY := A_CaretY+14
   if ((ToolTipSizeY + ToolTipPosY) > (PosY + SizeY))
       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 ,
   } 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,
                  }
               }
            }
         }
   Return
   
; Key definitions for autocomplete (0 to 9)
#MaxThreadsPerHotkey 1
$1::
$2::
$3::
$4::
$5::
$6::
$7::
$8::
$9::
$0::
CheckWord(A_ThisHotkey)
Return

; If hotkey was pressed, check wether there's a match going on and send it, otherwise send the number(s) typed
CheckWord(Key)
{
   global
   Local ATitle
   Local A_id2
   Local WordIndex
   
   StringRight, Key, Key, 1
   
   IfEqual, Key, 0
   {
      WordIndex = 10
   } else {
            WordIndex = %Key%
         } 
   
   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%
   {
      SendInput,%key%
      Gosub,clearallvars
      Return
   }
     
   IfNotEqual, OldCaretY, %A_CaretY% ;Make sure we are still on the same line
      {
         SendInput,%key%
         Gosub,clearallvars
         Return
      }

   ifequal, Word,        ; only continue if word is not empty
   {
      SendInput,%key%
      Setenv, Word, %key%
      clearword=0
      Gosub,clearallvars
      Return
   }
   
   ifequal, singlematch%WordIndex%,   ; only continue singlematch is not empty
      {
         SendInput,%key%
         Setenv, Word, %word%%key%
         clearword=0
         Gosub,clearallvars
         Return
      }

   Local sending
   Local len
   Local ClipboardSave
   ; SEND THE WORD!
   if key =0
      key = 10
   sending := singlematch%WordIndex%
   StringLen, len, Word
   ; Update Typed Count
   UpdateWordCount(sending)   
   SendPlay, {BS %len%}{Raw}%sending% ; First do the backspaces, Then send word (Raw because we want the string exactly as in wordlist.txt)
   ; below works but uses clipboard
   ;ClipboardSave:=ClipboardAll
   ;Clipboard = %sending%
   ;SendPlay, {BS %len%}^v ; First do the backspaces, Then send word (Raw because we want the string exactly as in wordlist.txt)
   ;Clipboard = %ClipboardSave%
   Gosub,clearallvars
   Return
}


; This is to blank all vars related to matches, tooltip and (optionally) word
clearallvars:
      Ifequal,clearword,1
      {
         Setenv,word,   
         OldCaretY=
      }
      ToolTip
      ; Clear all singlematches
      Loop, 10
      {
         singlematch%a_index% =
      }
      sending =
      key=
      match=
      clearword=1
      Return

AddWordToList(AddWord)
{
   global
   Local CharTerminateList
   Local Base
   Local AddWordInList
   Local CountWord
   Local pos
   
   Ifequal, Addword,  ;If we have no word to add, skip out.
      Return
   if ( Substr(addword,1,1) = ";" ) ;If first char is ";", clear word and skip out.
   {
      IfEqual, wordlistdone, 0 ;If we are still reading the wordlist file and we come across ;LEARNEDWORDS; set the LearnedWordsCount flag
      {
         IfEqual, AddWord, `;LEARNEDWORDS`;
            LearnedWordsCount=0
      }
      addword =
      Return
   }
   ifequal, wordlistdone, 1 ;if we are not reading the wordlist file, use the following characters in the terminate list
         CharTerminateList = 1,2,3,4,5,6,7,8,9,0
   else CharTerminateList =
   if addword contains %CharTerminateList% ;if one of the chars in the word is in the terminate list, don't add it
   {
      addword =
      CharTerminateList =
      Return
   }
   CharTerminateList =
   IF ( StrLen(addword) <= wlen ) ; don't add the word if it's not longer than the minimum length
   {
      addword =
      Return
   }

   Base := ConvertWordToAscii(SubStr(addword,1,wlen),1)
   AddWordInList =
   Loop ;Check to see if the word is already in the list, case sensitive
   {
      IfEqual, zword%base%%a_index%,, Break
      if ( zword%base%%a_index% == AddWord )
      {
         AddWordInList = 1
         Break
      }           
      Continue           
   }
     
   ifequal, AddWordInList,   ; if the word is not in the list
   {
      IfEqual, WordListDone, 0 ;if this is read from the wordlist
      {
         IfNotEqual,LearnedWordsCount,  ;if this is a stored learned word
         {
            CountWord := ConvertWordToAscii(addword,0)
            IfEqual, LearnedWords,     ;if we haven't learned any words yet, set the LearnedWords list to the new word
            {
               LearnedWords = %addword% 
            } else {   ;otherwise append the learned word to the list
                     LearnedWords = %LearnedWords%,%addword%
                  }
            zCount%CountWord% := LearnedWordsCount++    ;increment the count and store the Weight of the LearnedWord in reverse order (will be inverted later)
         }
      } else {    ; If this is an on-the-fly learned word
               CountWord := ConvertWordToAscii(addWord,0)
               zCount%CountWord% = 1   ;set the count to one as it's the first time we typed it
               IfEqual, LearnedWords,    ;if we haven't learned any words yet, set the LearnedWords list to the new word
               {
                  LearnedWords = %addword% 
               } else {   ;otherwise append the learned word to the list
                        LearnedWords = %LearnedWords%,%addword%
                     }
            }
      ; Increment the counter for each hash
      zbasenum%Base%++       
      pos := zbasenum%Base%
      ; Set the hashed value to the word
      zword%Base%%pos% = %addword%
      pos =
   } Else {
            IfEqual, WordListDone, 1   ;if we've already typed the word and we've loaded the wordlist increment the count
            {
               UpdateWordCount(addword)
            }
         }
   
   Return
}
   
; This sub will reverse the read numbers since now we know the total number of words
ReverseWordNums:
LearnedWordsCount+=4
Loop,parse,LearnedWords, `,
{
   AsciiWord := ConvertWordToAscii(A_LoopField,0)
   zCount%AsciiWord% := LearnedWordsCount - zCount%AsciiWord%
}

AsciiWord =
LearnedWordsCount =

Return

UpdateWordCount(word)
{
; If the Count for the word already exists - ie if it's a learned word, increment it, else don't.
   local CountWord := ConvertWordToAscii(word,0)
   IfNotEqual, zCount%CountWord%,
   {
      zCount%CountWord%++ 
      local WordBase
      StringLeft, WordBase, word, %wlen% ;find the pseudohash for the word
      WordBase := ConvertWordToAscii(WordBase,1)
      Local ConvertWord =
      Local LowIndex =
      Local WordList =
      Loop
      {
         ifequal, zword%WordBase%%A_Index%, ;Break the loop if no more words to read for the hash
            Break
         CountWord := zword%WordBase%%A_Index% ;Set CountWord to the current Word position
         ConvertWord := ConvertWordToAscii(CountWord,0) ; Find the Ascii equivalent of the word
         IfNotEqual, zCount%ConvertWord%,  ;If there's no count for this word do nothing
         {
            IfEqual, LowIndex,
               LowIndex = %A_Index% ;If this is the first word we've found with a count set this as our starting position
           
            IfEqual, WordList,  ;if we have no words in our wordlist, start it - prefix all words with (Count"z")
            {
               WordList := zCount%ConvertWord% . "z" . CountWord
            } Else {  ;else append to the wordlist
                     WordList := WordList . "," . zCount%ConvertWord% . "z" . CountWord
                  }
         }
      }
     
      ifnotequal, Wordlist, ;If we have no words to process, don't
      {
         Sort, WordList, N R D, ;Sort the wordlist by order of
         
         LowIndex-- ;A_Index starts at 1 so this value needs to be decremented
         Local IndexPos =
         Loop, Parse, WordList, `,
         {
            IndexPos := LowIndex + A_Index ;Set the current word we are processing to the starting pos plus word position
            StringTrimLeft, CountWord, A_LoopField, InStr(A_LoopField,"z") ;Strip (Number,"z") from beginning
            zword%WordBase%%IndexPos% = %CountWord% ; update the word in the list
           
         }
      }
   }
   Return
}
     
ConvertWordToAscii(Base,Caps)
{
; Return the word in Ascii numbers padded to length 3 per character
; Capitalize the string if NoCaps is not set
   IfEqual, Caps, 1
      StringUpper, Base, Base
   Loop, % StrLen(Base)
   {
      New := New . PadZeros(Asc(Base),3)
      StringTrimLeft, Base, Base, 1
   }
Return New
}

PadZeros(Word,Length)
{
; Pad a string out to Length numbers of 0's
   StringLen, WordLen, Word
   IfLess, WordLen, Length
   {
      Loop, % (Length - WordLen)
      {
         Word := "0" . Word
      }
   }
Return Word
}     
   
SaveScript:
; Add all the standard words to the tempwordlist
FileRead, ParseWords, %A_ScriptDir%\Wordlist.txt
Loop, Parse, ParseWords, `n, `r
{
   IfEqual, A_LoopField, `;LEARNEDWORDS`;
      SkipRest = 1
   IfEqual, SkipRest,
      TempWordList .= A_LoopField "`n"
}
ParseWords =
; Parse the learned words and store them in a new list by count if their total count is greater than 5.
; Prefix the word with the count and "z" for sorting
Loop, Parse, LearnedWords, `,
{
   SortWord := ConvertWordToAscii(A_LoopField,0)
   
   IfGreaterOrEqual, zCount%SortWord%, 5
   {
      IfEqual, SortWordList,
      {
         SortWordList := zCount%SortWord% . "z" . A_LoopField
      } else {
               SortWordList := SortWordList . "," . zCount%SortWord% . "z" . A_LoopField
            }
   }
}

Sort, SortWordList, N R D, ; Sort numerically, comma delimiter

IfNotEqual, SortWordList, ; If SortWordList exists write to the file, otherwise don't.
{
   TempWordList .= "`;LEARNEDWORDS`;`n"

   FirstTimeLoop = 1
   Loop, Parse, SortWordList, `,
   {
      StringTrimLeft, AppendWord, A_LoopField, InStr(A_LoopField,"z") ;Strip (Number,"z") from beginning
      IfEqual, FirstTimeLoop,  ;If we are not in our first time through the loop append a new line before the word
      {
         AppendWord = `n%AppendWord%
      } else {
               FirstTimeLoop =
         }
      TempWordList .= AppendWord
   }
   FileDelete, %A_ScriptDir%\Temp_Wordlist.txt
   FileAppend, %TempWordList%, %A_ScriptDir%\Temp_Wordlist.txt ;Only update the file if we have learned words
   FileCopy, %A_ScriptDir%\Temp_Wordlist.txt, %A_ScriptDir%\Wordlist.txt, 1
   FileDelete, %A_ScriptDir%\Temp_Wordlist.txt

}
ExitApp


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 11th, 2010, 8:11 pm 
Offline

Joined: May 27th, 2007, 9:41 am
Posts: 4999
This version no longer needs PadZeros
Code:
ConvertWordToAscii(Base,Caps)
{
; Return the word in Ascii numbers padded to length 3 per character
; Capitalize the string if NoCaps is not set
   IfEqual, Caps, 1
      StringUpper, Base, Base
   Loop, Parse, Base ; will automatically parse each character
         New := New . SubStr("00" . Asc(Base),-2)
Return New
}
There are a few more places where some loops could be removed

For example replace
Code:
; Add all the standard words to the tempwordlist
FileRead, ParseWords, %A_ScriptDir%\Wordlist.txt
Loop, Parse, ParseWords, `n, `r
{
   IfEqual, A_LoopField, `;LEARNEDWORDS`;
      SkipRest = 1
   IfEqual, SkipRest,
      TempWordList .= A_LoopField "`n"
}
loop with a one liner
Code:
; Add all the standard words to the tempwordlist
FileRead, ParseWords, %A_ScriptDir%\Wordlist.txt
TempWordList := SubStr(ParseWords, 1, InStr(ParseWords, "`;LEARNEDWORDS`;")-1)
would save you a long loop[/code]

_________________
AHK FAQ
TF : Text files & strings lib, TF Forum


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 12th, 2010, 8:40 am 
Offline

Joined: September 28th, 2009, 4:32 am
Posts: 86
Irfa wrote:
I wanted to use this version with the 1.3MB dict that is above.
I added ;LEARNEDWORDS; at the top of the dict.
When i exited the script, it started doing something in Temp_wordlist
an cut the wordlist.txt to 82KB.
Can you fix it?


Hi I keep a repository of word lists here:
http://www.artwinauto.com/downloads/typ ... l#wordlist
Do you mind sharing your dictionary? if it's not in any languages listed there:

maniac wrote:


That's wonderful! I tested the script with this version. It worked like charm.
I will be sending it to the Doctor to try. We may be able to help many Bosnian school kids with learning difficulty.

@hugov
Good to hear your suggestions. They really help to gain insights into the performance bottleneck.
This thread woke up from a long sleep and now is a locomotive.

_________________
TypingAid autocompletion program made with AHK.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 12th, 2010, 12:19 pm 
Offline

Joined: May 27th, 2007, 9:41 am
Posts: 4999
Rather than hasing each word individually character by character why not hash the entire wordlist in one go, here is some code to get you started
Code:
; hash entire wordlist in one go rather than word by word
_str=abcdefghijkmnkopqrstuvwxyzABCDEFGHIJKMNKOPQRSTUVWXYZ

FileRead, wordlist, wordlist.txt
StringCaseSense, On
Loop, Parse, _str
   {
    StringReplace, wordlist, wordlist, %A_LoopField%, % SubStr("00" . Asc(A_LoopField),-2), All
   }
FileAppend, %wordlist%, hashedwordlist.txt

wordlist=

; reverse

FileRead, wordlist, hashedwordlist.txt
wordlist:=RegExReplace(wordlist,"im)(\d{3})","$1|") ; we need this to prevent incorrect replacements
StringCaseSense, On
Loop, Parse, _str
   {
    StringReplace, wordlist, wordlist, % SubStr("00" . Asc(A_LoopField),-2), %A_LoopField%, All
   }
StringReplace, wordlist, wordlist, |,, all   
FileAppend, %wordlist%, newwordlist.txt

; newwordlist.txt will be the same wordlist.txt
and take it from there

_________________
AHK FAQ
TF : Text files & strings lib, TF Forum


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 12th, 2010, 1:48 pm 
Offline

Joined: August 28th, 2009, 3:00 pm
Posts: 275
hugov wrote:
This version no longer needs PadZeros

Ah-ha, that makes perfect sense. I hate it when my thinking gets boxed :).

hugov wrote:
There are a few more places where some loops could be removed


Thanks, I fixed that example and cleaned up some small inefficiencies (unnecessary IF statements) in some other loops, but I couldn't find any more that I could figure out how to remove.

kakarukeys wrote:
Hi I keep a repository of word lists here:
http://www.artwinauto.com/downloads/typ ... l#wordlist
Do you mind sharing your dictionary? if it's not in any languages listed there:

First page, last post:
http://www.autohotkey.com/forum/viewtop ... 781#296781

kakarukeys wrote:
That's wonderful! I tested the script with this version. It worked like charm.
I will be sending it to the Doctor to try. We may be able to help many Bosnian school kids with learning difficulty.

Did you try it when a unicode character is in the first three characters? As I said before this script relies on ASCII codes for hashing (and it hashes the first 3 characters).



I'll take a look at your hashing suggestion tomorrow hugov, thanks... for now here is the modified version:
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)

OnExit, SaveScript
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

WordListDone = 0
;reads list of words from file
FileRead, ParseWords, %A_ScriptDir%\Wordlist.txt
Loop, Parse, ParseWords, `n, `r
{
   AddWordToList(A_LoopField)
}
ParseWords =
SetTimer, Winchanged, 100
GoSub, ReverseWordNums
WordlistDone = 1

Loop
{
   ;Editor window check
    WinGetActiveTitle, ATitle
    WinGet, A_id, ID, %ATitle%
    IfNotInString, ATitle, %ETitle%
    {
      ToolTip
      Setenv, Word,
      WinWaitActive, %ETitle%
      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%
   {
      ; add the word if switching lines
      AddWordToList(Word)
         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
         {
            Setenv, Word, %word%%chr%
         } else {
                  ;addword = %Word%
                  ;Gosub, addwordtolist
                  AddWordToList(Word)
                  Gosub, clearallvars     
                }
   
   ;Wait till minimum letters
   IF ( StrLen(Word) < wlen )
   {
      ToolTip,
      Continue
   }
   
   ;Match part-word with command
   Num =
   Match =
   singlematch = 0
   number = 0
   StringLeft, baseword, Word, %wlen%
   baseword := ConvertWordToAscii(baseword,1)
   Loop
   {
      IfEqual, zword%baseword%%a_index%,, Break
      IfEqual, number, 10
         Break
      if ( SubStr(zword%baseword%%a_index%, 1, StrLen(Word)) = Word )
      {
         number ++
         singlematch := zword%baseword%%a_index%
         match := match . Mod(number,10) . ". " . 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%
   ToolTipSizeY := (number * 12)
   ToolTipPosY := A_CaretY+14
   if ((ToolTipSizeY + ToolTipPosY) > (PosY + SizeY))
       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 ,
   } 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,
                  }
               }
            }
         }
   Return
   
; Key definitions for autocomplete (0 to 9)
#MaxThreadsPerHotkey 1
$1::
$2::
$3::
$4::
$5::
$6::
$7::
$8::
$9::
$0::
CheckWord(A_ThisHotkey)
Return

; If hotkey was pressed, check wether there's a match going on and send it, otherwise send the number(s) typed
CheckWord(Key)
{
   global
   Local ATitle
   Local A_id2
   Local WordIndex
   
   StringRight, Key, Key, 1 ;Grab just the number pushed, trim off the "$"
   
   IfEqual, Key, 0
   {
      WordIndex = 10
   } else {
            WordIndex = %Key%
         } 
   
   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%
   {
      SendInput,%key%
      Gosub,clearallvars
      Return
   }
     
   IfNotEqual, OldCaretY, %A_CaretY% ;Make sure we are still on the same line
      {
         SendInput,%key%
         Gosub,clearallvars
         Return
      }

   ifequal, Word,        ; only continue if word is not empty
   {
      SendInput,%key%
      Setenv, Word, %key%
      clearword=0
      Gosub,clearallvars
      Return
   }
   
   ifequal, singlematch%WordIndex%,   ; only continue singlematch is not empty
      {
         SendInput,%key%
         Setenv, Word, %word%%key%
         clearword=0
         Gosub,clearallvars
         Return
      }

   Local sending
   Local len
   Local ClipboardSave
   ; SEND THE WORD!
   if key =0
      key = 10
   sending := singlematch%WordIndex%
   StringLen, len, Word
   ; Update Typed Count
   UpdateWordCount(sending)   
   SendPlay, {BS %len%}{Raw}%sending% ; First do the backspaces, Then send word (Raw because we want the string exactly as in wordlist.txt)
   ; below works but uses clipboard
   ;ClipboardSave:=ClipboardAll
   ;Clipboard = %sending%
   ;SendPlay, {BS %len%}^v ; First do the backspaces, Then send word (Raw because we want the string exactly as in wordlist.txt)
   ;Clipboard = %ClipboardSave%
   Gosub,clearallvars
   Return
}


; This is to blank all vars related to matches, tooltip and (optionally) word
clearallvars:
      Ifequal,clearword,1
      {
         Setenv,word,   
         OldCaretY=
      }
      ToolTip
      ; Clear all singlematches
      Loop, 10
      {
         singlematch%a_index% =
      }
      sending =
      key=
      match=
      clearword=1
      Return

AddWordToList(AddWord)
{
   global
   Local CharTerminateList
   Local Base
   Local AddWordInList
   Local CountWord
   Local pos
   
   Ifequal, Addword,  ;If we have no word to add, skip out.
      Return
   if ( Substr(addword,1,1) = ";" ) ;If first char is ";", clear word and skip out.
   {
      IfEqual, wordlistdone, 0 ;If we are still reading the wordlist file and we come across ;LEARNEDWORDS; set the LearnedWordsCount flag
      {
         IfEqual, AddWord, `;LEARNEDWORDS`;
            LearnedWordsCount=0
      }
      addword =
      Return
   }
   ifequal, wordlistdone, 1 ;if we are not reading the wordlist file, use the following characters in the terminate list
         CharTerminateList = 1,2,3,4,5,6,7,8,9,0
   else CharTerminateList =
   if addword contains %CharTerminateList% ;if one of the chars in the word is in the terminate list, don't add it
   {
      addword =
      CharTerminateList =
      Return
   }
   CharTerminateList =
   IF ( StrLen(addword) <= wlen ) ; don't add the word if it's not longer than the minimum length
   {
      addword =
      Return
   }

   Base := ConvertWordToAscii(SubStr(addword,1,wlen),1)
   AddWordInList =
   Loop ;Check to see if the word is already in the list, case sensitive
   {
      IfEqual, zword%base%%a_index%,, Break
      if ( zword%base%%a_index% == AddWord )
      {
         AddWordInList = 1
         Break
      }           
      Continue           
   }
     
   ifequal, AddWordInList,   ; if the word is not in the list
   {
      IfEqual, WordListDone, 0 ;if this is read from the wordlist
      {
         IfNotEqual,LearnedWordsCount,  ;if this is a stored learned word
         {
            CountWord := ConvertWordToAscii(addword,0)
            IfEqual, LearnedWords,     ;if we haven't learned any words yet, set the LearnedWords list to the new word
            {
               LearnedWords = %addword% 
            } else {   ;otherwise append the learned word to the list
                     LearnedWords = %LearnedWords%,%addword%
                  }
            zCount%CountWord% := LearnedWordsCount++    ;increment the count and store the Weight of the LearnedWord in reverse order (will be inverted later)
         }
      } else {    ; If this is an on-the-fly learned word
               CountWord := ConvertWordToAscii(addWord,0)
               zCount%CountWord% = 1   ;set the count to one as it's the first time we typed it
               IfEqual, LearnedWords,    ;if we haven't learned any words yet, set the LearnedWords list to the new word
               {
                  LearnedWords = %addword% 
               } else {   ;otherwise append the learned word to the list
                        LearnedWords = %LearnedWords%,%addword%
                     }
            }
      ; Increment the counter for each hash
      zbasenum%Base%++       
      pos := zbasenum%Base%
      ; Set the hashed value to the word
      zword%Base%%pos% = %addword%
      pos =
   } Else {
            IfEqual, WordListDone, 1   ;if we've already typed the word and we've loaded the wordlist increment the count
            {
               UpdateWordCount(addword)
            }
         }
   
   Return
}
   
; This sub will reverse the read numbers since now we know the total number of words
ReverseWordNums:
LearnedWordsCount+=4
Loop,parse,LearnedWords, `,
{
   AsciiWord := ConvertWordToAscii(A_LoopField,0)
   zCount%AsciiWord% := LearnedWordsCount - zCount%AsciiWord%
}

AsciiWord =
LearnedWordsCount =

Return

UpdateWordCount(word)
{
; If the Count for the word already exists - ie if it's a learned word, increment it, else don't.
   local CountWord := ConvertWordToAscii(word,0)
   IfNotEqual, zCount%CountWord%,
   {
      zCount%CountWord%++ 
      local WordBase
      StringLeft, WordBase, word, %wlen% ;find the pseudohash for the word
      WordBase := ConvertWordToAscii(WordBase,1)
      Local ConvertWord =
      Local LowIndex =
      Local WordList =
      Loop
      {
         ifequal, zword%WordBase%%A_Index%, ;Break the loop if no more words to read for the hash
            Break
         CountWord := zword%WordBase%%A_Index% ;Set CountWord to the current Word position
         ConvertWord := ConvertWordToAscii(CountWord,0) ; Find the Ascii equivalent of the word
         IfNotEqual, zCount%ConvertWord%,  ;If there's no count for this word do nothing
         {
            IfEqual, LowIndex,
               LowIndex = %A_Index% ;If this is the first word we've found with a count set this as our starting position
           
            IfEqual, WordList,  ;if we have no words in our wordlist, start it - prefix all words with (zCount"z")
            {
               WordList := zCount%ConvertWord% . "z" . CountWord
            } Else {  ;else append to the wordlist
                     WordList := WordList . "," . zCount%ConvertWord% . "z" . CountWord
                  }
         }
      }
     
      ifnotequal, Wordlist, ;If we have no words to process, don't
      {
         Sort, WordList, N R D, ;Sort the wordlist by order of
         
         LowIndex-- ;A_Index starts at 1 so this value needs to be decremented
         Local IndexPos =
         Loop, Parse, WordList, `,
         {
            IndexPos := LowIndex + A_Index ;Set the current word we are processing to the starting pos plus word position
            StringTrimLeft, CountWord, A_LoopField, InStr(A_LoopField,"z") ;Strip (Number,"z") from beginning
            zword%WordBase%%IndexPos% = %CountWord% ; update the word in the list
           
         }
      }
   }
   Return
}
     
ConvertWordToAscii(Base,Caps)
{
; Return the word in Ascii numbers padded to length 3 per character
; Capitalize the string if NoCaps is not set
   IfEqual, Caps, 1
      StringUpper, Base, Base
   Loop, % StrLen(Base)
   {
      New := New . SubStr("00" . Asc(Base),-2)
      StringTrimLeft, Base, Base, 1
   }
Return New
}
   
SaveScript:
; Add all the standard words to the tempwordlist
FileRead, ParseWords, %A_ScriptDir%\Wordlist.txt
LearnedwordsPos := InStr(ParseWords, "`;LEARNEDWORDS`;",true,1) ;Check for Learned Words
IfNotEqual, LearnedwordsPos, 0
{
   TempWordList := SubStr(ParseWords, 1, LearnedwordsPos - 1) ;Grab all non-learned words out of list
} else {
         TempWordList := ParseWords
      }
ParseWords =
; Parse the learned words and store them in a new list by count if their total count is greater than 5.
; Prefix the word with the count and "z" for sorting
Loop, Parse, LearnedWords, `,
{
   SortWord := ConvertWordToAscii(A_LoopField,0)
   
   IfGreaterOrEqual, zCount%SortWord%, 5
   {
      SortWordList := SortWordList . "," . zCount%SortWord% . "z" . A_LoopField
   }
}
   
StringTrimLeft, SortWordList, SortWordList, 1 ;remove extra starting comma

Sort, SortWordList, N R D, ; Sort numerically, comma delimiter

IfNotEqual, SortWordList, ; If SortWordList exists write to the file, otherwise don't.
{
   TempWordList .= "`;LEARNEDWORDS`;`r`n"
   Loop, Parse, SortWordList, `,
   {
      StringTrimLeft, AppendWord, A_LoopField, InStr(A_LoopField,"z") ;Strip (Number,"z") from beginning
      TempWordList .= AppendWord . "`r`n"
   }
   StringTrimRight, TempWordList, TempWordList, 2
   
   FileDelete, %A_ScriptDir%\Temp_Wordlist.txt
   FileAppend, %TempWordList%, %A_ScriptDir%\Temp_Wordlist.txt ;Only update the file if we have learned words
   FileCopy, %A_ScriptDir%\Temp_Wordlist.txt, %A_ScriptDir%\Wordlist.txt, 1
   FileDelete, %A_ScriptDir%\Temp_Wordlist.txt

}
ExitApp


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 12th, 2010, 2:05 pm 
Offline

Joined: September 28th, 2009, 4:32 am
Posts: 86
http://www.artwinauto.com/c-bowl%20recognition.jpg
:roll:
Any idea how it works underneath the layers of code?
I could only imagine it's an ascii c in there, when it's sent to the application, it became a Unicode c-bowl. This doesn't make much sense. What do you think?

_________________
TypingAid autocompletion program made with AHK.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 12th, 2010, 3:48 pm 
Offline

Joined: August 28th, 2009, 3:00 pm
Posts: 275
kakarukeys wrote:
http://www.artwinauto.com/c-bowl%20recognition.jpg
:roll:
Any idea how it works underneath the layers of code?
I could only imagine it's an ascii c in there, when it's sent to the application, it became a Unicode c-bowl. This doesn't make much sense. What do you think?

I'm not sure, if you type "poc" in all regular characters does it work then (ie does the autocomplete pop up for po(c-bowl)?

The other option is that ASC is returning a unicode value, I haven't tried the unicode version to see what is being returned. You'd have to look at the zBaseWord variables to find out.

Also, I just fixed some huge efficiency issues. So it turns out that doing:

SortWordList := SortWordList . "new value"

is WAYYY less efficient than doing:

SortWordList .= "new value"

I changed all my instances of the above to use .=
It now takes ~1 minute to start the script and less than 30 seconds to exit it (with the 1.3 MB wordlist). I also increased max CPU usage of the script from 50% to 66%, and I added a few other small performance boosts (ListLines, Off; #NoEnv).

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

#NoEnv
SetBatchLines, 20ms
ListLines Off

OnExit, SaveScript

; 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

WordListDone = 0

;reads list of words from file
FileRead, ParseWords, %A_ScriptDir%\Wordlist.txt
Loop, Parse, ParseWords, `n, `r
{
   AddWordToList(A_LoopField)
}
ParseWords =

SetTimer, Winchanged, 100

GoSub, ReverseWordNums
WordlistDone = 1

Loop
{
   ;Editor window check
    WinGetActiveTitle, ATitle
    WinGet, A_id, ID, %ATitle%
    IfNotInString, ATitle, %ETitle%
    {
      ToolTip
      Setenv, Word,
      WinWaitActive, %ETitle%
      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%
   {
      ; add the word if switching lines
      AddWordToList(Word)
         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
         {
            Setenv, Word, %word%%chr%
         } else {
                  ;addword = %Word%
                  ;Gosub, addwordtolist
                  AddWordToList(Word)
                  Gosub, clearallvars     
                }
   
   ;Wait till minimum letters
   IF ( StrLen(Word) < wlen )
   {
      ToolTip,
      Continue
   }
   
   ;Match part-word with command
   Num =
   Match =
   singlematch = 0
   number = 0
   StringLeft, baseword, Word, %wlen%
   baseword := ConvertWordToAscii(baseword,1)
   Loop
   {
      IfEqual, zword%baseword%%a_index%,, Break
      IfEqual, number, 10
         Break
      if ( SubStr(zword%baseword%%a_index%, 1, StrLen(Word)) = Word )
      {
         number ++
         singlematch := zword%baseword%%a_index%
         match .= Mod(number,10) . ". " . 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%
   ToolTipSizeY := (number * 12)
   ToolTipPosY := A_CaretY+14
   if ((ToolTipSizeY + ToolTipPosY) > (PosY + SizeY))
       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 ,
   } 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,
                  }
               }
            }
         }
   Return
   
; Key definitions for autocomplete (0 to 9)
#MaxThreadsPerHotkey 1
$1::
$2::
$3::
$4::
$5::
$6::
$7::
$8::
$9::
$0::
CheckWord(A_ThisHotkey)
Return

; If hotkey was pressed, check wether there's a match going on and send it, otherwise send the number(s) typed
CheckWord(Key)
{
   global
   Local ATitle
   Local A_id2
   Local WordIndex
   
   StringRight, Key, Key, 1 ;Grab just the number pushed, trim off the "$"
   
   IfEqual, Key, 0
   {
      WordIndex = 10
   } else {
            WordIndex = %Key%
         } 
   
   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%
   {
      SendInput,%key%
      Gosub,clearallvars
      Return
   }
     
   IfNotEqual, OldCaretY, %A_CaretY% ;Make sure we are still on the same line
      {
         SendInput,%key%
         Gosub,clearallvars
         Return
      }

   ifequal, Word,        ; only continue if word is not empty
   {
      SendInput,%key%
      Setenv, Word, %key%
      clearword=0
      Gosub,clearallvars
      Return
   }
   
   ifequal, singlematch%WordIndex%,   ; only continue singlematch is not empty
      {
         SendInput,%key%
         Setenv, Word, %word%%key%
         clearword=0
         Gosub,clearallvars
         Return
      }

   Local sending
   Local len
   Local ClipboardSave
   ; SEND THE WORD!
   if key =0
      key = 10
   sending := singlematch%WordIndex%
   StringLen, len, Word
   ; Update Typed Count
   UpdateWordCount(sending)   
   SendPlay, {BS %len%}{Raw}%sending% ; First do the backspaces, Then send word (Raw because we want the string exactly as in wordlist.txt)
   ; below works but uses clipboard
   ;ClipboardSave:=ClipboardAll
   ;Clipboard = %sending%
   ;SendPlay, {BS %len%}^v ; First do the backspaces, Then send word (Raw because we want the string exactly as in wordlist.txt)
   ;Clipboard = %ClipboardSave%
   Gosub,clearallvars
   Return
}


; This is to blank all vars related to matches, tooltip and (optionally) word
clearallvars:
      Ifequal,clearword,1
      {
         Setenv,word,   
         OldCaretY=
      }
      ToolTip
      ; Clear all singlematches
      Loop, 10
      {
         singlematch%a_index% =
      }
      sending =
      key=
      match=
      clearword=1
      Return

AddWordToList(AddWord)
{
   global
   Local CharTerminateList
   Local Base
   Local AddWordInList
   Local CountWord
   Local pos
   
   Ifequal, Addword,  ;If we have no word to add, skip out.
      Return
   if ( Substr(addword,1,1) = ";" ) ;If first char is ";", clear word and skip out.
   {
      IfEqual, wordlistdone, 0 ;If we are still reading the wordlist file and we come across ;LEARNEDWORDS; set the LearnedWordsCount flag
      {
         IfEqual, AddWord, `;LEARNEDWORDS`;
            LearnedWordsCount=0
      }
      addword =
      Return
   }
   ifequal, wordlistdone, 1 ;if we are not reading the wordlist file, use the following characters in the terminate list
         CharTerminateList = 1,2,3,4,5,6,7,8,9,0
   else CharTerminateList =
   if addword contains %CharTerminateList% ;if one of the chars in the word is in the terminate list, don't add it
   {
      addword =
      CharTerminateList =
      Return
   }
   CharTerminateList =
   IF ( StrLen(addword) <= wlen ) ; don't add the word if it's not longer than the minimum length
   {
      addword =
      Return
   }

   Base := ConvertWordToAscii(SubStr(addword,1,wlen),1)
   AddWordInList =
   Loop ;Check to see if the word is already in the list, case sensitive
   {
      IfEqual, zword%base%%a_index%,, Break
      if ( zword%base%%a_index% == AddWord )
      {
         AddWordInList = 1
         Break
      }           
      Continue           
   }
     
   ifequal, AddWordInList,   ; if the word is not in the list
   {
      IfEqual, WordListDone, 0 ;if this is read from the wordlist
      {
         IfNotEqual,LearnedWordsCount,  ;if this is a stored learned word
         {
            CountWord := ConvertWordToAscii(addword,0)
            IfEqual, LearnedWords,     ;if we haven't learned any words yet, set the LearnedWords list to the new word
            {
               LearnedWords = %addword% 
            } else {   ;otherwise append the learned word to the list
                     LearnedWords = %LearnedWords%,%addword%
                  }
            zCount%CountWord% := LearnedWordsCount++    ;increment the count and store the Weight of the LearnedWord in reverse order (will be inverted later)
         }
      } else {    ; If this is an on-the-fly learned word
               CountWord := ConvertWordToAscii(addWord,0)
               zCount%CountWord% = 1   ;set the count to one as it's the first time we typed it
               IfEqual, LearnedWords,    ;if we haven't learned any words yet, set the LearnedWords list to the new word
               {
                  LearnedWords = %addword% 
               } else {   ;otherwise append the learned word to the list
                        LearnedWords = %LearnedWords%,%addword%
                     }
            }
      ; Increment the counter for each hash
      zbasenum%Base%++       
      pos := zbasenum%Base%
      ; Set the hashed value to the word
      zword%Base%%pos% = %addword%
      pos =
   } Else {
            IfEqual, WordListDone, 1   ;if we've already typed the word and we've loaded the wordlist increment the count
            {
               UpdateWordCount(addword)
            }
         }
   
   Return
}
   
; This sub will reverse the read numbers since now we know the total number of words
ReverseWordNums:
LearnedWordsCount+=4
Loop,parse,LearnedWords, `,
{
   AsciiWord := ConvertWordToAscii(A_LoopField,0)
   zCount%AsciiWord% := LearnedWordsCount - zCount%AsciiWord%
}

AsciiWord =
LearnedWordsCount =

Return

UpdateWordCount(word)
{
; If the Count for the word already exists - ie if it's a learned word, increment it, else don't.
   local CountWord := ConvertWordToAscii(word,0)
   IfNotEqual, zCount%CountWord%,
   {
      zCount%CountWord%++ 
      local WordBase
      StringLeft, WordBase, word, %wlen% ;find the pseudohash for the word
      WordBase := ConvertWordToAscii(WordBase,1)
      Local ConvertWord =
      Local LowIndex =
      Local WordList =
      Loop
      {
         ifequal, zword%WordBase%%A_Index%, ;Break the loop if no more words to read for the hash
            Break
         CountWord := zword%WordBase%%A_Index% ;Set CountWord to the current Word position
         ConvertWord := ConvertWordToAscii(CountWord,0) ; Find the Ascii equivalent of the word
         IfNotEqual, zCount%ConvertWord%,  ;If there's no count for this word do nothing
         {
            IfEqual, LowIndex,
               LowIndex = %A_Index% ;If this is the first word we've found with a count set this as our starting position
               
            WordList .= "," . zCount%ConvertWord% . "z" . CountWord ;prefix all words with (zCount"z")
         }
      }
     
      ifnotequal, Wordlist, ;If we have no words to process, don't
      {
         StringTrimLeft, WordList, WordList, 1
         Sort, WordList, N R D, ;Sort the wordlist by order of
         
         LowIndex-- ;A_Index starts at 1 so this value needs to be decremented
         Local IndexPos =
         Loop, Parse, WordList, `,
         {
            IndexPos := LowIndex + A_Index ;Set the current word we are processing to the starting pos plus word position
            StringTrimLeft, CountWord, A_LoopField, InStr(A_LoopField,"z") ;Strip (Number,"z") from beginning
            zword%WordBase%%IndexPos% = %CountWord% ; update the word in the list
           
         }
      }
   }
   Return
}
     
ConvertWordToAscii(Base,Caps)
{
; Return the word in Ascii numbers padded to length 3 per character
; Capitalize the string if NoCaps is not set
   IfEqual, Caps, 1
      StringUpper, Base, Base
   Loop, % StrLen(Base)
   {
      New .= SubStr("00" . Asc(Base),-2)
      StringTrimLeft, Base, Base, 1
   }
Return New
}
   
SaveScript:
; Add all the standard words to the tempwordlist
FileRead, ParseWords, %A_ScriptDir%\Wordlist.txt
LearnedwordsPos := InStr(ParseWords, "`;LEARNEDWORDS`;",true,1) ;Check for Learned Words
IfNotEqual, LearnedwordsPos, 0
{
   TempWordList := SubStr(ParseWords, 1, LearnedwordsPos - 1) ;Grab all non-learned words out of list
} else {
         TempWordList := ParseWords
      }
ParseWords =
; Parse the learned words and store them in a new list by count if their total count is greater than 5.
; Prefix the word with the count and "z" for sorting
Loop, Parse, LearnedWords, `,
{
   SortWord := ConvertWordToAscii(A_LoopField,0)
   
   IfGreaterOrEqual, zCount%SortWord%, 5
   {
      SortWordList .= "," . zCount%SortWord% . "z" . A_LoopField
   }
}
   
StringTrimLeft, SortWordList, SortWordList, 1 ;remove extra starting comma

Sort, SortWordList, N R D, ; Sort numerically, comma delimiter

IfNotEqual, SortWordList, ; If SortWordList exists write to the file, otherwise don't.
{
   TempWordList .= "`;LEARNEDWORDS`;`r`n"
   Loop, Parse, SortWordList, `,
   {
      StringTrimLeft, AppendWord, A_LoopField, InStr(A_LoopField,"z") ;Strip (Number,"z") from beginning
      TempWordList .= AppendWord . "`r`n"
   }
   StringTrimRight, TempWordList, TempWordList, 2
   
   FileDelete, %A_ScriptDir%\Temp_Wordlist.txt
   FileAppend, %TempWordList%, %A_ScriptDir%\Temp_Wordlist.txt ;Only update the file if we have learned words
   FileCopy, %A_ScriptDir%\Temp_Wordlist.txt, %A_ScriptDir%\Wordlist.txt, 1
   FileDelete, %A_ScriptDir%\Temp_Wordlist.txt
}

ExitApp


Last edited by maniac on January 12th, 2010, 3:54 pm, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 12th, 2010, 3:57 pm 
Offline

Joined: May 27th, 2007, 9:41 am
Posts: 4999
Code:
 Loop, % StrLen(Base)
   {
      New .= SubStr("00" . Asc(Base),-2)
      StringTrimLeft, Base, Base, 1
   }
Minor optimisation:
Code:
Loop, parse, Base
   {
      New .= SubStr("00" . Asc(A_Loopfield),-2)
   }
:?:

_________________
AHK FAQ
TF : Text files & strings lib, TF Forum


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 12th, 2010, 4:01 pm 
Offline

Joined: August 28th, 2009, 3:00 pm
Posts: 275
hugov wrote:
Minor optimisation:

:?:


Good call, thanks.

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

#NoEnv
SetBatchLines, 20ms
ListLines Off

OnExit, SaveScript

; 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

WordListDone = 0

;reads list of words from file
FileRead, ParseWords, %A_ScriptDir%\Wordlist.txt
Loop, Parse, ParseWords, `n, `r
{
   AddWordToList(A_LoopField)
}
ParseWords =

SetTimer, Winchanged, 100

GoSub, ReverseWordNums
WordlistDone = 1

Loop
{
   ;Editor window check
    WinGetActiveTitle, ATitle
    WinGet, A_id, ID, %ATitle%
    IfNotInString, ATitle, %ETitle%
    {
      ToolTip
      Setenv, Word,
      WinWaitActive, %ETitle%
      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%
   {
      ; add the word if switching lines
      AddWordToList(Word)
         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
         {
            Setenv, Word, %word%%chr%
         } else {
                  ;addword = %Word%
                  ;Gosub, addwordtolist
                  AddWordToList(Word)
                  Gosub, clearallvars     
                }
   
   ;Wait till minimum letters
   IF ( StrLen(Word) < wlen )
   {
      ToolTip,
      Continue
   }
   
   ;Match part-word with command
   Num =
   Match =
   singlematch = 0
   number = 0
   StringLeft, baseword, Word, %wlen%
   baseword := ConvertWordToAscii(baseword,1)
   Loop
   {
      IfEqual, zword%baseword%%a_index%,, Break
      IfEqual, number, 10
         Break
      if ( SubStr(zword%baseword%%a_index%, 1, StrLen(Word)) = Word )
      {
         number ++
         singlematch := zword%baseword%%a_index%
         match .= Mod(number,10) . ". " . 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%
   ToolTipSizeY := (number * 12)
   ToolTipPosY := A_CaretY+14
   if ((ToolTipSizeY + ToolTipPosY) > (PosY + SizeY))
       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 ,
   } 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,
                  }
               }
            }
         }
   Return
   
; Key definitions for autocomplete (0 to 9)
#MaxThreadsPerHotkey 1
$1::
$2::
$3::
$4::
$5::
$6::
$7::
$8::
$9::
$0::
CheckWord(A_ThisHotkey)
Return

; If hotkey was pressed, check wether there's a match going on and send it, otherwise send the number(s) typed
CheckWord(Key)
{
   global
   Local ATitle
   Local A_id2
   Local WordIndex
   
   StringRight, Key, Key, 1 ;Grab just the number pushed, trim off the "$"
   
   IfEqual, Key, 0
   {
      WordIndex = 10
   } else {
            WordIndex = %Key%
         } 
   
   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%
   {
      SendInput,%key%
      Gosub,clearallvars
      Return
   }
     
   IfNotEqual, OldCaretY, %A_CaretY% ;Make sure we are still on the same line
      {
         SendInput,%key%
         Gosub,clearallvars
         Return
      }

   ifequal, Word,        ; only continue if word is not empty
   {
      SendInput,%key%
      Setenv, Word, %key%
      clearword=0
      Gosub,clearallvars
      Return
   }
         
   ifequal, singlematch%WordIndex%,   ; only continue singlematch is not empty
      {
         SendInput,%key%
         Setenv, Word, %word%%key%
         clearword=0
         Gosub,clearallvars
         Return
      }

   Local sending
   Local len
   Local ClipboardSave
   ; SEND THE WORD!
   if key =0
      key = 10
   sending := singlematch%WordIndex%
   StringLen, len, Word
   ; Update Typed Count
   UpdateWordCount(sending)   
   SendPlay, {BS %len%}{Raw}%sending% ; First do the backspaces, Then send word (Raw because we want the string exactly as in wordlist.txt)
   ; below works but uses clipboard
   ;ClipboardSave:=ClipboardAll
   ;Clipboard = %sending%
   ;SendPlay, {BS %len%}^v ; First do the backspaces, Then send word (Raw because we want the string exactly as in wordlist.txt)
   ;Clipboard = %ClipboardSave%
   Gosub,clearallvars
   Return
}

; This is to blank all vars related to matches, tooltip and (optionally) word
clearallvars:
      Ifequal,clearword,1
      {
         Setenv,word,   
         OldCaretY=
      }
      ToolTip
      ; Clear all singlematches
      Loop, 10
      {
         singlematch%a_index% =
      }
      sending =
      key=
      match=
      clearword=1
      Return

AddWordToList(AddWord)
{
   global
   Local CharTerminateList
   Local Base
   Local AddWordInList
   Local CountWord
   Local pos

   Ifequal, Addword,  ;If we have no word to add, skip out.
      Return
   if ( Substr(addword,1,1) = ";" ) ;If first char is ";", clear word and skip out.
   {
      IfEqual, wordlistdone, 0 ;If we are still reading the wordlist file and we come across ;LEARNEDWORDS; set the LearnedWordsCount flag
      {
         IfEqual, AddWord, `;LEARNEDWORDS`;
            LearnedWordsCount=0
      }
      addword =
      Return
   }
   ifequal, wordlistdone, 1 ;if we are not reading the wordlist file, use the following characters in the terminate list
         CharTerminateList = 1,2,3,4,5,6,7,8,9,0
   else CharTerminateList =
   if addword contains %CharTerminateList% ;if one of the chars in the word is in the terminate list, don't add it
   {
      addword =
      CharTerminateList =
      Return
   }
   CharTerminateList =
   IF ( StrLen(addword) <= wlen ) ; don't add the word if it's not longer than the minimum length
   {
      addword =
      Return
   }

   Base := ConvertWordToAscii(SubStr(addword,1,wlen),1)
   AddWordInList =
   Loop ;Check to see if the word is already in the list, case sensitive
   {
      IfEqual, zword%base%%a_index%,, Break
      if ( zword%base%%a_index% == AddWord )
      {
         AddWordInList = 1
         Break
      }           
      Continue           
   }
     
   ifequal, AddWordInList,   ; if the word is not in the list
   {
      IfEqual, WordListDone, 0 ;if this is read from the wordlist
      {
         IfNotEqual,LearnedWordsCount,  ;if this is a stored learned word
         {
            CountWord := ConvertWordToAscii(addword,0)
            IfEqual, LearnedWords,     ;if we haven't learned any words yet, set the LearnedWords list to the new word
            {
               LearnedWords = %addword% 
            } else {   ;otherwise append the learned word to the list
                     LearnedWords = %LearnedWords%,%addword%
                  }
            zCount%CountWord% := LearnedWordsCount++    ;increment the count and store the Weight of the LearnedWord in reverse order (will be inverted later)
         }
      } else {    ; If this is an on-the-fly learned word
               CountWord := ConvertWordToAscii(addWord,0)
               zCount%CountWord% = 1   ;set the count to one as it's the first time we typed it
               IfEqual, LearnedWords,    ;if we haven't learned any words yet, set the LearnedWords list to the new word
               {
                  LearnedWords = %addword% 
               } else {   ;otherwise append the learned word to the list
                        LearnedWords = %LearnedWords%,%addword%
                     }
            }
      ; Increment the counter for each hash
      zbasenum%Base%++       
      pos := zbasenum%Base%
      ; Set the hashed value to the word
      zword%Base%%pos% = %addword%
      pos =
   } Else {
            IfEqual, WordListDone, 1   ;if we've already typed the word and we've loaded the wordlist increment the count
            {
               UpdateWordCount(addword)
            }
         }
   
   Return
}
   
; This sub will reverse the read numbers since now we know the total number of words
ReverseWordNums:
LearnedWordsCount+=4
Loop,parse,LearnedWords, `,
{
   AsciiWord := ConvertWordToAscii(A_LoopField,0)
   zCount%AsciiWord% := LearnedWordsCount - zCount%AsciiWord%
}

AsciiWord =
LearnedWordsCount =

Return

UpdateWordCount(word)
{
; If the Count for the word already exists - ie if it's a learned word, increment it, else don't.
   local CountWord := ConvertWordToAscii(word,0)
   IfNotEqual, zCount%CountWord%,
   {
      zCount%CountWord%++ 
      local WordBase
      StringLeft, WordBase, word, %wlen% ;find the pseudohash for the word
      WordBase := ConvertWordToAscii(WordBase,1)
      Local ConvertWord =
      Local LowIndex =
      Local WordList =
      Loop
      {
         ifequal, zword%WordBase%%A_Index%, ;Break the loop if no more words to read for the hash
            Break
         CountWord := zword%WordBase%%A_Index% ;Set CountWord to the current Word position
         ConvertWord := ConvertWordToAscii(CountWord,0) ; Find the Ascii equivalent of the word
         IfNotEqual, zCount%ConvertWord%,  ;If there's no count for this word do nothing
         {
            IfEqual, LowIndex,
               LowIndex = %A_Index% ;If this is the first word we've found with a count set this as our starting position
               
            WordList .= "," . zCount%ConvertWord% . "z" . CountWord ;prefix all words with (zCount"z")
         }
      }
     
      ifnotequal, Wordlist, ;If we have no words to process, don't
      {
         StringTrimLeft, WordList, WordList, 1
         Sort, WordList, N R D, ;Sort the wordlist by order of
         
         LowIndex-- ;A_Index starts at 1 so this value needs to be decremented
         Local IndexPos =
         Loop, Parse, WordList, `,
         {
            IndexPos := LowIndex + A_Index ;Set the current word we are processing to the starting pos plus word position
            StringTrimLeft, CountWord, A_LoopField, InStr(A_LoopField,"z") ;Strip (Number,"z") from beginning
            zword%WordBase%%IndexPos% = %CountWord% ; update the word in the list
           
         }
      }
   }
   Return
}
     
ConvertWordToAscii(Base,Caps)
{
; Return the word in Ascii numbers padded to length 3 per character
; Capitalize the string if NoCaps is not set
   IfEqual, Caps, 1
      StringUpper, Base, Base
   Loop, Parse, Base
   {
      New .= SubStr("00" . Asc(A_LoopField),-2)
   }
Return New
}
   
SaveScript:
; Add all the standard words to the tempwordlist
FileRead, ParseWords, %A_ScriptDir%\Wordlist.txt
LearnedwordsPos := InStr(ParseWords, "`;LEARNEDWORDS`;",true,1) ;Check for Learned Words
IfNotEqual, LearnedwordsPos, 0
{
   TempWordList := SubStr(ParseWords, 1, LearnedwordsPos - 1) ;Grab all non-learned words out of list
} else {
         TempWordList := ParseWords
      }
ParseWords =
; Parse the learned words and store them in a new list by count if their total count is greater than 5.
; Prefix the word with the count and "z" for sorting
Loop, Parse, LearnedWords, `,
{
   SortWord := ConvertWordToAscii(A_LoopField,0)
   
   IfGreaterOrEqual, zCount%SortWord%, 5
   {
      SortWordList .= "," . zCount%SortWord% . "z" . A_LoopField
   }
}

StringTrimLeft, SortWordList, SortWordList, 1 ;remove extra starting comma

Sort, SortWordList, N R D, ; Sort numerically, comma delimiter

IfNotEqual, SortWordList, ; If SortWordList exists write to the file, otherwise don't.
{
   TempWordList .= "`;LEARNEDWORDS`;`r`n"
   Loop, Parse, SortWordList, `,
   {
      StringTrimLeft, AppendWord, A_LoopField, InStr(A_LoopField,"z") ;Strip (Number,"z") from beginning
      TempWordList .= AppendWord . "`r`n"
   }
   StringTrimRight, TempWordList, TempWordList, 2
   
   FileDelete, %A_ScriptDir%\Temp_Wordlist.txt
   FileAppend, %TempWordList%, %A_ScriptDir%\Temp_Wordlist.txt ;Only update the file if we have learned words
   FileCopy, %A_ScriptDir%\Temp_Wordlist.txt, %A_ScriptDir%\Wordlist.txt, 1
   FileDelete, %A_ScriptDir%\Temp_Wordlist.txt
}

ExitApp


Report this post
Top
 Profile  
Reply with quote  
 Post subject: more than 10 words
PostPosted: January 14th, 2010, 12:02 am 
Offline

Joined: December 23rd, 2007, 7:47 pm
Posts: 62
Location: Austin
Hi,

Thanks for the great script. I am trying version 1,2, and I found that if I have many items with the same first three characters, typingaid does not show them at all.

I don't know if this is a known problem. For example, I have about 35 items with "con," and when I type con, typingaid tooltip window does not show up.

Thanks,
Joon


Report this post
Top
 Profile  
Reply with quote  
 Post subject: Re: more than 10 words
PostPosted: January 14th, 2010, 2:50 am 
Offline

Joined: August 28th, 2009, 3:00 pm
Posts: 275
rogal wrote:
Hi,

Thanks for the great script. I am trying version 1,2, and I found that if I have many items with the same first three characters, typingaid does not show them at all.

I don't know if this is a known problem. For example, I have about 35 items with "con," and when I type con, typingaid tooltip window does not show up.

Thanks,
Joon

Hmm, that shouldn't occur. It should be limited to displaying 10, but it shouldn't be not showing any. I think I have a similar situation in my wordlist and mine all show.

Could you try the script in the post above yours rather than typingaid? Typingaid has a few modifications that script does not have (although they should not affect it).

Please let me know the result, thanks.


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 150 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6, 7, 8 ... 10  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: Google [Bot], iDrug, Ohnitiel and 21 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group