如何使用WPF和.NET 3.5注册一个全局热键以说CTRL + SHIFT +(LETTER)?

时间:2020-03-05 18:49:06  来源:igfitidea点击:

我在Cusing WPF中构建一个应用程序。如何绑定某些键?

另外,如何绑定Windows键?

解决方案

回答

我不确定WPF,但这可能会有所帮助。我使用了RegisterHotKey(user32)中描述的解决方案(根据我的需要进行了修改),用于CWindows Forms应用程序,以便在Windows中分配CTRL-KEY组合来生成Cform,并且效果很好(即使在Windows Vista中)。希望对我们有帮助,祝我们好运!

回答

John建议的RegisterHotKey()可以起作用,唯一的问题是它需要HWND(使用PresentationSource.FromVisual(),并将结果转换为HwndSource)。

但是,我们还需要响应" WM_HOTKEY"消息,我不确定是否可以通过某种方式访问​​WPF窗口的WndProc(这对于Windows Forms窗口是可行的)。

回答

我不确定我们在这里所说的"全局"是什么意思(但是我想假设我们是在应用程序级别指的是命令,例如,保存所有可以通过Ctrl + +从任何地方触发的命令) Shift+S`。)

我们可以找到自己选择的全局" UIElement",例如,顶层窗口,该窗口是需要此绑定的所有控件的父级。由于WPF事件的"冒泡",子元素上的事件将一直冒泡直到控制树的根。

现在,首先我们需要

  • 使用这样的" InputBinding"将键组合与命令绑定
  • 然后可以通过CommandBinding将命令连接到处理程序(例如,由SaveAll调用的代码)。

对于Windows键,请使用正确的Key枚举成员Key.LWin或者Key.RWin。

public WindowMain()
    {
       InitializeComponent();
       // Bind Key
       InputBinding ib = new InputBinding(
           MyAppCommands.SaveAll,
           new KeyGesture(Key.S, ModifierKeys.Shift | ModifierKeys.Control));
       this.InputBindings.Add(ib);
       // Bind handler
       CommandBinding cb = new CommandBinding( MyAppCommands.SaveAll);
       cb.Executed += new ExecutedRoutedEventHandler( HandlerThatSavesEverthing );
       this.CommandBindings.Add (cb );
    }

    private void HandlerThatSavesEverthing (object obSender, ExecutedRoutedEventArgs e)
    {
      // Do the Save All thing here.
    }

回答

一位同事写了一个示例,说明如何创建与WPF一起使用的低级键盘挂钩。

http://blogs.vertigo.com/personal/ralph/Blog/Lists/Posts/Post.aspx?ID=8

回答

如果我们要混合使用Win32和WPF,请按以下步骤操作:

using System;
using System.Runtime.InteropServices;
using System.Windows.Interop;
using System.Windows.Media;
using System.Threading;
using System.Windows;
using System.Windows.Input;

namespace GlobalKeyboardHook
{
    public class KeyboardHandler : IDisposable
    {

        public const int WM_HOTKEY = 0x0312;
        public const int VIRTUALKEYCODE_FOR_CAPS_LOCK = 0x14;

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool UnregisterHotKey(IntPtr hWnd, int id);

        private readonly Window _mainWindow;
        WindowInteropHelper _host;

        public KeyboardHandler(Window mainWindow)
        {
            _mainWindow = mainWindow;
            _host = new WindowInteropHelper(_mainWindow);

            SetupHotKey(_host.Handle);
            ComponentDispatcher.ThreadPreprocessMessage += ComponentDispatcher_ThreadPreprocessMessage;
        }

        void ComponentDispatcher_ThreadPreprocessMessage(ref MSG msg, ref bool handled)
        {
            if (msg.message == WM_HOTKEY)
            {
                //Handle hot key kere
            }
        }

        private void SetupHotKey(IntPtr handle)
        {
            RegisterHotKey(handle, GetType().GetHashCode(), 0, VIRTUALKEYCODE_FOR_CAPS_LOCK);
        }

        public void Dispose()
        {
            UnregisterHotKey(_host.Handle, GetType().GetHashCode());
        }
    }
}

我们可以在此处获取要注册的热键的虚拟键代码:http://msdn.microsoft.com/zh-cn/library/ms927178.aspx

也许有更好的方法,但这是我到目前为止所掌握的。

干杯!

回答

尽管有时RegisterHotKey正是我们想要的,但在大多数情况下,我们可能不想使用系统范围的热键。我最终使用了如下代码:

using System.Windows;
using System.Windows.Interop;

namespace WpfApp
{
    public partial class MainWindow : Window
    {
        const int WM_KEYUP = 0x0101;

        const int VK_RETURN = 0x0D;
        const int VK_LEFT = 0x25;  

        public MainWindow()
        {
            this.InitializeComponent();

            ComponentDispatcher.ThreadPreprocessMessage += 
                ComponentDispatcher_ThreadPreprocessMessage;
        }

        void ComponentDispatcher_ThreadPreprocessMessage(
            ref MSG msg, ref bool handled)
        {
            if (msg.message == WM_KEYUP)
            {
                if ((int)msg.wParam == VK_RETURN)
                    MessageBox.Show("RETURN was pressed");

                if ((int)msg.wParam == VK_LEFT)
                    MessageBox.Show("LEFT was pressed");
            }
        }
    }
}