Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Syntetisoitu näppäimistösyöte

Sivun loppuun

Uinotin [16.11.2009 14:04:51]

#

Ajattelin kirjoittaa ohjelman, joka painaessani näppäimistön nappia syntetisoi näppäimistösyötesarjan. Esim. kun painan nappia "a" ohjelma kirjoittaa erilliselle ikkunalle(esim. wordpadille) "abc".

Miten tämän saisi käytännössä toimimaan?

jalski [16.11.2009 14:17:20]

#

Hae sanoilla: OLE, COM ja ActiveX.

Metabolix [16.11.2009 14:28:09]

#

Funktiolla nimeltä keybd_event. Haku löytää nimellä monia ennakkotapauksia, esimerkiksi tämän.

Uinotin [17.11.2009 09:25:12]

#

MSDN: sivuilla lukee keybd_event funktion kohdalla:
This function has been superseded. Use SendInput instead.

En oikein löydä esimerkkejä SendInputin käytöstä C++:ssa. Onko sillä jotain merkitystä, että kumpaa funktiota käyttää?

goala [17.11.2009 09:54:28]

#

No eipä nuo MSDNn ohjeet voisi enää yhtään selvempiä olla. Luitko edes, mistä sielä kirjoitettiin?

Tässä nyt Sinulle pieni esimerkki, joka "painaa" A-kirjainta:

INPUT input[2];

memset(input, 0, sizeof(input));

input[0].type = INPUT_KEYBOARD;  // http://msdn.microsoft.com/en-us/library/ms646270%28VS.85%29.aspx

input[0].ki.wVk = 65; // ASCII A
input[0].ki.dwFlags = 0;
input[0].ki.time = 0;
input[0].ki.dwExtraInfo = 0;

input[1].ki.wVk = 65; // ASCII A
input[1].ki.dwFlags = KEYEVENTF_KEYUP;
input[1].ki.time = 0;
input[1].ki.dwExtraInfo = 0;

SendInput(2, input, sizeof(INPUT)); // http://msdn.microsoft.com/en-us/library/ms646310%28VS.85%29.aspx

Muista toki, että mikäli haluat lähettää nämä "näppäilyt" juuri tietylle ohjelmalle mahdollisimman joustavasti, olisi ehkä viisainta tutustua DLL-injektointiin. Esim. SendInput ei välttämättä ole kaikkein paras vaihtoehto juuri WordPadille, vaan pikemminkin ehkä DLL-injektion kautta WordPadin RichEdit20W-kontrollin sub-classing.

Tiedän, tiedän, paljon uusia v-mäisiä termejä, mutta Googlesta löytää sopivat linkit oikeisiin artikkeleihin asiasta.

Deffi [17.11.2009 15:45:18]

#

goala kirjoitti:

Muista toki, että mikäli haluat lähettää nämä "näppäilyt" juuri tietylle ohjelmalle mahdollisimman joustavasti, olisi ehkä viisainta tutustua DLL-injektointiin. Esim. SendInput ei välttämättä ole kaikkein paras vaihtoehto juuri WordPadille, vaan pikemminkin ehkä DLL-injektion kautta WordPadin RichEdit20W-kontrollin sub-classing.

DLL-injektio on huono, koska jotkin palomuurit ja virustentorjuntasoftat ei tykkää siitä ja koska hitler. Tähän malliin ois hyvä tehdä:

#include <windows.h>

int main(int argc, char *argv[])
{
    HANDLE hikku = FindWindow("WordPadClass", NULL);
    HANDLE hloota = FindWindowEx(hikku, NULL, "RICHEDIT50W", NULL);

    if(hloota)
        SendMessage(hloota, WM_SETTEXT, 0, (LPARAM)"tilpehööri");

    return 0;
}

Ongelmaks koituu että toi "RICHEDIT50W" class ei oo kaikis Windowseissa sama, eli se ois hyvä ettii jotenkin listaamalla kaikki hikku:n child ikkunat ja poimimalla sieltä sopivan nimisen classin muotoa RICHEDITxxx.

Uinotin [17.11.2009 17:18:59]

#

goala kirjoitti:

No eipä nuo MSDNn ohjeet voisi enää yhtään selvempiä olla. Luitko edes, mistä sielä kirjoitettiin?

Juu, olisi tosiaan pitänyt tutustua hieman tarkemmin noihin MSDN:n ohjeisiin. Nyt kun näin tuon esimerkin, sivun ohjeet alkavat muutenkin näyttää hieman selvemmiltä.

Tuohon RichEdittiin löytyykin aika reilusti tietoa MSDN:stä, joten täytyy käydä senkin kimppuun. Tuo Deffin esimerkkikoodi lieneekin aikalailla se mitä olen hakemassa.

goala [18.11.2009 10:07:00]

#

Deffi kirjoitti:

goala kirjoitti:

Muista toki, että mikäli haluat lähettää nämä "näppäilyt" juuri tietylle ohjelmalle mahdollisimman joustavasti, olisi ehkä viisainta tutustua DLL-injektointiin. Esim. SendInput ei välttämättä ole kaikkein paras vaihtoehto juuri WordPadille, vaan pikemminkin ehkä DLL-injektion kautta WordPadin RichEdit20W-kontrollin sub-classing.

DLL-injektio on huono, koska jotkin palomuurit ja virustentorjuntasoftat ei tykkää siitä ja koska hitler. Tähän malliin ois hyvä tehdä:

#include <windows.h>

int main(int argc, char *argv[])
{
    HANDLE hikku = FindWindow("WordPadClass", NULL);
    HANDLE hloota = FindWindowEx(hikku, NULL, "RICHEDIT50W", NULL);

    if(hloota)
        SendMessage(hloota, WM_SETTEXT, 0, (LPARAM)"tilpehööri");

    return 0;
}

Ongelmaks koituu että toi "RICHEDIT50W" class ei oo kaikis Windowseissa sama, eli se ois hyvä ettii jotenkin listaamalla kaikki hikku:n child ikkunat ja poimimalla sieltä sopivan nimisen classin muotoa RICHEDITxxx.

Nyt puhut paskaa. DLL-injektio ei ole millään normein huono. Se on täysin tuikitavallinen ja MS-dokumentoitu tapa ja käytäntö. Sun antivirus/palomuuris on todella perseestä, jos tämä triggeröi eventin. Itse asiassa, eihän tuommoiset voisi käytännössä edes toimia Windowsissa.

Kaiken kukkuraksi, tuo antamasi esimerkki ei toimi halutulla tavalla. Messageja lähettämällä et pääse itse kontrolliin suoraan käsiksi ja tarkastamaan, jos henkilö x painoi juuri A-kirjainta (ja joka kysymyksen mukaisesti pitäisi muuttaa vaikka ABC:ksi).

Grez [18.11.2009 11:20:47]

#

Itse tulkitsin alkuperäisen toivomuksen niin, että kun sovelluksessa X painetaan nappia A, niin syntetisoidaan painallukset ABC sovellukselle Y. Ei niin, että oltaisiin sovelluksessa Y kokoajan.

Mutta toki jos on tarkoitus olla siellä wordpadissa koko ajan, niin sitten ei tietenkään pelkkä viestien lähettely riitä.

goala [18.11.2009 11:35:12]

#

Grez kirjoitti:

Itse tulkitsin alkuperäisen toivomuksen niin, että kun sovelluksessa X painetaan nappia A, niin syntetisoidaan painallukset ABC sovellukselle Y. Ei niin, että oltaisiin sovelluksessa Y kokoajan.

Tässä tapauksessa olisi kenties parasta injektoida oma DLL CBT-hookin kautta koneen jokaiseen prosessiin.

Grez kirjoitti:

Mutta toki jos on tarkoitus olla siellä wordpadissa koko ajan, niin sitten ei tietenkään pelkkä viestien lähettely riitä.

Ei se riitä kummassakaan tapauksessa.

Uinotin [18.11.2009 14:19:22]

#

Eli siis kyse olisi juuri wordpadiin kirjoittamisesta näppäimellä tai näppäinyhdistelmällä. Millä tavalla tämä sitten olisi paras tehdä?

Deffi [18.11.2009 14:52:16]

#

RegisterHotKey:llä onnistuu näppäinyhdistelmään reagoiminen, löytyy esimerkkikin tuolta alhaalta. Jos tuota käyttää kannattaa luoda oma säie CreateThreadilla messageloopille (jossei kyseessä oo Win32-ohjelma, jolla on oma messagelooppi - sit kannattas tietty käyttää sitä). Käytä tätä nopeasti ennen kun toi tulee taas suosittelemaan jotai system wide hookkejansa tänne,,,

Vähän kyllä paha sanoa mikä olis se paras tapa, kun ei täysin tarkkaan tiedä mitä oot tekemässä. Esimerkiksi jos niitä "näppäimenpainalluksia" on tarkoitus lähettää muihinkin ikkunoihin kuin WordPadiin, niin toi FindWindowEx + viestien lähettely ei välttämättä oo kovin hyvä ja joustava tapa.

Uinotin [18.11.2009 17:45:19]

#

Deffi kirjoitti:

Vähän kyllä paha sanoa mikä olis se paras tapa, kun ei täysin tarkkaan tiedä mitä oot tekemässä. Esimerkiksi jos niitä "näppäimenpainalluksia" on tarkoitus lähettää muihinkin ikkunoihin kuin WordPadiin, niin toi FindWindowEx + viestien lähettely ei välttämättä oo kovin hyvä ja joustava tapa.

Ihan tasan tarkkaanhan kyseessä on siis ohjelma, joka kirjoittaa kahdeksan kirjainnäppäimen yhdistelmillä pelkästään yhteen wordpad-ikkunaan. Ohjelmassa on tarkoitus olla enemmän makroja kuin kahdeksan näppäimen painamisyhdistelmiä, joten tiettyä näppäintä painamalla saa valikosta otettua lisää vaihtoehtoja.

Tämä siis tarkoittaa, että ohjelman ei tarvitse olla ikkunoiden vaihdossa joustava.

Deffi [18.11.2009 20:09:37]

#

Tollasten pitempien näppäinyhdistelmien seuraaminen ei RegisterHotKeyllä kätevästi onnistu. Mihin noi näppäinyhdistelmät, joihin pitäisi reagoida, kirjoitetaan? Jos riittää että niihin reagoidaan vain sun ohjelman ikkunassa, niin sillon ikkunan luomiseen käytetty rajapinta (Win32, wxWidgets, SDL tai whatever) tarjoaa välineet näppäinten lukuun. Muuten joudut käyttämään GetAsyncKeyStatea tai sit niitä hookkeja. Kummassakin tapauksessa koodista tulee hyvin helposti purkkaa ja rumaa. SetWindowsHookExin käytöstä "keyloggerin" toteuttamiseen on joku esimerkki täällä.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta