C
C#ā€¢3mo ago
Kaenguruu24

Sending key presses to other applications without Windows Forms

Because I'm working with the Godot game engine for the graphics interface, I'm kinda restricted with their Mono implementation. That prevents me from using the windows forms stuff. So I've tried the solutions using user32.dll but they only work when I move my mouse. I assume that is happening because of the following: I have a touchscreen with a button. When that button is pressed, there should be the according key action. I think that because of the touch input, it's doing some funky stuff with the window focus and that results in the behaviour described above. Code looks as follows:
34 Replies
Kaenguruu24
Kaenguruu24ā€¢3mo ago
c#
using System;
using System.Linq;
using WindowsInput.Native;
using System.Runtime.InteropServices;
using System.Collections.Generic;

public class KeyboardSimulator
{
[DllImport("user32.dll")]
static extern uint SendInput(uint nInputs, [MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize);

[StructLayout(LayoutKind.Sequential)]
public struct INPUT
{
public uint type;
public InputUnion U;
public static int Size
{
get { return Marshal.SizeOf(typeof(INPUT)); }
}
}

[StructLayout(LayoutKind.Explicit)]
public struct InputUnion
{
[FieldOffset(0)]
public MOUSEINPUT mi;
[FieldOffset(0)]
public KEYBDINPUT ki;
[FieldOffset(0)]
public HARDWAREINPUT hi;
}

[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
public int dx;
public int dy;
public uint mouseData;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
public struct HARDWAREINPUT
{
public uint uMsg;
public ushort wParamL;
public ushort wParamH;
}
}
c#
using System;
using System.Linq;
using WindowsInput.Native;
using System.Runtime.InteropServices;
using System.Collections.Generic;

public class KeyboardSimulator
{
[DllImport("user32.dll")]
static extern uint SendInput(uint nInputs, [MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize);

[StructLayout(LayoutKind.Sequential)]
public struct INPUT
{
public uint type;
public InputUnion U;
public static int Size
{
get { return Marshal.SizeOf(typeof(INPUT)); }
}
}

[StructLayout(LayoutKind.Explicit)]
public struct InputUnion
{
[FieldOffset(0)]
public MOUSEINPUT mi;
[FieldOffset(0)]
public KEYBDINPUT ki;
[FieldOffset(0)]
public HARDWAREINPUT hi;
}

[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
public int dx;
public int dy;
public uint mouseData;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
public struct HARDWAREINPUT
{
public uint uMsg;
public ushort wParamL;
public ushort wParamH;
}
}
c#
public void SimulateKeyPresses(string keys, string target)
{
const uint INPUT_KEYBOARD = 1;
const uint KEYEVENTF_KEYUP = 0x0002;

var keyList = keys.Split(' ').Select(k => Enum.Parse<VirtualKeyCode>(k.ToUpper())).ToList();
ushort KeyCode = 0;

if (keyList.Count == 0) return;

List<INPUT> inputs = new List<INPUT>();

// Press down each key
foreach (var key in keyList)
{
KeyCode = (ushort)key;
inputs.Add(new INPUT
{
type = INPUT_KEYBOARD,
U = new InputUnion
{
ki = new KEYBDINPUT
{
wVk = KeyCode,
dwFlags = 0
}
}
});
}

// Release each key
foreach (var key in keyList)
{
KeyCode = (ushort)key;
inputs.Add(new INPUT
{
type = INPUT_KEYBOARD,
U = new InputUnion
{
ki = new KEYBDINPUT
{
wVk = KeyCode,
dwFlags = KEYEVENTF_KEYUP
}
}
});
}

// Send the input events
SendInput((uint)inputs.Count, inputs.ToArray(), INPUT.Size);
}
c#
public void SimulateKeyPresses(string keys, string target)
{
const uint INPUT_KEYBOARD = 1;
const uint KEYEVENTF_KEYUP = 0x0002;

var keyList = keys.Split(' ').Select(k => Enum.Parse<VirtualKeyCode>(k.ToUpper())).ToList();
ushort KeyCode = 0;

if (keyList.Count == 0) return;

List<INPUT> inputs = new List<INPUT>();

// Press down each key
foreach (var key in keyList)
{
KeyCode = (ushort)key;
inputs.Add(new INPUT
{
type = INPUT_KEYBOARD,
U = new InputUnion
{
ki = new KEYBDINPUT
{
wVk = KeyCode,
dwFlags = 0
}
}
});
}

// Release each key
foreach (var key in keyList)
{
KeyCode = (ushort)key;
inputs.Add(new INPUT
{
type = INPUT_KEYBOARD,
U = new InputUnion
{
ki = new KEYBDINPUT
{
wVk = KeyCode,
dwFlags = KEYEVENTF_KEYUP
}
}
});
}

// Send the input events
SendInput((uint)inputs.Count, inputs.ToArray(), INPUT.Size);
}
leowest
leowestā€¢3mo ago
hmmm what, I am not sure I understood what is going on, you're using godot to write an application and not a game and your complaining it lack certain supports u would normally have?
Kaenguruu24
Kaenguruu24ā€¢3mo ago
I'm not complaining I'm simply stating that I'm having issues. But effectively, yes, I'm saying that I'm missing certain features due to the fact that I'm using Godot for this
leowest
leowestā€¢3mo ago
ok but you're using it to write an application instead of a game? why was there no framework that could aid u?
Kaenguruu24
Kaenguruu24ā€¢3mo ago
Cause I don't have much time outside of school to learn something entirely new just because of this one thing. I tried Windows Forms once and hated it and I am simply not at a point where I want to invest significant time into this. It's a project for myself only and I'm not gonna rewrite everything because of this
leowest
leowestā€¢3mo ago
That prevents me from using the windows forms stuff.
by that I assume you mean using winform libraries?
Kaenguruu24
Kaenguruu24ā€¢3mo ago
Yes, at least thats what I've experienced. I tried adding the System.Windows.Forms dll to the project but it just won't compile. I've read that it's supposedly because of the way Godot integrates C#
leowest
leowestā€¢3mo ago
yes so you're trying to sendkeys from your godot to another application?
Kaenguruu24
Kaenguruu24ā€¢3mo ago
Yes. Imagine it as a sort of digital stream deck where pressing a button should execute a key combination (or just a single key) on another program
leowest
leowestā€¢3mo ago
sure but streamdeck is linux base what you're doing is accessing windows only api to send keys so it would not work on any other platform
Kaenguruu24
Kaenguruu24ā€¢3mo ago
Yes and as I mentioned it's for personal use only and I'm on Windows so thats not a problem
leowest
leowestā€¢3mo ago
and what are u trying to control because depending on what this would not work regardless not it being an issue with touch screen
Kaenguruu24
Kaenguruu24ā€¢3mo ago
all sorts of applications. Discord, Firefox, games like DCS or ETS 2
leowest
leowestā€¢3mo ago
so essentially you want to send keys to other games so type of automation
Kaenguruu24
Kaenguruu24ā€¢3mo ago
yes
Buddy
Buddyā€¢3mo ago
StreamDeck is hardware not Software
Kaenguruu24
Kaenguruu24ā€¢3mo ago
I'm aware, thank you
leowest
leowestā€¢3mo ago
streamdeck doesn't matter he wants it for windows and at this point I am not sure I can further assist him due to break of TOS
Buddy
Buddyā€¢3mo ago
Why did you choose to make it in Godot may I ask? Like why a game engine for an app? Considering the game engine redraws even if the UI hasn't been changed, so you basically waste resources continuously, which is important for streamers.
Kaenguruu24
Kaenguruu24ā€¢3mo ago
See the previous conversation. I know how to use it, it provides a quick way to set up a graphical user interface and my experience with winforms was horrible
Buddy
Buddyā€¢3mo ago
Avalonia is an option
leowest
leowestā€¢3mo ago
@Citizen of Pluto he is writing bots to automate games
Kaenguruu24
Kaenguruu24ā€¢3mo ago
honestly I don't care about that little performance impact
Buddy
Buddyā€¢3mo ago
It isn't little.
Kaenguruu24
Kaenguruu24ā€¢3mo ago
I have not experienced even the slightest drop in fps while the application was running. It's a personal use project only so nobody else is impacted by this
Buddy
Buddyā€¢3mo ago
You do you, but as Leowest pointed out. Unfortunately we cannot help unless you have proof that you are not automating games that forbids it by the ToS.
Kaenguruu24
Kaenguruu24ā€¢3mo ago
So you are not sure whether I'm trying to cheat is basically what you are saying?
Nox
Noxā€¢3mo ago
@Kaenguruu24 We don't allow help for any type of game automation because of the gray area. Please understand it's difficult to discern the rare case where it's okay compared to the thousands of times it's not allowed and why it's a blanket statement.
Kaenguruu24
Kaenguruu24ā€¢3mo ago
Kinda sad im gonna be honest. Have a good day then
Nox
Noxā€¢3mo ago
Thank you for understanding, sorry about that
leowest
leowestā€¢3mo ago
well he left the server heh
Nox
Noxā€¢3mo ago
s'alright. He seemed reasonable so I didn't nuke immediately.
leowest
leowestā€¢3mo ago
yeah I mean its fine, I just didnt proceed to help him because he clearly stated it was for games and the reason I was suspicious was because the game had protection against sending keys thus why it was not working and he thou it was something else šŸ˜›
oke
okeā€¢3mo ago
oof