Thanks for the kind words. I think you misunderstand however what I have written. I think you will see it goes hand in hand with your project, and thats why I posted it. I made a few small modifications to the library and posed a short example with it:
Code:
#SingleInstance, Force
#NoEnv
DetectHiddenWindows, On
CoordMode, Mouse, Screen
SetBatchLines, -1
SetWinDelay, 0
SetWorkingDir %A_ScriptDir%
File := "PT.dict"
Dictionary := FileExist(File) ? Dict_Read(File) : Dict_Create(File)
OnExit, SaveDict
Key = a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|space|enter|bs|tab|.
Loop, Parse, Key, |
Hotkey, ~*%A_LoopField%, PredictSub, On
GoSub, UpdateGui
SetTimer, CheckHover, 30
Return
;###############################################################################################
CheckHover:
MouseGetPos,,, Win
Hotkey, LButton, LButton, % (Win = hwnd1) ? "On" : "Off" ;%
Return
;###############################################################################################
LButton:
MouseGetPos,,, Win, Control
If (Win != hwnd1)
Return
ControlGetText, SendWord, %Control%, ahk_id %Win%
StringReplace, SendWord, SendWord, %Word%
SendInput, %SendWord%
Word := Words := ""
GoSub, UpdateGui
Return
;###############################################################################################
SaveDict:
Dict_Create(File, Dictionary)
ExitApp
Return
;###############################################################################################
PredictSub:
Key := SubStr(A_ThisHotkey, 3, StrLen(A_ThisHotkey)-2)
If Key not in space,enter,bs,tab
{
Word .= Key
Words := Dict_ListWords(Dictionary, Word)
GoSub, UpdateGui
}
Else If Key in bs
{
StringTrimRight, Word, Word, 1
Words := Dict_ListWords(Dictionary, Word)
GoSub, UpdateGui
}
Else
{
If Word
Dictionary := Dict_AddWord(Dictionary, Word)
Word := Words := ""
GoSub, UpdateGui
}
Return
;###############################################################################################
UpdateGui:
Gui, 1: Destroy
Gui, 1: +LastFound +ToolWindow +Border -Caption +AlwaysOnTop
Gui, 1: Color, ffffff
Gui, 1: Font, s30
hwnd1 := WinExist()
Loop, Parse, Words, `n
Gui, 1: Add, Text, % (A_Index = 1) ? "x0 y10" : "x+20 yp+0", %A_LoopField%
Gui, 1: Show, x0 y0 w%A_ScreenWidth% h70 NA
Return
;###############################################################################################
; Reads an existing dictionary file from disk
; Returns the dictionary file
Dict_Read(File)
{
If !FileExist(File)
Return, 0
FileRead, OutputVar, %File%
StringReplace, OutputVar, OutputVar, % Chr(10), % "", All
Return, OutputVar
}
; Can create a new dictionary file or save an existing one from memory
; Leave dictionary blank to create a new dictionary file or pass the dictionary file to save
; Returns 1 if exisitng dictionary data was saved or returns the new dictionary file if a new one was created
Dict_Create(File, Dictionary="")
{
FileDelete, %File%
If Dictionary
{
FileAppend, %Dictionary%, %File%
Return, 1
}
OffSet := 552
Loop, 26
{
NewFile .= Chr(64+A_Index) "=" SubStr("000000000" OffSet, -8) "¬000000000"
OffSet += 4
}
NewFile .= Chr(13)
Loop, 26
NewFile .= "[" Chr(64+A_Index) "]" Chr(13)
FileAppend, %NewFile%, %File%
Return, NewFile
}
; Deletes selected word from dictionary
; Returns dictionary data after word has been deleted
Dict_DeleteWord(Dictionary, Word)
{
Letter := SubStr(Word, 1, 1)
StringUpper, Letter, Letter
RegExMatch(Dictionary, Letter "=([0-9]+)¬([0-9]+)", Pointer)
If !Pointer
Return, 0
Words := SubStr(Dictionary, Pointer1, Pointer2)
If !Instr(Words, Word)
Return, Dictionary
Words := RegExReplace(Words, Word "¬[0-9]+" Chr(13), "")
Start := SubStr(Dictionary, 1, Pointer1-1), AscLetter := Asc(Letter)-1
Loop, % 26-(AscLetter-64) ;%
{
AscLetter++
RegExMatch(Start, Chr(AscLetter) "=([0-9]+)¬([0-9]+)", MatchPointer)
OffSet := (A_Index != 1) ? SubStr("000000000" MatchPointer1-(StrLen(Word)+11), -8) : MatchPointer1
Length := (A_Index != 1) ? MatchPointer2 : SubStr("000000000" MatchPointer2-(StrLen(Word)+11), -8)
Start := RegExReplace(Start, Chr(AscLetter) "=([0-9]+)¬([0-9]+)", Chr(AscLetter) "=" OffSet "¬" Length)
}
Return, Start Words SubStr(Dictionary, Pointer1+Pointer2, StrLen(Dictionary))
}
; Adds a new word to the dictionary or increments its use if it is already contained in the dictionary
; Returns dictionary data after word has been added
Dict_AddWord(Dictionary, Word)
{
Letter := SubStr(Word, 1, 1)
StringUpper, Letter, Letter
RegExMatch(Dictionary, Letter "=([0-9]+)¬([0-9]+)", Pointer)
If !Pointer
{
MsgBox, 1:`n%Dictionary%`n`n%Word%
Return, 0
}
Loop
{
LastLetter := SubStr(Word, 0)
If LastLetter in A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z
Break
If (A_Index >= 10)
Return, Dictionary
StringTrimRight, Word, Word, 1
}
ListWords := SubStr(Dictionary, Pointer1, Pointer2)
If InStr(ListWords, Word "¬")
{
RegExMatch(ListWords, Word "¬([0-9]+)", IncMatch)
ListWords := RegExReplace(ListWords, Word "¬([0-9]+)", Word "¬" SubStr("000000000" IncMatch1+1, -8))
Return, SubStr(Dictionary, 1, Pointer1-1) ListWords SubStr(Dictionary, Pointer1+Pointer2, StrLen(Dictionary))
}
Start := SubStr(Dictionary, 1, Pointer1-1), AscLetter := Asc(Letter)-1
Loop, % 26-(AscLetter-64) ;%
{
AscLetter++
RegExMatch(Start, Chr(AscLetter) "=([0-9]+)¬([0-9]+)", MatchPointer)
OffSet := (A_Index != 1) ? SubStr("000000000" MatchPointer1+StrLen(Word)+11, -8) : MatchPointer1
Length := (A_Index != 1) ? MatchPointer2 : SubStr("000000000" MatchPointer2+StrLen(Word)+11, -8)
Start := RegExReplace(Start, Chr(AscLetter) "=([0-9]+)¬([0-9]+)", Chr(AscLetter) "=" OffSet "¬" Length)
}
Return, Start Word "¬000000001" Chr(13) SubStr(Dictionary, Pointer1, StrLen(Dictionary))
}
; Returns a list of words that have characters equal to those specified in Match
; To return words such as AutoHotkey and AutoIt you could use: Dict_ListWords(Dictionary, "Aut")
; Order specifies whether matches are returned in order of use. So words used more often will be higher in the list. Default is On
; Returns list of matching words deliminated by Delimiters. Default is `n
Dict_ListWords(Dictionary, Match, Order=1, Delimiters="`n")
{
Letter := SubStr(Match, 1, 1)
StringUpper, Letter, Letter
RegExMatch(Dictionary, Letter "=([0-9]+)¬([0-9]+)", Pointer)
If !Pointer
Return, 0
ListWords := RegExReplace(SubStr(Dictionary, Pointer1, Pointer2), "([^" Chr(13) "]+)(¬)(\d+)", "$3$2$1")
If Order
Sort, ListWords, % "N R D" Chr(13) ;%
ListWords := RegExReplace(ListWords, "(\d+)(¬)([^" Chr(13) "]+)", "$3")
Loop, Parse, ListWords, % Chr(13) ;%
{
If (Match = SubStr(A_LoopField, 1, StrLen(Match)))
MatchWords .= A_LoopField Delimiters
}
StringTrimRight, MatchWords, MatchWords, 1
Return, MatchWords
}
Using that library, this script took only 15 minutes to write. The library isnt used for using a real dictionary. It creates a dictionary with words you pass to it, and retrieves words from it. So it is exactly the same as your txt file you are currently accessing, but much more robust.
Run the above example and you will see a white box appear at the top (remember this is only an example).
You will have started with a blank dictionary file. Now start typing words in any editor or window. Each word you type will be added to the dictionary. So now if you retype a word you have just typed, it will appear at the top. You can click on that word for it to finish typing the word for you.
Try out the above example and you will see what I mean as it is inefficient to constantly read and write words to/from disk.