DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Implement a Circuit Breaker for an Unavailable API Service Running in App Connect on CP4I Using Red Hat Service Mesh
  • How to Identify the Underlying Causes of Connection Timeout Errors for MongoDB With Java
  • Unlock AI Power: Generate JSON With GPT-4 and Node.js for Ultimate App Integration
  • Instant App Backends With API and Logic Automation

Trending

  • AI Agents in Java: Architecting Intelligent Health Data Systems
  • LLM Integration in Enterprise Applications: A Practical Guide
  • Understanding MCP Architecture: LLM + API vs Model Context Protocol
  • What Is Plagiarism? How to Avoid It and Cite Sources
  1. DZone
  2. Data Engineering
  3. Databases
  4. Sending Keystrokes to Other Apps with Windows API and C#

Sending Keystrokes to Other Apps with Windows API and C#

Recently I had to tackle a task where I needed to send keystrokes to another application, that are initiated from a .NET Windows app.

By 
Denzel D. user avatar
Denzel D.
·
Feb. 01, 13 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
48.3K Views

Join the DZone community and get the full member experience.

Join For Free

Recently I had to tackle a task where I needed to send keystrokes to another application, that are initiated from a .NET Windows app. Obviously, there is a way to do it through WinAPI, and the way is called SendInput - a core function that can be used to simulate key presses, mouse actions and button clicks.

Let's talk about what's needed. First of all, you are using it to send keystrokes, and not characters, to wherever the current input focus is located. So, for example, if I would want to print the { symbol on the screen, I would not be able to just get it's code representation because the actual key that carries it on a standard US QWERTY keyboard would be [. The problem that I've seen happen more than once is a developer attempting to leverage VkKeyScan to get the necessary virtual-key code to replicate it later, it producing another character instead.  

Now let's look at the native signature for it:


UINT WINAPI SendInput(
  _In_  UINT nInputs,
  _In_  LPINPUT pInputs,
  _In_  int cbSize
);

In the constraints of a managed environment, in my case - in a C# application, this declaration would look like this:


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

Remember, since you are using P/Invoke, you need to add a 


public struct INPUT
{
    public int type;
    public InputBatch u;
}

What exactly is InputBatch? If you look at the INPUT structure layout, you will notice that it relies on a union of MOUSEINPUT, KEYBDINPUT and HARDWAREINPUT - structs that are carrying data related to their own class of input simulation. A basic implementation of those in C# looks like this:


[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;
}


In our case, we are focusing on the keyboard, so let's go through the fields that we're using in the KEYBDINPUT struct.

  • wVk - the virtual key code. Not the same as the character code. You can find a list of virtual key codes 

  • wScan - the hardware scan code (read the spec here).

  • dwFlags - complementary flags that pre-determine input processing behavior. You can find the complete list on MSDN.
  • time - unless you need to specify a different timestamp, let Windows provide its own and set the value to 0.
  • dwExtraInfo - will be associated with a call to GetMessageExtraInfo.

Let's assume that I want to simulate the Enter key press. To do this, I first need to generate an array of INPUT structs that would act as the input descriptor:


WindowsAPI.INPUT[] data = new WindowsAPI.INPUT[] {
    new WindowsAPI.INPUT() 
    {
        type = WindowsAPI.INPUT_KEYBOARD,
        u = new WindowsAPI.InputBatch
        {
            ki = new WindowsAPI.KEYBDINPUT
            {
                wVk = 0x0D,
                wScan = 0,
                dwFlags = 0,
                dwExtraInfo = WindowsAPI.GetMessageExtraInfo(),
            }
        }
    } 
};

Notice that I am using the HEX representation for Enter (that's the proper associated virtual-key code). When I want to invoke SendInput, I can call this:


WindowsAPI.SendInput((uint)data.Length, data, Marshal.SizeOf(typeof(WindowsAPI.INPUT)));

Marshal.SizeOf will return the value for the size of the INPUT struct. What happens if I need to send a key combination? This is easily implemented through multiple INPUT instances. For example, for Ctrl+F5 you could use this:


public static WindowsAPI.INPUT[] Find()
{
    WindowsAPI.INPUT[] data = new WindowsAPI.INPUT[] {
        new WindowsAPI.INPUT() 
        {
            type = WindowsAPI.INPUT_KEYBOARD,
            u = new WindowsAPI.InputBatch
            {
                ki = new WindowsAPI.KEYBDINPUT
                {
                    wVk = 0xA2,
                    wScan = 0,
                    dwFlags = 0,
                    dwExtraInfo = WindowsAPI.GetMessageExtraInfo(),
                }
            }
        },
        new WindowsAPI.INPUT() 
        {
            type = WindowsAPI.INPUT_KEYBOARD,
            u = new WindowsAPI.InputBatch
            {
                ki = new WindowsAPI.KEYBDINPUT
                {
                    wVk = (ushort)WindowsAPI.VkKeyScan('f'),
                    wScan = 0,
                    dwFlags = 0,
                    dwExtraInfo = WindowsAPI.GetMessageExtraInfo(),
                }
            }
        }    
    };

    return data;
}

Afterwards, call SendInput the same way as you called it for the Enter key. There is one problem here, though. As you are going to call this function, you will notice that the OS will still consider the Ctrl key pressed. To avoid this, you would need to use a KEYBDINPUT instance with dwFlags for set to KEYEVENTF_KEYUP to release the key.

API app

Opinions expressed by DZone contributors are their own.

Related

  • Implement a Circuit Breaker for an Unavailable API Service Running in App Connect on CP4I Using Red Hat Service Mesh
  • How to Identify the Underlying Causes of Connection Timeout Errors for MongoDB With Java
  • Unlock AI Power: Generate JSON With GPT-4 and Node.js for Ultimate App Integration
  • Instant App Backends With API and Logic Automation

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook