• Advertisement
Sign in to follow this  

[.net] Simulate Keypress and Directx

This topic is 4121 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to write a program that will send a keypress (and eventually i will do a mouse move / press also) to an appliction. i tried using the managed sendinput and while it works in normal applications it does NOT work in Directx applications. any suggestions? i am trying to figure out the pinvoke version of SenInput but having very little luck at the moment so if you happen to know what to do in order to get this to work please help.

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by LostAgain
I'm trying to write a program that will send a keypress (and eventually i will do a mouse move / press also) to an appliction. i tried using the managed sendinput and while it works in normal applications it does NOT work in Directx applications. any suggestions? i am trying to figure out the pinvoke version of SenInput but having very little luck at the moment so if you happen to know what to do in order to get this to work please help.


If it's ANY application...this should do the trick. Just be sure to modify it for what you want...it's straight out of one of my toys.

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace wiseKontrol.CommandClasses
{
class InsertText : BaseCommand
{
public InsertText()
{
this.SCommandName = "InsertText";
this.SMenuItemName = "Insert Te&xt";
this.SArgumentHelp = "Enter the text to be inserted:";
}

public const ushort KEYEVENTF_KEYUP = 0x0002;
public const ushort KEYEVENTF_KEYDOWN = 0x0000;
public const ushort KEYEVENTF_SCANCODE = 0x0008;
public const ushort KEYEVENTF_UNICODE = 0x0004;

public struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public long time;
public uint dwExtraInfo;
};

[StructLayout(LayoutKind.Explicit, Size = 28)]
public struct INPUT
{
[FieldOffset(0)]
public uint type;
[FieldOffset(4)]
public KEYBDINPUT ki;
};


[DllImport("user32.dll")]
public static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);

public override void executeCommand()
{
INPUT structInput;
structInput = new INPUT();
structInput.type = 1;
structInput.ki.wScan = 0;
structInput.ki.wVk = 0;
structInput.ki.time = 0;
structInput.ki.dwFlags = 0;
structInput.ki.dwExtraInfo = 0;

foreach (char c in SArgument.ToCharArray())
{
structInput.ki.dwFlags = KEYEVENTF_UNICODE;
structInput.ki.wScan = (ushort)c;
SendInput(1, ref structInput, Marshal.SizeOf(structInput));

structInput.ki.dwFlags = KEYEVENTF_UNICODE;
structInput.ki.dwFlags += KEYEVENTF_KEYUP;
structInput.ki.wScan = (ushort)c;
SendInput(1, ref structInput, Marshal.SizeOf(structInput));

}
}
}
}

Share this post


Link to post
Share on other sites
Yup. go to a text window and it works go to my directx application and it doesn't.

Anyone else have some ideas?

I was thinking maybe throwing in a windowshookex and using the journalplay think like one of the msdn files i was reading said but reading that was like slamming my face into a wall. i got nothing out of it but a headache.

Share this post


Link to post
Share on other sites
Quote:
Original post by LostAgain
Yup. go to a text window and it works go to my directx application and it doesn't.

Anyone else have some ideas?

I was thinking maybe throwing in a windowshookex and using the journalplay think like one of the msdn files i was reading said but reading that was like slamming my face into a wall. i got nothing out of it but a headache.


That's odd...I use it just fine in Warcraft III to hold down my alt key for life checking =0 Well good luck finding a solution, I just tossed it out there since I had it lying around.

Share this post


Link to post
Share on other sites
For my program that simulates key presses in games I use the KEYEVENTF_SCANCODE in the dwFlags. I had a similar problem as you but I played around for a while and found that DirectInput will only react if you add KEYEVENTF_SCANCODE and you add the scan code in wScan.

Edit: Also I should mention that just casting the char to the scan code didn't work for me, the proper scan codes can be found at Microsoft.DirectX.DirectInput.Key (I'm not sure where they are in unmanaged, sorry).

Share this post


Link to post
Share on other sites
i am relativly certai i tried this (Ox100 or Ox001 i forget which it was that it's defined as) but i will try again. i am nearlly certain what i need to do is either hook in and inject my own code (ala another post on this board from almost 2 years ago) OR provide an alternative wrapper directinput dll that emulates the current dll but with a direct pipeline to access the keystates (either of which is an inelegant time consumming and risky method of doing this)

oh well will play with it some more to try.

on the possitive side they no longer use directinput for mouse work and instead use the system mouse and htis is pretty simple to work with. so i can do that relativly easilly.

Share this post


Link to post
Share on other sites
Odd, my program works perfectly in every single game I've tried it in (about 10), and I know for sure that some of them used DI for input. I can post some sections of my app if that would help...

Share this post


Link to post
Share on other sites
i would appriciate that greatly. in exchange i will package it into a nice little .net class library along with modified send cursor and send keyboard routines making everything in nice one package. figure other people have the same issue and would definatly like this also. if you have any form of repetitive stress syndrom not having to hit a button over and over just because a developer said to is so very nice. <clutches his wrist in agony> my wrist thanks you

Share this post


Link to post
Share on other sites
Ok, here is where I define the unmanaged stuff:

[StructLayout(LayoutKind.Sequential)]
struct INPUT
{
public UInt32 type;
//KEYBDINPUT:
public ushort wVk;
public ushort wScan;
public UInt32 dwFlags;
public UInt32 time;
public UIntPtr dwExtraInfo;
//HARDWAREINPUT:
public UInt32 uMsg;
public ushort wParamL;
public ushort wParamH;
}

enum SendInputFlags
{
KEYEVENTF_EXTENDEDKEY = 0x0001,
KEYEVENTF_KEYUP = 0x0002,
KEYEVENTF_UNICODE = 0x0004,
KEYEVENTF_SCANCODE = 0x0008,
}

[DllImport("user32.dll")]
static extern UInt32 SendInput(UInt32 nInputs, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] INPUT[] pInputs, Int32 cbSize);



And here is where I get the scan code. It's messy, I know, but I simply couldn't find any other way to do it.


private Key GetScanCode(char Letter)
{
switch(Letter)
{
case '0':
return Key.D0;

case '1':
return Key.D1;

case '2':
return Key.D2;

case '3':
return Key.D3;

case '4':
return Key.D4;

case '5':
return Key.D5;

case '6':
return Key.D6;

case '7':
return Key.D7;

case '8':
return Key.D8;

case '9':
return Key.D9;

case 'a':
case 'A':
return Key.A;

case 'b':
case 'B':
return Key.B;

case 'c':
case 'C':
return Key.C;

case 'd':
case 'D':
return Key.D;

case 'e':
case 'E':
return Key.E;

case 'f':
case 'F':
return Key.F;

etc...



And this is how I make the call:


INPUT[] InputData = new INPUT[1];
Key ScanCode = GetScanCode(ControllerScheme.KeyMappings[Count]);

InputData[0].type = 1; //INPUT_KEYBOARD
InputData[0].wScan = (ushort)ScanCode;
InputData[0].dwFlags = (uint)SendInputFlags.KEYEVENTF_SCANCODE;

if (SendInput(1, InputData, Marshal.SizeOf(InputData[0])) == 0)
{
System.Diagnostics.Debug.WriteLine("SendInput failed with code: " +
Marshal.GetLastWin32Error().ToString());
}



And that's all I do.

Share this post


Link to post
Share on other sites
ok will play with this some. i did notice you didn't use a fixed layout on the struct that could cause crashing issues some times. will play with it then post what i get out of it. thanks again

Share this post


Link to post
Share on other sites
working on a parse engine for your key input. should be able to send a string such as "{ENTER}press these keys then enter{ENTER}" and it would send this enter then it would type in 'press these keys then enter' then it would hit enter again.
should be usefull make it possible to send not just single keys easilly but also full strings. trouble is in the {ENTER} or {{} type stuff so you can send anything even special keys hehe.

Share this post


Link to post
Share on other sites
ok still fiddleing with it but so far i can send keys. i actually have to send a keydown then a keyup (keydown code is 0 by the way you don't have that one on your enum hehe) working on a buffered pulsed input script. so when you type in 'send all of this{ENTER}' it will send these keys 'send all of this' then hit enter. one big deal is that with your system your currently sending a key ata time in the buffer. if you try to send a stirng of text there is the possibility of someone sneaking in a key press while it's sending it. the solution i'm looking at is to search through the string for my insertion codes such as {ENTER} and replace it with one of the higher ascii codes then when it builds the array of key combos it searches through each key one at a time in the list parses them and converts them to the propper enums then sends the full buffer at once. sound good? and would you be interested in a copy of this code when i'm done? should make that switch case thing absolete or at least make it a little more intuitive to use. =D once again thanks for the assistance on this one. was driving me NUTS hehe

Share this post


Link to post
Share on other sites
Hey, this is great guys. You're right in that there are other people struggling with this. I use the SendInput function and it doesn't seem to work in most games. If you finish that library I'd be really interested. Keep us updated.

Share this post


Link to post
Share on other sites
Just another thought (it probably doesn't make much of a difference, since your looking into a way to do it without a lookup table). In my code, instead of using a big switch statement to look up scancodes, I just load a map with all the data that's needed. Works mighty fine.

Share this post


Link to post
Share on other sites
sure but eventually somewhere you must map one thing to another thing. i am using a hashcoded array to do it (the char code is the index of where the directx code is) this means there is a nice one to one relation AND none of that stupid switch case thng (which converts to a long string of if else blocks) this means also that if things change i need only change the mapping.

Share this post


Link to post
Share on other sites
Dear LostAgain,Daggett and KGodwin,
I have read your topic relate to sendkey to directx apps.
http://www.gamedev.net/community/forums/topic.asp?topic_id=419710&whichpage=1�
Knowing that you already done that. I have done the same, but it doesnt works (it works on normal windows). It would be nice if you could show me what i have wrong. I just want to simply send a key 0 to the game.
Btw the game I'm testing is 9 Dragons, you can found it here http://nine.nexon.com . And here is my code:

INPUT[] InputData = new INPUT[1];

//KEYBDINPUT:
InputData[0].type = 1;
InputData[0].wVk = 0;
InputData[0].wScan = 0;
InputData[0].dwFlags = 0;
InputData[0].time = 0;
InputData[0].dwExtraInfo = (UIntPtr)0;

int i=0;
while(i<30)
{
InputData[0].wScan = (ushort)'0';
InputData[0].dwFlags = (uint)SendInputFlags.KEYEVENTF_SCANCODE | (uint)SendInputFlags.KEYEVENTF_KEYDOWN;

SendInput(1, InputData, Marshal.SizeOf(InputData[0]));

InputData[0].wScan = (ushort)'0';
InputData[0].dwFlags = (uint)SendInputFlags.KEYEVENTF_SCANCODE | (uint)SendInputFlags.KEYEVENTF_KEYUP;

SendInput(1, InputData, Marshal.SizeOf(InputData[0]));

Thread.Sleep(1000);
i++;
}

Thank you very much for your concert,
Iam sorry for my bad english. Hope to hear from you soon.
Best regards.


Share this post


Link to post
Share on other sites
Well, your sending '0' as the scan code, when Microsoft.DirectX.DirectInput.Key.D0 (11) is the real scan code for '0';

Share this post


Link to post
Share on other sites
Ah yes, I realise that :) . But even when I send '0', it should send something to the game but it doesnt. Nothing was send to the game.

Share this post


Link to post
Share on other sites
Well, I assume it would send scan code 48(B). Otherwise it looks ok to me. How do you define the unmanaged stuff? It's also possible that the game uses a driver hook in which case I'm not sure SendInput would work, you could try keybd_event in that case which I think works at a lower level. Try sending the key press to notepad or the address box of you browser and see if it works there.

Quote:
sure but eventually somewhere you must map one thing to another thing. i am using a hashcoded array to do it (the char code is the index of where the directx code is) this means there is a nice one to one relation AND none of that stupid switch case thng (which converts to a long string of if else blocks) this means also that if things change i need only change the mapping.

I thought of a hashmap, but since a hash map uses int's to get a hash of a short, I figured it would be a waste of memory, and hash maps also break down into a series of ifs and elses, but they just guess where to start looking better than a switch would, which just starts at the beginning. A one-to-one lookup as just a big array would work also, but again it's very memory inefficient. Also, it's very unlikely the scan codes will change any time soon.

Share this post


Link to post
Share on other sites
ok well i have all the directx key presses working perfectly
heres the problem ont he mouse. for the longest time i couldn't get any responce int he directx windows (worked fine as allways in other programs) so i desided to step back use the directx codes SO

DIMOUSE_WHEEL = 2181038856, /* Z Axis */
DIMOUSE_BUTTON0 = 2181039116, /* Button 0 */
DIMOUSE_BUTTON1 = 2181039117, /* Button 1 */
DIMOUSE_BUTTON2 = 2181039118, /* Button 2 */
DIMOUSE_BUTTON3 = 2181039119, /* Button 3 */
DIMOUSE_BUTTON4 = 2181039120, /* Button 4 */
DIMOUSE_BUTTON5 = 2181039121, /* Button 5 */
DIMOUSE_BUTTON6 = 2181039122, /* Button 6 */
DIMOUSE_BUTTON7 = 2181039123, /* Button 7 */

and tada useing this code will press a mouse button

INPUT []Input = new INPUT[1];
Input[0].type = 0;
Input[0].mi.dwExtraInfo = IntPtr.Zero;
Input[0].mi.dx = 0;
Input[0].mi.dy = 0;
Input[0].mi.mouseData = 0;
Input[0].mi.time = 100;
Input[0].mi.dwFlags = (uint)DXMouseCode.DIMOUSE_BUTTON0;
SendInput(1,Input,Marshal.SizeOf(Input[0]));

the problem is that now the mouse button doesn't go UP and i can't figure out how to indicate that =P
it's not like the windows code where they have a upa nd down state no in directx it seems to have only the BUTTON.
now mousedata is not it thats just used for the wheel mouse delta (120 being max delta) when it's set to the wheel mouse move. thats the extent of it. i doubt it's extrainfo but it oculd be. any more help?

Share this post


Link to post
Share on other sites
Well, i also tried to use keybd_event but stil no help. However, it worth to metion that the microsoft on-screen keyboard works with the game. Can't figure out how they did that.
Also, I found another acticle by muhammad. I think I may stick to this one:
http://www.gamedev.net/community/forums/topic.asp?topic_id=371104

Thank you for your help guy.
Best regards,
Hoaian

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement