Thread: Selecting an area

  1. #1
    Registered User
    Join Date
    Oct 2005
    Posts
    29

    Selecting an area

    I'm making a capture screenshot program and I'm down to allowing the user to select any part of the screen to screenshot it.

    The problem I have is how to efficiently display the selection tool
    What I'm aiming for is a lookalike of when you left-click mouse and drag it on the desktop, or as when you are browsing a folder and you are selecting multiple files with only your mouse by leftclicking with mouse and dragging.

    I've tried to do as much as I can but now in stuck, the rectangle which shows what you are about to select flickers and remains partcially on the screen sometimes...
    I'm using global hooks for this to intercept mouseclicks and keyboard messages.

    I've basically intercepted the starting position of the mouse and stored it, then evertime the mouse moves an end position is gotten and then a rectangle of the bounds are drawn.
    All the drawings are made on an transpartent window and then evertime the mouse pos updates the old rectangle is removed...

    Any hints are highly appreciated since I'm all out of ideas and really don't know what to test anymore, been trying to fix this for a say 10 hours now

    Some of the code that I've used:
    Code:
    /*                */
    /*  Area Section  */
    /*                */
    #define AREA_ABORT 1
    #define AREA_CLICK 2
    #define AREA_POSMOVED 3
    
    HHOOK AreaMouseHook;
    HHOOK AreaKBHook;
    
    long __stdcall AreaCaptureProc(unsigned int _message, long _lParam)
    {
    	static HWND hWnd = FindWindow("XimaSSS", "");
    	static Win::Window ghostWindow;
    
    	static clock_t endWait;
    	static const int borderSize = 5;
    	static bool sizing(false);
    	static POINT startPos;
    	static POINT endPos;
    
    	switch(_message)
    	{
    	case AREA_ABORT:
    	{
    		sizing = false;
    		RECT rect;
    		{
    			rect.left = startPos.x;
    			rect.top = startPos.y;
    			rect.right = endPos.x;
    			rect.bottom = endPos.y;
    			RedrawWindow(ghostWindow, &rect, 0, RDW_ALLCHILDREN | RDW_UPDATENOW | RDW_INVALIDATE);
    		}
    		startPos.x = startPos.y = 0;
    		endPos.x = endPos.y = 0;
    		if(ghostWindow.isWindow())
    			ghostWindow.destroy();
    
    		PostMessage(hWnd, Area_Abort, 0, 0);
    		break;
    	}
    	case AREA_CLICK:
    	{
    		if(sizing)
    		{
    			sizing = false;
    			RECT rect;
    			{
    				rect.left = startPos.x;
    				rect.top = startPos.y;
    				rect.right = endPos.x;
    				rect.bottom = endPos.y;
    				RedrawWindow(ghostWindow, &rect, 0, RDW_ALLCHILDREN | RDW_UPDATENOW | RDW_INVALIDATE);
    			}
    			startPos.x = startPos.y = 0;
    			endPos.x = endPos.y = 0;
    			if(ghostWindow.isWindow())
    				ghostWindow.destroy();
    		}
    		else
    		{
    			if(!GetCursorPos(&startPos))
    				return AreaCaptureProc(AREA_ABORT, 0);
    			sizing = true;
    			{
    				Win::Class _class(0, GetModuleHandle(0), 0, 0, "Dummy", 0, 0);
    				if(!_class.reg())
    					return false;
    			}
    			ghostWindow.create(0, WS_VISIBLE | WS_CHILD, "Dummy", "", 0, 0, 1280, 1024, 0, GetDesktopWindow());
    		}
    		break;
    	}
    	case AREA_POSMOVED:
    	{
    		if(!sizing)
    			return 1;
    
    		RECT rect;
    		{
    			rect.left = startPos.x;
    			rect.top = startPos.y;
    			rect.right = endPos.x;
    			rect.bottom = endPos.y;
    			RedrawWindow(ghostWindow, &rect, 0, RDW_ALLCHILDREN | RDW_UPDATENOW | RDW_INVALIDATE);
    		}
    			GetCursorPos(&endPos);
    			{
    				HDC hMarkerDC = GetDC(ghostWindow);
    				HBRUSH hBorder = CreateSolidBrush(RGB(255, 0, 0));
    
    				// tl->tr
    				rect.left = startPos.x;
    				rect.top = startPos.y;
    				rect.right = endPos.x;
    				rect.bottom = startPos.y > endPos.y ? startPos.y - borderSize : startPos.y + borderSize;
    				FillRect(hMarkerDC, &rect, hBorder);
    
    				// tl->bl
    				rect.left = startPos.x;
    				rect.top = startPos.y;
    				rect.right = startPos.x > endPos.x ? startPos.x - borderSize : startPos.x + borderSize;
    				rect.bottom = endPos.y;
    				FillRect(hMarkerDC, &rect, hBorder);
    
    				// br->bl
    				rect.left = startPos.x;
    				rect.top = endPos.y > startPos.y ? endPos.y - borderSize : endPos.y + borderSize;
    				rect.right = endPos.x;
    				rect.bottom = endPos.y;
    				FillRect(hMarkerDC, &rect, hBorder);
    
    				// br->tr
    				rect.left = endPos.x > startPos.x ? endPos.x - borderSize : endPos.x + borderSize;
    				rect.top = startPos.y;
    				rect.right = endPos.x;
    				rect.bottom = endPos.y;
    				FillRect(hMarkerDC, &rect, hBorder);
    
    				DeleteObject(hBorder);
    				ReleaseDC(ghostWindow, hMarkerDC);
    			}
    		break;
    	}
    	}
    	return 1;
    }
    
    LRESULT __stdcall AreaMouseHookProc(int nCode, unsigned int _wParam, long _lParam)
    {
    	if(nCode != HC_ACTION)
    		return CallNextHookEx(AreaMouseHook, nCode, _wParam, _lParam);
    
    	switch(_wParam)
    	{
    	case WM_RBUTTONUP:
    		return AreaCaptureProc(AREA_ABORT, 0);
    		break;
    	case WM_LBUTTONUP:
    		return AreaCaptureProc(AREA_CLICK, 0);
    		break;
    	case WM_LBUTTONDOWN:
    		return AreaCaptureProc(AREA_CLICK, 0);
    
    		break;
    	case WM_MOUSEMOVE:
    		AreaCaptureProc(AREA_POSMOVED, 0);
    		return 0;
    		break;
    	default:
    		return CallNextHookEx(AreaMouseHook, nCode, _wParam, _lParam);
    	}
    	return 1;
    }
    
    LRESULT __stdcall AreaKBHookProc(int nCode, unsigned int _wParam, long _lParam)
    {
    	if(nCode != HC_ACTION)
    		return CallNextHookEx(AreaKBHook, nCode, _wParam, _lParam);
    
    	switch(_wParam)
    	{
    	case WM_KEYDOWN:
    		switch(reinterpret_cast<kbstruct*>(_lParam)->vkCode)
    		{
    		case VK_SPACE:
    			//PostMessage(hWnd, CW_WindowSelected, 0, 0);
    			break;
    		case VK_ESCAPE:
    			return AreaCaptureProc(AREA_ABORT, 0);
    			break;
    		default:
    			return CallNextHookEx(AreaKBHook, nCode, _wParam, _lParam);
    		}
    		break;
    	default:
    		return CallNextHookEx(AreaKBHook, nCode, _wParam, _lParam);
    	}
    	return 1;
    }

  2. #2
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Are you processing WM_ERASEBKGND mgs and returning non zero?

    All drawing should be done in the paint handler.

    You should redraw (erase) your rectangle on the transparent DC in response to a mouse move (but not to the screen yet.
    Call for a paint, bypassing the OS que and posting direcdtly to the app callback (InvalidateRect() + UpdateWindow() ).
    Draw the smallest possible area (from the transparent DC to the Paint DC) with a single BitBlt() in the paint handler.

    I use 'double buffering' to get flicker free drawing, doing exactly this. Try a search here.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. area of a circle
    By wise_ron in forum C Programming
    Replies: 2
    Last Post: 10-02-2006, 03:15 PM
  2. very weird problem (pointers I think)
    By hannibar in forum C Programming
    Replies: 2
    Last Post: 10-11-2005, 06:45 AM
  3. Need help with switch
    By 3kgt in forum C Programming
    Replies: 2
    Last Post: 02-26-2003, 12:43 PM
  4. Tab Controls - API
    By -KEN- in forum Windows Programming
    Replies: 7
    Last Post: 06-02-2002, 09:44 AM
  5. How do you search & sort an array?
    By sketchit in forum C Programming
    Replies: 30
    Last Post: 11-03-2001, 05:26 PM