PDA

Visualizza la versione completa : [C++] Problema con GetAsyncKeyState() in una procedura


kirakira93
02-04-2010, 15:13
Ciao ragazzi, ho un problema:
Se metto la funzione

if(GetAsyncKeyState(VK_F2) < 0) MessageBox(NULL,"","",0);

dentro una procedura per gestire una finestra e premo F2 non succede niente.
O meglio per far comparire il MessageBox() devo premere più volte perchè all'interno della procedura non sente i tasti al primo colpo.

Come posso fare?????

oregon
02-04-2010, 15:54
Se non mostri il contesto in cui opera quella riga, non si potrà dire molto ...

Serve il codice ...

kirakira93
02-04-2010, 19:53
Ecco il codice, preso dagli esempi di dev-c++ e aggiunto solo la parte del MessageBox.

Se lo eseguite e premete F2 e F3 quando la finestra è attiva, tutto ok.
Ma se provate a premere i tasti finchè la finestra è per esempio ridotta ad icona e siete su un altro programma (es. dev-c++), per far comparire i MessageBox dovrete premere o tentere premuto i tasti più volte.



#include <windows.h>

/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/* Make the class name into a global variable */
char szClassName[ ] = "WindowsApp";

int IntPerNonFareComparireUnBordelloDiMessageBox = 1;


int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)

{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */

/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);

/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default color as the background of the window */
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;

/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Windows App", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
544, /* The programs width */
375, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);

/* Make the window visible on the screen */
ShowWindow (hwnd, nFunsterStil);

/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}

/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}


/* This function is called by the Windows function DispatchMessage() */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{


if(GetAsyncKeyState(VK_F2) < 0 && IntPerNonFareComparireUnBordelloDiMessageBox == 1)
{
IntPerNonFareComparireUnBordelloDiMessageBox = 0;
MessageBox(NULL,"Il problema e' che non viene fuori sempre!\nInfatti bisogna premere F2 piu' di una volta!","Problema",MB_ICONERROR);
}

if(GetAsyncKeyState(VK_F3) < 0 && IntPerNonFareComparireUnBordelloDiMessageBox == 0)
{
IntPerNonFareComparireUnBordelloDiMessageBox = 1;
MessageBox(NULL,"Il problema e' che non viene fuori sempre!\nInfatti bisogna premere F3 piu' di una volta!","Problema",MB_ICONERROR);
}



switch (message) /* handle the messages */
{
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}

return 0;
}




PS eseiste un modo per evitare di fare tutto quel casino di
"IntPerNonFareComparireUnBordelloDiMessageBox"???? :D :D :D

MItaly
02-04-2010, 20:09
Originariamente inviato da kirakira93
Ecco il codice, preso dagli esempi di dev-c++ e aggiunto solo la parte del MessageBox.

Se lo eseguite e premete F2 e F3 quando la finestra è attiva, tutto ok.
Ma se provate a premere i tasti finchè la finestra è per esempio ridotta ad icona e siete su un altro programma (es. dev-c++), per far comparire i MessageBox dovrete premere o tentere premuto i tasti più volte.
Questo perché la tua window procedure viene richiamata solo quando ci sono messaggi per la tua finestra. Quando la tua finestra è attiva arrivano molti messaggi (in particolare, quando premi un tasto, i vari WM_KEYDOWN/WM_KEYUP/...), per cui il controllo avviene di frequente e la message box appare subito; al contrario, quando la tua applicazione non è in primo piano le arrivano solo di tanto in tanto dei messaggi, e quindi solo in queste occasioni la tua window procedure viene eseguita.


PS eseiste un modo per evitare di fare tutto quel casino di
"IntPerNonFareComparireUnBordelloDiMessageBox"???? :D :D :D
Questo dipende dal fatto che tu stai controllando se la GetAsyncKeyState restituisce un valore negativo, ossia che ha il bit più significativo attivo. Se controlli questo, di fatto vai a vedere se il tasto è premuto nel preciso istante in cui chiami GetAsyncKeyState. Per cui, se più messaggi arrivano uno dopo l'altro mentre è premuto il tasto, in tutte quelle occasioni GetAsyncKeyState ti dirà che il tasto è premuto, e verrà visualizzata la messagebox. Al contrario, tu devi verificare semplicemente se il tasto è stato premuto dall'ultima chiamata a GetAsyncKeyState, cosa che puoi fare controllando il bit meno significativo del valore restituito dalla funzione in questione, come spiegato nella documentazione (http://msdn.microsoft.com/en-us/library/ms646293%28VS.85%29.aspx).

In ogni caso, stai usando gli strumenti sbagliati per il lavoro che intendi fare. Se vuoi controllare le pressioni di tasti mentre la tua finestra è attiva, lo strumento giusto è il semplice controllo dei messaggi WM_KEYDOWN all'interno della tua window procedure. Se invece vuoi controllare tutte le pressioni di tasti nel sistema, allora lo strumento giusto sono le hook (http://msdn.microsoft.com/en-us/library/ms632589%28v=VS.85%29.aspx) globali, strumento comunque da utilizzare con cautela e parsimonia per motivi di prestazioni e per eventuali problemi che possono sorgere se la procedura di filtro ha dei bug.

Colgo l'occasione per ribadire il consiglio (http://forum.html.it/forum/showthread.php?postid=12904784#post12904784) che ti ho dato qualche tempo fa.

kirakira93
02-04-2010, 21:13
ok... MItaly hai ragione te..... adesso sono pienamente convinto: manuale in arrivo!
Comunque, per GetAsyncKeyState ho risolto ponendo == -32767.
In ogni caso, come potrei fare a richiamare una hook globale?

oregon
02-04-2010, 21:16
Originariamente inviato da kirakira93
...come potrei fare a richiamare una hook globale?

Ma come ... prima dici che attendi un manuale e poi chiedi per l'hook globale (che è un argomento tra i più complessi per i programmatori esperti ...?)

kirakira93
02-04-2010, 21:27
ok lasciando perdere le hook, come potrei fare (utilizzando WM_KEYDOWN)

MItaly
02-04-2010, 21:46
Originariamente inviato da kirakira93
ok... MItaly hai ragione te..... adesso sono pienamente convinto: manuale in arrivo!
Comunque, per GetAsyncKeyState ho risolto ponendo == -32767.

Tecnicamente dovresti scrivere


if((GetAsyncKeyState(/*bla bla bla */) & 1)==1)


Originariamente inviato da kirakira93
ok lasciando perdere le hook, come potrei fare (utilizzando WM_KEYDOWN)
Devi aggiungere allo switch della tua windows procedure un case per WM_KEYDOWN; per vedere come ottenere il tasto premuto, dai un'occhiata alla documentazione (http://msdn.microsoft.com/en-us/library/ms646280%28VS.85%29.aspx).

kirakira93
02-04-2010, 23:12
Grazie Mille, domani proverò il codice.
Comunque, ritornando alla questione del manuale 3 domande.
1> Il maunale di win 32 che mi consigleresti in assouluto qual'è tra quelli che mi hai consigliato.
2> Posso scaricare di quel manuale un e-book gratuito.
3> Da che sito devo ordinarlo (se non è possibile avere l'ebook), magari anche da e-bay
4> Ultima cosa --> Ma i manuali sono in inglese? Perchè in inglese me la cavo abbastanza bene, ma non ho mai provato a studiare in inglese (anche se penso che mi farebbe solo che bene :D)

MItaly
03-04-2010, 00:28
1) Io ho studiato sul Rector-Newcomer, ma ho sentito dire in giro che il Petzold è più completo; magari aspetta pareri di qualcun altro prima di comprare.
2) No, sono entrambi libri normali protetti da copyright.
3) Io andrei su Amazon.com, guardando magari nella sezione usati, tra cambio euro/dollaro e prezzo da usato finisce che spendi piuttosto poco. Tieni conto però che prima di qualche settimana non arriva se prendi la spedizione più economica, e se te lo bloccano in dogana potrebbe essere necessario inviare la documentazione in dogana (quando mi è capitato è bastato inviare una mail con un pdf del loro modulo compilato, più 5 € di spese non meglio precisate); altrimenti puoi andare di Amazon.co.uk (meno conveniente perché paghi in sterline, ma in UE, per cui arriva più in fretta e non hai problemi di dogana) o Play.com (che fa spedizione gratuita, ma ho visto che in generale non conviene rispetto ad Amazon).
4) Sono in inglese (oddio, forse li hanno anche tradotti, ma non mi sono mai informato, preferisco leggerli in inglese), ma vai tranquillo, l'inglese tecnico è una passeggiata, e visto che praticamente tutta la documentazione è in inglese è un buon allenamento.

Loading