DirectX/Message loop: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
m fix link e chiave
m Update syntaxhighlight tags - remove use of deprecated <source> tags
 
Riga 4:
== Messaggi ==
Ogni volta che un evento deve essere segnalato ad una finestra, Windows crea un messaggio per la finestra e lo inserisce in un buffer. L'applicazione ha il compito di prelevare i messaggi l'uno dopo l'altro e di processarli, eseguendo ogni compito che ritiene necessario. Se questi messaggi non vengono interpretati, la finestra non subisce eventi di alcun tipo (creazione, distruzione, mouse, tastiera, ...) e resta un bel rettangolo grigio. Normalmente il codice da eseguire per la gestione dei messaggi è il seguente:
<sourcesyntaxhighlight lang="cpp">
MSG msg = { 0 };
while (msg.message != WM_QUIT)
Riga 13:
}
}
</syntaxhighlight>
</source>
Questo codice andrebbe eseguito subito dopo lo ShowWindow del modulo precedente. '''GetMessage''' è una API che legge l'ultimo messaggio dal buffer e lo inserisce nella variabile puntata come primo argomento. Il secondo argomento è l'HANDLE della finestra da cui vogliamo ricevere i messaggi. Mettendolo a zero riceveremo anche i messaggi di altre finestre (create sempre dallo stesso processo ovviamente), nel caso in cui pensaste di crearne più di una. Gli ultimi due argomenti settati a zero, sono il codice minimo e massimo dei messaggi da ricevere. Per esempio ci potrebbe piacere leggere solo i messaggi con il tipo da 0x200 a 0x20E, ossia solo quelli legati strettamente alla gestione del mouse. Tutti gli altri verrebbero ignorati. Quando impostati a zero, non viene imposto alcun limite. Tutti i messaggi vengono interpretati. GetMessage ritorna 0 se il messaggio in arrivo è WM_QUIT, ossia il messaggio che chiede la chiusura del programma, e ritorna non-zero per ogni altro messaggio.
 
GetMessage, nonostante funzioni a dovere in normali applicazioni, purtroppo presenta una grave lacuna per un videogioco. Infatti nel caso in cui non ci fossero messaggi nel buffer, il processo viene messo in pausa fino all'arrivo di un nuovo messaggio. Questo per un videogame è inaccettabile, infatti le scene verrebbero mostrate solo in presenza di un messaggio. Per superare questo impedimento in applicazioni grafiche viene utilizzato '''PeekMessage'''. Questa funzione cerca un messaggio nel buffer e ritorna non-zero se un messaggio viene trovato e deve essere interpretato, e zero se non ci sono messaggi da leggere. In questo caso noi mostreremo una scena disegnata in DirectX.
<sourcesyntaxhighlight lang="cpp">
MSG msg = { 0 };
while (msg.message != WM_QUIT)
Riga 30:
}
}
</syntaxhighlight>
</source>
Se PeekMessage ritorna un valore diverso da zero, dobbiamo a questo punto gestire il messaggio. Questo normalmente si traduce con la chiamata di due funzioni:
<sourcesyntaxhighlight lang="cpp">
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
Riga 38:
DispatchMessage(&msg);
}
</syntaxhighlight>
</source>
'''TranslateMessage''' è una comoda funzione che trasforma alcuni codici in altri a noi più comprensibili. Ad esempio può tradurre lo [[w:en:Scancode|Scancode]] di un tasto, nel suo corrispondente nella tabella [[w:ASCII|ASCII]].
'''DispatchMessage''' invece chiamerà a sua volta una certa funzione responsabile di gestire i singoli messaggi. Quale funzione? Una creata da noi così:
<sourcesyntaxhighlight lang="cpp">
LRESULT CALLBACK MsgHandler(HWND window, UINT msg, WPARAM wParam, LPARAM lParam)
{
}
</syntaxhighlight>
</source>
 
Questa funzione il cui nome non è rilevante, prende quattro argomenti:
Riga 59:
== Facciamo chiudere la finestra ==
A questo punto la finestra dovrebbe essere ben visibile, ma non avrete alcuna speranza di riuscire a chiuderla. Infatti il click sulla X rossa, o Alt-F4 inviano un messaggio di tipo WM_DESTROY alla finestra, che fino ad ora noi avevamo completamente ignorato. Vediamo come chiudere la finestra:
<sourcesyntaxhighlight lang="cpp">
LRESULT CALLBACK MsgHandler(HWND window, UINT msg, WPARAM wParam, LPARAM lParam)
{
Riga 71:
}
}
</syntaxhighlight>
</source>
Ci sono qui due nuove funzioni. '''PostQuitMessage''' inserirà nel buffer dei messaggi un messaggio di tipo WM_QUIT. Quando il nostro Message Loop riceverà un WM_QUIT, il loop si interromperà facendo terminare il programma. L'argomento è il parametro da ritornare da WinMain.
 
Riga 137:
== Esempi ==
Proviamo a gestire l'utilizzo della tastiera. Utilizzando il messaggio WM_CHAR, possiamo sapere quando l'utente avrà premuto un tasto. WM_CHAR invia in wParam il codice UTF-16 del carattere Aggiungiamo quindi allo switch:
<sourcesyntaxhighlight lang="cpp">
case WM_CHAR:
printf("E' stato premuto il tasto: %lc\n", (WCHAR) wParam);
break;
</syntaxhighlight>
</source>
 
Ogni volta che la finestra sarà in primo piano ed un tasto verrà premuto, sarà visualizzato sul terminale. Se non avete ancora aperto il terminale seguite le istruzioni nel modulo [[DirectX/Terminale_di_debug | Terminale di debug]].
Riga 147:
== Sorgente per questo modulo ==
A questo punto il codice del nostro programma dovrebbe assomigliare a qualcosa di simile:
<sourcesyntaxhighlight lang="cpp">
#include <Windows.h>
#include <stdio.h>
Riga 216:
return 0;
}
</syntaxhighlight>
</source>
 
[[Categoria:DirectX|Message loop]]