将击键发送到 WPF 应用程序本身

问题描述 投票:0回答:1

在我的应用程序中,我正在捕获击键,当击键不是条形码的一部分时,我想将它们发送到应用程序。击键需要发送到应用程序本身。

我尝试了不同的方法但没有成功。

internal class InputSimulator
{
    #pragma warning disable SA1305 // Field names should not use Hungarian notation
    #pragma warning disable SA1307 // Accessible fields should begin with upper-case letter
    #pragma warning disable SA1400 // Access modifier should be declared

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

    [DllImport("user32.dll")]
    internal static extern uint MapVirtualKey(uint uCode, uint uMapType);

    struct INPUT
    {
        public INPUTType type;
        public INPUTUnion Event;
    }

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

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

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

    [StructLayout(LayoutKind.Sequential)]
    struct HARDWAREINPUT
    {
        public int uMsg;
        public short wParamL;
        public short wParamH;
    }

    enum INPUTType : uint
    {
        INPUT_KEYBOARD = 1
    }

    [Flags]
    enum KEYEVENTF : uint
    {
        EXTENDEDKEY = 0x0001,
        KEYUP = 0x0002,
        SCANCODE = 0x0008,
        UNICODE = 0x0004
    }

    public static void ProcessKeys(Key[] keys)
    {
        INPUT[] inputs = new INPUT[keys.Length + 1];
        for (int i = 0; i < keys.Length; i++)
        {
            var virtualKey = KeyInterop.VirtualKeyFromKey(keys[i]);
            uint skey = MapVirtualKey((uint)virtualKey, 0x0);
            inputs[i].type = INPUTType.INPUT_KEYBOARD;
            inputs[i].Event.ki.dwFlags = KEYEVENTF.SCANCODE;
            inputs[i].Event.ki.wScan = (ushort)skey;
        }
        inputs[keys.Length].type = INPUTType.INPUT_KEYBOARD;
        inputs[keys.Length].Event.ki.dwFlags = KEYEVENTF.UNICODE;
        inputs[keys.Length].Event.ki.dwFlags |= KEYEVENTF.KEYUP;
        uint cSuccess = SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));
    }

    public static void Send(Key key)
    {
        if (Keyboard.PrimaryDevice != null)
        {
            if (Keyboard.PrimaryDevice.ActiveSource != null)
            {
                var e = new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, key)
                {
                    RoutedEvent = Keyboard.PreviewKeyDownEvent
                };
                InputManager.Current.ProcessInput(e);
            }
        }
    }

    #pragma warning restore SA1305 // Field names should not use Hungarian 
    notation
    #pragma warning restore SA1307 // Accessible fields should begin with 
    upper-case letter
    #pragma warning restore SA1400 // Access modifier should be declared
}

下面的代码中有两种方法

ProcessKeys
Send
,但它们不起作用。我究竟做错了什么?还有其他方法可以实现这一目标吗?目前我使用
System.Windows.Forms.SendKeys.SendWait
但我更喜欢一种不引用
System.Windows.Forms

的方法

编辑:我的问题已被标记为可能重复:WPF应用程序中的SendKeys.Send方法我尝试了两种解决方案,但它们都不起作用,也许我的SendInput实现中有问题,但我无法找出问题所在

c# wpf
1个回答
0
投票

以下内容对我有用。确保您的应用程序具有焦点。

using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Input;
// https://learn.microsoft.com/en-us/windows/win32/inputdev/about-keyboard-input
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mapvirtualkeyw
// https://www.codeproject.com/Articles/5264831/How-to-Send-Inputs-using-Csharp

namespace Demo;

public static class WindowsEventSender // only for Windows 7+
{
    public static void SendChar(char c)
    {
        var input = new Input(InputType.Keyboard);
        input.Union.Keyboard.ScanCode = c;
        input.Union.Keyboard.Flags = KeyboardInputFlags.Unicode;
        input.Union.Keyboard.ExtraInfo = GetMessageExtraInfo();
        var inputs = new[] { input };
        var sent = SendInput((uint)inputs.Length, inputs, Marshal.SizeOf<Input>());
        if (sent == inputs.Length)
            return;
        ThrowWin32Exception(nameof(SendInput));
    }

    public static void SendKey(Key key, params Key[] modifiers)
    {
        // create input array
        var inputs = new Input[2 * (modifiers.Length + 1)];
        var idx = 0;
        // add key modifiers down
        foreach (var modifier in modifiers)
        {
            inputs[idx++] = GetKeyInput(modifier, true);
        }
        // add key down
        inputs[idx++] = GetKeyInput(key, true);
        // add key up
        inputs[idx++] = GetUpKeyInput(inputs[modifiers.Length]);
        // add key modifiers up
        for (var index = 0; index < modifiers.Length; ++index)
        {
            inputs[idx++] = GetUpKeyInput(inputs[index]);
        }
        // send keys
        var sent = SendInput((uint)inputs.Length, inputs, Marshal.SizeOf<Input>());
        if (sent == inputs.Length)
            return;
        ThrowWin32Exception(nameof(SendInput));
    }

    static Input GetKeyInput(Key key, bool pressed)
    {
        const int MAPVK_VK_TO_VSC_EX = 4;
        // calculate key values
        var virtualKey = KeyInterop.VirtualKeyFromKey(key);
        var scanCode = MapVirtualKey((uint)virtualKey, MAPVK_VK_TO_VSC_EX);
        var scanCodeFlag = scanCode > 0 ? KeyboardInputFlags.ScanCode : 0;
        var extendedKeyFlag = (scanCode & 0xE000) == 0xE000 ? KeyboardInputFlags.ExtendedKey : 0;
        var keyFlags = extendedKeyFlag | scanCodeFlag;
        // add key
        var input = new Input(InputType.Keyboard);
        input.Union.Keyboard.VirtualKey = (ushort)virtualKey;
        input.Union.Keyboard.ScanCode = (ushort)scanCode;
        input.Union.Keyboard.Flags = (pressed ? KeyboardInputFlags.KeyDown : KeyboardInputFlags.KeyUp) | keyFlags;
        return input;
    }

    static Input GetUpKeyInput(Input downKeyInput)
    {
        var input = new Input(InputType.Keyboard);
        input.Union.Keyboard.VirtualKey = downKeyInput.Union.Keyboard.VirtualKey;
        input.Union.Keyboard.ScanCode = downKeyInput.Union.Keyboard.ScanCode;
        input.Union.Keyboard.Flags = downKeyInput.Union.Keyboard.Flags | KeyboardInputFlags.KeyUp;
        return input;
    }

    static void ThrowWin32Exception(string functionId)
    {
        var errorCode = Marshal.GetLastWin32Error();
        throw new Win32Exception(errorCode, $"{functionId} error code {errorCode}: {new Win32Exception(errorCode).Message}");
    }

    [StructLayout(LayoutKind.Sequential)]
    struct Input(InputType type)
    {
        public InputType InputType = type;
        public InputUnion Union = new();
    }

    enum InputType : uint { Mouse = 0, Keyboard = 1, Hardware = 2 }

    [StructLayout(LayoutKind.Explicit)]
    struct InputUnion
    {
        [FieldOffset(0)] public MouseInput Mouse;
        [FieldOffset(0)] public KeyboardInput Keyboard;
        [FieldOffset(0)] public HardwareInput Hardware;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct MouseInput
    {
        public int DeltaX;
        public int DeltaY;
        public uint MouseData;
        public MouseEventFlags Flags;
        public uint Time;
        public IntPtr ExtraInfo;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct KeyboardInput
    {
        public ushort VirtualKey;
        public ushort ScanCode;
        public KeyboardInputFlags Flags;
        public uint Time;
        public IntPtr ExtraInfo;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct HardwareInput
    {
        public int uMsg;
        public short wParamL;
        public short wParamH;
    }

    [Flags]
    enum MouseEventFlags : uint
    {
        Move = 0x0001,
        LeftDown = 0x0002,
        LeftUp = 0x0004,
        RightDown = 0x0008,
        RightUp = 0x0010,
        MiddleDown = 0x0020,
        MiddleUp = 0x0040,
        XDown = 0x0080,
        XUp = 0x0100,
        Wheel = 0x0800,
        VirtualDesk = 0x4000,
        Absolute = 0x8000
    }

    [Flags]
    enum KeyboardInputFlags : uint
    {
        KeyDown = 0x0000,
        ExtendedKey = 0x0001,
        KeyUp = 0x0002,
        Unicode = 0x0004,
        ScanCode = 0x0008
    }

    [DllImport("user32.dll")]
    static extern IntPtr GetMessageExtraInfo();

    [DllImport("user32.dll")]
    static extern uint MapVirtualKey(uint uCode, uint uMapType);

    [DllImport("user32.dll", SetLastError = true)]
    static extern uint SendInput(uint cInputs, [In, MarshalAs(UnmanagedType.LPArray)] Input[] pInputs, int cbSize);
}
© www.soinside.com 2019 - 2024. All rights reserved.