1

我在 Windows 中遇到了全局热键问题。我和我的朋友正在开发一个程序(在 C# 中),它使用通过来自 User32.dll 的 RegisterHotkey 函数调用注册的 Windows 全局热键。

在我的电脑上一切正常,但在我朋友的电脑上注册热键时,即使按一次键并指定了 MOD_NOREPEAT 标志,它也会被调用两次。我尝试注册两个相同的热键,但这是不可能的(只允许对指定的热键组合进行一个注册调用,第二个相同的组合被 RegisterHotkey 函数拒绝)。

这是代码。我为已经注册的热键制作了一个简单的包装器(从我的代码管理注册的组合):

    public class HotkeyStructure
    {
        /// <summary>
        /// Id of registered hotkey structure
        /// </summary>
        public int HotkeyId { get; private set; }
        /// <summary>
        /// Hotkey modifiers (eg SHIFT + ALT etc)
        /// </summary>
        public int HotkeyModifiers { get; private set; }
        /// <summary>
        /// Virtual key code (all alphanumeric keys)
        /// </summary>
        public int VirtualKeyCode { get; private set; }

        /// <summary>
        /// Action executed when hotkey detected
        /// </summary>
        public Action OnHotkeyAction { get; set; }


        public HotkeyStructure(Modifiers hotkeyModifiers, VirtualKeyCode virtualKeyCode, int hotkeyId)
        {
            this.HotkeyModifiers = (int)hotkeyModifiers;
            this.VirtualKeyCode = (int)virtualKeyCode;
            this.HotkeyId = hotkeyId;
        }
    }

这是管理注册处理程序的类的代码:

[Flags]
public enum Modifiers : int
{
    NONE = 0,
    MOD_ALT = 0x0001,
    MOD_CONTROL = 0x0002,
    MOD_NOREPEAT = 0x4000,
    MOD_SHIFT = 0x0004,
    MOD_WIN = 0x0008
}    


public sealed class HotkeyApi
{
    //Constant which detects hotkey message
    private const int WM_HOTKEY = 0x0312;
    //processhandle pointer
    IntPtr processHandle;
    //process handle object
    private HwndSource source;

    //static list of all registered hotkeys
    private static List<HotkeyStructure> _registeredHotkeys = new List<HotkeyStructure>();

    //external library function import
    [DllImport("User32.dll")]
    private static extern bool RegisterHotKey(IntPtr handle, int hotkeyId, int modifiers, int virtualKey);

    [DllImport("User32.dll")]
    private static extern bool UnregisterHotKey(IntPtr handle, int hotkeyId);

    public HotkeyApi(HwndSource source)
    {
        this.processHandle = source.Handle;
        this.source = source;
        //attaching hook to system message sources
        this.source.AddHook(WndProc);
    }

    //message handler
    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == WM_HOTKEY)
        {
            HotkeyStructure structure = _registeredHotkeys.SingleOrDefault(h => h.HotkeyId == wParam.ToInt32());
            if (structure != null)
            {
                structure.OnHotkeyAction();
            }
        }
        return IntPtr.Zero;
    }

    /// <summary>
    /// Registers HotkeyStructure with custom Action passed in parameter (action can be changed during execution via public field in returned HotkeyStructure
    /// </summary>
    /// <param name="hotkeyModifiers">Which key should be pressed with other key to fire an event (option NONE causes disability for selected keycode)</param>
    /// <param name="keycode">Keycode which should be pressed with modifier</param>
    /// <param name="eventHadler">Action which will be fired with registered hotkey</param>
    /// <returns>null if register action failed (eg. registering new hotkey which is the same as one which already exist) otherwise new HotkeyStructure</returns>
    public HotkeyStructure RegisterHotkey(Modifiers hotkeyModifiers, VirtualKeyCode keycode, Action eventHadler)
    {
        int id = _registeredHotkeys.Count + 1;
        bool result = RegisterHotKey(processHandle, id, (int)hotkeyModifiers, (int)keycode);
        if (result)
        {
            HotkeyStructure structure = new HotkeyStructure(hotkeyModifiers, keycode, id);
            structure.OnHotkeyAction = eventHadler;
            _registeredHotkeys.Add(structure);
            return structure;
        }
        else
        {
            return null;
        }
    }

    /// <summary>
    /// Removes hotkey from the list 
    /// </summary>
    /// <param name="hotkeyId">Id of hotkey structure (obj.HotkeyId)</param>
    /// <returns>true if succeeds otherwise false</returns>
    public bool UnregisterHotkey(int hotkeyId)
    {
        if (UnregisterHotKey(processHandle, hotkeyId))
        {
            var str = _registeredHotkeys.SingleOrDefault(h => h.HotkeyId == hotkeyId);
            if (str != null)
            {
                _registeredHotkeys.Remove(str);
                return true;
            }
        }
        return false;
    }       }

这段代码在 App.xaml.cs 中的 OnLoadCompleted 方法中调用:

               var source = PresentationSource.FromVisual(App.Current.MainWindow) as HwndSource;
               Hotkeys = new HotkeyApi(source);

什么会导致这个问题?

(抱歉可能出现语言错误。)

4

0 回答 0