Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to push a key and release it using C#?

Tags:

c#

keyboard

I am writing a C# program which captures signals from a external device, and sends keystrokes to another application. I am using SendKeys and it works fine.

SendKeys does "press" a key by holding and releasing it immediately. I would like to make it push key and release it at will.

My question is : "is there a way to send a "push" signal to a key, then a "release" signal after a certain amount of time ?"

I am not sure SendKeys is able to do this. Any clue ?

like image 389
Larry Avatar asked Oct 05 '08 17:10

Larry


4 Answers

I don't think it's possible from .NET directly You could try using keybd_event native call by p/invoking the function as described here: http://pinvoke.net/default.aspx/user32.keybd_event

The MSDN for keybd_event is here: http://msdn.microsoft.com/en-us/library/ms646304(VS.85).aspx

Hope that helps!

like image 184
Adam Haile Avatar answered Oct 23 '22 07:10

Adam Haile


The accepted answer uses keybd_event which is deprecated. The official API is now SendInput. There's also a nice wrapper for it at http://inputsimulator.codeplex.com.

None of the above, however, fully caters to the "key holding" scenario. This is due to the fact that holding a key will generate multiple WM_KEYDOWN messages, followed by a single WM_KEYUP message upon release (you can check this with Spy++).

The frequency of the WM_KEYDOWN messages is dependent on hardware, BIOS settings and a couple of Windows settings: KeyboardDelay and KeyboardSpeed. The latter are accessible from Windows Forms (SystemInformation.KeyboardDelay, SystemInformation.KeyboardSpeed).

Using the aforementioned Input Simulator library, I've implemented a key holding method which mimics the actual behavior. It's await/async ready, and supports cancellation.

static Task SimulateKeyHold(VirtualKeyCode key, int holdDurationMs, 
                            int repeatDelayMs, int repeatRateMs, CancellationToken token)
{
    var tcs = new TaskCompletionSource<object>();
    var ctr = new CancellationTokenRegistration();
    var startCount = Environment.TickCount;
    Timer timer = null;
    timer = new Timer(s =>         
    {
        lock (timer)
        {
            if (Environment.TickCount - startCount <= holdDurationMs)
                InputSimulator.SimulateKeyDown(key);
            else if (startCount != -1)
            { 
                startCount = -1; 
                timer.Dispose();
                ctr.Dispose();                    
                InputSimulator.SimulateKeyUp(key);
                tcs.TrySetResult(null);
            }
        }
    });
    timer.Change(repeatDelayMs, repeatRateMs);

    if (token.CanBeCanceled)
        ctr = token.Register(() =>
                       {
                           timer.Dispose();
                           tcs.TrySetCanceled();
                       });
    return tcs.Task;
}
like image 22
Ohad Schneider Avatar answered Oct 23 '22 08:10

Ohad Schneider


You could use SendInput or keyb_event, both are native API functions. SendInput has some advantages over keybd_event, but SendInput is only available starting with XP.

Here is the msdn link http://msdn.microsoft.com/en-us/library/ms646310.aspx

Hope this helps

like image 39
Dan Cristoloveanu Avatar answered Oct 23 '22 08:10

Dan Cristoloveanu


I once was looking to do the same thing on powerpoint, to hide the cursor, and later to stop the slideshow. But it's hard and tricky as there's many top level windows appeared in powerpoint, also it's hard to figure out which part of the emulation failed if it doesn't work. After looking into the message queue using Spy++, I notice that the accelerator command was sent after the keypress, so instead, I emulated the accelerator command, and it works like charm. So you might want to look into alternative like this.

like image 35
faulty Avatar answered Oct 23 '22 09:10

faulty