Wykrywanie modalnych pętli komunikatów i systemowego menu

Wykrywanie modalnych pętli komunikatów i systemowego menu
flowCRANE
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Tuchów
  • Postów: 12269
0

Systemowe menu to to popup wyświetlany w lewym górnym rogu okna, po wciśnięciu skrótu Alt+Space, po kliknięciu PPM w obszarze paska tytułowego okna lub kliknięciu LPM na ikonkę obok tytułu okna. Wygląda tak, jakby się ktoś zastanawiał:

screenshot-20250203163830.png

Chciałbym mieć kontrolę nad tym menu, a konkretniej, móc wykryć moment gdy to menu zostaje wywołane, kiedy zostaje zamknięte (bez wyboru żadnej z jego opcji) oraz, gdy użytkownik wybierze którąś opcję odpalającą modalną pętlę komunikatów, mieć możliwość wykrycia momentu zakończenia tej modalnej pętli.

Obecnie mogę wykryć moment pojawienia się tego menu, dlatego że w każdym przypadku jest ono wywoływane przeze mnie ręcznie. Co prawda używam do tego funkcji SDL_ShowWindowSystemMenu, ale mam też dostęp do pętli komunikatów okna. Zawsze wywołuję je samodzielnie, dlatego że okno ma customową dekorację. Tak więc ten przypadek nie stanowi problemu.

Problemem jest jednak wykrycie momentu zamknięcia tego popupu — SDL ani nie generuje zdarzeń dotyczących jego pokazania, ani zamknięcia. Ponadto, jeśli użytkownik wybierze którąś z opcji odpalającej pętlę modalną (np. Size do zmiany rozmiaru okna za pomocą myszy lub klawiatury), nie mam pojęcia jak wykryć moment zakończenia pętli modalnej oraz wznowienia wykonywania wątku głównego okna (czyli wątku gry).

Ma ktoś pomysł jak to rozwiązać?

W teorii są do dyspozycji komunikaty WM_ENTERMENULOOP i WM_EXITMENULOOP, ale mam z nimi problem. Ten pierwszy komunikat nie jest w ogóle dostarczany do calbacku hooku (mała strata), a ten drugi co prawda jest dostarczany do callbacku, ale zawsze gdy systemowe menu jest zamykane, czyli bez względu na to czy użytkownik zamknął popup czy wybrał którąś opcję i uruchomił modalną pętlę. Tak więc drugi komunikat nie jest do końca tym czego oczekuję.

obscurity
  • Rejestracja: dni
  • Ostatnio: dni
1
flowCRANE napisał(a):

Problemem jest jednak wykrycie momentu zamknięcia tego popupu — SDL ani nie generuje zdarzeń dotyczących jego pokazania, ani zamknięcia.

Kiedyś dodawałem opcje do tego menu i nie było z tym problemu, nie pamiętam szczegółów ale myślę że możesz się czegoś nauczyć z kodu właśnie do dodawania własnych itemów

https://stackoverflow.com/questions/4615940/how-can-i-customize-the-system-menu-of-a-windows-form

Czyli z tego wychodzi że w momencie otworzenia wysyłany jest komunikat WM_SYSCOMMAND z WParam = SYSMENU_ABOUT_ID.

Stamtąd masz uchwyt do okna menu kontekstowego (GetSystemMenu) i możesz z nim robić co chcesz, w tym potencjalnie czekać aż zostanie zamknięty.

Ponadto, jeśli użytkownik wybierze którąś z opcji odpalającej pętlę modalną (np. Size do zmiany rozmiaru okna za pomocą myszy lub klawiatury), nie mam pojęcia jak wykryć moment zakończenia pętli modalnej oraz wznowienia wykonywania wątku głównego okna (czyli wątku gry).

To trochę wygląda jak problem X/Y. Po co ci ta wiedza? Powinieneś w grze znać time delta od ostatniej klatki kiedy wątek główny działał i to w zasadzie wszystko co w grze ci powinno być potrzebne.
Natomiast możesz z osobna przecież obsłużyć wszystkie przypadki, aplikacja dostanie komunikat po zmianie rozmiaru / przesunięciu okna i zmianie stanu na zmaksymalizowany itp. Więc wszystkie te rzeczy możesz sobie obsłużyć jeśli chcesz.

flowCRANE
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Tuchów
  • Postów: 12269
0
obscurity napisał(a):

Czyli z tego wychodzi że w momencie otworzenia wysyłany jest komunikat WM_SYSCOMMAND z WParam = SYSMENU_ABOUT_ID.

Niby tak, ale WM_SYSCOMMAND wysyłany jest dla mnóstwa innych przypadków, natomiast dedykowane otwieraniu i zamykaniu tego menu komunikaty to właśnie WM_ENTERMENULOOP i WM_EXITMENULOOP.

To trochę wygląda jak problem X/Y. Po co ci ta wiedza?

Żeby móc zaimplementować dodatkowe ficzery, gdy symulacja (główny wątek) jest zamrożona. Jednym z takich ficzerów jest inny sposób renderowania zawartości okna, gdy otwierane jest systemowe menu.

Powinieneś w grze znać time delta od ostatniej klatki kiedy wątek główny działał i to w zasadzie wszystko co w grze ci powinno być potrzebne.

To nie jest ani problemem, ani przedmiotem tego wątku. Choć, aby było wszystko jasne, pętlę główną mam napisaną tak, że zawsze prawidłowo dogania czas rzeczywisty — gdy nie ma lagów (pojedyncza aktualizacja), gdy wystąpi lag (wielokrokowa aktualizacja) oraz gdy wystąpi gigantyczny lag lub pętla zagłady (natychmiastowe dogonienie czasu rzeczywistego). Natomiast gdy systemowe menu jest widoczne oraz w trakcie modalnych pętli, wątek gry nie jest wykonywany (jest to domyślne zachowanie w Windows) i to mi jak najbardziej odpowiada.

Wykrywanie obecności systemowego menu jest mi potrzebne jedynie do dodatkowych ficzerów, takich jak renderowanie zawartości okna w skali szarości (i inne pierdy) gdy okno nie ma fokusu lub systemowe menu jest widoczne, a także renderowanie okna w kolorze w trakcie pętli modalnej (gdy okno jest rozciągane lub przesuwane).


Chyba wiem jak to ogarnąć — zamiast wykrywać wejście i wyjście do pętli modalnej niewiadomego rodzaju (rozciąganie, przeciąganie itp.), mogę złapać komunikaty WM_ENTERSIZEMOVE i WM_EXITSIZEMOVE. W ten sposób będę wiedział kiedy rozpoczyna się i kończy modalna pętla. Pytanie tylko czy system operacyjny używa pętli modalnej tylko do rozciągania i przeciągania okna, czy jeszcze do czegoś innego.

Przy okazji: zgłosiłem braki w SDL-u, bo callback hooku na systemowe komunikaty dostarcza tylko te dotyczące zamknięcia menu i wyjścia z modalnej pętli size/move, ale nie dostarcza tych dotyczących otwarcia menu i wejścia do modalnej pętli size/move.


Edit: ok, w sumie to wszystko już wiem — te cztery ww. komunikaty w zupełności wystarczą. Deweloperzy SDL-a szybciutko wrzucili poprawkę, dzięki której wszystkie komunikaty są dostarczane przez callback hooku. Sprawdziłem i wszystko śmiga bez zarzutów, tak więc mam wszystko czego potrzebuję do implementacji swoich ficzerów.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.