Skip to main content
GameDev.net gamedev.net
🔒 Locked

[.net] Simulate Keypress and Directx

Started by LostAgain Oct 16, 2006 at 11:03 PM 23 replies 30.2k views
Original Post
LostAgain
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.
The collective intelligence of the human race is a constant; the population is growing at an exponential rate. The conclusion is left as an exercise for the student.
KGodwin
KGodwin
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));

}
}
}
}
LostAgain
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.
The collective intelligence of the human race is a constant; the population is growing at an exponential rate. The conclusion is left as an exercise for the student.
KGodwin
KGodwin
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.

LostAgain
LostAgain
trying to use it in everquest and so far no luck. no CLUE wth is wrong.
The collective intelligence of the human race is a constant; the population is growing at an exponential rate. The conclusion is left as an exercise for the student.
Daggett
Daggett
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).
LostAgain
LostAgain
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.
The collective intelligence of the human race is a constant; the population is growing at an exponential rate. The conclusion is left as an exercise for the student.
Daggett
Daggett
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...
LostAgain
LostAgain
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. my wrist thanks you
The collective intelligence of the human race is a constant; the population is growing at an exponential rate. The conclusion is left as an exercise for the student.
Daggett
Daggett
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.
LostAgain
LostAgain
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
The collective intelligence of the human race is a constant; the population is growing at an exponential rate. The conclusion is left as an exercise for the student.
LostAgain
LostAgain
do you use the directx key codes? that your enum from Key?
The collective intelligence of the human race is a constant; the population is growing at an exponential rate. The conclusion is left as an exercise for the student.
LostAgain
LostAgain
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.
The collective intelligence of the human race is a constant; the population is growing at an exponential rate. The conclusion is left as an exercise for the student.
Daggett
Daggett
Yeah, Key is the Microsoft.DirectX.DirectInput.Key enum.
LostAgain
LostAgain
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
The collective intelligence of the human race is a constant; the population is growing at an exponential rate. The conclusion is left as an exercise for the student.
DillyDaDally
DillyDaDally
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.
DillyDaDally
DillyDaDally
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.
LostAgain
LostAgain
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.
The collective intelligence of the human race is a constant; the population is growing at an exponential rate. The conclusion is left as an exercise for the student.
novice4ever
novice4ever
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.


Daggett
Daggett
Well, your sending '0' as the scan code, when Microsoft.DirectX.DirectInput.Key.D0 (11) is the real scan code for '0';

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.