Newsgroup: it.comp.programmare.win32
Titolo: Simulare la pressione di un tasto

Salve a tutti
Sto' realizzando un piccolo programmino (in C++ per Windows, usando
le API) per simulare ad intervalli regolari la pressione di un tasto in un'altra
applicazione. Per fare cio', sto' usando banalmente la SendMessage
con i WM_KEYDOWN e WM_KEYUP. Con i tasti normali non ho avuto
problemi, ma adesso vorrei simulare anche le combinazioni di tasti, ad
es. CTRL+W. Rer fare questo ho pensato di fare cosi' :
SendMessage(hFinestra,WM_KEYDOWN, VK_CONTROL,0);
SendMessage(hFinestra,WM_KEYDOWN,VK_W,0);
SendMessage(hFinestra,WM_KEYUP,VK_W,0);
SendMessage(hFinestra,WM_KEYUP,VK_CONTROL,0);
(sperando di non aver sbagliato qualcosa nel ricopiare)
Ma per le combinazioni come ALT+W? MSDN che ho installato sul
PC mi dice che esiste un VK_ALT, ma il compilatore (Visual C++ 6) mi
dice che non e' definito (e cercando nei vari .h non l'ho appunto trovato).
Quale codice devo usare?
Grazie
Killer

 (sperando di non aver sbagliato qualcosa nel ricopiare)
Sono riuscito a testarlo e in questo modo il programma ricevente processa solo
la W, non la sua combinazione con il CTRL :/
Come mai? Avete idee a riguardo?
Grazie ancora
Killer

(sperando di non aver sbagliato qualcosa nel ricopiare)
Usa keybd_event o SendInput.
--
Andrea Laforgia - walkietalkie(at)
libero.it
#exclude <windows.h>

 Usa keybd_event o SendInput.
Ma cosi' non "mando il tasto" a tutte le finestre? O solo a quella col focus?
La finestra a cui voglio inviare i tasti spesso non ha il focus...
Bow-wow
--
Killer, webmaster di 
http://go.to/KingdomAmiga
ICQ: 73998132
Mastro di Cerimonie del Ghouls
In pace con il re Bersy (re de che?)

La finestra a cui voglio inviare i tasti spesso non ha il focus...
No, tu generi un evento di tastiera, poi se in quel momento la
tua finestra ha focus, sara' lei a elaborarlo.


>La finestra a cui voglio inviare i tasti spesso non ha il focus...
In questo caso non credo che tu possa usare keybd_event.


 tua finestra ha focus, sara' lei a elaborarlo.
Appunto. Io invece voglio che sia solo la finestra che dico io a gestire
i tasti, non chi si trova: per questo avevo ripiegato sui  SendMessage
(scusa se non mi ero spiegato bene all'inizio)
Cmq grazie
Killer

 dice che non e' definito
Prova con VK_MENU.
---
Bye! Lorenzo Lutti
http://antani.virtualave.net/

 > SendMessage(hFinestra,WM_KEYDOWN, VK_CONTROL,0);
Cosi` a occhio devi specificare anche qualcosa nel lParam, ad esempio leggo
che il bit 24 deve essere posto a 1 se il tasto e` "extended" (come Alt,
Ctrl ecc...).
In generale comunque per fare cose del genere si usa SendInput() o
keybd_event().


(scusa se non mi ero spiegato bene all'inizio)
Ciao,
forse si può fare... (forse! :P)
Allora... ti confermo quanto detto da Andrea, la keybd_event genera un 
evento tastiera, non manda un messaggio alle finestre.
Per quanto ne so io infatti,non è possibile inviare le combinazioni di 
tasti CTRL+ e SHIFT+, ma solo ALT+
Se hai i sorgenti dei componenti di Delphi, guarda il file Controls.pas 
alla implementazione
function TWinControl.DoKeyDown(var Message: TWMKey): Boolean;
... se noti c'è una chiamata a "KeyDataToShiftState" che genera ciò che 
verrà passato all'evento OnKeyDown. Se risali a questa funzione 
(Forms.pas), ti accorgi che per decidere se ALT è premuto, la funzione 
processa direttamente il messaggio (if KeyData and AltMask).
**invece per CTRL e SHIFT utilizza la GetKeyState.
Fortunatamente (forse) esiste una bella funzione che si chiama 
SetKeyboardState... a proposito della quale l'SDK dice :
The SetKeyboardState function copies a 256-byte array of keyboard key 
states into the calling thread's keyboard-input state table. ***This is the 
same table accessed by the GetKeyboardState and GetKeyState functions.*** 
Changes made to this table do not affect keyboard input to any other 
thread. 
Ora l'approccio che ti propongo io è quello del classico hook che viene 
richiamato dalla tua applicazione (ad esempio filtrando un messaggio 
nonstandard o qualcosa del genere) che al momento giusto chiama, se 
necessario, la SetKeyboardState.
Non so se funziona... almeno in linea teorica e a naso mi sembra di sì... 
se hai bisogno di aiuto o non sono stato chiaro scrivi pure!
Ciao!!
Davide DG.

sì... se hai bisogno di aiuto o non sono stato chiaro scrivi pure!
Ok... siccome mi interessava l'argomento ho provato a sviluppare questa 
soluzione... FUNZIONA!! ^_^
Ciao! Davide DG.

 soluzione... FUNZIONA!! ^_^
Scusami, ma credo di non essere molto esperto in materiale(= non ho capito
quello che mi avevi consigliato di fare :D)
Potresti spiegarti in parole + semplici (magari con qualche pezzettino di
codice? :DDD)
Bow-wow
Killer

codice? :DDD)
Scusa se non ho risposto subito ma ero impegnato con gli esami.
Ci provo...
Allora, ti faccio qualche premessa : 
1) Windows mantiene un "KeyboardState" per ogni singolo thread.
   Un Keyboard state è, intuibilmente, lo stato (istantaneo o dipendendte
   dalla coda dei messaggi del thread) di tutti i tasti per ogni thread.
   Il KeyboardState è definito come un array di 1 byte per ogni tasto
   virtuale (guardati la definizione di TKeyboardState).
2) Il KeyboardState può essere modificato e impostato tramite la
   SetKeyboardState:
Var localKeyboardState : TKeyboardState;
GetKeyboardState (localKeyboardState); // lo "scarico"in una var temporanea
localKeyboardState [VK_SHIFT] := $FF;  // lo modifico ($FF > tasto premuto)
SetKeyboardState (localKeyboardState); // lo imposto
 
2) Da un altro thread (quale quello della tua applicazione, che tra l'altro 
appartiene addirittura ad un altro processo), ti è impossibile modificare 
il keyboardstate di un altro thread.
3) Esistono gli hook! Se sai cosa sono e hai un po' di dimestichezza con 
questi potenti strumenti ( ;P ), sei a cavallo... e dovresti a questo punto 
aver già iniziato a scrivere la tua dll  ;D
Se invece non sai cosa sono... ti posso dire brevemente che servono a 
"iniettare" del codice (attraverso una dll) in un altro thread.
Per una descrizione più dettagliata : "Hooks" sul Platform SDK.
***************************************************************************
Il programma e la dll li ho scritti in delphi... mi pare che tu usi c++ : 
provo a postartelo lo stesso... casomai qualcuno tradurrà (farei veramente 
troppi errori!!) ;P  :
La dll filtra i messaggi che arrivano alla coda del thread... se il 
messaggio è WM_APP (che verrà spedito dalla tua applicazione), la dll, che 
opera dall'interno del thread di "destinazione", chiama la SetKeyboardState 
e manda i messaggi WM_KEYDOWN e UP
Il tipo di hook è WH_GETMESSAGE.
La tua applicazione spedisce il messaggio WM_APP con questi parametri :
wParam : TShiftState;
// ssCtrl e/o ssShift ... per ssAlt è diverso
lParam : Cardinal;
// KeyData : contiene il virtual keycode, lo scancode e il bit per ssAlt 
... più eventualmente altre info...
Keydata viene passato come secondo parametro dei messaggi WM_KEYDOWN e UP
Come primo parametro passi il Virtual KeyCode (che viene "estratto" dalla 
MapVirtualKey).
ECCO LA procedura di hook (GetMsgProc) :
Function HookProc
(code : integer; wParam : WPARAM; lParam : PMSG) : LRESULT; stdcall;
// lParam^.wParam è ShiftState
// lParam^.lParam è KeyData
Var KS : TKeyboardState;
    VirtualKey : UINT;
Begin
  if Code = HC_ACTION then
    Case PMSG (lParam)^.message of
      wm_app : begin
        GetKeyboardState (KS);
        KS[VK_SHIFT]   := $FF * byte(ssShift in 
TShiftState(byte(lParam^.wParam)));
        KS[VK_CONTROL]   := $FF * byte(ssCtrl in 
TShiftState(byte(lParam^.wParam)));
        SetKeyboardState (KS);
        VirtualKey := MapVirtualKey (GetByte (lParam^.lParam,2), 1);
        SendMessage ( lParam^.hwnd, WM_KEYDOWN, VirtualKey, lParam^.lParam 
);
        SendMessage ( lParam^.hwnd, WM_KEYDOWN, VirtualKey, lParam^.lParam 
);
        GetKeyboardState (KS);
        KS[VK_SHIFT]     := 0;
        KS[VK_CONTROL]   := 0;
        SetKeyboardState (KS);
        Result := CallNextHookEx (HookHandle, code, wParam, 
integer(lParam));
      end;
      else Result := CallNextHookEx (HookHandle, code, wParam, 
integer(lParam));
    end
  else Result := CallNextHookEx (HookHandle, code, wParam, 
integer(lParam));
end;
**** Dalla tua applicazione, una volta installato l'hook:
 PostMessage ( WindowHandle,
               WM_APP,
               byte(aShiftState),
               aKeyData);
aKeyData contiene anche il bit per ssAlt (VK_MENU penso) ... questo viene 
passato dalla GetMsgProc della DLL col messaggio WMKey... 
Spero di essere stato esauriente ma non logorroico ;P
Ti consiglio anche la lettura di tutto l'argomento "Keyboard Input".
Nella MSDN lo trovi sotto :
Platform SDK\User Interface Services\User Input\Keyboard Input
Se hai problems scrivi ! Ciao.
Davide DG.

 >codice? :DDD)
[CUT]
Un bel lavoretto :D
Non ho mai fatto un hook, ma la cosa mi ha sempre incuriosito,
quindi mi studio con calma la questione.
Ultima domandina: ma l'hook rallenta l'applicazione "agganciata"?
Dato che l'applicazione in questione e' un gioco on-line, i
rallentamenti sono abbastanza pericolosi...
Grazie tante, inizio a studiarmi questo hook :D
Killer

rallentamenti sono abbastanza pericolosi...
Ti prego ... non dirmi che è Ultima Online !!!
ghghgh... io mi sono studiato tutta la sezione di Keyboard Input
proprio per fare un MACRO editor per UO !!
Per rispondere alla tua domanda : sì, ma l'entità (rilevabile) del 
rallentamento dipende da:
1) La velocità del tuo computer
2)* La dimensione della procedura di hook ... tanto più codice esegue tanto 
più rallenta :(
Comunque, a meno di non scrivere mooooolteeee linee di codice, o inserire 
dei delay... l'unica cosa di cui ti devi preoccupare è della correttezza 
del codice... cioè che non faccia piantare il gioco, che non generi leak di 
risorse ecc..
Ciao!! Davide DG 

 risorse ecc..
Ok, grazie di tutto, mi metto al lavoro :D
Bow-wow
Killer

>Ebbene si', il gioco in questione e' quello :D
Ummmmm.... mi fai pensare una cosa...
Io al tempo risolsi senza hook ... semplicemente mettendo in primo piano la 
finestra di Ultima e andando di keybd_event.. potresti considerare l'idea 
di non aver bisogno degli hook... :D
Vabbe... buon divertimento... e mi raccomando ... MACRA MACRA ;PPP
Davide DG.

 Vabbe... buon divertimento... e mi raccomando ... MACRA MACRA ;PPP
Contaci :D
Bow-wow
Killer