Autovervollständigung für ein Gui Edit Feld

Stelle Fragen zur Programmierung mit Autohotkey

Moderator: jNizM

User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Autovervollständigung für ein Gui Edit Feld

22 Jul 2015, 01:16

Hey hey =)

ich hab dieses Script im alten Forum gefunden was eine Autovervollständigung für ein Edit Feld hinzufügt.
Meine Frage an euch (wahrscheinlich eher just me ;D) geht das auch etwas kürzer und unkomplizierter?
Ich verstehe aus der Funktion nämlich fasts nichts ^^

Code: Select all

; http://www.autohotkey.com/board/topic/96129-ahk-l-custom-autocompletion-for-edit-control-with-drop-down-list/

Gui, -Caption +AlwaysOnTop +Border +hwndhgui +LastFound +ToolWindow
Gui, Add, Edit, w300 hwndhedit
Gui, Show

txt := "cmd;firefox;chrome;outlook;word;excel"
AutoComplete(hedit, "init", txt, ";")
AutoComplete(hedit, "option", "AUTOSUGGEST AUTOAPPEND USETAB", 0)
return

GuiClose:
GuiEscape:
ExitApp

/*   Autocompletion

	Function      :    Autocomplete(hwnd , action , p1=0 , p2=0)
	Parameter
		- hwnd    :    hwnd of edit control
		- action  :    init, enable, disable, release, option


	Usage:

	1.    Initializes the autocomplete object.
	Function      :    Autocomplete(hwnd , "init" , txt , delim)
	Parameter
		- txt     :    Autocomplete list
		- delim   :    delimiter seperate each item

	2.    Enables autocompletion.
	Function      :    Autocomplete(hwnd , "enable" , 0 , 0)

	3.    Disables autocompletion.
	Function      :    Autocomplete(hwnd , "disable" , 0 , 0)

	4.    Release autocompletion.
	Function      :    Autocomplete(hwnd , "release" , 0 , 0)

	5.    Sets the current autocomplete options.
	Function      :    Autocomplete(hwnd , "option" , mode , 0)
	Parameter
        - mode    :    options seperated by space
          AUTOSUGGEST           :    Enable the autosuggest drop-down list.
          AUTOAPPEND            :    Enable autoappend.
          SEARCH                :    Add a search item to the list of completed strings. When the user selects this item, it launches a search engine.
          FILTERPREFIXES        :    Do not match common prefixes, such as "www." or "http://".
          USETAB                :    Use the TAB key to select an item from the drop-down list.
          UPDOWNKEYDROPSLIST    :    Use the UP ARROW and DOWN ARROW keys to display the autosuggest drop-down list.
          RTLREADING            :    read right-to-left (RTL). 
          WORD_FILTER           :    If set, the autocompleted suggestion is treated as a phrase for search purposes.
          NOPREFIXFILTERING     :    Disable prefix filtering when displaying the autosuggest dropdown. Always display all suggestions.
*/

AutoComplete(self, celt, rgelt, pceltFetched)
{
    static es:=[]
    ; =============================================================================================================================================================================
    if (celt = "init")    ; Initializes the autocomplete object.
    {
        sList:=[]
        loop, parse, rgelt, %pceltFetched%, %A_Space%%A_Tab%
            sList[A_Index] := A_LoopField
        obj:=[]
        obj.List := sList
        obj.CurrentElement := 1
        obj.hwnd := self
        obj.SetCapacity("EnumString", A_PtrSize * 8)
        pes := obj.GetAddress("EnumString")
        ,NumPut(pes + A_PtrSize, pes + 0)
        ,NumPut(RegisterCallback("_IUnknown_QueryInterface",  "F"), pes + A_PtrSize * 1)               ; IUnknown::QueryInterface     http://msdn.com/library/ms682521(vs.85,en-us)
        ,NumPut(RegisterCallback("_IUnknown_AddRef",          "F"), pes + A_PtrSize * 2)               ; IUnknown::AddRef             http://msdn.com/library/ms691379(vs.85,en-us)
        ,NumPut(RegisterCallback("_IUnknown_Release",         "F"), pes + A_PtrSize * 3)               ; IUnknown::Release            http://msdn.com/library/ms682317(vs.85,en-us)
        ,NumPut(RegisterCallback(A_ThisFunc,                  "F"), pes + A_PtrSize * 4)               ; IEnumString::Next            http://msdn.com/library/ms693735(vs.85,en-us)
        ,NumPut(RegisterCallback("_IEnumString_Skip",         "F"), pes + A_PtrSize * 5)               ; IEnumString::Skip            http://msdn.com/library/ms688527(vs.85,en-us)
        ,NumPut(RegisterCallback("_IEnumString_Reset",        "F"), pes + A_PtrSize * 6)               ; IEnumString::Reset           http://msdn.com/library/ms686598(vs.85,en-us)
        ,NumPut(RegisterCallback("_IEnumString_Clone",        "F"), pes + A_PtrSize * 7)               ; IEnumString::Clone           http://msdn.com/library/ms693436(vs.85,en-us)
		/*
			ObjIdl.h    #ifdef COBJMACROS

			#define IEnumString_QueryInterface(This,riid,ppvObject)	\
				( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 

			#define IEnumString_AddRef(This)	\
				( (This)->lpVtbl -> AddRef(This) ) 

			#define IEnumString_Release(This)	\
				( (This)->lpVtbl -> Release(This) ) 


			#define IEnumString_Next(This,celt,rgelt,pceltFetched)	\
				( (This)->lpVtbl -> Next(This,celt,rgelt,pceltFetched) ) 

			#define IEnumString_Skip(This,celt)	\
				( (This)->lpVtbl -> Skip(This,celt) ) 

			#define IEnumString_Reset(This)	\
				( (This)->lpVtbl -> Reset(This) ) 

			#define IEnumString_Clone(This,ppenum)	\
				( (This)->lpVtbl -> Clone(This,ppenum) ) 
		*/
        pac2 := ComObjCreate("{00BB2763-6A77-11D0-A535-00C04FD7D062}", "{EAC04BC0-3791-11d2-BB95-0060977B464C}")   
        /*
            IAutoComplete2                                                                                                            http://msdn.com/library/bb776288(vs.85,en-us)

            CLSID_IAutoComplete = {00BB2763-6A77-11D0-A535-00C04FD7D062}
            IID_IAutoComplete2  = {EAC04BC0-3791-11d2-BB95-0060977B464C}
        */
        obj.pac := pac2
        DllCall(NumGet(NumGet(pac2 + 0) + 3 * A_PtrSize), "Ptr", pac2, "Ptr", self, "Ptr", pes, "Ptr", 0, "Ptr", 0, "Int")
        /*
            IAutoComplete::Init                                                                                                       http://msdn.com/library/bb776293(vs.85,en-us)

            HRESULT Init(
                [in]           HWND     hwndEdit,
                [in]           IUnknown *punkACL,
                [in, optional] LPCWSTR  pwszRegKeyPath,
                [in, optional] LPCWSTR  pwszQuickComplete
            );
        */
        es[pes] := obj
        return 0
    }
    ; =============================================================================================================================================================================
    else if (celt = "enable")    ; Enables autocompletion.
    {
        for k, v in es
        {
            if (v.hwnd = self)
                return DllCall(NumGet(NumGet(v.pac + 0) + 4 * A_PtrSize), "Ptr", v.pac, "Int", 1, "Int")
                /*
                    IAutoComplete::Enable                                                                                             http://msdn.com/library/bb776291(vs.85,en-us)

                    HRESULT Enable(
                        [in] BOOL fEnable
                    );
                */
        }
        return
    }
    ; =============================================================================================================================================================================
    else if (celt = "disable")    ; Disables autocompletion.
    {
        for k, v in es
        {
            if (v.hwnd = self)
                return DllCall(NumGet(NumGet(v.pac + 0) + 4 * A_PtrSize), "Ptr", v.pac, "Int", 0, "Int")
                /*
                    IAutoComplete::Enable                                                                                             http://msdn.com/library/bb776291(vs.85,en-us)

                    HRESULT Enable(
                        [in] BOOL fEnable
                    );
                */
        }
        return
    }
    ; =============================================================================================================================================================================
    else if (celt = "release")    ; Release autocompletion.
    {
        for k, v in es
        {
            if (v.hwnd = self)
                ObjRelease(v.pac), es.remove(k)
        }
        return
    }
    ; =============================================================================================================================================================================
    else if (celt = "option")    ; Sets the current autocomplete options.
    {
        if rgelt is Integer
        {
            if (rgelt < 0x200)
                option := rgelt
            else
                return
        }
        else
        {
            mode := { AUTOSUGGEST:        0x1        ; Enable the autosuggest drop-down list.
                    , AUTOAPPEND:         0x2        ; Enable autoappend.
                    , SEARCH:             0x4        ; Add a search item to the list of completed strings. When the user selects this item, it launches a search engine.
                    , FILTERPREFIXES:     0x8        ; Do not match common prefixes, such as "www." or "http://".
                    , USETAB:             0x10       ; Use the TAB key to select an item from the drop-down list.
                    , UPDOWNKEYDROPSLIST: 0x20       ; Use the UP ARROW and DOWN ARROW keys to display the autosuggest drop-down list.
                    , RTLREADING:         0x40       ; read right-to-left (RTL).
                    , WORD_FILTER:        0x80       ; If set, the autocompleted suggestion is treated as a phrase for search purposes. The suggestion, Microsoft Office, would be treated as "Microsoft Office" (where both Microsoft AND Office must appear in the search results).
                    , NOPREFIXFILTERING:  0x100 }    ; Disable prefix filtering when displaying the autosuggest dropdown. Always display all suggestions.
            option := 0
            loop, parse, rgelt, %A_Space%
                if (mode[A_LoopField])
                    option |= mode[A_LoopField]
        }
        for k, v in es
        {
            if (v.hwnd = self)
                return DllCall(NumGet(NumGet(v.pac + 0) + 5 * A_PtrSize), "Ptr", v.pac, "UInt", option, "Int")
                /*
                    IAutoComplete2::SetOptions                                                                                        http://msdn.com/library/bb776290(vs.85,en-us)

                    HRESULT SetOptions(
                        [in] DWORD dwFlag
                    );
                */
        }
        return
    }
    ; =============================================================================================================================================================================
    else if !(es.haskey(self))
    {
        return 1
    }
    ; =============================================================================================================================================================================
    else if (celt = "reset")    ; Resets the enumeration sequence to the beginning.
    {
        es[self].CurrentElement := 1
    }
    ; =============================================================================================================================================================================
    if !(celt)
        celt := 1
    i := 0
    loop % celt                                                                                                ; IEnumString::Next    http://msdn.com/library/ms693735(vs.85,en-us)
    {
        if (es[self].CurrentElement = es[self].List.maxindex() + 1)
            break
        string := es[self].List[es[self].CurrentElement]
        NumPut(p := DllCall("ole32.dll\CoTaskMemAlloc", "UPtr", 2 * (StrPut(string, "UTF-16")), "Ptr"), rgelt + (A_Index - 1) * A_PtrSize) ; http://msdn.com/library/ms692727(vs.85,en-us)
        StrPut(string, p, "UTF-16")
        NumPut(NumGet(pceltFetched + 0, "UInt") + 1, pceltFetched, 0, "UInt")
        es[self].CurrentElement := es[self].CurrentElement + 1
        i++
    }
    return (i = celt) ? 0 : 1
}

; =================================================================================================================================================================================
_IUnknown_QueryInterface(self, riid, pObj)                                                              ; IUnknown::QueryInterface    http://msdn.com/library/ms682521(vs.85,en-us)
{
    DllCall("ole32.dll\StringFromCLSID", "Ptr", riid, "Ptr*", sz)                                                                   ; http://msdn.com/library/ms683917(vs.85,en-us)
    string := StrGet(sz, "UTF-16")
    if (string = "{00000101-0000-0000-C000-000000000046}")    ; IID_IEnumString = {00000101-0000-0000-C000-000000000046}
        return NumPut(self, pObj + 0) * 0
    else
        return 0x80004002
}
; =================================================================================================================================================================================
_IUnknown_AddRef(self)                                                                                          ; IUnknown::AddRef    http://msdn.com/library/ms691379(vs.85,en-us)
{
    return 1
}
; =================================================================================================================================================================================
_IUnknown_Release(self)                                                                                        ; IUnknown::Release    http://msdn.com/library/ms682317(vs.85,en-us)
{
    return 0
}
; =================================================================================================================================================================================
_IEnumString_Skip(self, celt)                                                                                  ; IEnumString::Skip    http://msdn.com/library/ms688527(vs.85,en-us)
{
    return 0
}
; =================================================================================================================================================================================
_IEnumString_Reset(self)                                                                                      ; IEnumString::Reset    http://msdn.com/library/ms686598(vs.85,en-us)
{
    AutoComplete(self, "reset", 0, 0)
    return 0
}
; =================================================================================================================================================================================
_IEnumString_Clone(self, ppenum)                                                                              ; IEnumString::Clone    http://msdn.com/library/ms693436(vs.85,en-us)
{
    NumPut(self, ppenum + 0)
    return 0
}
; =================================================================================================================================================================================
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
just me
Posts: 9425
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Autovervollständigung für ein Gui Edit Feld

22 Jul 2015, 01:44

Hi jNizM,

das ist COM, und COM ist mir immer noch recht fremd.

Wie ich das sehe, wird im Skript das IAutoComplete2 Interface genutzt, und diesem wird auch noch ein selbstgebasteltes IEnumString Interface für die Vorschlagsliste untergeschoben. Ich glaube nicht, dass man das anders/kürzer machen kann, wenn man es per COM automatisieren will.
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Autovervollständigung für ein Gui Edit Feld

22 Jul 2015, 01:49

Hey just me,

kennst du zufällig eine Alternative zu COM um das zu bewerkstelligen?
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
just me
Posts: 9425
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Autovervollständigung für ein Gui Edit Feld

22 Jul 2015, 02:08

Hallo jNizM,

das geht bestimmt auch mit viel Handarbeit:
  • Aktuellen Inhalt des Edits auslesen.
  • Den Teil des Textes vor dem Caret bestimmen, der als Suchbegriff genutzt werden soll.
  • In der Vorschlagsliste nach Treffern suchen.
  • Eine ListBox mit den Treffern aufbauen und anzeigen.
  • Sahnehäubchen: Den Text im Edit um den Rest des ersten passenden Vorschlags ergänzen und diese Ergänzung selektieren, damit sie, wenn der Vorschlag nicht genehm ist, bei Eingabe weiterer Zeichen automatisch verschwindet.
  • Solange rumbasteln, bis das wirklich zuverlässig funktioniert.
Ich glaube, dass sowas auch schon in das alte Forum gestellt wurde.
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Autovervollständigung für ein Gui Edit Feld

22 Jul 2015, 07:35

Ich versuche mir mal nach und nach die Informationen zu der Funktion zu suchen und es mit Kommentaren zu versehen, damit man es mal später (vlt.) leichter versteht.
Update des Quelltextes ist dann immer im ersten Post.
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
just me
Posts: 9425
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Autovervollständigung für ein Gui Edit Feld

22 Jul 2015, 08:40

Hallo jNizM,

das Ganze ist eigentlich nicht übermäßig kompliziert, wenn man die notwendigen Informationen findet. Ich habe das gerade mit dem IDropTarget Interface durchgespielt.
Was da über RegisterCallback() aufgebaut bzw. per DllCall(Numget(...) aufgerufen wird, ist die von mir so genannte "Virtuelle Methodentabelle" (VTable). Der Interfacepointer zeigt auf ein Feld, in dem die Adresse dieser Tabelle steht. Die Tabelle selbst ist einfach ein Array von Pointern, die die Adressen der Methodenaufrufe enthalten. Das funktioniert wie Sean's alte COM-Implementation für AHK 1.0.

Alle mir bekannten Interfaces leiten sich vom Standard-Interface IUnknown ab, das die ersten drei Tabellenplätze mit den Adressen Methoden QueryInterface, AddRef und Release belegt. Direkt darauf folgen die Adressen der Methoden, die das Interface zusätzlich bereitstellt. Leider entspricht die Reihenfolge der Methoden selten der Auflistung innerhalb der Beschreibung im MSDN. Deshalb sollte man immer einen Blick in die zugehörige Headerdatei werfen.
User avatar
oldbrother
Posts: 273
Joined: 23 Oct 2013, 05:08

Re: Autovervollständigung für ein Gui Edit Feld

04 Jul 2019, 08:49

Sorry I don't speak Germany.

I changed the sample code a little bit to fit my needs:

Code: Select all

Gui, -Caption +AlwaysOnTop +Border +hwndhgui +LastFound +ToolWindow
Gui, Add, Edit, w300 hwndhedit
Gui, Show

Txt=0930-1208
txt=%txt%`n0930-1213
txt=%txt%`n0930-1612
txt=%txt%`n0930-1620
txt=%txt%`n0930-1630
txt=%txt%`n0930-2016
txt=%txt%`n0930-2025
txt=%txt%`n0930-2416
txt=%txt%`n0930-2422
txt=%txt%`n0930-2430
txt=%txt%`n0930-2440
txt=%txt%`n0930-2818
txt=%txt%`n0930-2835

AutoComplete(hedit, "init", txt, "`n")
AutoComplete(hedit, "option", "AUTOSUGGEST AUTOAPPEND USETAB", 0)
return

GuiClose:
GuiEscape:
ExitApp
It works perfectly with the short word list, but it doesn't work with the long word list. Can someone help me? Thanks!

The word list:
Spoiler
User avatar
divanebaba
Posts: 806
Joined: 20 Dec 2016, 03:53
Location: Diaspora

Re: Autovervollständigung für ein Gui Edit Feld

05 Jul 2019, 05:16

Autovervollständigung für ein ComboBox Feld :mrgreen:

Code: Select all

Werte = anthracite|black|blue|brown|gold|green|grey|orange|purple|red|silver|turquoise|violet|white|yellow

Gui, 1: Add, ComboBox
	, % " hwndGG1ID x" 10 " y" 10 " vGG1 gGG1"
	, %Werte%
Gui, show
return

GG1:
	ControlGetText, Eingabe,, ahk_id %GG1ID%
	ControlGet, Liste, List, , , ahk_id %GG1ID%
	If ( !GetKeyState("Delete") && !GetKeyState("BackSpace") && RegExMatch(Liste, "`nmi)^(\Q" . Eingabe . "\E.*)$", Match)) {
	ControlSetText, , %Match%, ahk_id %GG1ID%
	Selection := StrLen(Eingabe) | 0xFFFF0000
	SendMessage, CB_SETEDITSEL := 0x142, , Selection, , ahk_id %GG1ID%
	} Else {
	CheckDelKey = 0
	CheckBackspaceKey = 0
	}
return
Mit dem gewünschten Edit-Feld funktioniert es leider nicht ohne weiteres.

Return to “Ich brauche Hilfe”

Who is online

Users browsing this forum: No registered users and 28 guests