Wykrywanie modalnych pętli komunikatów i systemowego menu

Wykrywanie modalnych pętli komunikatów i systemowego menu
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około godziny
  • Lokalizacja:Tuchów
  • Postów:12167
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ę.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 1x, ostatnio: flowCRANE
obscurity
  • Rejestracja:około 6 lat
  • Ostatnio:3 minuty
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.


"A car won't take your job, another horse driving a car will." - Horse influencer, 1910
edytowany 2x, ostatnio: obscurity
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około godziny
  • Lokalizacja:Tuchów
  • Postów:12167
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.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 9x, ostatnio: flowCRANE
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)