@@ -78,15 +78,16 @@ typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*);
7878
7979struct ImGui_ImplWin32_Data
8080{
81+ INT64 Time;
82+ INT64 TicksPerSecond;
8183 HWND hWnd;
8284 HWND MouseHwnd;
8385 bool MouseTracked;
84- int MouseButtonsDown;
85- INT64 Time;
86- INT64 TicksPerSecond;
87- ImGuiMouseCursor LastMouseCursor;
8886 bool HasGamepad;
8987 bool WantUpdateHasGamepad;
88+ int MouseButtonsDown;
89+ int MouseX, MouseY; // against spurious WM_MOUSEMOVE events
90+ ImGuiMouseCursor LastMouseCursor;
9091
9192#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
9293 HMODULE XInputDLL;
@@ -129,7 +130,10 @@ bool ImGui_ImplWin32_Init(void* hwnd)
129130 bd->WantUpdateHasGamepad = true ;
130131 bd->TicksPerSecond = perf_frequency;
131132 bd->Time = perf_counter;
133+ // bd->LastMouseCursor = ImGuiMouseCursor_Arrow; //windows default is the arrow, no need to reset it
132134 bd->LastMouseCursor = ImGuiMouseCursor_COUNT;
135+ bd->MouseX = -1 ;
136+ bd->MouseY = -1 ;
133137
134138 // Set platform dependent data in viewport
135139 ImGui::GetMainViewport ()->PlatformHandleRaw = (void *)hwnd;
@@ -180,8 +184,17 @@ static bool ImGui_ImplWin32_UpdateMouseCursor()
180184 if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
181185 return false ;
182186
187+ ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData ();
188+
189+ ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor ();
190+ if (bd->LastMouseCursor == mouse_cursor)
191+ return false ;
192+
193+ bd->LastMouseCursor = mouse_cursor;
194+
195+
183196 ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor ();
184- if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor )
197+ if (imgui_cursor == ImGuiMouseCursor_None /* || io.MouseDrawCursor*/ )
185198 {
186199 // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
187200 ::SetCursor (NULL );
@@ -328,20 +341,59 @@ static void ImGui_ImplWin32_UpdateGamepads()
328341#endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
329342}
330343
331- void ImGui_ImplWin32_NewFrame ()
344+ bool ImGui_ImplWin32_NewFrame (bool poll_only )
332345{
333346 ImGuiIO& io = ImGui::GetIO ();
334347 ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData ();
335348 IM_ASSERT (bd != NULL && " Did you call ImGui_ImplWin32_Init()?" );
336349
350+ INT64 current_time;
351+
352+
353+
354+
355+ for (;;)
356+ {
357+ ::QueryPerformanceCounter ((LARGE_INTEGER*)¤t_time);
358+
359+ double next_refresh = !poll_only ? io.NextRefresh : 0.0 ;
360+
361+ double cur_delta = double (current_time - bd->Time ) / bd->TicksPerSecond ;
362+ if (cur_delta <= next_refresh)
363+ {
364+ double ms_to_wait_double = (next_refresh - cur_delta) * 1000 .0f ;
365+ unsigned int ms_to_wait = ms_to_wait_double >= MAXDWORD ? INFINITE : unsigned int (ms_to_wait_double);
366+ if (ms_to_wait)
367+ MsgWaitForMultipleObjectsEx (0 , nullptr , ms_to_wait, QS_ALLEVENTS, 0 );
368+ }
369+
370+
371+ MSG msg;
372+ while (::PeekMessage (&msg, NULL , 0U , 0U , PM_REMOVE))
373+ {
374+ if (msg.message != WM_QUIT)
375+ {
376+ ::TranslateMessage (&msg);
377+ ::DispatchMessage (&msg);
378+ continue ;
379+ }
380+ return false ;
381+ }
382+
383+
384+ if (cur_delta <= next_refresh)
385+ continue ;
386+
387+ break ;
388+ }
389+
390+
337391 // Setup display size (every frame to accommodate for window resizing)
338392 RECT rect = { 0 , 0 , 0 , 0 };
339393 ::GetClientRect (bd->hWnd, &rect);
340394 io.DisplaySize = ImVec2 ((float )(rect.right - rect.left ), (float )(rect.bottom - rect.top ));
341395
342396 // Setup time step
343- INT64 current_time = 0 ;
344- ::QueryPerformanceCounter ((LARGE_INTEGER*)¤t_time);
345397 io.DeltaTime = (float )(current_time - bd->Time ) / bd->TicksPerSecond ;
346398 bd->Time = current_time;
347399
@@ -352,15 +404,12 @@ void ImGui_ImplWin32_NewFrame()
352404 ImGui_ImplWin32_ProcessKeyEventsWorkarounds ();
353405
354406 // Update OS mouse cursor with the cursor requested by imgui
355- ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor ();
356- if (bd->LastMouseCursor != mouse_cursor)
357- {
358- bd->LastMouseCursor = mouse_cursor;
359- ImGui_ImplWin32_UpdateMouseCursor ();
360- }
361-
407+ ImGui_ImplWin32_UpdateMouseCursor ();
408+
362409 // Update game controllers (if enabled and available)
363410 ImGui_ImplWin32_UpdateGamepads ();
411+
412+ return true ;
364413}
365414
366415// There is no distinct VK_xxx for keypad enter, instead it is VK_RETURN + KF_EXTENDED, we assign it an arbitrary value to make code more readable (VK_ codes go up to 255)
@@ -504,33 +553,57 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
504553 if (ImGui::GetCurrentContext () == NULL )
505554 return 0 ;
506555
556+ const char * key_refresh_reason;
507557 ImGuiIO& io = ImGui::GetIO ();
508558 ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData ();
509559
510560 switch (msg)
511561 {
512562 case WM_MOUSEMOVE:
563+
513564 // We need to call TrackMouseEvent in order to receive WM_MOUSELEAVE events
565+ if (!bd->MouseHwnd ) // mouse entered client area
566+ bd->LastMouseCursor = ImGuiMouseCursor_COUNT;
567+
514568 bd->MouseHwnd = hwnd;
515569 if (!bd->MouseTracked )
516570 {
517571 TRACKMOUSEEVENT tme = { sizeof (tme), TME_LEAVE, hwnd, 0 };
518572 ::TrackMouseEvent (&tme);
519573 bd->MouseTracked = true ;
520574 }
521- io.AddMousePosEvent ((float )GET_X_LPARAM (lParam), (float )GET_Y_LPARAM (lParam));
575+
576+ {
577+ int m_x = GET_X_LPARAM (lParam), m_y = GET_Y_LPARAM (lParam);
578+ if (bd->MouseX != m_x || bd->MouseY != m_y) // spurious WM_MOUSEMOVE events are a real thing. don't act on them
579+ {
580+ bd->MouseX = m_x, bd->MouseY = m_y;
581+
582+ io.SetNextRefresh (0 , " mouse move" ); // return 0;
583+
584+ io.AddMousePosEvent ((float )m_x, (float )m_y);
585+ }
586+ }
522587 break ;
523588 case WM_MOUSELEAVE:
524589 if (bd->MouseHwnd == hwnd)
525590 bd->MouseHwnd = NULL ;
526591 bd->MouseTracked = false ;
592+ // bd->LastMouseCursor = ImGuiMouseCursor_COUNT;
593+ bd->MouseX = -1 , bd->MouseY = -1 ;
527594 io.AddMousePosEvent (-FLT_MAX, -FLT_MAX);
528595 break ;
529- case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
530- case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
531- case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:
532- case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK:
596+ case WM_LBUTTONDOWN: key_refresh_reason = " mouse lbuttonup down" ; goto md;
597+ case WM_LBUTTONDBLCLK: key_refresh_reason = " mouse lbuttonup dblclk" ; goto md;
598+ case WM_RBUTTONDOWN: key_refresh_reason = " mouse rbuttonup down" ; goto md;
599+ case WM_RBUTTONDBLCLK: key_refresh_reason = " mouse rbuttonup dblclk" ; goto md;
600+ case WM_MBUTTONDOWN: key_refresh_reason = " mouse mbuttonup donw" ; goto md;
601+ case WM_MBUTTONDBLCLK: key_refresh_reason = " mouse mbuttonup dblclk" ; goto md;
602+ case WM_XBUTTONDOWN: key_refresh_reason = " mouse xbuttonup down" ; goto md;
603+ case WM_XBUTTONDBLCLK: key_refresh_reason = " mouse xbuttonup dblclk" ;
604+ md:
533605 {
606+ io.SetNextRefresh (0 , key_refresh_reason);
534607 int button = 0 ;
535608 if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0 ; }
536609 if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1 ; }
@@ -542,11 +615,13 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
542615 io.AddMouseButtonEvent (button, true );
543616 return 0 ;
544617 }
545- case WM_LBUTTONUP:
546- case WM_RBUTTONUP:
547- case WM_MBUTTONUP:
548- case WM_XBUTTONUP:
618+ case WM_LBUTTONUP: key_refresh_reason = " mouse lbuttonup up" ; goto mu;
619+ case WM_RBUTTONUP:key_refresh_reason = " mouse rbutton up" ; goto mu;
620+ case WM_MBUTTONUP:key_refresh_reason = " mouse mbutton up" ; goto mu;
621+ case WM_XBUTTONUP:key_refresh_reason = " mouse xbutton up" ;
622+ mu:
549623 {
624+ io.SetNextRefresh (0 , key_refresh_reason);
550625 int button = 0 ;
551626 if (msg == WM_LBUTTONUP) { button = 0 ; }
552627 if (msg == WM_RBUTTONUP) { button = 1 ; }
@@ -559,19 +634,27 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
559634 return 0 ;
560635 }
561636 case WM_MOUSEWHEEL:
637+ io.SetNextRefresh (0 , " wheel up" );
562638 io.AddMouseWheelEvent (0 .0f , (float )GET_WHEEL_DELTA_WPARAM (wParam) / (float )WHEEL_DELTA);
563639 return 0 ;
564640 case WM_MOUSEHWHEEL:
641+ io.SetNextRefresh (0 , " wheel down" );
565642 io.AddMouseWheelEvent ((float )GET_WHEEL_DELTA_WPARAM (wParam) / (float )WHEEL_DELTA, 0 .0f );
566643 return 0 ;
567644 case WM_KEYDOWN:
645+ key_refresh_reason = " key down" ; goto l;
568646 case WM_KEYUP:
647+ key_refresh_reason = " key up" ; goto l;
569648 case WM_SYSKEYDOWN:
649+ key_refresh_reason = " syskey down" ; goto l;
570650 case WM_SYSKEYUP:
571651 {
652+ key_refresh_reason = " key up" ;
653+ l:
572654 const bool is_key_down = (msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN);
573655 if (wParam < 256 )
574656 {
657+ io.SetNextRefresh (0 , key_refresh_reason);
575658 // Submit modifiers
576659 ImGui_ImplWin32_UpdateKeyModifiers ();
577660
0 commit comments