CbAutoComplete - Auto-completes typed values in a ComboBox

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
Pulover
Posts: 612
Joined: 29 Sep 2013, 19:51
Location: Brazil
Contact:

CbAutoComplete - Auto-completes typed values in a ComboBox

16 Mar 2016, 15:34

I have found a few scripts out there to accomplish this task, but all of them had some bug. So I decided to make my own and share it here.

Code: Select all

;=======================================================================================
;
; Function:      CbAutoComplete
; Description:   Auto-completes typed values in a ComboBox.
;
; Author:        Pulover [Rodolfo U. Batista]
; Usage:         Call the function from the Combobox's gLabel.
;
;=======================================================================================
CbAutoComplete()
{	; CB_GETEDITSEL = 0x0140, CB_SETEDITSEL = 0x0142
	If ((GetKeyState("Delete", "P")) || (GetKeyState("Backspace", "P")))
		return
	GuiControlGet, lHwnd, Hwnd, %A_GuiControl%
	SendMessage, 0x0140, 0, 0,, ahk_id %lHwnd%
	MakeShort(ErrorLevel, Start, End)
	GuiControlGet, CurContent,, %lHwnd%
	GuiControl, ChooseString, %A_GuiControl%, %CurContent%
	If (ErrorLevel)
	{
		ControlSetText,, %CurContent%, ahk_id %lHwnd%
		PostMessage, 0x0142, 0, MakeLong(Start, End),, ahk_id %lHwnd%
		return
	}
	GuiControlGet, CurContent,, %lHwnd%
	PostMessage, 0x0142, 0, MakeLong(Start, StrLen(CurContent)),, ahk_id %lHwnd%
}

MakeLong(LoWord, HiWord)
{
	return (HiWord << 16) | (LoWord & 0xffff)
}

MakeShort(Long, ByRef LoWord, ByRef HiWord)
{
	LoWord := Long & 0xffff
,   HiWord := Long >> 16
}
I only wish there was a better way to detect when the user is deleting content. Checking key state of bs and del keys doesn't work with Right-Click > Delete or with simulated keystrokes. But I'm not going to try OnMessage either...

:arrow: Sources and examples on GitHub

Feedback and improvements are welcome.
Rodolfo U. Batista
Pulover's Macro Creator - Automation Tool (Recorder & Script Writer)
burque505
Posts: 1731
Joined: 22 Jan 2017, 19:37

Re: CbAutoComplete - Auto-completes typed values in a ComboBox

01 Nov 2017, 20:03

Pulover, I can't believe I found this at the very moment I needed it. What a gift. Very nice indeed!
I was just about to try a ListBox and Sift, but this will certainly get me going faster.
Regards,
burque505
User avatar
Delta Pythagorean
Posts: 627
Joined: 13 Feb 2017, 13:44
Location: Somewhere in the US
Contact:

Re: CbAutoComplete - Auto-completes typed values in a ComboBox

02 Nov 2017, 07:05

If you want to detect if the user is deleting content, try checking the current string with the previous string that was captured.

[AHK]......: v2.0.12 | 64-bit
[OS].......: Windows 11 | 23H2 (OS Build: 22621.3296)
[GITHUB]...: github.com/DelPyth
[PAYPAL]...: paypal.me/DelPyth
[DISCORD]..: tophatcat

five
Posts: 2
Joined: 31 Jan 2018, 16:00

Re: CbAutoComplete - Auto-completes typed values in a ComboBox

02 Feb 2018, 08:46

Great script. Once I've made my selection, how do I get the current selection into a variable that I can do something with. My source is a csv file.

Some sample code that I put online:
https://p.ahkscript.org/?p=6493c881

I realized after the fact that I had the sample csv backwards. It is actually computer name, ip address.

Code: Select all

csv =
(
CMJ8023, 192.168.1.1
CMK3689, 192.168.1.2 
C0I739H, 192.168.1.3
A20JK29, 192.168.1.4
RT9HJ90, 192.168.1.5 
F0MSSH4, 192.168.1.6
EBSDUNM, 192.168.1.7 
84LHXKX, 192.168.1.8 
NREP2LX, 192.168.1.9 
I6D3C3Q, 192.168.1.10 
24UL3Q1, 192.168.1.11 
SV62S85, 192.168.1.12 
EQCNAUU, 192.168.1.13 
68UZGK3, 192.168.1.14 
C4XNBY5, 192.168.1.15 
1MDVV9K, 192.168.1.16 
L750VIV, 192.168.1.17 
N068R9H, 192.168.1.18 
NT6NN8Z, 192.168.1.19 
6QVFJPS, 192.168.1.20
FWWSLSN, 192.168.1.21 
28SM0M1, 192.168.1.22 
GWHL7NB, 192.168.1.23 
4VJ7LCM, 192.168.1.24 
LBVJV30, 192.168.1.25 
)
And while I am asking questions. How hard would it be to change this code from search as you type to fuzzy search? Where you can type any part of the string and it would display the applicable results.
User avatar
SL5
Posts: 879
Joined: 12 May 2015, 02:10
Contact:

Re: CbAutoComplete - Auto-completes typed values in a ComboBox

28 Apr 2018, 11:27

five wrote:Great script. Once I've made my selection, how do I get the current selection into a variable that I can do something with. My source is a csv file.
...
And while I am asking questions. How hard would it be to change this code from search as you type to fuzzy search? Where you can type any part of the string and it would display the applicable results.
i dont know if this helps: https://autohotkey.com/boards/viewtopic ... 67#p215367
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: CbAutoComplete - Auto-completes typed values in a ComboBox

11 Sep 2018, 07:32

Thanks alot for this. And also for your macro recorder. It has taught me some of the hardest things to understand since its able to write code and give real-life examples
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: CbAutoComplete - Auto-completes typed values in a ComboBox

22 Sep 2018, 08:10

Hi Rodolfo,

EDIT: I have noticed after posting that you were aware of that complexity. I'll try some stuff but I'm out of solutions thats why I requested. :)

If by any chance you fall on this post, would it be possible to add a feature to autocomplete also AFTER a backspaceor deletekey was pressed?
What I mean by this is that when you type a word and it doesnt currently match because you make a mistake, you will most probably backspaceor deletea couple of letters until you cleaned your mistake - but then it stops there rather than re-choosing automatically a string that matches.
How would you make it re-analyze the new and cleaned current string AFTER the backspace/delete? But also considering that the user did not type any new letter or press space

Why it would be nice, I think, is that it would re-choose the matching string automatically.
So if you then press Tabor clickaway from the ComboBox, the cleaned string will automatically be matched to a string rather than wait a new input.
Currently when you backspace/delete, it will require the user to re-trigger the function manually with any lettersor a spacebefore it chooses a string.

For example: In this adapted version of your function I'm trying to add a non matching string to the user list of names and I have tried to loop back to the top of the function to auto-update on delete/backspace but it prevents from deleting the last matching string.

Code: Select all

cbAutoComplete() 
{ ; CB_GETEDITSEL = 0x0140, CB_SETEDITSEL = 0x0142
	Global NOM_Nouveau_Ajouter											; addition
	;cbAutoComplete:
	If ((GetKeyState("Delete", "P")) || (GetKeyState("Backspace", "P")))
	{
		;Goto, cbAutoComplete
		return
	}
	GuiControlGet, cbHwnd, Hwnd, %A_GuiControl%
	SendMessage, 0x0140, 0, 0,, ahk_id %cbHwnd%
	MakeShort(ErrorLevel, Start, End)
	GuiControlGet, cbCurContent,, %cbHwnd%
	GuiControl, ChooseString, %A_GuiControl%, %cbCurContent%
	If (ErrorLevel)
	{
		ControlSetText,, %cbCurContent%, ahk_id %cbHwnd%
		PostMessage, 0x0142, 0, MakeLong(Start, End),, ahk_id %cbHwnd%
		NOM_Nouveau_Ajouter:=True										; addition
		SetTimer, NOM_Nouveau_Ajouter, -10								; addition 
		return
	}
	NOM_Nouveau_Ajouter:=False											; addition
	GuiControl, Hide, NOM_Nouveau_Text									; addition
	GuiControlGet, cbCurContent,, %cbHwnd%
	PostMessage, 0x0142, 0, MakeLong(Start, StrLen(cbCurContent)),, ahk_id %cbHwnd%
}
Hope I was able to make myself understandable, if not the case please let me know.

In the waiting, thanks in advance.
Alex
A_AhkUser
Posts: 1147
Joined: 06 Mar 2017, 16:18
Location: France
Contact:

Re: CbAutoComplete - Auto-completes typed values in a ComboBox

23 Sep 2018, 09:13

Hi DRocks,

Try this:

Code: Select all

#NoEnv
#Warn
#SingleInstance Force
; #Include ..\CbAutoComplete.ahk

; from https://raw.githubusercontent.com/Pulover/CbAutoComplete/master/Examples/CbAutoCompleteDemo.ahk
list := ""
Loop, Files, C:\Windows\System32\*.exe
	list .= A_LoopFileName . "|"
f := Func("CbAutoComplete")
Gui, Add, Combobox, w300 vcb, % list
Gui, Add, Combobox, w300 vcb2, % list
GuiControl, +g, cb, % f
GuiControl, +g, cb2, % f
Gui, Show,, CbAutoComplete Demo
return

CbAutoComplete(_lHwnd) { ; from https://github.com/Pulover/CbAutoComplete/blob/master/CbAutoComplete.ahk
	static CB_GETEDITSEL := 0x0140, CB_SETEDITSEL := 0x0142
	static _f := "", _hwnd := ""
	if ((GetKeyState("Delete", "P")) || (GetKeyState("Backspace", "P"))) {
		((_lHwnd = _hwnd) || _f:=Func(A_ThisFunc).bind(_lHwnd))
		_hwnd := _lHwnd
		SetTimer % _f, % -650 ; if the period is negative, the timer runs only once
	return
	}
	_ahkid := "ahk_id " . _lHwnd ; a shorthand for convinience
	SendMessage % CB_GETEDITSEL, 0, 0,, % _ahkid
	_start := ErrorLevel & 0xffff, _end := ErrorLevel >> 16
	GuiControlGet, _input,, %_lHwnd%
	GuiControl, ChooseString, % _lHwnd, % _input
	if (ErrorLevel)
	{
		ControlSetText,, % _input, % _ahkid
		PostMessage, CB_SETEDITSEL, 0, % (_start << 16) | (_end & 0xffff),, % _ahkid
	return
	}
	GuiControlGet, _input,, %_lHwnd%
	PostMessage, 0x0142, 0, (_start << 16) | (StrLen(_input) & 0xffff),, % _ahkid
}
Hope this helps
my scripts
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: CbAutoComplete - Auto-completes typed values in a ComboBox

25 Sep 2018, 07:23

thank you very much!

I had few time to thouroughly study the example. But it actually works and seems brilliant.
I like that multiple backspaces will not trigger autocomplete until a timer is past-due-time.

Thanks alot, I'll be studying it more.. !

EDIT: holy sh -- your eAutoComplete is crazy!! good job
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: CbAutoComplete - Auto-completes typed values in a ComboBox

15 Oct 2018, 14:15

Hello,

So after receiving help from A_AhkUser, I found myself in front of two functions that I did not fully understand - (first from Pulover and second from User). So I thought it was not acceptable to rely fully on them before I try to get my head around the way they work.

In this exercice, I think I found another way to solve the Backspace and Delete problem and I like the behavior.
To do this, I've reused Pulover's codelines and reordered them by trial and error inside the GetKeyState Condition check { }.
Then, the little modification that made it all finally work was to add -1 to the Start pos of the CB_SETEDITSEL

I hope this can be useful for someone else and If you have better ways to do this please let me know I'd really appreciate it :)

Code: Select all

;=======================================================================================
; https://github.com/pulover/cbautocomplete
;
; Function:      CbAutoComplete
; Description:   Auto-completes typed values in a ComboBox.
;
; Author:        Pulover [Rodolfo U. Batista]
; Usage:         Call the function from the Combobox's gLabel.
;
;=======================================================================================
CbAutoComplete()	{	
	global
	;CB_GETEDITSEL = 0x0140, CB_SETEDITSEL = 0x0142
	If ((GetKeyState("Delete", "P")) || (GetKeyState("Backspace", "P"))) {
		SendMessage, 0x0140, 0, 0,, ahk_id %lHwnd%
		MakeShort(ErrorLevel, Start, End)
		GuiControl, ChooseString, %A_GuiControl%, %cbCurContent%
		GuiControlGet, cbCurContent,, %lHwnd%
		PostMessage, 0x0142, 0, MakeLong(Start-1, StrLen(cbCurContent)),, ahk_id %lHwnd%
		return
	}
	GuiControlGet, lHwnd, Hwnd, %A_GuiControl%
	SendMessage, 0x0140, 0, 0,, ahk_id %lHwnd%
	MakeShort(ErrorLevel, Start, End)
	GuiControlGet, cbCurContent,, %lHwnd%
	GuiControl, ChooseString, %A_GuiControl%, %cbCurContent%
	If (ErrorLevel) {
		ControlSetText,, %cbCurContent%, ahk_id %lHwnd%
		PostMessage, 0x0142, 0, MakeLong(Start, End),, ahk_id %lHwnd%
		return
	}
	GuiControlGet, cbCurContent,, %lHwnd%
	PostMessage, 0x0142, 0, MakeLong(Start, StrLen(cbCurContent)),, ahk_id %lHwnd%
}
MakeLong(LoWord, HiWord)	{
	return (HiWord << 16) | (LoWord & 0xffff)
}
MakeShort(Long, ByRef LoWord, ByRef HiWord)	{
	LoWord := Long & 0xffff
   , HiWord := Long >> 16
}
MrHue
Posts: 17
Joined: 01 Oct 2015, 02:51

Re: CbAutoComplete - Auto-completes typed values in a ComboBox

20 Apr 2020, 03:52

Many thanks to Pulover, A_AhkUser, and D Rocks for this function. I had problems calling CbAutoComplete because my combobox GUI is inside a function and GuiControl and GuiControlGet do not work when the GUI variables are static instead of global. So I modified it to use control handles instead (which will work regardless of whether GUI variables are static or global). I also modified the handling of backspace to take into account of whether backspace was done on selected text or not.

Code: Select all

Entry:=Combobox("Matthew|Mark|Luke|John")
Msgbox User entered %Entry%
Combobox(var)
{
	Static
	id:=WinActive(A)
	CoordMode,Mouse,Screen
	MouseGetPos,x,y
	Gui, Combobox:New
	Gui, -Caption -Border
	Gui, Margin, 0, 0
	Gui, Add, ComboBox, vChoice gCbAutoComplete HwndCbHwnd Simple r10 Sort, %var%
	Gui, Combobox:+LastFound
	Gui, Show, x%x% y%y%, GuiCombobox
	CoordMode,Mouse,Window
	WinWaitClose
	WinActivate, ahk_id %id%
	Return Choice

	;=======================================================================================
	; https://www.autohotkey.com/boards/viewtopic.php?t=15002
	;
	; Function:      CbAutoComplete
	; Description:   Auto-completes typed values in a ComboBox.
	;
	; Authors:       Pulover [Rodolfo U. Batista], DRock, MrHue
	; Usage:         Call the function from the Combobox's gLabel.
	;
	;=======================================================================================
	CbAutoComplete:
		;CB_GETEDITSEL = 0x0140, CB_SETEDITSEL = 0x0142
		SendMessage, 0x0140, 0, 0,, ahk_id %CbHwnd%		; Get current edit selection
		Pos := ErrorLevel					; Position = Start in low word, end in high word; note any keypress cancels selection before arriving at the g-label 
		GuiControlGet, cbCurContent,, %CbHwnd%			; Get current content
		If BS:=GetKeyState("Backspace", "P") 			; If backspace
			if BS:=(choice==cbCurContent)			; If after backspace current input is same as last input 
				cbCurContent := SubStr(cbCurContent,1,-1)	; then remove one character (backspace only deletes selected when selection is present)
		GuiControl, ChooseString, %CbHwnd%, %cbCurContent%	; Auto-complete with first matching string
		If (ErrorLevel) {					; If ChooseString failed (which will wipe out entire input), restore previous input (minus one char if BS pressed - a problem if there was no previous selection)
			ControlSetText,, %cbCurContent%, ahk_id %CbHwnd%
			PostMessage, 0x0142, 0, Pos,, ahk_id %CbHwnd%
		}							; Otherwise select everything from cursor (-1 if BS done on selection) to end of string (length = -1)
		else PostMessage, 0x0142, 0, (Pos & 0xFFFF) - BS + 0xFFFF0000,, ahk_id %CbHwnd%
		choice := cbCurContent					; Save last input so can check if BS changed input length or not
		return
}

#IfWinActive, GuiCombobox
Enter::
	Gui, Combobox:SubMit
	Gui, Combobox:Destroy
	return

Escape::
ComboboxGuiEscape:
	Gui, Combobox:destroy
	return
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: CbAutoComplete - Auto-completes typed values in a ComboBox

21 Apr 2020, 20:05

MrHue wrote:
20 Apr 2020, 03:52
Nice, your example works very well good job!
User avatar
Pulover
Posts: 612
Joined: 29 Sep 2013, 19:51
Location: Brazil
Contact:

Re: CbAutoComplete - Auto-completes typed values in a ComboBox

26 Sep 2020, 18:41

I've been away from the forum in the last years and haven't visited this thread in a while. Looks like you people have found a solution to the problem. That's great! I'm going to try it out and update it with credits to everyone involved. Thanks.
Rodolfo U. Batista
Pulover's Macro Creator - Automation Tool (Recorder & Script Writer)
User avatar
Pulover
Posts: 612
Joined: 29 Sep 2013, 19:51
Location: Brazil
Contact:

Re: CbAutoComplete - Auto-completes typed values in a ComboBox

28 Sep 2020, 10:15

So after testing the alternative versions I realize those are actually different tastes in behavior, so I'm not going to update my version. Still It's good to have them here as I know they will be useful for others, so thanks everyone.

I even made some quick tests with OnMessage but couldn't detect changes on the edit control.
Rodolfo U. Batista
Pulover's Macro Creator - Automation Tool (Recorder & Script Writer)
patel8786
Posts: 4
Joined: 16 Jan 2019, 02:51

Re: CbAutoComplete - Auto-completes typed values in a ComboBox

15 Feb 2021, 15:04

Hi @Pulover

Is there a version of this that's compatible with AHK v2?

Many thanks
User avatar
Pulover
Posts: 612
Joined: 29 Sep 2013, 19:51
Location: Brazil
Contact:

Re: CbAutoComplete - Auto-completes typed values in a ComboBox

15 Feb 2021, 16:16

Not that I'm aware of. You should ask at the v2 forum.
Rodolfo U. Batista
Pulover's Macro Creator - Automation Tool (Recorder & Script Writer)
MrHue
Posts: 17
Joined: 01 Oct 2015, 02:51

Re: CbAutoComplete - Auto-completes typed values in a ComboBox

18 May 2023, 01:49

v2 update

Code: Select all

msgbox ComboBox(["abc","b","c"])
msgbox ComboBox(["abc","b","c"])
msgbox ComboBox(["abcd","b","c"])

Combobox(prompt,timeout:=90) {	; Prompt = array of choices
	static ComboBox, Choice, LastPrompt 
	if !IsSet(ComboBox) {
		Combobox := Gui("-Caption -Border"),
		Combobox.OnEvent("Escape", CbEscape),
		Combobox.MarginX := "0", Combobox.MarginY := "0",
		Combobox.SetFont("s12"),
		Combobox.Add("ComboBox", "vChoice Simple r10", prompt).OnEvent("Change", CbAutoComplete),
		Combobox.Add("Button", "Default w0 h0 hidden").OnEvent("Click", CbSubmit)
	} else if Prompt!=LastPrompt 
		Combobox["Choice"].Delete(), Combobox["Choice"].Add(prompt)
	CoordMode("Mouse", "Screen"),
	MouseGetPos(&x, &y), x+=5,
	CoordMode("Mouse", "Window"),
	LastPrompt := Prompt, Choice := "",
	ComboBox.Show("x" x " y" y)
	WinWaitClose(Combobox.Hwnd,,timeout) 
	Return Choice

	CbSubmit(*) {
		Choice := Combobox["Choice"].Text,
		Combobox.Show("Hide")
	}

	CbEscape(*) {
		ComboBox.Show("Hide")
	}

	CbAutoComplete(Ctrl, Info, *) {	 ; CB_GETEDITSEL = 0x0140, CB_SETEDITSEL = 0x0142
		static prev
		Pos:=SendMessage(0x0140,0,0,,Ctrl.Hwnd)	; Get position = Start in low word, end in high word; note any keypress cancels selection
		, cbText := Ctrl.Text					; Get current content
		if BS:=GetKeyState("Backspace", "P") && (prev=cbText) ; If backspace and after backspace current input is same as prev input 
			cbText := SubStr(cbText,1,-1)		; backspace one char (backspace deletes selection without backspacing if selection present)
		try Ctrl.Choose(cbText)					; try Choose first matching string
		catch {									; throws error and deletes text if no match
			Ctrl.Text := cbText					; so need to restore text
		}
		PostMessage(0x0142, 0, (Pos&0xFFFF)-BS+0xFFFF0000, Ctrl.Hwnd)	; Select from cursor (-1 if BS) to end of string (length = -1)
		, prev := cbText						; Save input minus additional selected text so can check if BS changed input or not
	}
}

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: charlie89, gwarble and 127 guests