Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Click-through Transparent window, no dragging allowed [C++]

There are several ways to do this using .NET (take this for instance), yet I wasn't able to reproduce the same thing using only C++ win32.

My approach was to use WS_EX_LAYERED and then SetLayeredWindowAttributes to have some control over the opacity, but I read more and I found out that WS_EX_TRANSPARENT is 'better'- it allows click-through.

However, using

hWnd = CreateWindowEx(WS_EX_TRANSPARENT, fooName, fooName, WS_OVERLAPPEDWINDOW | WS_POPUP | WS_CLIPSIBLINGS, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

doesn't seem to do the trick. There is also another thing: once I get the click-through window working, can I use

PostMessage(hWnd, WM_LBUTTONUP, 0, MAKELPARAM(GET_X_LPARAM(lParam) ,GET_Y_LPARAM(lParam)));

to block the dragging state from passing through?

Note: the dragging state is produced using a touchpad device.

like image 326
George Netu Avatar asked Jul 09 '15 09:07

George Netu


1 Answers

The click-through part:

Indeed, WS_EX_TRANSPARENT by itself is a big lie; so I used WS_EX_COMPOSITED | WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOPMOST instead.

I have control over the opacity using SetLayeredWindowAttributes(hWnd, 0, (255 * opacity) / 100, LWA_ALPHA); (quite unorthodox, but it works) and I also use

SetCapture(hWnd);
ShowCursor(false);

to grab the mouse focus as the top level window doesn't let go and hides the cursor.

I also tried to force the focus on the window adding WM_NCACTIVATE and WM_ACTIVEAPP:

case WM_MOUSEMOVE:
        fprintf(stdout, "Mouse move [%d][%d]\n", GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
        SetForegroundWindow(hWnd);
        break;

case WM_LBUTTONDOWN:
        printf("Mouse click\n");
        SetForegroundWindow(hWnd);
        break;

case WM_NCACTIVATE:
        return false;

case WM_ACTIVATEAPP:
        wActive = (bool)wParam;

        if(wActive == false)
            return 0;
        else
            return DefWindowProc(hWnd, message, wParam, lParam);

The dragging part:

In my particular case I wanted to 'poke' the window underneath (child window) without losing focus; unfortunately, any mouse click event will change the focus to that child window - a solution would be to:

  1. set a timer (SetTimer, WM_TIMER) and check whether your application lost focus or not
  2. set a hook to your window and reply to a WM_KILLFOCUS message with a WM_SETFOCUS message
like image 84
George Netu Avatar answered Oct 12 '22 17:10

George Netu