Jump to content
Tuts 4 You

How to select all in edit control by mouse click on the outline?


LCF-AT

Recommended Posts

Hi guys,

short question.I'am using a tool called "Everything" from voidtools to find files on my HDD etc.I see that this tool is using a simple edit control where you can enter text.If I now wanna get selected the whole edit control then I just need to click once on the outline of that edit control and I got all selected in edit control.Thats pretty cool and now I wanna know how to manage that = what kind of "Edit Control Notification Messages" I have to catch?

https://docs.microsoft.com/en-us/windows/win32/controls/bumper-edit-control-reference-notifications

Don't find any who does it.Do you know how?Below a example image...

MP1_2021-06-13_002037.png.09968549a90d14112562567810817f73.png....AND....MP2_2021-06-13_002037.png.f62f1d4d80f1b5e880487e8fd6b0be55.png

...so if I see it right then I do click inside of the edit control = must be belong to it right?Just wanna know what EN_X I have to check out to notify that click on the outline of the edit control.Otherwise it would be a click on the main dialog background or?Maybe you know it and can tell us. :) Thank you.

greetz

Link to comment

Hi guys,

seems you didn't understand what I was talking about.I'am not looking for a EM_SETSEL = sendmessage, I'am looking for EN_ X notify message to catch if I press with the mouse on the outline of the edit control itself = not in edit control itself / text area.

I need to catch the left mouse click on the edit outline (not in text field) and right after that I can send a EM message to select all inside but how to catch that mouse click?Just look at my images, right there where you can see the mousepointer I did click.

greetz

Link to comment

PS: I did check the controls with WinSpy and it seems that the edit control & combobox (not to see on my image) are inside of a ToolBar.Somehow this must be the reason.Not sure how to put a edit control and others into a toolbar yet.

greetz

Link to comment

Could use EN_SETFOCUS and EN_UPDATE and/or EN_CHANGE. For setfocus once a user clicks in the edit box the EN_SETFOCUS should trigger via the WM_COMMAND and you can then call the EM_SETSEL to select the whole edit contents.

  • Like 2
Link to comment

Hi,

EN_SETFOCUS = triggers if I press inside of edit control = keyboard focus

EN_UPDATE = triggers if I did enter anything in edit control

EN_CAHNGE = triggers if I enter anything / paste etc

All not what I'am looking for.I want to have that one mouseclick on outline = selecting entire edit control.Below a example animation to see what I mean.

Video_2021-06-13_232646_merged..gif.0595162d88896bb29b6a53c73f21a3b0.gif

greetz

Link to comment

Hi again,

ok, so if that is not possible to do (as you can see on the animation above) then I would trying the other thing.....catching EN_SETFOCUS and select all in edit control if the edit control gets the focus.Problem here seems that its not working when using the mouse itself and to click on the edit control = nothing gets selected.Just when using the tab key to switch from control to control it gets selected.So how to get all selected if I click inside of the edit control for the first time to set the focus?

greetz

Link to comment

I use Delphi and have done similar using the click event...
 

procedure TtestFrm.EditBox1Click(Sender: TObject);
begin
    EditBox1.SelectAll;
end;

procedure TtestFrm.EditBox2Click(Sender: TObject);
begin
    EditBox2.SelectAll;
end;

 

Test.rar

  • Like 1
Link to comment

Hi,

and what does it mean for me?Whats click event?I dont have something to enable in WinASM etc.Otherwise this method is also bad because you can't do any good selection if you need it.The best method is really that method the Everything tool does use by selecting all by clicking on outline of edit control.Would really like know how to make that happen.Maybe anyone of you coders could check that out how it works.Just look at the animation I did post above.It works pretty nice and look beautiful. :) Just a must have feature in my opinion.Just don't know how to make it. :(

greetz

Link to comment
Extreme Coders

Here's something similar: Selects the entire text if its' clicked at any position after the text ends

Spoiler

demo.gif.235c7911a885e958023bfad0e25d4ae1.gif

 

Relevant code from Pelles C.:

The main idea is to attach a window procedure to the edit control using SetWindowLongPtr. Within there handle WM_LBUTTONDOWN messages and check if the click is within the existing text or outside it. The code is not perfect but it works :)

Spoiler

LONG_PTR previousEditProc;

static INT_PTR CALLBACK EditProc(HWND hwndEdit, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{
	POINT clickPt;
	LRESULT res;
	LRESULT closestChar;
	int textLength;

	res = CallWindowProc((WNDPROC)previousEditProc, hwndEdit, uMsg, wParam, lParam);
	switch (uMsg)
    {
		case WM_LBUTTONDOWN:
			clickPt.x = GET_X_LPARAM(lParam);
			clickPt.y = GET_Y_LPARAM(lParam);

			closestChar = SendMessage(hwndEdit, EM_CHARFROMPOS, 0, MAKEWPARAM(clickPt.x, clickPt.y));
			textLength = GetWindowTextLength(hwndEdit);
			if (closestChar == textLength)
			{
				SendMessage(hwndEdit, EM_SETSEL, 0, -1);
			}
	}
	return res;
}


static INT_PTR CALLBACK MainDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	HWND hwndEdit;
    switch (uMsg)
    {
        case WM_INITDIALOG:			 
			hwndEdit = GetDlgItem(hwndDlg, ID_EDIT);
			previousEditProc = SetWindowLongPtr(hwndEdit, GWLP_WNDPROC, (LONG_PTR)EditProc);
            return TRUE;

        case WM_SIZE:
            return TRUE;

        case WM_COMMAND:
            switch (LOWORD(wParam))
            {
                case IDOK:
                    EndDialog(hwndDlg, TRUE);
                    return TRUE;
            }
            break;

        case WM_CLOSE:
            EndDialog(hwndDlg, 0);
            return TRUE;
    }
    return FALSE;
}

 

 

  • Like 3
Link to comment

Hi,

thank you for that example. :) Its a better method and also working for me so far.Only disadvantage is that I can not paste anymore anything after the whole content in edit control because all gets selected (if I just use the mouse).

Otherwise I would still really like to know how the guys of the Everything tool did it.They made it really great with that outline click / select all etc.So if anyone does find it out then just tell us.That would  be perfect. :)

PS: Sorry for my late answer but somehow the forum didn't show all new posts on my unread content page. :( Strange.

greetz

Link to comment

This requires subclassing and lower down messages.  If you have a tool that does this, easy to disassemble and see how they did it.  Probably WM_LBUTTONDOWN and some coordinate checks.  Thanks to windows not giving the source to controls, calculating boundaries is practically impossible for all Windows versions or all settings such as accessibility,  global display settings, DPI, etc

  • Like 2
Link to comment

Hi,

so WM_LBUTTONDOWN gets triggered on click on the outline.

WM_LBUTTONDOWN                       equ 201h

0019F870   004853E5  /CALL to GetClientRect from Everythi.004853DF
0019F874   001E064A  |hWnd = 001E064A (class='EVERYTHING_TOOLBAR',parent=000604FA)
0019F878   0019F88C  \pRect = 0019F88C

0019F868   00485439  /CALL to SendMessageW from Everythi.00485433
0019F86C   000A0664  |hWnd = A0664
0019F870   000000B1  |Message = EM_SETSEL
0019F874   00000000  |Start = 0
0019F878   FFFFFFFF  \End = FFFFFFFF (-1.)

0019F874   00485443  /CALL to SetFocus from Everythi.0048543D
0019F878   000A0664  \hWnd = 000A0664 (class='Edit',parent=001E064A)

0019F868   00484C49  RETURN to Everythi.00484C49 from ntdll.NtdllDefWindowProc_W

Just dont check what the Everything_toolbar class does.

$ ==>    0019F338 <cbSize>            00000030
$+4      0019F33C <style>             0000000B
$+8      0019F340 <lpfnWndProc>       00484B10  Everythi.00484B10
$+C      0019F344 <cbClsExtra>        00000000
$+10     0019F348 <cbWndExtra>        00000000
$+14     0019F34C <hInstance>         00400000  Everythi.00400000
$+18     0019F350 <hIcon>             00000000
$+1C     0019F354 <hCursor>           00010003
$+20     0019F358 <hbrBackground>     00000010
$+24     0019F35C <lpszMenuName>      00000000
$+28     0019F360 <lpszClassName>     0019F374  UNICODE "EVERYTHING_TOOLBAR"
$+2C     0019F364 <hIconSm>           00000000

The toolbar is right behind or same as edit control / background + few pixel more.Not sure how to do that.Somehow it must be done simple but how.

|----------------|  <--- toolbar class
|----------------|  <---- edit control
|________________|  <---- edit control
|----------------|  <--- toolbar class
0019F104   00470BCC  /CALL to CreateWindowExW from Everythi.00470BC6
0019F108   00000000  |ExtStyle = 0
0019F10C   0019F35C  |Class = "EVERYTHING_TOOLBAR"
0019F110   0019F148  |WindowName = ""
0019F114   56000000  |Style = WS_CHILD|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_VISIBLE
0019F118   00000000  |X = 0
0019F11C   00000000  |Y = 0
0019F120   00000000  |Width = 0
0019F124   00000000  |Height = 0
0019F128   001A076A  |hParent = 001A076A (class='EVERYTHING')
0019F12C   00002716  |hMenu = 00002716
0019F130   00400000  |hInst = 00400000
0019F134   00000000  \lParam = NULL

greetz

Link to comment

Hi again,

ok I think I got it working now. :) But looks bad of course.Somehow I must paint the extra class with same white color like edit control has inside + the outline / edge around the class to fake / show a border like in Edit control if you use clientedge.

MaybeSo.gif.26db7c1d588fc5270858463a0adc6252.gif

		invoke RtlZeroMemory,addr wc,sizeof wc
		mov		wc.cbSize, sizeof WNDCLASSEX
		mov		wc.style,  0	
		mov		wc.lpfnWndProc, offset WndProc_2
		push	hInstance
		pop		wc.hInstance
		Invoke LoadCursor, NULL, IDC_ARROW
		mov		wc.hCursor, eax
		mov		wc.hbrBackground,COLOR_BTNTEXT
		mov		wc.lpszClassName, chr$("MyApp_Toolbar")
		Invoke RegisterClassEx, addr wc
		mov edi, eax
		invoke CreateWindowEx,0,chr$("MyApp_Toolbar"),0,WS_CHILD or WS_VISIBLE or WS_CLIPSIBLINGS or WS_CLIPCHILDREN,0,0,352,20,hWin,0,hInstance,0

WndProc_2 proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

	.if uMsg == WM_NCCREATE
		mov eax, TRUE
		ret
	.elseif uMsg == WM_CREATE
		mov eax, 0
		ret
	.elseif uMsg == WM_NCDESTROY
		mov eax, 0
		ret
	.elseif uMsg == WM_LBUTTONDOWN
		invoke SendMessage,EditHandle,EM_SETSEL,0,-1h
		invoke SetFocus,EditHandle
	.endif
	Invoke DefWindowProc, hWin, uMsg, wParam, lParam
	Ret
WndProc_2 endp

Edit_OutlineClassClick.7z

greetz

Link to comment

Hi again,

short question.How can I get the actually position state of a control element to place another element on the same position?Just have problems with the calc operation...

GetClientRect = height and width

GetWindowRect

SetWindowPos / MoveWindow

...just wanna get same coordinates of control A and set control B on same coordinates.Just dont remember the calc process for that so maybe you can tell me again.

greetz

Link to comment

Hi guys,

just wanna ask again today so I still didnt find it out. :( I made a simple image so just have a look on it...

Pos_2021-06-25_203313.png.870f51ccdd10c3cc3bc2992a06536e7a.png

...so I know I can use GetClientRect function to get the Widht & Height of the button control in this example but how to get the position / location in the dialog where the button control is set?My simple goal is it just to get the Width & Height & position X / Y and set another control on the same location like another button (Hide button control A and showing button control B ).I just dont remember anymore.Something with GetWindowRect & calc xy etc.Could you maybe tell me quickly how it was again?Thank you.

greetz

Link to comment

You could use GetWindowRect to get the coordinates relative to the screen, then use ScreenToClient to get them relative to the window.

  • Like 2
Link to comment

Hi,

I need a example code.

		invoke GetWindowRect,hWin,addr rc
		invoke GetClientRect,hWin,addr rc2
		mov eax, rc.left
		add eax, rc2.left
		mov left, eax
		mov eax, rc.top
		add eax, rc2.top
		mov top, eax
		
		invoke GetWindowRect,edi,addr rc3
		invoke GetClientRect,edi,addr rc4 ; exit
		mov eax, rc3.left
		sub eax, left
		mov ecx, rc3.top
		sub ecx, top
		
		
		mov eax, left
		mov ecx, top
		mov p.x, eax
		mov p.y, ecx
		invoke ScreenToClient,hWin,addr p
		
		
		invoke MoveWindow,esi,eax, ecx, rc4.right, rc4.bottom, 1

I dont get it work for 100% correctly yet.

Data of Dialog....

F1_2021-06-25_231516.png.3eb894eec4d75848af89aed5de72733d.png

...data of Exit button...

F2_2021-06-25_231516.png.9ab260ad3e904e0f635fd0d4acf42039.png

....now I need to calc out that X: 131 and Y:55 values to use them with MoveWindow on the Test button to set it on same place like the exit button.How to do it right?Is there some formula I can remember?Some rule etc?I always forgot that.

greetz

Link to comment

Edit: I think I got it now... :)

	invoke GetWindowRect,edi,addr rc
	invoke GetClientRect,edi,addr rc2
	mov eax, rc.left
	mov ecx, rc.top
	mov p.x, eax
	mov p.y, ecx
	invoke ScreenToClient,hWin,addr p
	invoke MoveWindow,esi,p.x, p.y, rc2.right, rc2.bottom, 1

....just using that ScreenToClient function.Anyhow I dont check that function and ClientToScreen too. :(

greetz

  • Like 1
Link to comment

Windows XP source code leak will give you more accuracy for all scenarios.  It is worth a read of the edit control source to see optimal methods.  As far as I remember they do not have to deal with screen coordinates and conversions because the control data is accessed directly.  But that data structure is platform dependent and noone is targeting XP anymore.  Nonetheless some complications of accessibility and others can be seen there.  Just because it looks good in your one specific case does not mean it works well everywhere.  And no developer in their right mind has time to do such testing.

I never understood why they dont open source the basic UI elements.  Either you use the limited functionality, you resort to hacks, or you use some owner draw or custom drawing.  But customizing is bound to break some details whether it be keyboard only mode or whatever.  It's such an approximation because they do not give us any high quality option in between.  Ideally when you want to custom draw the edit control, the source of the base WM_PAINT handler should appear for work to begin.   Certainly it would make life harder for Microsoft to do this and still deal with forward and backward compatibility, and non reliance on internal control data structures.  But we would have much better custom implementations that saved hours of developer time.

  • Like 1
Link to comment

Hi again,

so in my example case I do not change or mod the edit control itself so I kept all untouched so far.I'am just using WM_PAINT to make the draw around the edit control + a frame so that it sill looks like a original edit control. :) Its just like a picture frame I made.

So I have another little question.How can I get the used color of a control (edit control in this case)?So I mean if I just create a edit control then the background is has white color but if I use WM_CTLCOLOREDIT to change color of edit background etc then I need to find out the actually background color of it.How to do that?I tried to play around with GetPixel function but dosent work.

Example: I know where the control / edit is set (rect/position) and right from there I need to get a color pixel from.You know what I mean right?So how to do that?Just need to know the used background color of the specific edit control so that I can create a frame in same color.

greetz

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...