m5k3ky
Input
Fiind un meniu prin excelenta interactiv, Windows-ul se bazeaza in mare parte pe dispozitivele de intrare, in primul rand pe tastatura si mouse. Aceasta obliga programatorii de aplicatie sa echipeze produsele lor cu un suport consistent pentru ambele. Stim deja cum functioneaza o aplicatie Windows. Ea primeste de la nucleu mesajele ce-i sunt adresate, intre care o categorie speciala o formeaza mesajele de intrare. Acestea pot fi clasificate dupa cum urmeaza:
hard- Tastatura: cand se actioneaza asupra tastelor
Mouse: cand se actioneaza asupra mouse-ului
Timer: cand a trecut o anumita fractiune de timp
soft- Caracter: mesajele de tastatura sunt translate pentru a produce caractere
Bare de defilare: intrarile sunt modificate folosind aceste bare si mouse-ul
Meniul: utilizatorul modifica intrarile folosindu-se de meniuri si de mouse
Tastatura
Cand utilizatorul apasa o tasta sau o elibereaza, driver-ul de tastatura transmite aceste evenimente nucleului Windows. Acesta construieste mesajele ce descriu aceste evenimente, pe care le plaseaza in coada sistem de unde vor fi transferate cozii aplicatiei care este activa in acel moment
(are "Input Focus", adica spre ea se focalizeaza fluxul evenimentelor
de intrare). Driver-ul de tastatura, keyboard.drv, este configurat inca de la instalarea Windows-ului pentru a suporta tipul specific de tastatura al calculatorului d-voastra. La fiecare lansare a Windows-ului el devine rezident in memorie si intercepteaza INT 09H. S-ar putea crede de aici ca aplicatiile
Windows ruleaza similar cu cele DOS care intercepteaza acesta intrerupere.
Acest lucru nu este adevarat deoarece fata de o aplicatie DOS care poate fi intrerupta aleator ( INT 09H - este o intrerupere asincrona ) pentru tratarea tastaturii, mecanismul de lucru cu mesaje din Windows presupune urmatoarea succesiune de actiuni: intreruperea cauzata de apasarea sau eliberarea tastei lanseaza un modul al driver-lui de tastatura care decodeaza tasta si apeleaza apoi modulul User din nucleu. Aceasta construieste structura de mesaj corespunzatoare si depune mesajul in coada sistem, dupa care detecteaza aplicatia activa si-l depune si in coada ei. Aplicatia interogheaza coada de mesaje prin functia GetMessage() din bucla de mesaje si mesajul corespunzator evenimentului de tastatura va fi translatat si apoi dispecerizat catre procedura ferestrei. Lucrurile par iarasi similare cu o aplicatie DOS ce ar folosi INT 16H sau 21H, dar si in acest caz presupunerea nu este corecta deoarece cantitatea de informatie disponibila printr-un mesaj Windows este mult mai mare.
Se va vedea mai incolo care este aceasta informatie.
Pana atunci, mai trebuie clarificat un aspect. Tastatura poate fi privita in 2 feluri:
-ca o colectie de "butoane" ce pot fi actionate prin apasare si prin
eliberare.
-ca un dispozitiv ce produce caractere ce vor fi afisate pe ecran.
Mesaje de actionare taste
Prima observatie este mai mult de natura hard si in legatura cu ea avem cele 4 mesaje:
WM_KEYDOWN,
WM_KEYUP,
WM_SYSKEYDOWN si
WM_SYSKEYUP.
Primele 2 sint pentru activarea prin apasare, respectiv eliberare a unei taste, iar celelalte 2 se refera la aceleasi actiuni doar ca tasta ALT este apasata - in general lansarea de comenzi de meniuri, acceleratori, Alt + Tab,
Alt + ESC si alte asemenea combinatii utilizate in Windows. Particula SYS vine dupa cum se banuie de la "system" - adica combinatii mai importante
pentru nucleul Windows decat pentru aplicatia propriu-zisa.
Din structura unui mesaj prezentata la analiza buclei de mesaje, s-a spus atunci ca lParam si wParam sunt parametri ce contin informatii specifice mesajului.
Sa-i explicitam acum in cazul celor 4 mesaje : lParam cuprinde in cei 32 de
biti ai sai 6 campuri.
ÉIIIIIIIIÑIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII»
º Bit ³ Semnificatie º
ÇAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º 31 ³ Stare tranzit, tasta a fost:0 apasata, 1 eliberata º
ÇAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º 30 ³ Stare anterioara, tasta a fost:0 sus, 1 jos º
ÇAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º 29 ³ Context, este apasat si ALT º
ÇAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º 28..25 ³ rezervati º
ÇAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º 24 ³ tasta din grupul extins (tastatura AT 101/102) º
ÇAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º 23..16 ³ Scan code º
ÇAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º 15..0 ³ Contor repetitii º
ÈIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII¼ tabel 1
Desi lParam cuprinde multe informatie, totusi wParam este mult mai important in aceste mesaje. In wParam se depune asa-numitul cod virtual al tastei -virtual key code. Acesta provine dintr-un tabel pus la dispozitie de
windows.h. Cateva exemple din acest tablou sunt prezentate in continuare.
ÉIIIIIIIIIÑIIIIIIÑIIIIIIIIIIIIIIIÑIIIIIIIIIIIIIII»
º Zecimal ³ Hexa ³ Identificator ³ Tasta º
ÇAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º 1 ³ 01 ³ VK_LBUTTON ³ º
ÇAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º 2 ³ 02 ³ VK_RBUTTON ³ º
ÇAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º 3 ³ 03 ³ VK_CANCEL ³ CTRL+BREAK º
ÇAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º 4 ³ 04 ³ VK_MBUTTON ³ º
ÇAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º 13 ³ 0D ³ VK_RETURN ³ ENTER º
ÇAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º 16 ³ 10 ³ VK_SHIFT ³ SHIFT º
ÇAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º 17 ³ 11 ³ VK_CONTROL ³ CTRL º
ÇAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º 18 ³ 12 ³ VK_MENU ³ ALT º
ÈIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII¼ tab 2
Se observa ca nu toate codurile au corespondenta pe tastatura. In fapt
VK_LBUTTON, _MBUTTON si _RBUTTON sunt produse de mouse. Trebuie sa vedeti aceste coduri ca o incercare a realizatorilor Windows de a creea un dispozitiv de intrare independent.
Recomandari pentru folosirea mesajelor de actionare taste:
-in general mesajele WM_SYSKEYUP, WM_SYSKEYDOWN sunt lasate spre tratare functiei DefWinProc().
-daca dorim sa tratam tastatura WM_KEYDOWN este suficient pentru o procesare
sumara.
-in cazul in care dorim sa cunoastem starea unor taste cu functia
GetKeyState(VK_...) putem determina starea de apasare a unei taste virtuale
(retur cu valoarea negativa reprezinta tasta apasata). Deoarece asa cum s-a
mai aratat driverul functioneaza independent de aplicatie daca se doreste cunoasterea la un moment dat a adevaratei stari a unei taste va trebui sa folosim
GetAsyncKeyState ( VK_...)
-in proiectarea unei interfete bune pentru o aplicatie, este bine sa folosim cit mai mult acceleratorii si cit mai putin supravegherea directa prin tratarea, de exemplu, a mesajului WM_KEYDOWN. Totusi daca aceasta este necesara e bine ca in prealabil sa fim familiarizati cu specificatiile CUA - Common
User Access: Advance Interface Design Guide - recomandari de uz general in privinta interfetei, pentru ca utilizatorul aplicatiilor Windows sa poata sa se familiarizeze rapid cu o noua aplicatie.
Mesaje de caracter
Aplicatia care are nevoie de caractere de la tastatura trebuie sa foloseasca in bucla de mesaje functia TranslateMessage(). Aceasta functie interpreteaza mesajul WM_KEYDOWN sau WM_SYSKEYDOWN si in conformitate cu starea celorlalte taste de "alterare" se obtine codul ASCII al caracterului corespunzator. Acest cod este livrat aplicatiei prin parametrul wParam al noului mesaj construit:
WM_CHAR sau WM_SYSCHAR.
La o apasare-eliberare a unei taste se trimit deci catre functia ferestrei
3 mesaje in ordinea: mesaj wParam
WM_KEYDOWN cod virtual
WM_CHAR caracterul ASCII
WM_KEYUP cod virtual
In afara de mesajele WM_CHAR, respectiv _SYSCHAR mai exista doua mesaje de caracter WM_DEADCHAR si respectiv WM_SYSDEADCHAR. Aceste mesage sunt obtinute la folosirea unor tastaturi cu specific national, deci care au simboluri diacritice atasate unor caractere normale. Caracter mort-DEADCHAR vine de la modul in care se obtine o litera cu diacritice. Windows lucreaza
in felul urmator: la apasarea unui simbol diacritic (de exemplu) se genereaza mesajul WM_DEADCHAR cu codul ASCII pentru acel simbol. Apoi cind utilizatorul apasa litera careia ii este atasat diacriticul, de exemplu ƒ, se genereaza mesajul WM_CHAR cu codul ASCII pentru ƒ. Acest mecanism pune in evidenta faptul ca in mod normal nu este necesara tratarea mesajelor WM_DEADCHAR.
Procedura aceasta apelata de TranslateMessage si rezidenta in driver-ul de tastatura are inclusiv o verificare de corectitudine, caci daca nu exista caracterul cu diacritic se vor genera doua mesaje WM_CHAR corespunzatoare celor doua simboluri ca si caractere separate.
Atentie :
Poate ca puterea mesajelor _SYS... nu vi se pare evidenta. Priviti atunci codul urmator:
... case WM_SYSKEYDOWN: case WM_SYSKEYUP: case WM_SYSCHAR: return 0;
Daca acesta nu este prezent in procedura ferestrei dumneavoastra, orice incercare de a mai folosi combinatii de taste sistem va esua (exceptie facind evident CTRL+ALT+DEL).
Citeva aspecte in scrierea unui editor
Acest scurt paragraf este menit sa familiarizeze cu o notiune noua
- caret sau cursor text. Daca pina acum prompterul -liniuta clipitoare care
va asteapta sa introduceti text- s-a numit cursor, sub Windows ea se numeste caret.
Cursorul ramine doar acel mic desen alb-negru ce marcheaza pe ecran pozitia mouse-ului. Pentru a putea gestiona acest indicator exista definite citeva functii :
CreateCaret creaza un caret(care initial nu este vizibil)
DestroyCaret- distruge un caret creat in prealabil
HideCaret- ascunde caret-ul
ShowCaret- face vizibil caret-ul
SetCaretPos- pozitioneaza caret-ul in fereastra
GetCaretPos- gaseste pozitia caret-ului
SetCaretBlinkTime- fixeaza factorul de blinking a caret-ului
GetCaretBlinkTime- gaseste factorul de blinking a caret-ului
Deoarece in timpul lucrului doar o fereastra poate fi activa si cu focalizare (Input-focus) nucleul gestioneaza un singur caret. Mesajul
WM_SETFOCUS anunta procedura ca a primit input-focus. In cadrul tratarii acestui mesaj trebuie creat un caret si afisat. Cind procedura primeste
WM_KILLFOCUS ea pierde focus-ul si aici trebuie distrus caret-ul.
Atunci cind se doreste desenarea in fereastra, de exemplu la un mesaj WM_PAINT, caret-ul trebuie ascuns si apoi reafisat.
Seturile de caractere sub Windows
Pentru a putea intelege complet mecanismele interfetei cu tastatura trebuie aprofundata aceasta problema. Am precizat in laboratorul trecut, ca
una din resursele unui program Windows este font-ul, pe care l-am apelat atunci cu sintagma "set de caractere". Apelativul a fost in acel moment suficienta,
dar are un caracter aproximativ.
Set de caractere reprezinta multimea codurilor atasate univoc simbolurilor unei scrieri pe cind font-ul in acceptiunea Windows reprezinta
un tip de corp de litera, adica stilul grafic al simbolurilor.
Cind s-a vorbit de WM_CHAR s-a spus ca acesta aduce codul ASCII al caracterului. Nici aceasta informatie nu este perfect adevarata. Dupa cum stiti codul ASCII este un cod pe sapte biti, cuprinzind pentru valorile 0-1F si 7F
caractere de control (neafisabile), iar intre 20-7E caractere afisabile.
Producatorii de calculatoare au extins acest cod la 8 biti, asa incit in spatiul 7F-FF au putut fi inserate si caracterele speciale sau literele cu diacritice. Cum modelul a fost impus de IBM-PC, setul de caractere conceput
de
IBM a devenit standard pentru majoritatea calculatoarelor din familie. Dar in acele timpuri, in pagina extinsa, erau mult mai necesare caracterele cu care
sa se poata "desena" in mod text chenare, sau litere grecesti, pe cind
Windows este o suprafata grafica si nu are nevoie de acest suport. In plus setul IBM standard cuprindea prea putine caractere cu diacritice. Din aceste motive
Microsoft a conceput pentru Windows un alt set de caractere.
Iata deci ca in loc de un set de caractere avem doua. Primul este raportat de Windows pe considerente istorice si de compatibilitate cu aplicatiile DOS. El se numeste OEM character set (Original Equipement
Manufactured)- fiind deci setul original al calculatorului pe care ruleaza
Windows. Cel de-al doilea este numit ANSI character set (American National
Standard Institute), acesta fiind setul natural cu care lucreaza Windows.
Cind in primul exemplu de program s-a obtinut un device context contextul dispozitivului de iesire, pentru a desena textul "Salut Windows!" acesta cuprindea printre alte atribute ale sale si fontul cu care urma sa apara textul. In mod implicit acesta este SYSTEM_FONT care foloseste setul ANSI.
Daca am fi dorit ca acesta sa apara cu setul OEM, ar fi trebuit sa selectam acest lucru prin
SelectObject(hDc,GetStockObject(OEM_FIXED_FONT));
Atentie insa la caracterele cu diacritice. Deoarece acestea pot fi obtinute doar din setul ANSI este bine ca setul OEM sa fie cit mai rar folosit. Altfel putem avea surpriza ca in loc de un astfel de caracter sa apara un cu totul alt simbol.
Deoarece in setul ANSI caracterele diacritice nu respecta neaparat regula majuscula+20h=minuscula, pentru o conversie corecta din una in alta este recomandabil sa folositi functiile :
AnsiUpper(pszString); conversie sir terminat cu zero
AnsiUpperBuff(pString,nLenght); conversie sir pe lungime data
AnsiUpper((LPSTR)(LONG)(BYTE)ch); conversia unui caracter precum si echivalentele AnsiLower si AnsiLowerBuff.
Pentru o conversie intre cele doua seturi de caractere exista functiile :
OemToAnsi(lpszOemStr,lpszAnsiStr); si
AnsiToOem(lpszAnsiStr,lpszOemStr);
Aceste functii sint impementate in driver-ul de tastatura al Windows.
Ele sint folosite implicit si atunci cind se tasteaza codul unui caracter din setul extins folosindu-se ALT+taste numerice. Daca se tasteaza ALT+acodi se apeleaza OemToAnsi pentru a face o conversie cit mai buna a paginii extinse
OEM in pagina extinsa ANSI. Daca se foloseste conventia Windows pentru acest gen de introducere caracter ALT+O+acodi se obtine caracterul ANSI.
Mouse-ul
Chiar daca mouse-ul este considerat ca o parte importanta a interfetei utilizator, el nu este obligatoriu. Windows-ul se poate instala foarte bine
si fara mouse, iar aplicatiile pot fi utilizate, desi mai putin comod de la tastatura. Prezenta unui mouse poate fi detectata folosind functia:
GetSystemMetrics(SM_MOUSEPRESENT);
Rezultatul este TRUE(!=0) daca mouse-ul este prezent. Totusi nu exista posibilitatea de a afla cite butoane are mouse-ul (unu,doua sau trei).
Citeva consideratii generale:
-mouse-ul este un dispozitiv indicator simbolizat pe ecran prin cursorul mouse-ului (prezentat in lab de resurse). Acest cursor are un punct cald hotspot-a carui coordonate sint de fapt pozitia cursorului.
-operatiile pe care le poate executa mouse-ul:
-miscarea in planul ecranului
-clic -apasarea si eliberarea unui buton
-dublu clic -doua clicuri in succesiune rapida
-tragere -miscarea mouse-ului cu un buton apasat.
La un mouse cu trei butoane aceste se numesc LBUTTON(left - stinga),
MBUTTON (middle - mijloc) si RBUTTON(right - dreapta). In ceea ce priveste zona din fereastra aplicatiei in care se produce un eveniment cauzat de mouse, avem doua regiuni distincte:
-cea in care se lucreaza -zona de lucru sau client
-restul(titlul, bordura, buton max, min etc.) numita zona sistem sau non client (NC). Mesajele produse de mouse sunt :
ÉIIIIIIIIÑIIIIIIIIÑIIIIIIIIIIIIIIIIÑIIIIIIIIIIIIIIÑIIIIIIIIIIIIIIIIII»
º Zona ³ Buton ³ Apasat ³ Eliberat ³ Dublu apasat º
ÇAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º client ³ stinga ³ VM_LBUTTONDOWN ³ WM_LBUTTONUP ³
WM_LBUTTONDBLCLK º
º AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º ³ mijloc ³ VM_MBUTTONDOWN ³ WM_MBUTTONUP ³ WM_MBUTTONDBLCLK
º
º AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º ³ dreapta³ VM_RBUTTONDOWN ³ WM_RBUTTONUP ³ WM_RBUTTONDBLCLK
º
º AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º ³ WM_MOUSEMOVE º
ÇAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º non ³ stinga ³VM_NCLBUTTONDOWN³WM_NCLBUTTONUP³WM_NCLBUTTONDBLCLKº
º client AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º ³ mijloc ³VM_NCMBUTTONDOWN³WM_NCMBUTTONUP³WM_NCMBUTTONDBLCLKº
º AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º ³ dreapta³VM_NCRBUTTONDOWN³WM_NCRBUTTONUP³WM_NCRBUTTONDBLCLKº
º AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¶
º ³ WM_NCMOUSEMOVE º
º ³ WM_NCHITTEST º
ÈIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII¼ tab 3
Pentru toate mesajele de mouse valoarea din lParam contine pozitia mouse-ului (mai precis a punctului cald al cursorului). Structura POINT pt poate fi incarcata cu aceste valori de exemplu: pt=MAKEPOINT(lParam); sau cu ajutorul macrourilor LOWORD si HIWORD pentru separarea unui long; pt.x=LOWORD(lParam); pt.y=HIWORD(lParam);
Parametrul wParam contine flag-uri de stare a butoanelor si tastelor ce se folosesc in conjunctie cu mouse-ul. Aceste valori sint:
MK_LBUTTON buton stinga apasat
MK_MBUTTON buton mijloc apasat
MK_RBUTTON buton dreapta apasat
MK_SHIFT tasta SHIFT apasata
MK_CONTROL tasta CONTROL apasata
Mesajele de mouse referitoare la butoanele apasate sint clare si nu necesita comentarii suplimentare. La o miscare a mouse-ului in zona client procedura ferestrei respective primeste mesajul WM_MOUSEMOVE. Acest mesaj nu este generat pentru fiecare noua pozitie, frecventa lui depinzind de tipul mouse-ului.
Mesajele de clic dublu - double click - sint directionate spre functia ferestrei doar daca aceasta apartine unei clase definite cu stilul CS_DBLCLKS.
Un clic dublu va provoca urmatoarea succesiune de mesaje :
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDBLCLK (inlocuieste al doilea LBUTTONDOWN )
WM_IBUTTONUP
Mesajele corespunzatoare zonei non-client sint in general lasate spre procesare functiei DefWinProc. La acestea coordonatele trimise in lParam sint relative la ecran, spre deosebire de mesajele din zona client care sint relative la coltul stinga-sus al acesteia. Exista posibilitatea unei conversii dintr-un sistem de coordonate in celalalt prin intermediul functiilor:
ScreenToClient (lWnd,lpPoint);
ClientToScreen (lWnd,lpPoint);
Parametrul wParam are si el semnificatia schimbata. El desemneaza printr-un identificator partea zonei non-client in care s-a produs evenimentul de mouse. Astfel avem HTCAPTION,HTSYSMENU,etc.
Mesajul WM_NCHITTEST este poate cel mai special. El precede orice alt nesaj de mouse ce este trimis unei proceduri de ferastra. De obicei aplicatiile il lasa spre procesare functiei DefWinProc. Acest mesaj are in wParam un identificator ce poate fi oricare din cei ai mesajelor non-client sau unul din urmatoarele:
HTCLIENT zona client
HTNOWHEARE nici intr-o fereastra
HTTRANSPARENT intr-o fereastra acoperita de alta fereastra
HTERROR DefWinProc va produce un beep.
Dupa prelucrarea mesajului procedura trebuie sa returneze wParam-ul mesajului. Daca de exemplu aceasta a fost HTCLIENT, nucleul Windows va face conversia coordonatelor de ecran in coordonare de zona client pentru mesajul de mouse ce va fi depus in coada aplicatiei.
Atentie:
Si utilizarea mouse-ului poate fi blocata total daca aveti undeva in procedura: case WM_NCHITTEST: return (long) HITNOWHERE;
Functii suport pentru mouse:
Cursorul mouse-ului poate fi ascuns sau afisat - chiar independent de prezenta unui mouse - prin incrementarea sau decrementarea unui contor de afisari. Aceste operatii se pot face prin:
ShowCursor(TRUE) ; incrementare
ShowCursor(FALSE) ; decrementare
Pozitia pe ecran poate fi aflata si eventual modificata (coordonatele sunt relative la ecran) prin:
GetCursorPos(lpPoint);
SetCursorPos(x,y);
O fereastra poate primi mesaje de mouse daca cursorul se gaseste undeva in zona sa client sau non-client. Daca aplicatia are nevoie de mesajele de mouse si in afara spatiului ei, ea poate "captura" mouse-ul si apoi sa-l
elibereze.
Aceasta este posibil prin : SetCapture(hWnd); coordonatele din lParam sunt tot timpul relative la zona client.
ReleaseCapture();
Timer-ul
Considerati timerul ca un dispozitiv periferic ce informeaza permanent aplicatia ca a trecut un interval specific de timp. Desi pare putin important, iata in continuare citeva lucruri ce se pot face cu el:
-contorizarea timpului (de exemplu aplicatia Clock)
-intretinerea si completarea unor rapoarte de urmarire si/sau stare
-anunt, alarma (de exemplu Calendar)
-multitasking - folositor unei aplicatii care are mult de procesat si careia i se poate imparti lucrul pe fragmente executate la cite o cuanta de timp.
-implementarea unor aplicatii de autosalvare sau lansarea la o ora fixa a unor activitati
-temporizarea derularii cadrelor intr-o animatie sau prezentare
-utilizarea comunicatiilor seriala si paralela, care in windows nu mai produc intreruperi la evenimente de interfata trebuind deci sa fie interogate regulat
-multe altele...
Notiuni de baza relativ la utilizarea timerului
Alocarea unui timer la o aplicatie se face cu functia SetTimer() iar renuntarea la el cu functia KillTimer(). Unul din parametrii functiei de setare specifica ce marime va avea intervalul de timp dupa care aplicatia va primii
un mesaj WM_TIMER. Deoarece unitatea de masura este ms, putem teoretic programa intervale de la 1ms la 65535ms (aproximativ 1 min.). Lucrurile stau asa doar teoretic deoareca, practic, avem urmatoarea situatie. Cind Windows-ul se incarca el aduca in memorie System.drv-driverul care intre altele intercepteaza INT 08H. Deoarece el nu reprogrameaza circuitul hard, rezolutia acestuia ramine, ca si in DOS, de 54,925ms. De aici rezulta ca pentru orice interval programat la mai putin de 55ms se obtine doar un WM_TIMER deci pe secunda avem 18 astfel de mesaje.
Mesajul de timer este produs de nucleu intr-o maniera similara cu cel de la tastatura. Ca si acolo, evenimentul desi asincron-sau mai bine zis izocron, caci apare la intervale regulate-fata de derularea aplicatiei, nu intrerupe aplicatia ci "impachetat" sub forma de mesaj asteapta in
coada aplicatiei sa fie citit de acesta. Deoarece Windows-ul este nonpreemptiv el lucreaza doar atunci cind aplicatiile lansate au bunavointa sa cedeze controlul (de exemplu cind apeleaza functii ca GetMessage, PeekMessage,
WaitMessage sau Yield) deci daca un program are o procesare costisitoare ca timp, e foarte posibil ca unele mesaje WM_TIMER sa nu fie generate. Pierderea unor astfel de mesaje nu este chiar o tragedie deoarece exista metode de a recupera intirzierile provocate de absenta lor. In sens invers, daca o aplicatie nu-si ia mesajele din linia de asteptare, nucleul reuneste toate mesajele WM_TIMER intr-unul singur, de o maniera similara cu ceea ce se intimpla la WM_KEYDOWN, doar ca aici nu exista contor de repetitii.
Mesajele WM_TIMER sint de prioritate scazuta ca si WM_PAINT. Aceasta inseamna ca daca o aplicatie are un mesaj WM_TIMER in coada si o alta face cerere deodata cu prima pentru a obtine si ea un mesaj din propria coada
(dar nu WM_TIMER sau WM_PAINT) ea va avea prioritate la primirea controlului.
Functii de timer
SetTimer(HWND hWnd, WORD wTimerID, WORD wInterval, CALLBACK lpTimerFunc);
Functia seteaza un timer (daca nucleul o permite, caci pot fi pornite la un moment dat max 16 timere) care va avea identiticatorul
wTimerID si va genera WM_TIMER la intervale de wInterval ms. Daca ultimul parametru este NULL, nucleul va genera mesajul si il va directiona cind dispecerizeaza mesajele spre procedura ferestrei hWnd. In acest caz deci primul parametru nu poate fi NULL iar daca al doilea este NULL, functia va returna identificatorul timer-ului setat. Daca ultimul parametru -far pointer la o functie de tip callback- este diferit de NULL, el reprezinta adresa functiei ce va fi apelata, in locul procedurii ferestrei, pentru a executa codul atasat de eveniment. Vom reveni cu detalii asupra functiilor callback intr-un
laborator urmator.
KillTimer(HWND hWnd, WORD wTimerID); functia elimina timerul cu identificatorul wTimerID, atasat ferestrei hWnd.
Aplicatia
Programul captureaza o zona oarecare si o mareste la spatiul ferestrei aplicatiei.
//******************************************************************
//
//program -w3.c
//scop -Exemplu de utilizare input-uri
// sub Windows.
//
//******************************************************************
#include <windows.h>
#include "w3.h>
char szAppNameai="Exemplu intrari"; char Titlua32i;
HANDLE hInst,hAccel;
long FAR PASCAL WinMain(HWND,WORD,WORD,LONG);
BOOL FAR PASCAL Despre(HWND,WORD,WORD,LONG);
int PASCAL WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,int cmdShow)
A
HWND hWnd;
MSG msg;
WNDCLASS wndClass;
hInst=hInstance; if(!hPrevInstance)A
wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wndClass.lpszClassName = szAppName;
wndClass.lpfnWndProc = WndProc;
wndClass.cbClsExtra = 0;
wndClass.CbWndExtra = 0;
wndClass.hInstance = hInst;
wndClass.hIcon = LoadIcon(hInst,"Iconul");
wndClass.hCursor = LoadCursor(hInst,"Cursorul");
wndClass.lpszMenuName = "Meniul";
wndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&wndClass);
S
hWnd = CreateWindow(szAppName,"Exemplu de intrari",
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);
ShowWindow(hWnd,cmdShow);
UpdateWindow(hWnd);
while(!SetTimer (hWnd,ID_TIMER,500,NULL)) if(IDCANCEL == MessageBox
(hWnd,"Nu exista timer disponibil !",szAppName,MB_ICONEXCLAMATION
|
MB_RETRYCANCEL)) return FALSE;
hAccel = LoadAccelerators(hInst,"Acceleratori");
while(GetMessage(&msg,NULL,0,0))A if(!TranslateAccelerator(hWnd,hAccel,&msg))A
TranslateMessage(&msg);
DispatchMessage(&msg);
S
S
return(msg.wParam);
S
void InvertBlock(HWND hWnd,POINT ptLT,POINT ptRB)
A
HDC hDC;
hDC = CreateDC("DISPLAY",NULL,NULL,NULL);
ClientToScreen(hWnd,&ptLT);
ClientToScreen(hWnd,&ptRB);
PatBlt(hDC,ptLT.x,ptLT.y,ptRB.x-ptLT.x,ptRB.y-ptLT.y,DSTINVERT);
DeleteDC(hDC);
S
long FAR PASCAL WndProc(HWND hWnd,WORD message,WORD wParam,LONG lParam)
A
FARPROC fpDespre;
HDC hDC;
RECT rect; static BOOL fCapt,fBlock,fSpeed=TRUE; static POINT pt,ptLT,ptRB; static BYTE Speed=1;
switch(message)A
//Interfata cu mouse-ul case WM_LBUTTONDOWN: if(!fCapt)A fCapt = TRUE;
SetCapture(hWnd);
SetCursor(LoadCursor(NULL,IDC_CROSS));
SendMessage(hWnd,WM_ERASEBKGND,hDC);
ReleaseDC(hWnd,hDC); break; case IDM_DESPRE: fpDespre=MakeProcInstance(Despre,hInst);
DialogBox(hInst,"Despre",hWnd,fpDespre);
FreeProcInstance(fpDespre); break; case IDM_EXIT:
DestroyWindow(hWnd); break;
S break;
//Timer si alte mesaje case WM_TIMER: if (fSpeed)
Speed++; break; case WM_DESTROY:
KillTimer(hWnd,ID_TIMER);
PostQuitMessage(0); break; default: return(DefWindowProc(hWnd,message,wParam,lParam))
S return 0L;
S
BOOL FAR PASCAL Despre (HWND hDlg,WORD message, WORD wParam,LONG lParam)
A switch (message)A case WM_COMMAND: switch(wParam)A case IDOK: case IDCANCEL:
EndDialog(hDlg,NULL); break;
S break; default: return (FALSE);
S return (TRUE);
S
// w3.rc
------------------------------------------------------------------- #include "w3.h"
Iconul ICON "icon.ico"
Cursorul CURSOR "cursor.cur"
Meniul MENU
BEGIN
POPUP "&Meniu"
BEGIN
POPUP "&Viteza variabila"
BEGIN
MENUITEM "&Da",IDM_VV,CHECKED
MENUITEM "&NU",IDM_VN
END
MENUITEM "&Sterge fereastra",IDM_STERGE
MENUITEM SEPARATOR
MENUITEM "&Despre aplicatie",IDM_DESPRE
MENUITEM SEPARATOR
MENUITEM "E&xit",IDM_EXIT
END
END
Despre DIALOG 57,37,101,46
STYLE DS_MODALFRAME|WS_POPUP|WS_CAPTION|WS_SYSMENU
CAPTION "Despre aplicatie ..."
FONT 10,"System"
BEGIN
ICON "Iconul",-1,4,8,16,16,WS_CHILD|WS_VISIBLE
CTEXT "Exemplu la soc11.txt\nProgramare Windows",-1,24,9,68,16,WS_CHILD|
WS_VISIBLE|WS_GROUP
PUSHBUTTON "Da",IDOK,3,30,96,14,WS_CHILD|WS_VISIBLE|WS_TABSTOP
END
// w3.def
------------------------------------------------------------------- NAME Input
DESCRIPTION "Demonstratie de intrari"
EXETYPE WINDOWS
STUB "WINSTUB.EXE"
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE
HEAPSIZE 1024
STACKSIZE 8192
EXPORTS WndProc
// w3.h
--------------------------------------------------------------------
#define IDM_VV 101
#define IDM_VN 105
#define ID_TIMER 100
#define IDM_VITEZA 101
#define IDM_STERGE 102
#define IDM_DESPRE 103
#define IDM_EXIT 104