如何在 WPF 中使用 C# 手动切换 NumLock 键?

How do I manually toggle the NumLock Key with C# in WPF?

我已经搜索了一段时间,大部分结果都是 C++ 或其他语言,而不是 C#。我看过的东西:

   keybd_event() // A c++ method that theoretically can be included with a DLL import, but hasn't worked in testing
   System.Windows.Forms.SendKeys.Send("{NUMLOCK}"}; // Forms namespace doesn't exist in Windows

目前,我有大约每秒执行一次的代码来观察 numlock 的状态并相应地更新我的表单中的图形。如果设置了 bool 切换,我还希望它强制启用 NumLock:


        internal partial class Interop
        {
            public static int VK_NUMLOCK = 0x90;
            public static int VK_SCROLL = 0x91;
            public static int VK_CAPITAL = 0x14;
            public static int KEYEVENTF_EXTENDEDKEY = 0x0001; // If specified, the scan code was preceded by a prefix byte having the value 0xE0 (224).
            public static int KEYEVENTF_KEYUP = 0x0002; // If specified, the key is being released. If not specified, the key is being depressed.

            [DllImport("User32.dll", SetLastError = true)]
            public static extern void keybd_event(
                byte bVk,
                byte bScan,
                int dwFlags,
                IntPtr dwExtraInfo);

            [DllImport("User32.dll", SetLastError = true)]
            public static extern short GetKeyState(int nVirtKey);

            [DllImport("User32.dll", SetLastError = true)]
            public static extern short GetAsyncKeyState(int vKey);
        }

    private void watcher(object source, ElapsedEventArgs e) 
        {
            bool NumLock = (((ushort)GetKeyState(0x90)) & 0xffff) != 0;

            if (!NumLock && fixers.watchNumL)
            {
                // Force NumLock back on
                // Simulate a key press
                Interop.keybd_event((byte)0x90,0x45,Interop.KEYEVENTF_EXTENDEDKEY | 0,IntPtr.Zero);

                // Simulate a key release
                Interop.keybd_event((byte)0x90,0x45,Interop.KEYEVENTF_EXTENDEDKEY | Interop.KEYEVENTF_KEYUP,    IntPtr.Zero);
                NumLock = (((ushort)GetKeyState(0x90)) & 0xffff) != 0;
            }

            if (NumLock)
            {
                this.Dispatcher.Invoke(() =>
                {
                    fixerBoxes["NumL"].FixerImg.Source = new BitmapImage(new Uri(@"/graphics/num_lock_on.png", UriKind.Relative));
                    StatusBox.Text = "Num Lock ON";
                });
            }
            else {
                this.Dispatcher.Invoke(() =>
                {
                    fixerBoxes["NumL"].FixerImg.Source = new BitmapImage(new Uri(@"/graphics/num_lock_off.png", UriKind.Relative));
                    StatusBox.Text = "Num Lock OFF";
                });
            }

        }


        public MainWindow()
        {
            // Start the watcher
            System.Timers.Timer myTimer = new System.Timers.Timer();
            // Tell the timer what to do when it elapses
            myTimer.Elapsed += new ElapsedEventHandler(watcher);
            // Set it to go off every second
            myTimer.Interval = 1000;
            // And start it        
            myTimer.Enabled = true;

        }

Here 是一个 class(带有库),可以为您完成此操作。该库做的更多,因此仅用于此可能有点矫枉过正。该方法使用 keybd_event 函数使用 pinvoke:

// Simulate a key press
Interop.keybd_event((byte)virtualKey,
    0x45,
    Interop.KEYEVENTF_EXTENDEDKEY | 0,
    IntPtr.Zero);

// Simulate a key release
    Interop.keybd_event((byte)virtualKey,
    0x45,
    Interop.KEYEVENTF_EXTENDEDKEY | Interop.KEYEVENTF_KEYUP,
    IntPtr.Zero);

按下并松开按钮会改变 LED 的状态。 virtualKey 是 VK_ 常量之一。

声明如下:

internal partial class Interop
{
    public static int VK_NUMLOCK = 0x90;
    public static int VK_SCROLL = 0x91;
    public static int VK_CAPITAL = 0x14;
    public static int KEYEVENTF_EXTENDEDKEY = 0x0001; // If specified, the scan code was preceded by a prefix byte having the value 0xE0 (224).
    public static int KEYEVENTF_KEYUP = 0x0002; // If specified, the key is being released. If not specified, the key is being depressed.

    [DllImport("User32.dll", SetLastError = true)]
    public static extern void keybd_event(
        byte bVk,
        byte bScan,
        int dwFlags,
        IntPtr dwExtraInfo);

    [DllImport("User32.dll", SetLastError = true)]
    public static extern short GetKeyState(int nVirtKey);

    [DllImport("User32.dll", SetLastError = true)]
    public static extern short GetAsyncKeyState(int vKey);
}