Zoom Icon

Tutorial 7: Input dal Mouse

From UIC

Tutorial 7: Input dal mouse

Contents


Tutorial 7: Input dal Mouse
Author: Iczelion
Email: Traduttore: -NeuRaL_NoiSE
Website: Mirror
Date: 01/01/2001 (dd/mm/yyyy)
Level: Working brain required
Language: Italian Flag Italian.gif
Comments:



Introduzione

Impareremo come ricevere input dal mouse e rispondervi nella nostra window procedure. Il programma esempio attendera' i clicks del tasto sinistro del mouse e mostrera' una stringa di testo nel punto esatto della client area in cui l'utente ha clickato.

Preliminari

Come con l'input da tastiera, Windows rileva e notifica le attivita' del mouse che sono rilevanti per ciascuna finestra. Tali attivita' includono clicks del tasto sinistro e destro, movimenti del puntatore nella finestra, doppi clicks. Diversamente dall'input da tastiera che e' diretto alla finestra che detiene l'input focus, i messaggi del mouse sono inviati a qualsiasi finestra su cui si trova il puntatore del mouse, sia essa attiva o non. In piu', ci sono messaggi del mouse relativi anche alla non-client area. Ma la maggior parte delle volte, possiamo tranquillamente ignorarli. Possiamo focalizzare la nostra attenzione su quelli relativi alla client area. Per ciascun tasto, sinistro e destro, del mouse, ci sono due messaggi associati: WM_LBUTTONDOWN, WM_RBUTTONDOWN e WM_LBUTTONUP, WM_RBUTTONUP. Per un mouse a tre tasti, ci sono in piu' WM_MBUTTONDOWN e WM_MBUTTONUP. Quando il puntatore del mouse si muove all'interno della client area, Windows manda messaggi WM_MOUSEMOVE alla finestra relativa. Una finestra puo' ricevere messaggi di doppio click, WM_LBUTTONDBCLK o WM_RBUTTONDBCLK, se e solo se la sual window class e' stata istruita a riceverli, tramite l'inclusione della flag CS_DBLCLKS nel class style, altrimenti la finestra ricevera' soltanto una serie di "mouse button up" e "mouse button down". Per tutti questi messaggi, il valore di lParam equivale alla posizione del mouse. La low word e' la coordinata x, e la high word e' la coordinata y, relative all'angolo superiore sinistro della client area della finestra. wParam indica lo stato dei tasti del mouse e dei tasti Shift e Ctrl.

Contenuto

include windows.inc
includelib user32.lib
includelib kernel32.lib
includelib gdi32.lib
.data
ClassName db "SimpleWinClass",0
AppName  db "Our First Window",0
MouseClick db 0         ; 0=non si e' ricevuto ancora nessun click
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hitpoint POINT <>
.code
start:
    invoke GetModuleHandle, NULL
    mov    hInstance,eax
    invoke GetCommandLine
    invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
    invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:SDWORD
    LOCAL wc:WNDCLASSEX
    LOCAL msg:MSG
    LOCAL hwnd:HWND
    mov   wc.cbSize,SIZEOF WNDCLASSEX
    mov   wc.style, CS_HREDRAW or CS_VREDRAW
    mov   wc.lpfnWndProc, OFFSET WndProc
    mov   wc.cbClsExtra,NULL
    mov   wc.cbWndExtra,NULL
    push  hInstance
    pop   wc.hInstance
    mov   wc.hbrBackground,COLOR_WINDOW+1
    mov   wc.lpszMenuName,NULL
    mov   wc.lpszClassName,OFFSET ClassName
    invoke LoadIcon,NULL,IDI_APPLICATION
    mov   wc.hIcon,eax
    mov   wc.hIconSm,0
    invoke LoadCursor,NULL,IDC_ARROW
    mov   wc.hCursor,eax
    invoke RegisterClassEx, addr wc

    invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
           WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
           CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
           hInst,NULL

    mov   hwnd,eax
    invoke ShowWindow, hwnd,SW_SHOWNORMAL
    invoke UpdateWindow, hwnd
    .WHILE TRUE
                invoke GetMessage, ADDR msg,NULL,0,0
                .BREAK .IF (!eax)
                invoke DispatchMessage, ADDR msg
    .ENDW
    mov     eax,msg.wParam
    ret
WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    LOCAL hdc:HDC
    LOCAL ps:PAINTSTRUCT
    mov   eax,uMsg
    .IF eax==WM_DESTROY
        invoke PostQuitMessage,NULL
    .ELSEIF eax==WM_LBUTTONDOWN
        mov eax,lParam
        shl eax,16
        shr eax,16
        mov hitpoint.x,eax
        mov eax,lParam
        shr eax,16
        mov hitpoint.y,eax
        mov MouseClick,TRUE
        invoke InvalidateRect,hWnd,NULL,TRUE
    .ELSEIF eax==WM_PAINT
        invoke BeginPaint,hWnd, ADDR ps
        mov    hdc,eax
        .IF MouseClick
            invoke lstrlen,ADDR AppName
            invoke TextOut,hdc,hitpoint.x,hitpoint.y,ADDR AppName,eax
        .ENDIF
        invoke EndPaint,hWnd, ADDR ps
    .ELSE
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        ret
    .ENDIF
    xor    eax,eax
    ret
WndProc endp
end start

E' ora di analizzare il programma.

.ELSEIF eax==WM_LBUTTONDOWN
    mov eax,lParam
    and eax,0FFFFh ; comment
    mov hitpoint.x,eax
    mov eax,lParam
    shr eax,16
    mov hitpoint.y,eax
    mov MouseClick,TRUE
    invoke InvalidateRect,hWnd,NULL,TRUE

La window procedure attende un click dal tasto sinistro del mouse. Quando riceve il messaggio WM_LBUTTONDOWN, lParam contiene le coordinate del puntatore del mouse nella client area. Le coordinate vengono salvate in una variabile di tipo POINT che e' definita cosi':

POINT STRUCT
    x   dd ?
    y   dd ?
POINT ENDS

e cambia la flag, MouseClick, in TRUE, a significare che c'e' stato almeno un click del tasto sinistro del mouse nella client area.

mov eax,lParam
        and eax,0FFFFh
        mov hitpoint.x,eax

Poiche' la coordinata x e' la low word di lParam e i membri della struttura POINT sono a 32-bits come dimensioni, noi dobbiamo azzerare la high word di eax prima di conservarla in hitpoint.x.

shr eax,16
        mov hitpoint.y,eax

E poiche' la coordinata y e' la high word di lParam, dobbiamo metterla nella low word di eax prima di conservarla in hitpoint.y. Facciamo cio' spostando (shifting) eax di 16 bit a destra (con shr). Dopo aver salvato la posizione del mouse, settiamo la flag, MouseClick, a TRUE per far si che le istruzioni di "scrittura" nella sezione WM_PAINT sappiano che c'e' stato almeno un click nella client area, e di conseguenza disegnino la stringa alla posizione del mouse. Successivamente chiamiamo la funzione InvalidateRect per costringere la finestra a ridisegnare la sua intera client area.

.IF MouseClick
            invoke lstrlen,ADDR AppName
            invoke TextOut,hdc,hitpoint.x,hitpoint.y,ADDR AppName,eax
        .ENDIF

Le istruzioni di scrittura nella sezione WM_PAINT devono controllare se MouseClick e' TRUE, dal momento che quando la finestra e' stata creata, ha ricevuto ugualmente un messaggio WM_PAINT, ma in quel momento non c'era stato nessun click e quindi non doveva disegnare la stringa nella client area. Pertanto noi inizializziamo MouseClick come FALSE e cambiamo il suo valore in TRUE quando l'utente clicka effettivamente il tasto sinistro del mouse. Se c'e' stato almeno un click del mouse, il codice disegna la stringa nella client area alla posizione del mouse. Notate che chiamiamo lstrlen per ottenere la lunghezza della stringa da mostrare, e utilizziamo tale lunghezza come ultimo parametro della funzione TextOut.


Note finali

Questi tutorials erano presenti nel sito di RingZero. Li rimettiamo a disposizione a chiunque voglia poter leggerli nella loro traduzione in italiano che fu curata da NeuralNoise.

phobos


Disclaimer

I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.

Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevole e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.