How to send Keys to an application - c#

I have a very basic problem, For a game (Dota 2) I want to write a little macro which opens the console, writes "setinfo name ".........................."" into it and then closes it, the hotkey for console is set to '#'. For this I wrote an application which listens for the key 'f' to be pressed, and then send
1) '#' (open the console)
2) "messag ebla bla b...."
3) '#' (close the console)
everything is working except that it will not open the console (but if the console is already open it will write #messagej.j....# into it when i press f just as wanted)
my code for sending the keys.
SendKeys.Send("#");
SendKeys.Send("my message for consol");
SendKeys.Send("#");
does anybody know why the hotkeys dont work by sending keys? I thought its an simulation of when the user presses F or Q.

First thing You should try is adding a "software" delay between keypresses.
string MSG = "#yourmessage#";
foreach (object c_loopVariable in MSG) {
c = c_loopVariable;
Sendkeys.Send(c);
sleep(20);
}
The other thing to consider - sendkeys do not emulate the keypress at the hardware layer - it is on windows API level, and the DirectX DirectInput., witch most games use for user input processing goes a level further. So it is possible You will not be able to do it this easy.
You should check out more of keybd_event. Ive had better luck using that - as i understand it goes a level deeper than just sendkeys.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646304(v=vs.85).aspx
Anyways, I hope u are not going to use this for some spamming in a great game! :)

Related

Chrome remote desktop Console.ReadKey yelds System.ConsoleKey.Packet instead of keystroke

This is more of a curiosity to be completely honest.
Inside a console project I am developing I request input from the user in a looped form of this:
ConsoleKey response;
Console.Write("Write messages to log? [y/n] ");
response = Console.ReadKey(false).Key;
assume 4 cases:
case 1: Pressing the 'y' key on a keyboard directly atached to the pc running the software.
case 2: Connecting from another computer trough remote desktop connection and pressing the 'y' key on that machine.
case 3: Using on screen keyboard and press the 'y' key trough clicking on it (remotely or locally had no difference)
case 4: Connecting from another machine (specifically a phone) trough chrome remote desktop and pressing the 'y' key.
In case 1, 2 and 3, 'response' will contain 'Y'.
In case 4 'response' will instead contain System.ConsoleKey.Packet aka enum 231 PACKET key (used to pass Unicode characters with keystrokes).
I have tried the same thing trough a second pc and I noticed this behavior does not appear to occurr.
The most interesting thing is that the console shows me this
Write messages to log? [y/n] y
From this I evince that the keystroke is indeed received but handled incorrectly by my code.
I am at a loss as to how to proceed.
Console.ReadLine yelds the correct keystrokes but i would prefer to use Console.ReadKey if possible.
Is this specific behavior for phone keyboards? How would I obtain the actual key?
How would I obtain the actual key?
The MSDN docs for ConsoleKey.Packet doesn't say anything useful, so I found references to ConsoleKey in the source which lead here. That's casting ir.keyEvent.virtualKeyCode to a ConsoleKey where ir is an InputRecord.
A quick google finds the WinApi equivalent is INPUT_RECORD, and chasing the docs through KEY_EVENT_RECORD leads to this doc of Virtual-Key codes, which contains some more docs for VK_PACKET:
Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP
The Remarks for KEYBDINPUT say:
INPUT_KEYBOARD supports nonkeyboard-input methods—such as handwriting recognition or voice recognition—as if it were text input by using the KEYEVENTF_UNICODE flag. If KEYEVENTF_UNICODE is specified, SendInput sends a WM_KEYDOWN or WM_KEYUP message to the foreground thread's message queue with wParam equal to VK_PACKET. Once GetMessage or PeekMessage obtains this message, passing the message to TranslateMessage posts a WM_CHAR message with the Unicode character originally specified by wScan. This Unicode character will automatically be converted to the appropriate ANSI value if it is posted to an ANSI window.
From my searching it doesn't look like .NET implements this mechanism for you, so you might have to do it yourself!
I'm afraid I've no idea why it's happening in your case however...
I just ran into this issue too! In my case, it only happened when connecting to my development pc from a phone as well. (I was using the RDP app)
Here's what I came up with today that works!
public static bool Confirm(string prompt)
{
Console.Write($"{prompt} [y/n] ");
char letter;
do
{
letter = char.ToLower(Console.ReadKey(true).KeyChar);
} while (letter != 'y' && letter != 'n');
Console.WriteLine(letter);
return letter == 'y';
}
Thanks for confirming that I'm not the only one with the issue!

The new Input System doesn't trigger anything anymore

This post is shamelessly a copy/paste from my post on the Unity Forums : https://forum.unity.com/threads/input-system-doesnt-trigger-anything-anymore.717386/, but Stack Overflow seems more active
TL;DR : InputSystem worked some days ago, don't trigger anything anymore, halp.
I tried the new Input System some days ago, and that's really neat ! I did a lot of stuff, trying to understand the best way to use it, and, in the end, I had a character jumping and moving everywhere, that was cool ! Then, I merged my code in our develop branch and went to bed.
Today, I want to continue my code, but my character doesn't move anymore, Actions are not triggered (even if inputs are detected in debugger) and I really don't know why. Either the code merge overwrote some important settings (I know what you're thinking and yes, the "Active Input Handling" is set on "Both" and I tried only running the preview) or I did something important during my little tests and I didn't realize.
So I decided to try to reproduce my steps on a fresh new project, maybe you guys can help me figure what do I do wrong ?
1/ Create a new 2D project (via the Hub)
2/ Install the latest Package (version 0.9.0)
3/ Click Yes on that message prompt to activate the new Input management in the settings
4/ Restart Unity Editor since it didn't restart even if the message said it would and check the project settings (yes, it's on "Both", and yes, my Scripting Runtime Version is 4.0)
5/ Create a new GameObject and add a PlayerInput on it
6/ Click on "Open Input Settings" and create an "InputSettings" asset
7/ Click on "Create Actions..." to create my ActionMap asset
8/ Create a "TestAction" on my "Player" ActionMap and set it to the key "t"
9/ Create a new Script "TestScript" that contains a OnTestAction() method (that only logs "test") and enables the test map/action (just to be sure) :
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.PlayerInput;
public class TestScript : MonoBehaviour
{
void Start()
{
InputActionMap playerActionMap = GetComponent<PlayerInput>().actions.GetActionMap("Player");
playerActionMap.Enable();
playerActionMap.GetAction("TestAction").Enable(); //Just to be sure
}
public void OnTestAction()
{
Debug.Log("test");
}
}
10/ Pressing "Play" and spamming "T" like a madman to try to display a debug (note that, in the debugger, a User is created, my "t" presses are detected, my TestAction exists and is mapped on the "t" key but no debug is displayed
It's probably a silly problem, but it's driving me crazy, what do I do wrong ? It's even more infuriating that it worked some days ago !
Additional information :
- Switching the Input Management from "Both" to "New Input System (preview) does nothing
- Checking in Update() is my action is enabled returns "True" every frame
- Checking in Update() is my action is triggered returns "False" every frame
- Using action.started/triggered/performed does nothing (I tried also switching to UnityEvent or C# events for this) :
public class TestScript : MonoBehaviour
{
InputAction a;
void Start()
{
InputActionMap playerActionMap = GetComponent<PlayerInput>().actions.GetActionMap("Player");
playerActionMap.Enable();
a = playerActionMap.GetAction("TestAction");
a.Enable(); //Just to be sure
a.started += OnTriggeredTestAction;
a.performed += OnTriggeredTestAction;
a.canceled += OnTriggeredTestAction;
}
public void OnTestAction()
{
Debug.Log("test");
}
public void OnTriggeredTestAction(InputAction.CallbackContext ctx)
{
Debug.Log("test triggered");
}
}
Injecting directly the InputActionReference of my TestAction and using it does nothing
Forcing "Default Control Scheme" and "Default Action Map" does nothing
Using BroadcastMessage or UnityEvents doesn't work
You probably tried to import a new input system package for multiple input devices compatibility. These types of errors are due to conflict between old and new input system packages and are probably resolved in the latest updates.
To resolve this issue, Go to Edit -> Project Settings->Player->Under Other Settings under Configuration is the option Active Input Handling. Select Both. Unity will restart. Now your problem should be solved. You will be able to use old input system packages and the new ones also simultaneously.
Check for rogue users in the input debugger
I was having very similar symptoms (Input System would randomly just stop sending callbacks). When I opened up the input debugger, it was registering the key presses, but the callbacks were never being called in my script.
Restarting Unity didn't help.
Rebooting didn't help.
I also discovered in the input debugger that there were 2 "users" in the input system and (by process of disabling Game Objects in the scene one at a time) discovered that I had accidentally attached another copy of my Input Action Asset to a different Game Object in the scene and that Unity was registering this other object as a 2nd player or "user", which was assigned all the input action bindings I was trying to capture.
The rogue Action Asset was essentially intercepting the actions, preventing the callbacks from being called on the intended script. I don't know if that's your particular issue, but maybe it will help someone else who (like me) has spent hours pouring through forums, looking for a solution to this elusive problem.
An easy way to tell if you have the same problem is to open the input debugger and see if the desired actions are actually mapped to the user of interest.
Screen clip of input debugger:
For me, there was an unexpected User #1 and only one of the users (not the intended one) actually had keys bound to the desired actions
Posting just incase others run into this issue, as this solved my problem. Make sure to call Enable() for it to start routing events.
//Create a and set the reference
private InputControls _inputMapping;
private void Awake() => _inputMapping = new InputControls();
//Route and Un-route events
private void OnEnable() => _inputMapping.Enable();
private void OnDisable() => _inputMapping.Disable();
I don't know if this will work for you but it worked for me and I was having the same issue.
I had created 2 control schemes. Mobile and Pc. Mobile required touch screen and PC required keyboard and Mouse. Doing this made my Mobile input event stop firing. So adding the Gamepad to my Mobile Control scheme allowed the events to fire again.
TLDR. Check your control scheme make sure it allows for the inputs your binding to.
I had a similar problem, reproduced with exactly the steps described in the question.
In my case, I forgot to set control schemes.
The problem was fixed after adding them.
To do so:
Open your Input Action Asset.
Select a control scheme, in the upper left corner. (say, Keyboard) (if you haven't added a control scheme to begin with, your problem may be different than mine)
Go Right Click > Edit Control Scheme.
EditControlScehme Screen Img
Click on the plus sign to add a control scheme to the list.
Add control scheme to the list Screen Img
Select the control scheme you want to add. (in this case, Keyboard)
Select control scheme Screen Img
Should look like this:
Added control scheme Screen Img
You're all set. Save everything and the problem should be fixed.
Play your game and it should work.
As of at least Unity 2020.1.2 and Input System 1.0.0 the input system will randomly stop working correctly. The only fix I'm aware of is restarting Unity.

Can't send keys (string) to notepad

I thought that code is pretty good, bu it isn't. I'm trying to add something text to my notepad, which look like:
string text = "TESTTESTTESTTEST";
[DllImport("user32.dll")]
private static extern int SetForegroundWindow(IntPtr hWnd);
public void EditTxtFile(string text)
{
Process p = Process.GetProcessesByName("notepad").FirstOrDefault();
if (p != null)
{
IntPtr handle = p.MainWindowHandle;
SetForegroundWindow(handle);
SendKeys.SendWait(text);
p.Kill(); //also process doesn't shoutdown
}
}
When i try to debug this function (actually SendKeys), that message is showing up:
Changes are not allowed while code is runnig.
If it's important i try to edit this from web page/application.
The problem is, that Visual Studio catches Focus when it hits the break point, and then SendKeys is send to Visual Studio instead of notepad, and this produces the error.
What you can do ist the following:
Right Click on the Breakpoint and select "When Hit..."
There you can output whatever you want without Notepad losing Focus
Problem was in function which was responsible for opening that notepad (not enough time to start and open him). I've just add wait function for 4s.
To mine, it's about I use a reference value text from the source WinForms's control, call SendKeys' function while the source form is not yet close or hide before (still the active form). This can produce a similar result: SendKeys.Send() or SendKeys.SendWait() does not send a desired text to the target application.
The steps to workaround this:
1. transfer the text value from the active form to a new temporary variation or a Clipboard,
2. close or hide the active form,
3. activate the target application's form,
4. wait a bit to ensure the target application's form to become active 5. and give the temporary text variation or Clipboard to SendKeys. Works.
PS: Please make sure your application has runtime permission equals or more than the target application.

Simulate KeyPress in C# to Game

I'm trying to simulate a keypress into another window, which is a game. The things that don't work are:
SendKey - Send the input as strings like some text or something but doesn't go for ENTER TAB or other critical keys
InputSimulator - Complete waste of time
SendInput - Have some problems with this as well. It doesn't compile, and I've never used it before
PostMessage - it seems these 2 are pretty much the same and again they do send text but again no other keys such as ENTER TAB or other. Also couldn't figure out the value for wParam if i wanna hold down the key for a number of seconds. It is a 32bit Hex value in which seems the last 16 are repetition number.
SendMessage - See PostMessage
AUTOIT or AHK it seems that they have troubles being incorporated into C# if anyone knows how to do that, it would help immensely, this meaning I'd be able to write AHK script in the C# .cs file so it would compile. COM, ref, or anything.
Having problems with DirectInput
public void Test_KeyDown()
{
INPUT[] InputData = new INPUT[2];
Key ScanCode = Microsoft.DirectX.DirectInput.Key.W;
InputData[0].type = 1; //INPUT_KEYBOARD
InputData[0].ki.wScan = (short)VirtualKeyCode.NUMPAD2 ; //ScanCode;
InputData[0].ki.dwFlags = (int)KEYEVENTF.SCANCODE;
InputData[1].type = 1; //INPUT_KEYBOARD
InputData[1].ki.wScan = (short)VKeys.VK_W;
InputData[1].ki.dwFlags = (int)(KEYEVENTF.KEYUP | KEYEVENTF.UNICODE);
// send keydown
if (SendInput(2, InputData, Marshal.SizeOf(InputData[1])) == 0)
{
System.Diagnostics.Debug.WriteLine("SendInput failed with code: " +
Marshal.GetLastWin32Error().ToString());
}
}
It gives this error:
Could not load file or assembly 'Microsoft.DirectX.DirectInput.dll' or one of
its dependencies. is not a valid Win32 application.
(Exception from HRESULT: 0x800700C1)
I've referenced it from DirectX SDK tool kit 2007
I'm trying to send a key to another instance or handle. C++ or C# anything that works is fine, too.
Looks like you are trying to load a 32bit dll in a 64 bit solution, so please use the 64bit dll

How to implement text-to-speech (TTS) in Visual C#/C++?

I want to write a simple Windows app in Visual C#/C++ that lets users input different segments of text, and then press a set of hotkeys to hear the various text segments in TTS at any time. The program should accept hotkeys while running in background or even when fullscreen applications have focus.
Example use case: user enters "hello world" and saves it as the first text segment, and then enters "stack overflow" and saves it as the second text segment. The user can switch to another program, then press hotkey CTRL-1 to hear the TTS say "hello world" or CTRL-2 to hear the TTS say "stack overflow." The program should of course be able to run entirely offline (just in case that affects any suggestions)
As a sidenote, I'm fairly new to programming in Visual whatever, but have a decent enough background in C#/C+, so even though I'm mainly looking for help on the TTS part, I'm open to suggestions of any kind if someone's done this kind of thing before.
if you want to talk something on C# use Introp.SpeechLib.dll
E.g:
private void ReadText()
{
int iCounter = 0;
while (Convert.ToInt32(numericUpDown1.Value) > iCounter)
{
SpVoice spVoice = new SpVoice();
spVoice.Speak("Hello World", SpeechVoiceSpeakFlags.SVSFPurgeBeforeSpeak);
spVoice.WaitUntilDone(Timeout.Infinite);
iCounter = iCounter + 1;
}
}
read this: Speech Technologies
Reference System.Speech.dll. You can instantiate a System.Speech.Synthesis.Synthesizer and call .Speak("TEXT HERE");
You have to use the Microsoft Speech SDK.
Have a look at this link for details:
http://dhavalshah.wordpress.com/2008/09/16/text-to-speech-in-c/

Categories