Simulating Keyboard with SendInput API in DirectInput applications - c#

I'm trying to simulate keyboard commands for a custom game controller application. Because I'll need to simulate commands in a DirectInput environment most of the usual methods don't work. I know that using a hook would work 100% but I'm trying to find an easier implementation.
I've done quite a bit of searching and found that by using the SendInput API with Scancodes instead of virtual keys should work, but it seems to behave like the key's are "sticking". I've sent both the KEYDOWN and KEYUP events but when I attempt to send the message in a DirectInput environment, the game acts as if the key is being held down.
For instance, if I simulate a "W" keypress and have that key mapped in a First Person Shooter to the "move forward" action, once I'm in game, the function below will cause the character to move forward. However, just by issuing the command once, it will move the character forward indefinitely.
Here is a code snippet (in C#) for the SendInput function I'm calling:
[DllImport("user32.dll")]
static extern UInt32 SendInput(UInt32 nInputs, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] INPUT[] pInputs, Int32 cbSize);
public static void Test_KeyDown()
{
INPUT[] InputData = new INPUT[2];
Key ScanCode = Microsoft.DirectX.DirectInput.Key.W;
InputData[0].type = 1; //INPUT_KEYBOARD
InputData[0].wScan = (ushort)ScanCode;
InputData[0].dwFlags = (uint)SendInputFlags.KEYEVENTF_SCANCODE;
InputData[1].type = 1; //INPUT_KEYBOARD
InputData[1].wScan = (ushort)ScanCode;
InputData[1].dwFlags = (uint)(SendInputFlags.KEYEVENTF_KEYUP | SendInputFlags.KEYEVENTF_UNICODE);
// send keydown
if (SendInput(2, InputData, Marshal.SizeOf(InputData[1])) == 0)
{
System.Diagnostics.Debug.WriteLine("SendInput failed with code: " +
Marshal.GetLastWin32Error().ToString());
}
}
I'm not sure if this method is a lost cause, or if there is just something silly I'm missing. I hate to over complicate my code if I don't have to by using hooks, but this is also new territory for me.
Any help anyone can give is much appreciated.
Thanks!

I've found the solution to my own problem. So, I thought I'd post here to help anyone who may have similar issues in the future.
The keyup command was not working properly because when only sending the scan code, the keyup must be OR'ed with the scan code flag (effectively enabling both flags) to tell the SendInput() API that this is a both a KEYUP and a SCANCODE command.
For instance, the following code will properly issue a scan code key-up:
INPUT[] InputData = new INPUT[1];
InputData[0].Type = (UInt32)InputType.KEYBOARD;
//InputData[0].Vk = (ushort)DirectInputKeyScanCode; //Virtual key is ignored when sending scan code
InputData[0].Scan = (ushort)DirectInputKeyScanCode;
InputData[0].Flags = (uint)KeyboardFlag.KEYUP | (uint)KeyboardFlag.SCANCODE;
InputData[0].Time = 0;
InputData[0].ExtraInfo = IntPtr.Zero;
// Send Keyup flag "OR"ed with Scancode flag for keyup to work properly
SendInput(1, InputData, Marshal.SizeOf(typeof(INPUT)))
Thanks to Hans for the response. I did some investigating and sending two messages back to back like the original example does indeed simulate a "keypress" but it's very fast. It would not work well for a movement command, but would be ideal when action keys are to be "tapped" and not held down.
Also, the virtual key field is ignored when sending a scan code. MSDN had the following to say on the subject:
"Set the KEYEVENTF_SCANCODE flag to define keyboard input in terms of the scan code. This is useful to simulate a physical keystroke regardless of which keyboard is currently being used. The virtual key value of a key may alter depending on the current keyboard layout or what other keys were pressed, but the scan code will always be the same."
http://msdn.microsoft.com/en-us/library/ms646271%28v=VS.85%29.aspx

I was trying to simulate keyboards for a presentation in Flash, and was also having the same problem. It did work for apps like Notepad, but not for flash. After hours of googling I finally made it work:
public static void GenerateKey(int vk, bool bExtended)
{
INPUT[] inputs = new INPUT[1];
inputs[0].type = INPUT_KEYBOARD;
KEYBDINPUT kb = new KEYBDINPUT(); //{0};
// generate down
if ( bExtended )
kb.dwFlags = KEYEVENTF_EXTENDEDKEY;
kb.wVk = (ushort)vk;
inputs[0].ki = kb;
SendInput(1, inputs, System.Runtime.InteropServices.Marshal.SizeOf(inputs[0]));
// generate up
//ZeroMemory(&kb, sizeof(KEYBDINPUT));
//ZeroMemory(&inputs,sizeof(inputs));
kb.dwFlags = KEYEVENTF_KEYUP;
if ( bExtended )
kb.dwFlags |= KEYEVENTF_EXTENDEDKEY;
kb.wVk = (ushort)vk;
inputs[0].type = INPUT_KEYBOARD;
inputs[0].ki = kb;
SendInput(1, inputs, System.Runtime.InteropServices.Marshal.SizeOf(inputs[0]));
}

Related

BASS WASAPI BPMCounter

I want to analyse my default playback device and detect the beats. I've been using the BASS WASAPI to get the FFT data of the selected device with:
int ret = BassWasapi.BASS_WASAPI_GetData(_fft, (int)BASSData.BASS_DATA_FFT2048);
Now I was using the data to generate spectrum data and display this to the user. In addition I want to detect the Beats using the BPMCounter Class from BASS. However as far as I can tell the BPMCounter.ProcessAudio() function requires a stream (which I don't get with WASAPI) in order to work. Is there a ways I can use BPMCounter with WASAPI? Would be great if someone can point me to the right direction. Thanks
Edit:
Tried this to convert the data to a stream, but without success:
int ret = BassWasapi.BASS_WASAPI_GetData(_fft, (int)BASSData.BASS_DATA_FFT2048); //get channel fft data
var chan = Bass.BASS_StreamCreate(0, 44100, BASSFlag.BASS_DEFAULT, BASSStreamProc.STREAMPROC_PUSH);
Bass.BASS_ChannelPlay(chan, false);
Bass.BASS_StreamPutData(chan, _fft, _fft.Length);
bool beat = _count.ProcessAudio(chan, true);
Debug.Write(beat);
beat is always False, however I can see at the Spectrum that the capturing of the FFT Data is corrent.
I've just started playing with this lib a few hours ago and i am still going through the examples. So my answer maybe is not what you want. For my project i also want to transform WASAPI into a stream and use it for a displaying a spectrum. What i did was to create a StreamPush, right after BASS_WASAPI initialization.
To init your WASAPI use this call and this delegate:
private InitWasapi()
{
WASAPIPROC _process = new WASAPIPROC(Process); // Delegate
bool res = BassWasapi.BASS_WASAPI_Init(_YourDeviceNumber, 0, 0, BASSWASAPIInit.BASS_WASAPI_BUFFER, 1f, 0f, _process, IntPtr.Zero);
if (!res)
{
// Do error checking
}
// This is the part you are looking for (maybe!)
// Use these flags because Wasapi needs 32-bit sample data
var info = BassWasapi.BASS_WASAPI_GetInfo();
_stream = Bass.BASS_StreamCreatePush(info.freq, info.chans, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT, IntPtr.Zero);
BassWasapi.BASS_WASAPI_Start();
}
private int Process(IntPtr buffer, int length, IntPtr user)
{
Bass.BASS_StreamPutData(_stream, buffer, length);
return length;
}
Please note: This works, but i am still experimenting. For example i am not getting the same spectrum output as when i create the stream from the music file itself. There are some (small) differences. Maybe it's because i am using a custom EQ in Winamp for playing the same .mp3. So if anyone knows more on this subject, i would like also to hear it!

SendKeys with C# PostMessage - Underscore

I'm trying to send an underscore with PostMessage but the best I can get is -, can anyone help here I cannot find the answer anywhere.
I send a string to a character loop that gets each one and uses PostMessage to send the key, which works fine for almost everything but I cannot figure out _.
public bool SendKeys(string message)
{
var success = false;
uint wparam = 0 << 29 | 0;
foreach (var child in GetChildWindows(Window.Windowhandle))
{
var sb = new StringBuilder(100);
GetClassName(child, sb, sb.Capacity);
//(IntPtr)Keys.H
if (sb.ToString() != Window.TargetWindow) continue;
foreach (var c in message)
{
var k = ConvertFromString(c.ToString());
if (String.Equals(c.ToString(), c.ToString().ToUpper(), StringComparison.Ordinal))
{
PostMessage(child, WM_CHAR, (IntPtr) k, (IntPtr) wparam);
}
else
{
PostMessage(child, WM_KEYDOWN, (IntPtr)k, (IntPtr)wparam);
}
success = true;
Thread.Sleep(200);
}
}
return success;
}
ConvertFromString is just (Keys)Enum.Parse(typeof (Keys), keystr); really, getting the key from System.Form.Keys
Can anyone identify how to send an underscore??
ConvertFromString is just (Keys)Enum.Parse(typeof (Keys), keystr);
That is the fundamental flaw, there is no Keys enumeration value that represent an underscore. Keys are virtual keys, they are the same anywhere in the world. But the characters they produce are not the same, it depends the modifier keys and the active keyboard layout that the user selected.
An American user must first press the Shift key, then press Keys.OemMinus. A German user must press Shift, then Keys.OemQuestion. A French user only presses Keys.D8. A Spanish user presses AltGr, then Keys.D7. Etcetera.
You'll need to get ahead by dropping your dependency on Keys if you want a predictable result. Use WM_CHAR and pass the actual character you want.

Disconnect and Reconnect Displays Programmatically

Question: What is the best way to programmatically disconnect and reconnect displays programmatically?
The Goal: Kill the video output (black screen with no backlight) on a display and later turn it back on. Imagine unplugging the video cord from the monitor, then plugging it back in.
My Attempt:
// Get the monitor to disable
uint iDevNum = 0;
DISPLAY_DEVICE displayDevice = new DISPLAY_DEVICE();
displayDevice.cb = Marshal.SizeOf(displayDevice);
EnumDisplayDevices(null, iDevNum, ref displayDevice, 0))
DEVMODE devMode = new DEVMODE();
EnumDisplaySettings(displayDevice.DeviceName, 0, ref devMode);
//
// Do something here to disable this display device!
//
// Save the display settings
ChangeDisplaySettingsEx(displayDevice.DeviceName, ref devMode,
IntPtr.Zero, ChangeDisplaySettingsFlags.CDS_NONE, IntPtr.Zero);
I can interact with each display, but I can't figure out how to disconnect one.
It is similar to "Disconnect this display" in the Screen Resolution properties in Windows 7:
Notes:
Turning off video output on all displays won't work because I need the other monitors to stay on.
The desktop area on the "dead" display does NOT need to be usable when it is off. Also, it is fine if windows move around.
References:
SO: Enabling a Second Monitor
How to Turn Off a Monitor
1) Get MultiMonitorHelper from here:
https://github.com/ChrisEelmaa/MultiMonitorHelper/tree/master
2) Extend Win7Display to disconnect the display:
using MultiMonitorHelper.DisplayModels.Win7.Enum;
using MultiMonitorHelper.DisplayModels.Win7.Struct;
/// <summary>
/// Disconnect a display.
/// </summary>
public void DisconnectDisplay(int displayNumber)
{
// Get the necessary display information
int numPathArrayElements = -1;
int numModeInfoArrayElements = -1;
StatusCode error = CCDWrapper.GetDisplayConfigBufferSizes(
QueryDisplayFlags.OnlyActivePaths,
out numPathArrayElements,
out numModeInfoArrayElements);
DisplayConfigPathInfo[] pathInfoArray = new DisplayConfigPathInfo[numPathArrayElements];
DisplayConfigModeInfo[] modeInfoArray = new DisplayConfigModeInfo[numModeInfoArrayElements];
error = CCDWrapper.QueryDisplayConfig(
QueryDisplayFlags.OnlyActivePaths,
ref numPathArrayElements,
pathInfoArray,
ref numModeInfoArrayElements,
modeInfoArray,
IntPtr.Zero);
if (error != StatusCode.Success)
{
// QueryDisplayConfig failed
}
// Check the index
if (pathInfoArray[displayNumber].sourceInfo.modeInfoIdx < modeInfoArray.Length)
{
// Disable and reset the display configuration
pathInfoArray[displayNumber].flags = DisplayConfigFlags.Zero;
error = CCDWrapper.SetDisplayConfig(
pathInfoArray.Length,
pathInfoArray,
modeInfoArray.Length,
modeInfoArray,
(SdcFlags.Apply | SdcFlags.AllowChanges | SdcFlags.UseSuppliedDisplayConfig));
if (error != StatusCode.Success)
{
// SetDisplayConfig failed
}
}
}
3) Extend Win7Display to reconnect the display using an answer from this post:
using System.Diagnostics;
/// <summary>
/// Reconnect all displays.
/// </summary>
public void ReconnectDisplays()
{
DisplayChanger.Start();
}
private static Process DisplayChanger = new Process
{
StartInfo =
{
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
FileName = "DisplaySwitch.exe",
Arguments = "/extend"
}
};
4) Update the methods in IDisplay.
5) Implement the methods:
IDisplayModel displayModel = DisplayFactory.GetDisplayModel();
List<IDisplay> displayList = displayModel.GetActiveDisplays().ToList();
displayList[0].DisconnectDisplay(0);
displayList[0].ReconnectDisplays();
There's a github project that I STILL haven't got around, but it's a starting point. You need to use Win7 specific API in order to change settings. ChangeDisplaySettings won't work.
Have a look: https://github.com/ChrisEelmaa/MultiMonitorHelper
This is what you need to do:
update the IDisplay interface to support TurnOff() method,
and then call it:
var displayModel = DisplayFactory.GetDisplayModel();
var displayList = displayModel.GetActiveDisplays().ToList();
var firstDisplay = displayList[0].TurnOff();
How to implement TurnOff()? I WOULD imagine this is how(I might be wrong here now):
You need to break the connection between GPU & monitor through breaking the "paths". You can break path between source and target like this:
Call SetDisplayConfig() and pass inside specific paths and make sure you map out the DISPLAYCONFIG_PATH_ACTIVE from the DISPLAY_PATH_INFO structure flags integer.
http://msdn.microsoft.com/en-us/library/windows/hardware/ff553945(v=vs.85).aspx
Sorry for not being more helpful, but this is pretty hardcore stuff, it took me quite a while to even understand the basics of that API. It's a starting point :-),
take a look at the example how to rotate specific monitor in Win7: How do I set the monitor orientation in Windows 7?
In all honesty, just wrap the DisplaySwitch.exe for Win7, and pass /internal or /external(depending if you want to disable/enable first/second monitor), this might or might not work for >2 monitors.

Xamarin Monotouch Audio Units Callbacks

I have a problem with Audio Units in MonoTouch/Xamarin.
It seems like I can't get a callback on recording, just playback.
I used this example:
https://github.com/xamarin/monotouch-samples/blob/master/AUSoundTriggeredPlayingSoundMemoryBased/ExtAudioBufferPlayer.cs
and looked for Obj C examples. The Obj C examples are pretty much the same like my code so Im a little bit confused about this thing.
The output if running my example is:
INPUT0
Which is the bus number for output.
So the expected output should be:
INPUT1
So my question is: How do I get a recording callback and a playback callback running the same time, or just how do I get a recording callback.
My Code:
void prepareAudioUnit()
{
// AudioSession
AudioSession.Initialize();
AudioSession.Category = AudioSessionCategory.PlayAndRecord;
AudioSession.PreferredHardwareIOBufferDuration = Config.packetLength;
AudioSession.PreferredHardwareSampleRate = Format.samplingRate;
//AudioSession.SetActive (false);
AudioSession.SetActive(true);
Logger.log("HWSR:" + AudioSession.CurrentHardwareSampleRate);
// Getting AudioComponent Remote output
_audioComponent = AudioComponent.FindComponent(AudioTypeOutput.VoiceProcessingIO);
// creating an audio unit instanc
_audioUnit = new AudioUnit(_audioComponent);
// turning on microphone
_audioUnit.SetEnableIO(true,
AudioUnitScopeType.Input,
1 // Remote Input
);
_audioUnit.SetEnableIO(true,
AudioUnitScopeType.Output,
0 // Remote output
);
// setting audio format
_audioUnit.SetAudioFormat(Format.AudioStreamBasicDescription,
AudioUnitScopeType.Output,
1
);
_audioUnit.SetAudioFormat(Format.AudioStreamBasicDescription,
AudioUnitScopeType.Input,
0
);
// setting callback method
_audioUnit.SetRenderCallback(_audioUnit_OutputCallback, AudioUnitScopeType.Global, 0);
_audioUnit.SetRenderCallback(_audioUnit_InputCallback, AudioUnitScopeType.Global, 1);
}
AudioUnitStatus _audioUnit_OutputCallback(AudioUnitRenderActionFlags actionFlags, AudioTimeStamp timeStamp, uint busNumber, uint numberFrames, AudioBuffers data)
{
Logger.log("OUTPUT" + busNumber);
return AudioUnitStatus.NoError;
}
AudioUnitStatus _audioUnit_InputCallback(AudioUnitRenderActionFlags actionFlags, AudioTimeStamp timeStamp, uint busNumber, uint numberFrames, AudioBuffers data)
{
Logger.log("INPUT" + busNumber);
return AudioUnitStatus.NoError;
}
This problem is a bug in Xamarin, they forgot to add a method for InputCallbacks.
I reported the bug but for the people needing the same:
http://nopaste.info/8d0aca98d9.html
Its not good, but it shows how to solve the problem to write a fix yourself till Xamarin updates this.

Can I use SetErrorMode in C# process?

I'm preparing for writing an online judge core,
A program that can compile user's code and run the program to check the answer like uva online judge.
And I'm having problem in catching the exception of submit program like below.
int main()
{
while(~scanf("%d %d",n,&m))
{
printf("%d\n",n+m);
}
return 0;
}
it's access denied at first line because it scan an integer to error position.
how can I catch runtime error for my process?
I used to use "try catch" to catch the exception,
but it didn't reply anything about runtime error.
so I only check the exit code of the submit program although it's not a good method to check except for a process..
and it shows like photo
I have to close the error message box manually,
and I find a solution that is to use a SEH Handler DLL for the process.
SetErrorMode(SEM_NOGPFAULTERRORBOX);
but I don't know how to use it in C# process.
and below is my code of judger
timer = new Stopwatch();
timer.Reset();
submitProg = new Process();
submitProg.StartInfo.FileName = outputFile;
submitProg.StartInfo.UseShellExecute = false;
submitProg.StartInfo.CreateNoWindow = true;
submitProg.StartInfo.RedirectStandardInput = true;
submitProg.StartInfo.RedirectStandardOutput = true;
submitProg.StartInfo.RedirectStandardError = true;
submitProg.StartInfo.ErrorDialog = false;
submitProg.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
submitProg.EnableRaisingEvents = true;
submitProg.Start();
timer.Start();
progInput = submitProg.StandardInput;
progOutput = submitProg.StandardOutput;
progInput.Write(inputStream.ReadToEnd());
submitProg.StandardInput.Close();
while (!submitProg.HasExited)
{
peakPagedMem = submitProg.PeakPagedMemorySize64;
peakVirtualMem = submitProg.PeakVirtualMemorySize64;
peakWorkingSet = submitProg.PeakWorkingSet64;
if (peakPagedMem > memLimit)
{
submitProg.Kill();
}
if (timer.ElapsedMilliseconds > timeLimit)
{
timeLimitExceed = true;
submitProg.Kill();
}
}
timeUsed = timer.ElapsedMilliseconds;
timer.Stop();
if(submitProg.ExitCode!=0)systemRuntimeError = true;
Thanks for helping, and so sorry for my poor English.
==================================
p.s.
the question is how can I set error mode for the child process in C#.
My English is not good enough to explain the problem, so sorry.<(_ _)>
If you mean the Win32 API function SetErrorMode then you'll need to use P/Invoke, which is easy with such a simple signature:
[DllImport("kernel32.dll")]
static extern ErrorModes SetErrorMode(ErrorModes uMode);
[Flags]
public enum ErrorModes : uint {
SYSTEM_DEFAULT = 0x0,
SEM_FAILCRITICALERRORS = 0x0001,
SEM_NOALIGNMENTFAULTEXCEPT = 0x0004,
SEM_NOGPFAULTERRORBOX = 0x0002,
SEM_NOOPENFILEERRORBOX = 0x8000
}
(The Site http://www.pinvoike.net/ is always a good place to start to get the right declaration.)
You cannot set the error mode in another process without injecting code into that process. Which is impossible to do easily in C#. It isn't going to work well in C/C++ either, these kind of programs don't live long enough to give you time to inject.
It doesn't solve your problem anyway, you also have to protect against programs that never exit after they got stuck in an endless loop. The simple solution is to give every program a limited amount of time to execute. Say 10 seconds. If it doesn't complete then Process.Kill() it and declare a failure. This will also take care of the programs that bomb with a message box.
Trivial to implement with the Process.WaitForExit(milliseconds) overload.

Categories

Resources