• Advertisement
Sign in to follow this  

Win32: Mouse capture problem

This topic is 3621 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I have a problem with losing the mouse capture in certain situations. I want to use the edit control when the user double clicks an item in a listbox. Left and right mouse button clicks outside the edit control should end the editing. The problem: if I double click in the listbox, it appears and when I right click it will be closed. So far so good, but when I double click an item, then select something in the edit control and right click outside the edit control it doesn't close as it's lost the mouse capture (WM_CAPTURECHANGED messages are sent and GetCapture() returns 0). Why does it happen and what's the best way to handle it?
WNDPROC oldproc, oldeditproc;
HWND hedit = NULL;

void EndEdit()
{
	MSG msg;
	if (!hedit)
		return;
	ReleaseCapture();
	while (PeekMessage(&msg, hedit, 0, 0, PM_REMOVE))
		;
	DestroyWindow(hedit);
	hedit = NULL;
}

LRESULT CALLBACK TestEditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	POINT pt;
	RECT r;
	switch (message) {
		case WM_LBUTTONDOWN:
		case WM_RBUTTONDOWN:
			pt.x = LOWORD(lParam);
			pt.y = HIWORD(lParam);
			GetClientRect(hWnd, &r);
			if (!PtInRect(&r, pt)) {
				EndEdit();
				return 0;
			}
			break;
		case WM_KILLFOCUS:
			EndEdit();
			break;
		case WM_DESTROY:
			SetWindowLongPtr(hWnd, GWL_WNDPROC, (LONG_PTR)oldeditproc);
			break;
	}
	return CallWindowProc(oldeditproc, hWnd, message, wParam, lParam); 
}

void StartEdit(HWND hWnd, int x, int y)
{
	int cursel = SendMessage(hWnd, LB_GETCURSEL, 0, 0);
	RECT r;
	HFONT hfont;
	if (hedit || cursel < 0)
		return;
	SendMessage(hWnd, LB_GETITEMRECT, cursel, (LPARAM)&r);
	hedit = CreateWindow("EDIT", "Test", WS_BORDER | WS_CHILD | WS_VISIBLE | ES_WANTRETURN, r.left, r.top, r.right-r.left, r.bottom-r.top, hWnd, NULL, hInst, NULL);
	oldeditproc = (WNDPROC)SetWindowLongPtr(hedit, GWL_WNDPROC, (LONG_PTR)TestEditProc);
	hfont = (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0);
	SendMessage(hedit, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
	SetWindowText(hedit, "testtesttest");
	SetFocus(hedit);
	SetCapture(hedit);
}

LRESULT CALLBACK TestLBProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message) {
		case WM_LBUTTONDBLCLK:
			StartEdit(hWnd, LOWORD(lParam), HIWORD(lParam));
			return 0;
	}
	return CallWindowProc(oldproc, hWnd, message, wParam, lParam); 
}

INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	HWND hwnd;

	switch (message)
	{
	case WM_INITDIALOG:
		hwnd = GetDlgItem(hDlg, IDC_TESTLB);
		oldproc = (WNDPROC)SetWindowLongPtr(hwnd, GWL_WNDPROC, (LONG_PTR)TestLBProc);
		SendMessage(hwnd, LB_ADDSTRING, 0, (LPARAM)"line 1");
		SendMessage(hwnd, LB_ADDSTRING, 0, (LPARAM)"line 2");
		SendMessage(hwnd, LB_ADDSTRING, 0, (LPARAM)"line 3");
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}
		break;
	case WM_DESTROY:
		hwnd = GetDlgItem(hDlg, IDC_TESTLB);
		SetWindowLongPtr(hwnd, GWL_WNDPROC, (LONG_PTR)oldproc);
		break;
	}
	return (INT_PTR)FALSE;
}

IDD_TESTDLG DIALOGEX 0, 0, 300, 100
STYLE DS_LOCALEDIT | DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_CAPTION | WS_THICKFRAME | WS_VISIBLE
EXSTYLE WS_EX_CONTROLPARENT
CAPTION "Test Dialog"
FONT 8, "Courier New", 0, 0, 0x0
BEGIN
    DEFPUSHBUTTON   "OK",IDOK,20,3,50,14
    PUSHBUTTON      "Cancel",IDCANCEL,230,3,50,14
    LISTBOX         IDC_TESTLB,10,20,280,80,LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT
END

Share this post


Link to post
Share on other sites
Advertisement
The functions r.left, r.top etc...
- do they return values or references?
- use the same logic to the data being passed to CreateWindow( ... )

If you pass by value the calculations will be done but data will be lost because the operations are performed on copies, where as to pass data by reference would mean you're altering and using the very values you take into a function - does that make any sense?

Also you're doing this
StartEdit( ... int x, int y)
- not (... int &i, int &j)


This might also be possible...

RECT *r = new RECT(...) // whatever goes in the constructor


... then in CreateWindow:

CreateWindow( ... &r.left, &r.top ...etc )// reference the pointer to the object

Share this post


Link to post
Share on other sites
That definitely is not the problem, the edit control is created just fine and x/y values are not relevant for the mouse capture problem. Btw. plain C has no call by reference, you would need a pointer, but I don't need the values outside the function.

The problem is that when I select something in the edit control, the mouse capture, that I aquired with SetCapture(hedit), so mouse messages outside the control are being sent to the edit control, is lost without having ReleaseCapture() called in my code.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement