C# problema con GetAsyncKeyState

mercoledì 04 febbraio 2009 - 20.33

Fiez Profilo | Newbie

Ciao a tutti
Vi espongo il mio problema:
sto scrivendo un programma che "cattura" tutti i tasti e i click del mouse che vengono fatti ( una specie di KeyLogger diciamo ), tutto il codice fin'ora non mi ha dato problemi, tranne che per un punto:
Praticamente usando GetAsyncKeyState trovo il codice Virtual-Key corrispondente, dopo metto tutto in una stringa che salvo in un file di testo.
Quando si tratta di tasti con un esadecimale senza lettere (A,B,C,D,E,F) non ho problemi e faccio cosi:
switch (i) { case 1: //1 è il codice esadecimale per il click sinistro return "[Click Sinistro]"; case 2: //2 è il codice esadecimale per il click destro return "[Click Destro]";

i è una variabile di tipo intero
Ora il problema è quando mi trovo a inserire tasti come la M il cui esadecimale è 0x4D.
Ho pensato di convertire l'esadecimale in binario facendo cosi 0x4D = 77
Peccato che il 77 corrisponde al tasto F8
Potrei provare ad usare una stringa al posto della variabile i, però GetAsyncKeyState accetta solo interi come parametri

Mi scuso in anticipo se ho sbagliato a postare o altro...ma è la prima volta
Grazie a tutti in anticipo

Jeremy Profilo | Guru

Sinceramente il tuo problema non l'ho capito.

Prova a scrivere questa condizione all'interno dell'evento tick del timer

if (!GetAsyncKeyState(i) == 0)
{
textbox1.text = Convert.ToChar(i).ToString;
}

Giusto per capire se ho capito il tuo problema.

Facci sapere...
Ciao

Fiez Profilo | Newbie

Non penso di aver capito la tua risposta, ma penso che neanche tu hai capito il mio problema
Provo a rispiegarlo:
il mio problema è riuscire ad inserire nello switch anche dei numeri esadecimali.
Per esempio:
Ox00 non ho problemi perchè faccio 00
Ox01 non ho problemi perchè faccio 01
OxF4 ho dei grossi problemi perchè non so come fare

Praticamente i valori che ti ho scritto sopra non li metto io a piacere, ma vengono passati al programma in base a quale tasto premo, ed è difficile (se non impossibile) associare come valore di una variabile intera "F4"...e non posso neanche cambiare tipo di variabile passando magari ad una stringa perchè la funzione GetAsyncKeyState che devo usare accetta come paremetri solo interi (almeno cosi mi pare di aver capito dalla guida microsoft)

intanto grazie per la risposta

Jeremy Profilo | Guru

...forse ho omesso una parte di codice....

Cerco di spiegarmi meglio
for (int i = 0; i < 265; i++) { if (!GetAsyncKeyState(i) == 0) { textbox1.text = Convert.ToChar(i).ToString; } }

Scrivi questo codice...nell'evento tick di un timer....l'obbiettivo è quello di, ogni tot millisecondi.....interrogare GetAsyncKeyState con il valore integer "i" e, se restituisce diverso da zero....converte il valore integer "i" nel carattere corrispondente.

Tu prova.......a me funziona.

Facci sapere...
Ciao

Fiez Profilo | Newbie

Grazie mille per il codice
Dovrei riuscire a provarlo più tardi (adesso sono su un computer che sta acceso perchè non c'è vento )

Comunque io uso un programma console, faccio
while (variabile del log < tot) { cattura tasti }
dopo che finisce il while mette tutta la variabile su un file di testo e la svuoto...dopo riparto

Jeremy Profilo | Guru

Occhio che il meteo non dà buone notizie.....salva tutto prima che puoi

Fiez Profilo | Newbie

Scusa mi sono accorto che hai messo il ! prima di GetAsyncKeyState e dopo ==
Intendevi scrivere "diverso da",cioè -----> GetAsyncKeyState !=..... ?

Sto provando il tuo pezzo di codice e ti faccio sapere

EDIT:
scusa ma c'è una cosa che non capisco nella tua risposta, oppure tu non capisci qualcosa nella mia domanda (penso che sia colpa mia )
Praticamente il ciclo for serve per scorrere tutta la funzione GetAsyncKeyState (da 0 a 255), dopo se GetAsyncKeyState(i) è diverso da zero, (seguendo il tuo codice) una textbox.text diventa uguale alla conversione chart di i..ma i è un numero perciò la textbox diventerebbe ogni volta 1,2,3,4,5,6,7,8,9,10,11,12 e cosi via
Invece quello che deve fare il programma è andare a vedere GetAsyncKeyState(i) a quale lettera corrisponde e per farlo ci vuole uno switch, il mio problema sta proprio nello switch
Non so in che modo posso farmi capire...è poco che programmo io

RI EDIT:
il problema qual'è? che GetAsyncKeyState non arriva fino a 255 ma arriva a OxFE (che sarebbe 254 in decimale)...come faccio entrare OxFE nello switch?

Jeremy Profilo | Guru

Tieni conto che io uso VB.NET e il mio uso di C# si limita a tradurre gli esempi a chi conosce solo il C#....quindi se vedi qualche errrore di sintassi...aggiustalo tu e fammi pure notare l'errore....così imparo anche io.

Ciao.

Fiez Profilo | Newbie

Intanto grazie lo stesso per le risposte
Ho editato di sopra, guarda se ci capisci qualcosa più di me

Se vuoi posso passarti tutto il codice via PM

Jeremy Profilo | Guru

Allora.....ho capito quello che vuoi fare....ma non riesco a capire il tuo problema...
con questo codice....non serve lo switch....componi direttamente la stringa con il carattere corrispondente al valore integer che ti fornisce esito positivo interrogando la funzione.
for (int i = 0; i < 265; i++) { if (!GetAsyncKeyState(i) == 0) { tuastringa += convert.tochar(i).tostring; } }

se il valore di "i" è minore di 49,allora non è una lettera od un numero....quindi puoi eventualmente integrarlo in questo modo:


for (int i = 0; i < 265; i++) { if (!GetAsyncKeyState(i) == 0) { if(i<49) { fai il tuo switch per il click sinistro è 1....per il destro 2.....etc...etc..etc.. } else { tuastringa += convert.tochar(i).tostring; } } }

Spero di essere stato più chiaro.....e che la sintassi sia corretta

Facci sapere...
Ciao



[edit]

Cazzarola....lo switch lo fai sul valore integer di i....

[endedit]

Fiez Profilo | Newbie

Almeno uno dei due riesce a capire quando parla l'altro

Allora provo a capire il tuo codice (sono completamente fuso scusami... )
tuastringa += convert.tochar(i).tostring;

Se quella i è la stessa del ciclo for, allora è un numero, e se è un numero va da 0 a 255...non potrà mai essere una lettera, o sbaglio?
Di conseguenza la mia stringa avrà sempre valore numerico...mai una lettera o un simbolo.
Avrebbe avuto più senso una cosa del genere
tuastringa += convert.tochar(GetAsyncKeyState(i)).tostring;
forse è lo stesso che volevi dire tu, però anche in questo modo è sbagliato perchè la posizione 255 (che è un valore che la i assume sicuramente) non va bene con GetAsyncKeyState...io devo ficcare nello switch un valore esadecimale (che sono quelli che assume regolarmente GetAsyncKeyState )
Non so io ho capito questo da qui -----> http://msdn.microsoft.com/it-it/library/ms645540(en-us,VS.85).aspx
Se ti fa comodo posso mandarti il codice per PM
Per esempio :
se la i vale 35 vuol dire che è stato premuto il tasto 5
se la i vale 2 vuol dire che è stato clickato il tasto destro del mouse
se la i vale FE vuol dire che è stato premuto un altro tasto
Domanda...come faccio ad aggiungere un case nello switch per i che vale FE?

Jeremy Profilo | Guru

>Se quella i è la stessa del ciclo for, allora è un numero, e
>se è un numero va da 0 a 255...non potrà mai essere una lettera,
>o sbaglio?
Sbagli.....la i è la stessa del ciclo For......i è un numero.....ma io lo converto in Char....quindi diventerà una lettera (se la conversione lo permette)

Prova a fare così:
metti una textbox ed un timer sul form.
Nell'evento tick del timer scrivi questo:
for (int i = 0; i < 265; i++) { if (!GetAsyncKeyState(i) == 0) { Textbox.text = convert.tochar(i).tostring + " " + i; } }

Noterai che premendo le lettere in ordine alfabetico(A..B...C..D)
ti compariranno i numeri 65...66...67...68...e le lettere che tu hai realmente premuto.(quindi vorrà dire che corrispondono i numeri alle lettere)

in questo modo dovrebbe chiarirti un pò più le idee.

Questo:
>tuastringa += convert.tochar(GetAsyncKeyState(i)).tostring;
non ti azzardare a farlo....non è la stessa cosa che intendo io......ti complichi la vita.

Prova a fare uno switch di prova(per me select case)

[CODE] select case i case 65 messagebox.show("Hai premuto la A") case 66 messagebox.show("Hai premuto la B") case 67 messagebox.show("Hai premuto la C") case 68 messagebox.show("Hai premuto la D") end case [/CODE]

Vedrai che il case si verificherà esattamente quando premerai le lettere il cui valore corrisponde al valore integer di quella i del ciclo for.....
Forse è un accrocchio...io questo non lo so...fatto stà che io lo uso e funziona...poi fai le tue valutazioni in merito.
Io, comunque, rimango a disposizione per eventuali chiarimenti.

Ohhhh....attento alla privacy.....io lo uso a scopo didattico......

Facci sapere...
ciao

Fiez Profilo | Newbie

Cazzo sei un genio
Adesso mi è venuto un flash mentre leggevo il tuo post e penso di aver capito
Praticamente seguendo il tuo metodo:
premo un tasto e lascio che sia il pc a darmi il codice del tasto premuto, poi sapendo il codice del tasto premuto so anche la lettera che ho premuto
Invece seguendo il mio metodo:
mi giro tutti i codici possibili ( tra cui quelli esadecimali che non riuscivo a fare) e dopo faccio la corrispondenza...
Questo è quello che ho capito, e l'importante è che ho capito io

Domani provo il codice e ti faccio sapere, intanto grazie duemila

P.S.
logicamente è per scopo informativo...io lo faccio per vedere se sono capace di farlo, ed è anche per questo che non ho postato codice significativo qui

Fiez Profilo | Newbie

Grande ho provato il codice e funziona benissimo
Ecco il codice in c# anche se il tuo era praticamente giusto
private void tLog_Tick(object sender, EventArgs e) { for (int i = 0; i < 265; i++) { if (GetAsyncKeyState(i) != 0) { txtLog.Text = Convert.ToString(Convert.ToChar(i)); } } }
Da quanto ho visto non consuma neanche la CPU come faceva il mio
Ci sono anche un paio di cosette che devo sistemare che comunque credo di riuscire a fare senza troppi problemi
Un paio di domande:
Ad esempio quando faccio il click con il mouse non lo prende, oppure al posto di F8 F7 mi scrive p oppure t (minuscole)...per evitare questo devo fare degli altri if dentro al for giusto?
E poi...tutte le lettere che batto diventano maiuscole nel form anche se ho premuto le minuscole...c'è un modo per ovviare a questo?

EDIT:
non è vero
mi sono accorto adesso che mi scrive sia la lettera minuscola che quella maiuscola...
Per farti capire meglio, mi esce una stringa palindroma, a sinistra minuscola a destra maiuscola tipo:
abcd--DCBA

Jeremy Profilo | Guru

Caspiterina....hai ragione .....

Però ho la soluzione.

sostituisci questa riga:
>txtLog.Text = Convert.ToString(Convert.ToChar(i));
con questa
txtLog.Text = Convert.ToString((Keys)i);

Nel caso in cui la sintassi non sia corretta, tieni presente che la mia intenzione in vb è questa:
txtLog.Text = directcast(i,Keys).tostring
che in vb funziona(provata)

Dove Keys sta per l'enumeratore che rappresenta i tasti della tastiera....
A questo punto non fare più neanche lo switch.....non serve...prova e vedrai.

Se hai bisogno .....Facci sapere.....
Ciao

Fiez Profilo | Newbie

Risolto in parte di già
Praticamente se scrivo nella textbox mi compare appunto quella scritta palindroma che io interpreto cosi:
la lettera minuscola c'è perchè io ho realmente premuto quel tasto, la lettera maiuscola c'è perchè è quella mi viene fuori dalla funziona. Infatti se non scrivo nella textbox ma in qualsiasi altra finestra mi compare solo la maiuscola ovvero quella che MI DEVE comparire
quindi problema risolto

Ora mi restano solo questi 2 problemi:
1° Tutte le lettere che vengono loggate sono appunto maiuscole, quindi non fa distinzione se il caps lock è attivo o se è premuto lo shift. Cercando in rete ho elaborato una possibile soluzione. Sarebbe una cosa del genere:
IF ( getKeyPressed(shift)) { scrive le lettere maiuscole } ELSE { scrive lettere minuscole }
penso che potrebbe funzionare...però non sono sicuro che la funziona da usare sia getKeyPressed oppure altro
2° problema: alcuni input come ad esempio il click del mouse destro mi vengono loggati in modo diverso...il click destro diventa questo ^, F8 diventa p, F7 diventa t...e cosi via.
Possibili soluzioni?

Jeremy Profilo | Guru

>1° Tutte le lettere che vengono loggate sono appunto maiuscole, quindi non fa distinzione se il caps lock è attivo o se è premuto lo shift. Cercando in rete ho elaborato una >possibile soluzione. Sarebbe una cosa del genere:
per questo problema la soluzione credo che sia quella che hai già trovato tu.

>2° problema: alcuni input come ad esempio il click del mouse destro mi vengono loggati in modo diverso...il click destro diventa questo ^, F8 diventa p, F7 diventa t...e cosi >via.
>Possibili soluzioni?
La soluzione certa è questa:
txtLog.Text = Convert.ToString((Keys)i);
che vorrebbe dire in vb:
txtLog.Text = directcast(i,Keys).tostring
solo che...in vb l'ho provata e funziona alla grande......in c#.....devo solo rassicurarmi sulla sintassi....dammi un pò di tempo e la provo.

Ciao

Fiez Profilo | Newbie

direct cast sarebbe mettere insieme i con keys? perchè non c'ho capito granchè
E poi questo keys mi ha detto che è l'enumeratore della tastiera....anche qui non c'ho capito più di tanto

Comunque senza fretta logicamente, aspetto il tuo codice
Per adesso comunque funziona alla grande, poco consumo di cpu/ram, logga praticamente tutto giusto, non si blocca mai...perfect
Sono solamente quei 2 dettagli che mi lasciano un po l'amaro in bocca

Jeremy Profilo | Guru

Inserisci nel tuo progetto un form nuovo e sostituisci TUTTO il contenuto con il mio codice:

Codice cancellato

Mi manca da risolvere solo il problema del case sensitive......
Intanto testa questo se è quello che vuoi.

prova a premere il tasti del mouse.....F1,F2..etc... e i numeri del PAD....o cos'altro vuoi premere...
Intanto vedo come risolvere il resto...


Ciao

Fiez Profilo | Newbie

Ho copiato il codice
Adesso lo testo e ti dico subito.
Magari cancellalo dal tuo messaggio cosi evitiamo di distribuire keylogger, a gratis per di più

Fiez Profilo | Newbie

Scusa ma sinceramente non mi va il tuo programma
Comunque ho dato un occhiata al codice ed è praticamente uguale al mio, tranne che per:
for (int i = 0; i < 265; i++) { if (GetAsyncKeyState(i) != 0) { txtLog.Text = Convert.ToString((Keys)i); } }

Magari mi spieghi cosa fa questo codice, e lo pianto dentro nel mio

Jeremy Profilo | Guru

Questo codice:
>txtLog.Text = Convert.ToString((Keys)i);
Non fà altro che assegnare alla proprietà Text della Label txtLog la rappresentazione simbolica dell'elemento dell'enumeratore Keys corrispondente al valore della variabile i.

Esempio:
Se scrivi Keys. l'intellisense ti proporrà tutti gli elementi di questo enumeratore.
Se guardi l'elemento LButton, noterai che corrisponde al valore integer 1.
Quindi, con quella riga di codice che ho scritto io, nella label otterrai LButton e non 1.


Comunque....se a me funziona perfettamente e a te no.....c'è qualcosa che non va che non riguarda di certo il codice.
Io ho compilato il progetto per il .Net Framework 3.5 ed è l'unica cosa che potrebbe causare la differenza del risultato.

Non funziona...cosa vuol dire....non te lo compila???o non ottieni il risultato che volevi??

Questo è quello che ottengo io premendo il tasto sinistro del Mouse:

499x296 19Kb


Prova a spiegare il risultato che ottieni tu.

Facci sapere...
Ciao



Fiez Profilo | Newbie

Questo è il primo errore che mi compare appena copio il tuo codice in un nuovo progetto


286x172 8Kb


464x116 12Kb


Il problema si risolve cambiando Form3 con Form1
Dopo avvio il debug e non succede niente qualsiasi tasto premo...dove sbaglio?

EDIT:
comunque non è un problema, ho copiato questo pezzettino di codice nel mio e funziona anche per i click del mouse e gli altri tasti che prima mi davano problemi
Convert.ToString((Keys)i);

Ora resta solo il problema del case sensitive

Jeremy Profilo | Guru

Quello non centra nulla con il codice del KeyLogger.....quell'errore stà ad indicare che non trova la Routine InitializeComponent che si dovrebbe trovare nel file .Designer del Form e che probabilmente non è stata creata perchè,(colpa mia) ti ho detto di creare un form nuovo senza aggiungere nessun componente all'interno di esso.

Facciamo così :
Aggiungi questa parte di codice a quello che ti ho dato prima:

private void InitializeComponent() { this.SuspendLayout(); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(482, 264); this.Name = "Form3"; this.Text = "Form3"; this.Load += new System.EventHandler(this.Form3_Load); this.ResumeLayout(false); }

Fondamentalmente, il motivo per cui non succede nulla è perchè mancava questo:
> this.Load += new System.EventHandler(this.Form3_Load);

Facci sapere...
Ciao

Fiez Profilo | Newbie

ahahahah ora funziona
Sei un grande
Purtroppo quando parli con me non devi dare nulla per scontato, sono un filo ignorante in materia


Coooooomunque....un problema me l'hai risolto
Per il case sensitive ti è venuto in mente qualcosa?

Allora visto che sei cosi disponibile ne approffito
Praticamente il log viene salvato quando la variabile string sLog supera o diventa uguale a un certo numero di caratteri.
Ora se per esempio mentre sta loggando, il programma viene chiuso, quelle che aveva memorizzato nella variabile sLog va perduto, come posso fare?
Praticamente voglio che in qualsiasi momento in cui il programma sta per essere chiuso , prenda tutto il contenuto di sLog e lo salvi...idee su come procedere?
io pensavo a qualcosa tipo:
Application.exit........
ma non so come andare avanti
E poi che limite massimo mi consigli di tenere per la variabile sLog?
Il parametro è sLog.Length

Jeremy Profilo | Guru

>Per il case sensitive ti è venuto in mente qualcosa?

Sto finendo una relazione.....appena finito mi ci metto.....

Ti faccio sapere...
Ciao

Fiez Profilo | Newbie

Vai tranquillo
Ho già parecchio su cui sbattere la testa per adesso
Comunque ho aggiunto un paio di cosette al mio post di prima
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5