c# - 使用 RegisterHotKey api 调用时,为什么它接受 1、2、4 和 8 作为修饰符?

标签 c# enums pinvoke flags

我引用了这篇文章;

http://www.pinvoke.net/default.aspx/user32/RegisterHotKey.html

    #region fields
    public static int MOD_ALT = 0x1;
    public static int MOD_CONTROL = 0x2;
    public static int MOD_SHIFT = 0x4;
    public static int MOD_WIN = 0x8;
    public static int WM_HOTKEY = 0x312;
    #endregion

    [DllImport("user32.dll")]
    private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);

    [DllImport("user32.dll")]
    private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

    private static int keyId;
    public static void RegisterHotKey(Form f, Keys key)
    {
        int modifiers = 0;

        if ((key & Keys.Alt) == Keys.Alt)
            modifiers = modifiers | WindowsShell.MOD_ALT;

        if ((key & Keys.Control) == Keys.Control)
            modifiers = modifiers | WindowsShell.MOD_CONTROL;

        if ((key & Keys.Shift) == Keys.Shift)
            modifiers = modifiers | WindowsShell.MOD_SHIFT;

        Keys k = key & ~Keys.Control & ~Keys.Shift & ~Keys.Alt;

        Func ff = delegate()
            {
                keyId = f.GetHashCode(); // this should be a key unique ID, modify this if you want more than one hotkey
                RegisterHotKey((IntPtr)f.Handle, keyId, modifiers, (int)k);
            };

        f.Invoke(ff); // this should be checked if we really need it (InvokeRequired), but it's faster this way
    }

我的问题是,RegisterHotKey api 如何知道 124 8是windows键吗?因为 ctrl、shift 和菜单 (alt) 的按键代码会返回完全不同的按键值? RegisterHotKey 函数中到底发生了什么,它正在检查:

if ((key & Keys.Control) == Keys.Control)
                modifiers = modifiers | WindowsShell.MOD_CONTROL;

它在这里做什么?

Keys k = key & ~Keys.Control & ~Keys.Shift & ~Keys.Alt;

最佳答案

MOD_ALTMOD_CONTROL等与关联按键的键码没有任何关系。

您会看到一个 enum 类型,用于表示一组 flags 。这是一种特别紧凑的方式来表示表示事物组合的状态(例如同时按下修饰键、文件访问权限等)

当以这种方式使用enum时,枚举类型变量的每一位都可以用来指示设置了特定的“标志”。

// Note that powers of 2 are used; each value has only a single bit set
public static int MOD_ALT = 0x1;     // If bit 0 is set, Alt is pressed
public static int MOD_CONTROL = 0x2; // If bit 1 is set, Ctrl is pressed
public static int MOD_SHIFT = 0x4;   // If bit 2 is set, Shift is pressed 
public static int MOD_WIN = 0x8;     // If bit 3 is set, Win is pressed

// If we wanted to represent a combination of keys:
int altAndControl = MOD_ALT | MOD_CONTROL; // == 3
int controlAndShift = MOD_CONTROL | MOD_SHIFT; // == 6

这有两个优点:

  • API 不必为每个修饰键采用单独的 bool 参数
  • 可以扩展 API 以包含其他修饰键,而无需更改界面

按位&|可用于确定值中设置了哪些标志,以及设置或取消设置值中的标志。

您询问的代码正是这样做的:

if ((key & Keys.Control) == Keys.Control) 
   modifiers = modifiers | WindowsShell.MOD_CONTROL

表示“如果该键设置了控制位,则在修饰符中设置控制位”

Keys k = key & ~Keys.Control & ~Keys.Shift & ~Keys.Alt;

表示“k 被分配给 key 以及 ControlShiftAlt 标志已清除”

我不确定为什么 pinvoke 的贡献者选择使用常量;您可以轻松地使用适当的枚举:

[Flags]
public enum Modifiers
{
   None = 0,
   Alt = 1,
   Control = 2,
   // ...
}

My answer to a similar question有关标志如何工作的更多详细信息以及更多示例。

关于c# - 使用 RegisterHotKey api 调用时,为什么它接受 1、2、4 和 8 作为修饰符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/676341/

相关文章:

c# - 如何在 Windows 8 (WinRT) 上从图像创建视频

C++:在类内、类外应用枚举

具有复合值的 Java 枚举

c# - 枚举标志属性

c# - SetProcessDpiAwareness 没有效果

c# - 如何将非托管应用程序窗口置于最前面,并使其成为(模拟)用户输入的事件窗口

c# - PInvoke C# : Function takes pointer to function as argument

c# - 如何添加标有 [DatabaseGenerate(DatabaseGenerateOption.None)] 的新实体

c# - 有没有办法在 C# 中限制 API 的处理器资源?

c# - 我如何将 AllowHtml 属性与 Entity Framework 一起使用