如何在WPF单元测试中模拟按键组合?

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

我正在尝试为 WPF 组件编写单元测试。如何模拟组合键(不仅仅是 1 个键)?

模拟按 1 个键很简单:

        var window = new Window();

        var keyEventArgs = new KeyEventArgs(Keyboard.PrimaryDevice, Substitute.For<PresentationSource>(), 0, Key.E)
        {
            RoutedEvent = Keyboard.KeyDownEvent,
        };

        window.RaiseEvent(keyEventArgs);

查明是否使用了特定的组合键(例如 Ctrl+Alt+Shift+E):

if(EventArgs.KeyboardDevice.Modifiers.HasFlag(ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift)
   && EventArgs.Key == Key.E)

我们看到:可以通过 EventArgs.KeyboardDevice 访问修饰符。

但是我们如何设置它们呢?

我做了很多尝试。我尝试模拟 KeyEventArgs 构造函数的第一个参数,但没有成功。

如何模拟组合键?

wpf unit-testing mocking event-handling
1个回答
0
投票

您可以使用

SetKeyboardState
为当前线程设置修饰键。这当然只适用于 Windows。

我创建了一个简单的方法,可以根据

ModifierKeys
设置键盘状态。它返回一个
IDisposable
,它将返回
Dispose

中未设置的状态
public static class Keyboard
{
    public static IDisposable SetModifierKeys(ModifierKeys keys)
    {
        var keyState = new byte[256];
        keyState[(int)Win32.VirtualKeyStates.LeftShift] = (byte)(keys.HasFlag(ModifierKeys.Shift) ? 0x80 : 0);
        keyState[(int)Win32.VirtualKeyStates.LeftControl] = (byte)(keys.HasFlag(ModifierKeys.Control) ? 0x80 : 0);
        keyState[(int)Win32.VirtualKeyStates.LeftAlt] = (byte)(keys.HasFlag(ModifierKeys.Alt) ? 0x80 : 0);
        keyState[(int)Win32.VirtualKeyStates.LeftWin] = (byte)(keys.HasFlag(ModifierKeys.Windows) ? 0x80 : 0);

        SetKeyboardState(keyState);

        return new Disposable();
    }

    private static void SetKeyboardState(byte[] keyState)
    {
        if (!Win32.SetKeyboardState(keyState))
        {
            var error = Marshal.GetLastWin32Error();
            throw new Win32Exception(error);
        }
    }

    private static class Win32
    {
        public enum VirtualKeyStates
        {
            Shift = 0x10,
            Control = 0x11,
            Alt = 0x12,
            LeftWin = 0x5B,
            LeftControl = 0xA2,
            LeftShift = 0xA0,
            LeftAlt = 0xA4,
        }

        [DllImport("user32.dll")]
        public static extern bool SetKeyboardState(byte[] lpKeyState);

    }

    private sealed class Disposable : IDisposable
    {
        public void Dispose()
        {
            var keyState = new byte[256];
            SetKeyboardState(keyState);
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.