Search code examples
windowswindowgdioverlaycreatewindow

(Windows API) WM_PAINT Mouse problems


I created a window with the following flags to overlay a d3d application: WS_EX_TOPMOST | WS_EX_COMPOSITED | WS_EX_TRANSPARENT | WS_EX_LAYERED I proceeded with colorkeying the window for transperacy and all worked well. However once I began drawing on it using GDI an unforeseen problem occurred:

For some reason the mouse events (especially movement) are not passed correctly through the window when WM_PAINT is in progress, and so it appears as though the mouse and the keyboard for that matter lag. the FPS is fine, this is some API problem, I suspect that for some reason the keyboard/mouse messages are not handled as they should while the WM_PAINT is in progress, because the slower the timer is set to the less jerking there is.

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

 switch(msg)
 {
  case WM_DESTROY:
  {
          KillTimer(hwnd, ID_TIMER);
          PostQuitMessage(0);
          break;
         }
  case WM_CREATE:
  {
   SetTimer(hwnd, ID_TIMER, 10, NULL);
   break;
  }
  case WM_TIMER:
  {
   InvalidateRect(hwnd, 0, 1);
   break;
         }
  case WM_PAINT:
  {
   paint(hwnd);
   break;
  }
 }
 return DefWindowProc(hwnd, msg, wParam, lParam);
}

and

void paint (HWND hwnd)
{
 PAINTSTRUCT Ps;
 HDC hdc = BeginPaint(hwnd, &Ps);

 SetBkColor(hdc, RGB(0,0,0));
 SetBkMode(hdc, TRANSPARENT);



 LOGBRUSH log_brush;
 log_brush.lbStyle = BS_NULL;
 HBRUSH handle_brush = CreateBrushIndirect(&log_brush);
 SelectObject(hdc, handle_brush);


..........................................


 DeleteObject(font);
 DeleteObject(pen);
 DeleteObject(handle_brush);

 EndPaint(hwnd, &Ps);
}

Thank you for any help you may be able to give.


Solution

  • WM_PAINT messages are never delivered to your window unless someone calls UpdateWindow or there are no keyboard or mouse messages in your input queue.

    Once you begin processing WM_PAINT, if a keyboard or mouse message arrives, it just sits in your queue until you are done with WM_PAINT. So What you are describing isn't possible.

    If your WM_PAINT code takes a long time to execute, that could cause jerkiness, but you say that's not a problem so perhaps it's your handling of WM_ERASEBKGND? I don't see that code, but I do see that when you InvalidateRect, you are passing TRUE as the last parameter which means that you want the background to be erased.

    If you don't handle WM_ERASEBKGND, then DefWindowProc will do it for you erasing your entire window with the brush from from your window class. This could result in windows thinking that no part of your window is transparent.

    If you want mouse messages to pass through your window, a more reliable way is to handle the WM_NCHITTEST message and return HTTRANSPARENT where you want the mouse to pass through.
    This is basically what how the WS_EX_TRANSPARENT style works. like this

    case WM_NCHITTEST:
       {
       lRet = DefWindowProc(hwnd, uMsg, wParam, lParam);
       if (HTCLIENT == lRet)
          lRet = HTTRANSPARENT;
       }
    

    If your window has no non-client area, then you can skip the call to DefWindowProc.