Documente Academic
Documente Profesional
Documente Cultură
Mouse-ul
Mouse-ul este un dispozitiv de indicare cu unul sau mai multe butoane. În ciuda experimentelor făcute cu mai
multe tipuri de dispozitive de indicare, cum ar fi ecranele sensibile la atingere (touch screen) sau creioanele optice
(light pen), mouse-ul (şi alte produse asemănătoare precum bilele - trackballs - folosite pentru calculatoarele
portabile) este singurul dispozitiv care a pătruns pe scară largă pe piaţa calculatoarelor personale.
Lucrurile nu au fost, însă, întotdeauna aşa. Primii dezvoltatori ai sistemului de operare Windows şi-au dat
seama că nu pot să oblige utilizatorii să cumpere un mouse, pentru a utiliza produsul software. Ca urmare, au
considerat mouse-ul un accesoriu opţional şi au furnizat o interfaţă cu tastatura pentru toate operaţiile din
Windows şi din aplicaţiile livrate împreună cu acesta, lucru pe care l-au făcut şi alţi dezvoltatori.
Deşi mouse-ul a devenit un dispozitiv aproape universal pentru calculatoarele pe care rulează Windows, eu
cred încă în acest principiu. Cei care se descurcă foarte bine cu tastatura (şi în special dactilografele) preferă să
ţină mâinele deasupra tastaturii şi presupun că multe persoane au avut surpriza de a „pierde" uneori mouse-ul pe
un birou aglomerat. Din aceste motive, eu încă mai recomand - atunci când este posibil - includerea în program a
unei interfeţe cu tastatura, care să dubleze funcţiile mouse-ului.
Elemente de bază despre mouse
Windows 95 permite folosirea mouse-ului cu un buton, cu două butoane sau cu trei butoane, precum şi
folosirea unui joystick sau a unui creion optic, pentru simularea unui mouse cu un buton. Deoarece mouse-ul cu un
singur buton reprezintă un numitor comun, mulţi programatori Windows au evitat multă vreme să folosească
celelalte butoane ale mouse-ului. Totuşi, mouse-ul cu trei butoane a devenit un standard de facto, aşa că reticenţa
tradiţională privind folosirea celui de-al doilea buton nu mai este justificată. Al doilea buton al mouse-ului este
recomandat pentru apelarea „meniurilor de context" - meniuri care apar în fereastră în afara barei de meniu - sau
pentru operaţii speciale de tragere (despre care vom discuta în curând). Puteţi să determinaţi dacă mouse-ul este
prezent folosind funcţia GetSystemMetrics:
fMouse = GetSystemMetrics (SM_MOUSEPRESENT) ;
Variabila fMouse va avea valoarea TRUE (diferită de zero) dacă mouse-ul este instalat. Pentru determinarea
numărului de butoane ale mouse-ului instalat, folosiţi tot funcţia GetSystemMetrics:
cButtons = GetSystemMetrics (SM_CMOUSEBUTTONS) ;
Dacă în program sunt folosite atât butonul din stânga cât şi cel din dreapta al mouse-ului şi vreţi să permiteţi
folosirea programului şi de către utilizatorii care folosesc un mouse cu un singur buton, puteţi să scrieţi codul
astfel încât apăsarea tastei Shift în combinaţie cu butonul din stânga să fie echivalentă cu butonul din dreapta. În
acest caz, codul de prelucrare a mesajelor generate de mouse pentru acţionarea buloanelor ar trebui să arate astfel:
case WM_ LBUTTONDOWN
if (!MK_SHIFT & wParam)
{
[codul pentru butonul din stânga al mouse-ulul]
return 0 ;
}
// trece la următoarea secvenţa case, deoarece nu am folosit instrucţiunea break
case WM_RBUTTONDOMN
[codul pentru butonul din dreapta al mouse-ului]
return 0 ;
Funcţia GetKeyState va raporta că butonul din stânga al mouse-ului este apăsat numai dacă butonul era deja
apăsat atunci când a fost generat mesajul în timpul prelucrării căruia apelaţi funcţia GetKeyState.
Dublu clic cu mouse-ul
Dublu clic înseamnă să executaţi de două ori clic, într-o secvenţă rapidă. Pentru a se considera că s-a executat
dublu clic, cele două clicuri trebuie să fie executate într-un interval de timp numit „interval de dublu clic" („double
click time"). Dacă vreţi ca procedura de fereastră să primească mesajele generate de dublu clic, trebuie să includeţi
identificatorul CS_DBLCLKS în stilul ferestrei, atunci când definiţi structura clasei de ferestre, înaintea apelării
funcţiei RegisterClassEx:
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS
Veţi dezactiva toate mesajele de mouse trimise procedurii de fereastră pentru zona client şi pentru porţiunile
din afara zonei client. Butoanele mouse-ului nu vor mai funcţiona cât timp indicatorul mouse-ului se află în
fereastra dumneavoastră, inclusiv deasupra pictogramei meniului sistem, a butoanelor de redimensionare şi a
butonului pentru închiderea ferestrei.
Mesajele generează mesaje
Windows foloseşte mesajul WM_NCHITTEST ca să genereze alte mesaje de mouse. Ideea mesajelor care
generează alte mesaje este des întâlnită în Windows. După cum ştiţi, dacă executaţi dublu clic pe pictograma
meniului sistem a unui program Windows, execuţia acestuia se încheie. Executarea unui dublu clic generează o
Recepţionaţi un mesaj generat de un clic de mouse cu coordonatele cxMouse şi cyMouse. Puteţi să determinaţi
coloana indicată de utilizator folosind formula:
iColumn = cxMouse/cxColWidth ;
Evident, dacă valoarea iIndex depăşeşte numărul de fişiere din matrice, înseamnă că utilizatorul a executat
clic pe o zonă liberă de pe ecran.
În multe situaţii operaţiile de testare a poziţiei sunt mai complexe decât sugerează acest exemplu. Ele pot
deveni de-a dreptul încurcate într-un procesor de texte (cum ar fi WORDPAD) care foloseşte fonturi de
dimensiuni variabile. Atunci când afişaţi ceva în zona client, trebuie să determinaţi coordonatele fiecărui element
afişat. În calculele de verificare a poziţiei trebuie să porniţi de la coordonatele obiectului. Totuşi daca obiectul este
un şir de caractere, această operaţie implică determinarea poziţiei caracterului în şir.
Nu trebuie să determinaţi dacă mouse-ul este instalat înainte de apelarea funcţiei ShowCursor. Dacă vreţi să
afişaţi indicatorul mouse-ului indiferent dacă mouse-ul este prezent sau nu, incrementaţi contorul de afişare. În
cazul în care incrementaţi contorul o singură dată, după decrementare indicatorul va dispărea dacă mouse-ul nu
este instalat, dar va rămâne afişat dacă mouse-ul este instalat. Contorul de afişare este unic pentru toate programele
din Windows, aşa că trebuie să vă asiguraţi că îl incrementaţi şi îl decrementaţi de tot atâtea ori.
Puteţi să folosiţi în procedura de fereastră următoarea logică de prelucrare:
Procedura de fereastră primeşte mesajul WM_SETFOCUS atunci când fereastra obţine cursorul de intrare
(input focus) şi mesajul WM_KILLFOCUS atunci când pierde cursorul de intrare. Acestea sunt momentele cele
mai potrivite pentru afişaREA ŞI MASCAREA INDICATORULUI. ÎN PRIMUL RÂND, mesajele WM_SETFOCUS şi
WM_KILLFOCUS sunt transmise în număr egal - ceea ce înseamnă că procedura de fereastră va incrementa şi va
decrementa de tot atâtea ori contorul de afişare a indicatorului. În al doilea rând, pentru calculatoarele pe care nu
este instalat un mouse folosirea mesajelor WM_SETFOCUS şi WM_KILLFOCUS va determina afişarea
indicatorului numai atunci când fereastra dumneavoastră deţine cursorul de intrare. În acest fel, utilizatorul poate
să mute indicatorul mouse-ului folosind interfaţa cu tastatura pe care o proiectaţi.
Windows păstrează poziţia curentă a mouse-ului chiar dacă acesta nu este instalat. Dacă mouse-ul nu este
instalat şi afişaţi indicatorul, acesta poate apărea în orice punct al ecranului şi va rămâne acolo pană când îl mutaţi
în mod explicit. Puteţi să obţineţi poziţia indicatorului folosind funcţia GetCursorPos:
GetCursorPos (pPoint) ;
unde point este un pointer la o structură de tip POINT. Funcţia GetCursorPos completează câmpurile structurii
POINT cu coordonatele x si y ale mouse-ului. Puteţi să stabiliţi poziţia indicatorului folosind funcţia
SetCursorPos:
SetCursorPos (x, y) ;
În ambele cazuri, valorile x şi y reprezintă coordonate ecran, nu coordonate ale zonei clent. (Acest lucru ar
trebui să fie evident, deoarece funcţia nu primeşte un parametru hwnd). Aşa cum am arătat anterior, puteţi să
transformaţi coordonatele ecran în coordonate ale zonei client şi invers, folosind funcţiile ScreenToClient şi
ClientToScreen.
Dacă apelaţi funcţia GetCursorPos în timpul prelucrării unui mesaj generat de mouse şi transformaţi valorile
obţinute în coordonate ale zonei client, rezultatele obţinute s-ar putea să fie diferite de cele transmise prin
parametrul lParam al mesajului. Coordonatele returnate de funcţia GetCursorPos indică poziţia curentă a mouse-
ului, iar coordonatele transmise prin parametrul lParam indică poziţia mouse-ului în momentul generării
mesajului.
Probabil veţi dori să implementaţi o interfaţă cu tastatura care să permită deplasarea indicatorului mouse-ului
cu săgeţile de pe tastatură şi simularea butoanelor cu bara de spaţiu şi tasta Enter. Desigur, nu doriţi să mutaţi
indicatorul cu un singur pixel la fiecare apăsare de tastă. Aceasta ar obliga utilizatorul să ţină o tasta cu săgeată
apăsată mai mult de un minut ca să mute indicatorul mouse-ului dintr-o parte în alta a ecranului.
Dacă doriţi să implementaţi o interfaţă eficientă cu tastatura pentru indicatorul mouse-ului, dar să aveţi totuşi
posibilitatea să-l poziţionaţi cu precizie, trebuie să prelucraţi mesajele generate de acţionarea tastelor astfel încât
atunci când ţineţi apăsată o tastă, indicatorul să se deplaseze mai întâi încet, apoi din ce în ce mai repede. Vă
amintiţi că parametrul IParam al mesajului WM_KEYDOWN precizează dacă mesajul respectiv este rezultatul
autorepetării tastei apăsate. Aceasta poate fi o aplicaţie excelentă a informaţiei respective.
Adăugarea unei interfeţe cu tastatura la programul CHECKER
Programul CHECKER2, prezentat în Figura 6.6, este identic cu programul CHECKER1, exceptând faptul că
include şi o interfaţă cu tastatura. Puteţi să folosiţi săgeţile ca să deplasaţi indicatorul între cele 25 de
dreptunghiuri. Tasta Home trimite indicatorul în dreptunghiul din colţul din stânga-sus; tasta End îl trimite în
dreptunghiul din colţul din dreapta-jos. Tasta Enter şi bara de spaţiu au acelaşi rol: şterg sau afişează semnul X din
dreptunghiul în care se află indicatorul.
#include <windows.h> {
static char szAppName[] = "Checker2" ;
HWND hwnd ;
#define DIVISIONS 5 MSG msg ;
#define MoveTo(hdc, x, y) MoveToEx (hdc, x, y, NULL) WNDCLASSEX wndclass ;
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, wndclass.cbSize = sizeof (wndclass) ;
LPARAM) ; wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE wndclass.cbClsExtra = 0 ;
hPrevInstance, wndclass.cbWndExtra = 0 ;
PSTR szCmdLine, int iCmdShow) wndclass.hInstance = hInstance ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE while (GetMessage (&msg, NULL, 0, 0))
hPrevInstance, {
PSTR szCmdLine, int iCmdShow) TranslateMessage (&msg) ;
{ DispatchMessage (&msg) ;
static char szAppName[] = "Checker3" ; }
HWND hwnd ; return msg.wParam ;
MSG msg ; }
WNDCLASSEX wndclass ;
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg,
wndclass.cbSize = sizeof (wndclass) ; WPARAM wParam, LPARAM lParam)
wndclass.style = CS_HREDRAW | CS_VREDRAW ; {
wndclass.lpfnWndProc = WndProc ; static HWND hwndChild[DIVISIONS][DIVISIONS] ;
wndclass.cbClsExtra = 0 ; int cxBlock, cyBlock, x, y ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ; switch (iMsg)
wndclass.hIcon = LoadIcon (NULL, {
IDI_APPLICATION) ; case WM_CREATE :
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) for (x = 0 ; x < DIVISIONS ; x++)
; for (y = 0 ; y < DIVISIONS ; y++)
wndclass.hbrBackground = (HBRUSH) GetStockObject {
(WHITE_BRUSH) ; hwndChild[x][y] = CreateWindow (szChildClass,
wndclass.lpszMenuName = NULL ; NULL,
wndclass.lpszClassName = szAppName ; WS_CHILDWINDOW | WS_VISIBLE,
wndclass.hIconSm = LoadIcon (NULL, 0, 0, 0, 0,
IDI_APPLICATION) ; hwnd, (HMENU) (y << 8 | x),
(HINSTANCE) GetWindowLong (hwnd,
RegisterClassEx (&wndclass) ; GWL_HINSTANCE),
NULL) ;
wndclass.lpfnWndProc = ChildWndProc ; }
După apelarea funcţiei SetCapture, Windows trimite toate mesajele generate de mouse către fereastra indicată
de variabila handle hwnd. Mesajele trimise sunt generate pentru zona client a ferestrei, chiar dacă mouse-ul se află
în afara acesteia. Parametrul lParam indică poziţia indicatorului mouse-ului în coordonatele zonei client. Aceste
coordonate pot avea valori negative dacă mouse-ul se află în stânga sau deasupra zonei client a ferestrei.
După capturarea mouse-ului, funcţiile de sistem ale tastaturii sunt dezactivate. Atunci când doriţi să eliberaţi
mouse-ul, apelaţi funcţia ReleaseCapture:
ReleaseCapture () ;