[ Milos Stojanovic @ 13.09.2005. 17:37 ] @
Evo već nekoliko dana pretražujem po netu i nikako da nađem odgovor. Možda tema i nije za ovde, ali nisam našao bolje mesto. Dakle:

Da li postoji način da se sintetiše keyboard event i da se pošalje aplikaciji koja keyboard koristi preko DirectInput APIja? Za aplikacije koje koriste standardne win32 evente, rešenje je vrlo prosto i svodi se na poziv SendInput funkcije, ili keybd_event funkcije ili SendMessage pa pošaljem WM_KEYDOWN... mogućnosti neograničene :)
Ali džaba sve to, kad ni jedan od ovih metoda ne radi sa DirectInput aplikacijama... Razmišljao sam da pišem neki driver za tastaturu, al opet, možda DirectInput lagano zaobiđe i to?

Spasite me, molim vas. :(
[ Milos Stojanovic @ 14.09.2005. 01:40 ] @
heh, nevermind :)
Našao sam rešenje, radi keybd_event, ali treba malo drugačij proslediti parametre:

Code:

// TheKey = 'a' // neki keycode, nebitno
keybd_event(VkKeyScan(TheKey), MapVirtualKey(VkKeyScan(TheKey), 0), 0, 0);
Sleep(30); //da nahvata event? ovo mi nije bas najjasnije
keybd_event(VkKeyScan(TheKey), MapVirtualKey(VkKeyScan(TheKey), 0), KEYEVENTF_KEYUP, 0);
[ ((BugA)) @ 26.12.2008. 20:34 ] @
Ja se iskreno, najiskrenije izvinjavam sto vadim ovu temu iz naftalina, ali nadam se da ce mi biti oprosteno, jer ova tema to zasluzuje :)

Brate mili, sad bih te izljubio da mogu! (ili mozda i ne bih bas :p )

Ne znam gde sve nisam trazio i sta sve nisam pokusavao, i preko SendKeys, i keybd_event, i SendMessage, i SendInput, i uvek sve lepo radi kada su neke "obicnije" Windows aplikacije u pitanju, ali kada sam dosao do DirectX programa (igre), jednostavno nikako nisam mogao da simuliram pritisak tastera. Nigde na netu nisam nasao resenje, a ne znam ni sam na koliko foruma sam video isto pitanje - kako simulirati pritisak tastera koristeci DirectInput.

Odakle ti ovo resenje? :))

Da malo osvezim temu, ako neko ima problema sa gorepomenutim kodom, evo dopune (Visual Studio 2008, C#):

Dodati u listu using:
Code:
using System.Threading; // potrebno zbog Thread.Sleep

Ovo ubaciti u klasu forme:
Code:
// prototipovi procedure i funkcija
[DllImport("user32.dll")]
static extern void keybd_event(short bVk, uint bScan, uint dwFlags, int dwExtraInfo);

[DllImport("user32.dll")]
public static extern uint MapVirtualKey(short uCode, uint uMapType);

[DllImport("user32.dll")]
public static extern short VkKeyScan(char ch);

Ovo staviti u proceduru koja ce da simulira pritisak:
Code:
const int KEYEVENTF_KEYUP = 0x2; // deklaracija i definicija KEYEVENT_KEYUP konstante

char TheKey = 'd'; // neki keycode, nebitno
keybd_event(VkKeyScan(TheKey), MapVirtualKey(VkKeyScan(TheKey), 0), 0, 0);
Thread.Sleep(30); // da nahvata event? ovo mi nije bas najjasnije
keybd_event(VkKeyScan(TheKey), MapVirtualKey(VkKeyScan(TheKey), 0), KEYEVENTF_KEYUP, 0);

Meni ovako radi bez greske :) Ne mogu ni da zamislim za sta sve ovo moze da se iskoristi, ja odoh da se igram i istrazujem :)

Jos jednom se izvinjavam zbog ovog "skoka u proslost", mislim da ova tema to svakako zasluzuje ;)

[Ovu poruku je menjao ((BugA)) dana 28.12.2008. u 16:12 GMT+1]
[ ((BugA)) @ 27.12.2008. 01:26 ] @
Evo i prvog problema... (nisam se bas dugo radovao :p)

Sve ovo lepo radi kada zelimo da "posaljemo" (simuliramo pritisak) tastera koji ima ASCII kod, ali sta radimo sa tasterima koji ga nemaju - strelice (levo/desno/gore/dole)?

Opet se javlja problem sa pocetka price. Ako koristimo
Code:
const int KEYEVENTF_KEYUP = 0x2;
const char VK_DOWN = (char)Keys.Down; // jedna od mogucnosti

keybd_event(VK_DOWN, 0, 0, 0);
keybd_event(VK_DOWN, 0, KEYEVENTF_KEYUP, 0);

... poruka o pritisnutom tasteru (kursorska strelica, dole) se salje i lepo se moze videti kako radi u npr. Notepad-u (izudaramo par puta "enter", pa se vratimo koji red na gore i cekamo da nas program spusti red dole, kao da smo pritisnuli taster "dole"). Medjutim, DirectInput ovo ne hvata.

Ako zelimo da koristimo postupak za koji znamo da radi sa npr. slovima...
Code:
keybd_event(VkKeyScan(TheKey), MapVirtualKey(VkKeyScan(TheKey), 0), 0, 0);
keybd_event(VkKeyScan(TheKey), MapVirtualKey(VkKeyScan(TheKey), 0), KEYEVENTF_KEYUP, 0);

... javlja se problem - koju vrednost dodeliti promenljivoj TheKey, kada taster - strelica na dole nema ekvivalentan karakter koji bi je predstavljao, niti ima ASCII kod...?

I zasto uopste prvi slucaj DirectInput ne vidi, a drugi prepoznaje i reaguje?

Za slovo 'd' smo pisali TheKey = 'd' (moze i npr. TheKey = Convert.ToChar(100)), za ESC (escape) mozemo pisati TheKey = Convert.ToChar(0x1B), a jedino sto nam ostaje a vezano je za kursorske strelice jesu virtuelni kodovi, za strelicu dole VK_DOWN = 0x28, tj. VK_DOWN = 40, ali kako to iskoristiti u keybd_event, preko VkKeyScan i MapVirtualKey, a da naglasimo da unosimo virtual keycode, a ne ASCII...? Da prepravljamo deklaracije prototipova procedure i funkcija, ili nesto drugo?

[Ovu poruku je menjao ((BugA)) dana 28.12.2008. u 16:13 GMT+1]
[ ((BugA)) @ 27.12.2008. 11:15 ] @
Uspeo sam :))

Bilo je potrebno samo (cuj, "samo" :)) ukljuciti KEYEVENTF_EXTENDEDKEY flag kod keybd_event procedure, obzirom da se scan code tastera/strelice "dole" sastoji od dva bajta - e0 50 :) (e0 je dodatni bajt koje je potrebno "preskociti", upravo postavljanjem KEYEVENTF_EXTENDEDKEY flega).

Sa ovom ispravkom, pritisak na kursorsku strelicu "dole" izgleda ovako:

Dodatno deklarisemo i definisemo KEYEVENTF_EXTENDEDKEY flag (KEYEVENTF_KEYUP nam je ostao od malopre):
Code:
const int KEYEVENTF_EXTENDEDKEY = 0x1;
const int KEYEVENTF_KEYUP = 0x2;

Postupak za simuliranje izgleda ovako:
Code:
keybd_event(0x28, MapVirtualKey(0x28, 0), KEYEVENTF_EXTENDEDKEY, 0);
Thread.Sleep(30);
keybd_event(0x28, MapVirtualKey(0x28, 0), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);

Ovde primecujemo jos dve stvari - prvo da smo izbacili promenljivu TheKey koju smo prethodno deklarisali kao char jer char (karakter) oznaka tastera "DOWN" ne postoji, a zatim da smo izbacili i VkKeyScan(TheKey) funkciju iz istog razloga - nemamo TheKey karakter, pa ne mozemo ni naci virtual key code "ni iz cega", vec key code tastera "DOWN" (cija je vrednost 0x28) prinosimo kao direktan parametar u proceduri keybd_event.

I jos jedna napomena/objasnjenje za ovo Thread.Sleep(30) - potrebno je na trenutak zaustaviti thread kako bi aplikacija uspela da procita pritisak tastera (dovoljna pauza je vec od 20 milisekundi, za manje vrednosti je pitanje) pre no sto posaljemo signal da je taster otpusten. Ako je pauza manja od 20 milisekundi ili je uopste nema, citav dogadjaj simulacije pritiska tastera ce vrlo verovatno proci neopazeno jer se desio previse brzo. U primeru koristimo pauzu od 30 milisekundi, za svaki slucaj :)

Na kraju bih samo podsetio kako smo deklarisali prototip procedure keybd_event:
Code:
static extern void keybd_event(short bVk, uint bScan, uint dwFlags, int dwExtraInfo);

... gde su parametri sledeci:

bVk // "Virtual Keycode" vrednost tastera, npr. VK_RETURN, VK_TAB…
bScan // "Scan Code" vrednost tastera, npr. 0xb8 za taster "Left Alt" (levi "Alt" taster)
dwFlags // fleg koji se postavlja za trenutno stanje tastera, npr. KEYEVENTF_KEYUP (taster podignut)
dwExtraInfo // dodatna 32-bit-na informacija o stanju tastera


Koga zanima vise o ovome (npr. ove dodatne informacije poslednjeg parametra) moze pogledati link - http://www.codeproject.com/KB/system/keyboard.aspx?display=Print, a za tabelu "scan code"-ova pogledajte npr. ovaj link - http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html .

PoZz svima, i srecni Vam praznici!

BugA :)

[Ovu poruku je menjao ((BugA)) dana 28.12.2008. u 16:15 GMT+1]