Per sapere quali pulsanti del mouse erano stati premuti al momento
dell'invio di un messaggio del mouse, oltre che controllare il parametro
nFlags del gestore, è possibile richiamare le funzioni ::GetKeyState
e ::GetAsincKeyState con i parametri VK_LBUTTON, VK_MBUTTON, VK_RBUTTON
o qualsiasi altro codice di tasto virtuale che identifichi i tasti
delle tastiera.
Per semplificare, un valore di ritorno negativo significa che il
tasto è premuto, se 0 il tasto non è premuto.
Nei dettagli invece accade che il bit di ordine alto è 1, se il
tasto è premuto, altrimenti 0 se non lo è.
Quando il bit di ordine alto di un numero (il primo dalla sinistra)
è 1, allora il numero assume segno negativo.
Inoltre se il bit di ordine basso è 1 (numero dispari), allora il
tasto con il codice virtuale specificato è attivato. Un tasto come
CAPS LOCK o BLOCK NUM è attivato se l'indicatore sulla tastiera
è acceso. Se il tasto non è attivo, allora il bit di ordine basso
è zero (numero pari) e l'indicatore luminoso è spento.
La differenza tra ::GetKeyState e ::GetAsincKeyState sta nel fatto
che la prima è sincrona cioè restituisce lo stato del pulsante al
momento dell'invio del messaggio di tastiera relativo a quel pulsante;
per tale motivo andrebbe per lo più utilizzato in un gestore di
messaggi della tastiera.
Lo stato di ritorno da tale funzione cambia non appena un thread
legge dei messaggi di tasto dalla sua coda dei messaggi. Tale stato
non riflette lo stato a livello di interrupt associato con l'hardware;
per avere questa informazione usare ::GetAsyncKeyState.
Quest'ultima è infatti asincrona e funziona in tempo reale restituendo
lo stato del pulsante al momento dell'invocazione della funzione.
É possibile anche 'costringere' il cursore a muoversi in un'area
predefinita e vincolarlo a restarci fino a quando non lo si sblocca
da tale situazione. Per definire un'area rettangolare all'interno
del quale si vuole vincolare il cursore si può utilizzare la funzione
::ClipCursor; il suo prototipo è il seguente:
BOOL ClipCursor(CONST RECT lpRect);
Il valore di ritorno è diverso da zero se non ci sono errori, mentre
il parametro passato è un puntatore ad una struttura RECT che definisce
appunto l'area di movimento del cursore. Se tale parametro è NULL,
si sblocca il cursore abilitandolo ad usare l'intero schermo.
Come al solito la raccomandazione è di ripristinare lo stato del
cursore (essendo una risorsa condivisa) prima di cedere il controllo
ad altre applicazioni o finestre. In caso contrario il mouse potrebbe
non funzionare correttamente.
Vediamo adesso come è possibile recuperare la posizione del mouse
dall'esterno di una funzione di gestione del mouse.
La funzione chiave è ::GetMessagePos, questa ritorna una DWORD contenente
le coordinate del mouse (in coordinate di schermo) al momento dell'invio
dell'ultimo messaggio recuperato da ::GetMessage.
Ad esempio se ci troviamo nel gestore di messaggio di WM_SETCURSOR
e richiamiamo ::GetMessagePos le coordinate del mouse sono relative
al momento in cui tale messaggio è stato prelevato dalla coda; in
seguito a tale prelievo verrà poi richiamata la funzione in cui
ci troviamo.
Le coordinate ritornate da ::GetMessagePos necessitano di un paio
di trasformazioni, primo perché non sono in un oggetto CPoint, ma
in una DWORD e secondo perché sono in coordinate di schermo.
Vediamo un po' queste trasformazioni che vi serviranno spessissimo
nella vostra vita di programmatori:
DWORD dwPos= ::GetMessagePos();
CPoint pt (LOWORD(dwPos), HIWORD (dwPos));
ScreenToClient(&pt);
La prima riga di codice serve a recuperare le coordinate del mouse,
la seconda a convertire la DWORD in un oggetto CPoint e la terza
infine trasforma da coordinate di schermo a coordinate client.
Nella seconda riga di codice sono da notare le due macro LOWORD
e HIWORD che ritornano della DWORD ( doppia parola ) la WORD bassa
e quella alta. Come è facilmente intuibile, della DWORD la parte
alta contiene le coordinate orizzontali, mentre la parte bassa quelle
verticali.
Piccolissima nota:
La parte alta è quella più significativa, quella che in pratica
quando varia fa cambiare maggiormente il valore del numero. Ad esempio
in un numero di 4 bit se il primo bit di ordine alto passa da 0
a 1, il numero aumenta di 16 unità ( 2^4 ), se invece cambia il
bit di ordine più basso, il valore del numero cambia di un'unità
( 2^0 ).
Usando le macro LOWORD e HIWORD però potrebbero esserci dei problemi
con i sistemi con monitor multipli, si consiglia quindi di usare
la macro MAKEPOINTS che ritorna una struttura di tipo POINTS.
La procedura corretta quindi diventa:
DWORD dwPos= ::GetMessagePos();
POINTS pts = MAKEPOINTS(dwPos);
CPoint pt (pts.x,pts.y);
ScreenToClient(&pt);
Per la gestione del mouse, questo è tutto, dalla prossima puntata
inizieremo a descrivere in dettaglio la gestione della tastiera.
Torna all'indice Generale del corso di Corso di Visual C++ di Software Planet