Skip to content

Commit

Permalink
*Once the listbox flips above caret, it will stay there until the nex…
Browse files Browse the repository at this point in the history
…t word.

*(Vista+ only)Accented Characters in the wordlist are now normalized for matching. Accented characters the user typed are NOT normalized. Even if case correction is OFF, the word will be backspaced to add in the accented characters, but case will NOT be changed.
*The wordlist will no longer be cleaned up when exiting the script, only launching. This will help when 2 processes access the same database.
  • Loading branch information
ManiacDC committed Jul 8, 2015
1 parent deda168 commit 256dd1c
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 8 deletions.
35 changes: 34 additions & 1 deletion Source/Includes/Conversions.ahk
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
; these functions handle database conversion
; always set the SetDbVersion default argument to the current highest version

SetDbVersion(dBVersion = 3)
SetDbVersion(dBVersion = 4)
{
global g_WordListDB
g_WordListDB.Query("INSERT OR REPLACE INTO LastState VALUES ('databaseVersion', '" . dBVersion . "', NULL);")
Expand Down Expand Up @@ -59,6 +59,11 @@ MaybeConvertDatabase()
RunConversionThree()
}

if (databaseVersion < 4)
{
RunConversionFour()
}

return, false
}

Expand Down Expand Up @@ -135,6 +140,34 @@ RunConversionThree()
g_WordListDB.EndTransaction()
}

; normalize accented characters
RunConversionFour()
{
global g_WordListDB
g_WordListDB.BeginTransaction()

Words := g_WordListDB.Query("SELECT word, wordindexed, wordreplacement FROM Words;")

for each, row in Words.Rows
{
Word := row[1]
WordIndexed := row[2]
WordReplacement := row[3]

WordIndexedTransformed := StrUnmark(WordIndexed)

StringReplace, WordIndexedTransformedEscaped, WordIndexedTransformed, ', '', All
StringReplace, WordEscaped, Word, ', '', All
StringReplace, WordIndexEscaped, WordIndexed, ', '', All
StringReplace, WordReplacementEscaped, WordReplacement, ', '', All

g_WordListDB.Query("UPDATE Words SET wordindexed = '" . WordIndexedTransformedEscaped . "' WHERE word = '" . WordEscaped . "' AND wordindexed = '" . WordIndexEscaped . "' AND wordreplacement = '" . WordReplacementEscaped . "';")
}

SetDbVersion(4)
g_WordListDB.EndTransaction()
}

CreateLastStateTable()
{
global g_WordListDB
Expand Down
13 changes: 12 additions & 1 deletion Source/Includes/ListBox.ahk
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,7 @@ ShowListBox()
; Any changes to this function may need to be reflected in ComputeListBoxMaxLength()
ForceWithinMonitorBounds(ByRef ListBoxPosX,ByRef ListBoxPosY,ListBoxActualSizeW,ListBoxActualSizeH,Rows)
{
global g_ListBoxFlipped
global g_SM_CMONITORS
global prefs_ListBoxOffset
;Grab the number of non-dummy monitors
Expand All @@ -687,9 +688,19 @@ ForceWithinMonitorBounds(ByRef ListBoxPosX,ByRef ListBoxPosY,ListBoxActualSizeW,

; + prefs_ListBoxOffset Move ListBox down a little so as not to hide the caret.
ListBoxPosY := ListBoxPosY + prefs_ListBoxOffset
If ( (ListBoxPosY + ListBoxActualSizeH ) > MonBottom )
if (g_ListBoxFlipped) {
OldListBoxPosY := ListBoxPosY
ListBoxPosY := HCaretY() - Ceil(prefs_ListBoxOffset - (ListBoxActualSizeH / Rows )) - ListBoxActualSizeH

if ( ListBoxPosY < MonTop ) {
ListBoxPosY := OldListBoxPosY
g_ListBoxFlipped =
}

} else If ( (ListBoxPosY + ListBoxActualSizeH ) > MonBottom )
{
ListBoxPosY := HCaretY() - Ceil(prefs_ListBoxOffset - (ListBoxActualSizeH / Rows )) - ListBoxActualSizeH
g_ListBoxFlipped := true
}

Break
Expand Down
51 changes: 50 additions & 1 deletion Source/Includes/Sending.ahk
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ SendFull(SendValue,ForceBackspace=false)
BackSpaceWord := true
}

; capitalize first letter if we are forcing a backspace AND CaseCorrection is off
; match case on first letter if we are forcing a backspace AND CaseCorrection is off
if (ForceBackspace && !(prefs_NoBackspace = "Off")) {
IfEqual, A_IsUnicode, 1
{
Expand All @@ -79,6 +79,55 @@ SendFull(SendValue,ForceBackspace=false)
SendValue := FirstLetter . SendValue
}

; if the user chose a word with accented characters, then we need to
; substitute those letters into the word
StringCaseSenseOld := A_StringCaseSense
StringCaseSense, Locale
if (!BackSpaceWord && !(SubStr(SendValue, 1, BackSpaceLen) = g_Word)) {
BackSpaceWord := true

SendIndex := 1
WordIndex := 1
NewSendValue =
While (WordIndex <= BackSpaceLen) {
SendChar := SubStr(SendValue, SendIndex, 1)
WordChar := SubStr(g_Word, WordIndex, 1)
SendIndex++

if (SendChar = WordChar) {
WordIndex++
NewSendValue .= WordChar
} else {

SendCharNorm := StrUnmark(SendChar)
; if character normalizes to more than 1 character, we need
; to increment the WordIndex pointer again

StringUpper, SendCharNormUpper, SendCharNorm
StringLower, SendCharNormLower, SendCharNorm
StringUpper, SendCharUpper, SendChar
StringLower, SendCharLower, SendChar
WordChar := SubStr(g_Word, WordIndex, StrLen(SendCharNorm))

if (SendCharNorm == WordChar) {
NewSendValue .= SendChar
} else if (SendCharNormUpper == WordChar) {
NewSendValue .= SendCharUpper
} else if (SendCharNormLower == WordChar) {
NewSendValue .= SendCharLower
} else {
NewSendValue .= SendChar
}
WordIndex += StrLen(SendCharNorm)
}
}

NewSendValue .= SubStr(SendValue, SendIndex, StrLen(SendValue) - SendIndex + 1)

SendValue := NewSendValue
}
StringCaseSense, %StringCaseSenseOld%

; If we are not backspacing, remove the typed characters from the string to send
if !(BackSpaceWord)
{
Expand Down
29 changes: 27 additions & 2 deletions Source/Includes/Wordlist.ahk
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ AddWordToList(AddWord,ForceCountNewOnly,ForceLearn=false, ByRef LearnedWordsCoun

StringUpper, AddWordIndex, AddWord

; normalize accented characters
AddWordIndex := StrUnmark(AddWordIndex)

StringReplace, AddWordEscaped, AddWord, ', '', All
StringReplace, AddWordIndexEscaped, AddWordIndex, ', '', All
StringReplace, AddWordReplacementEscaped, AddWordReplacement, ', '', All
Expand Down Expand Up @@ -354,8 +357,6 @@ MaybeUpdateWordlist()
IfEqual, g_WordListDone, 1
{

CleanupWordList()

SortWordList := g_WordListDB.Query("SELECT Word FROM Words ORDER BY count DESC;")

for each, row in SortWordList.Rows
Expand Down Expand Up @@ -390,4 +391,28 @@ MaybeUpdateWordlist()

g_WordListDB.Close(),

}

;------------------------------------------------------------------------

; Removes marks from letters. Requires Windows Vista or later.
; Code by Lexikos, based on MS documentation
StrUnmark(string) {
if (A_OSVersion == "WIN_2003" || A_OSVersion == "WIN_XP" || A_OSVersion == "WIN_2000")
{
return string
}

len := DllCall("Normaliz.dll\NormalizeString", "int", 2, "wstr", string, "int", StrLen(string), "ptr", 0, "int", 0) ; Get *estimated* required buffer size.
Loop {
VarSetCapacity(buf, len * 2)
len := DllCall("Normaliz.dll\NormalizeString", "int", 2, "wstr", string, "int", StrLen(string), "ptr", &buf, "int", len)
if len >= 0
break
if (A_LastError != 122) ; ERROR_INSUFFICIENT_BUFFER
return string
len *= -1 ; This is the new estimate.
}
; Remove combining marks and return result.
return RegExReplace(StrGet(&buf, len, "UTF-16"), "\pM")
}
38 changes: 35 additions & 3 deletions Source/TypingAid.ahk
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ ProcessKey(InputChar,EndKey)
ClearAllVars(true)
Return
}

;Wait till minimum letters
IF ( StrLen(g_Word) < prefs_Length )
{
Expand Down Expand Up @@ -316,7 +316,38 @@ RecomputeMatches()
LimitTotalMatches = 200
}

StringUpper, WordMatch, g_Word
StringUpper, WordMatchOriginal, g_Word

WordMatch := StrUnmark(WordMatchOriginal)

; if a user typed an accented character, we should exact match on that accented character
if (WordMatch != WordMatchOriginal) {
WordAccentQuery =
LoopCount := StrLen(g_Word)
Loop, %LoopCount%
{
Position := A_Index
SubChar := SubStr(g_Word, Position, 1)
SubCharNormalized := StrUnmark(SubChar)
if !(SubCharNormalized == SubChar) {
StringUpper, SubCharUpper, SubChar
StringLower, SubCharLower, SubChar
StringReplace, SubCharUpperEscaped, SubCharUpper, ', '', All
StringReplace, SubCharLowerEscaped, SubCharLower, ', '', All
PrefixChars =
Loop, % Position - 1
{
PrefixChars .= "?"
}
; because SQLite cannot do case-insensitivity on accented characters using LIKE, we need
; to handle it manually, so we need 2 searches for each accented character the user typed.
;GLOB is used for consistency with the wordindexed search.
WordAccentQuery .= " AND (word GLOB '" . PrefixChars . SubCharUpperEscaped . "*' OR word GLOB '" . PrefixChars . SubCharLowerEscaped . "*')"
}
}
} else {
WordAccentQuery =
}

StringReplace, WordExactEscaped, g_Word, ', '', All
StringReplace, WordMatchEscaped, WordMatch, ', '', All
Expand All @@ -331,7 +362,7 @@ RecomputeMatches()
}
}

WhereQuery := " WHERE wordindexed GLOB '" . WordMatchEscaped . "*' " . SuppressMatchingWordQuery
WhereQuery := " WHERE wordindexed GLOB '" . WordMatchEscaped . "*' " . SuppressMatchingWordQuery . WordAccentQuery

NormalizeTable := g_WordListDB.Query("SELECT MIN(count) AS normalize FROM Words" . WhereQuery . "AND count IS NOT NULL LIMIT " . LimitTotalMatches . ";")

Expand Down Expand Up @@ -1081,6 +1112,7 @@ ClearAllVars(ClearWord)
g_OldCaretY=
g_OldCaretX=
g_LastInput_id=
g_ListBoxFlipped=
}

g_SingleMatch =
Expand Down

0 comments on commit 256dd1c

Please sign in to comment.