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

2020-02-05 08:58发布

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 ?

标签: c# keyboard
4条回答
做个烂人
2楼-- · 2020-02-05 09:31

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!

查看更多
Fickle 薄情
3楼-- · 2020-02-05 09:32

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;
}
查看更多
▲ chillily
4楼-- · 2020-02-05 09:39

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

查看更多
做自己的国王
5楼-- · 2020-02-05 09:48

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.

查看更多
登录 后发表回答