【问题标题】:How does this bitmask apply to LParam (WM_HOTKEY)此位掩码如何应用于 LParam (WM_HOTKEY)
【发布时间】:2014-02-03 11:13:05
【问题描述】:

目前我正在开发一个简单的类库来处理global hot keys,并借助各种blog postsSO answers

考虑一下我整理的这段完整的代码。

protected override void WndProc(ref Message m)
{
    const int WM_HOTKEY = 0x0312;

    if (m.Msg == WM_HOTKEY)
    {
        var modifier = (int) m.LParam & 0xFFFF;
        var key = ((int) m.LParam & 0xFFFF);
    }

    base.WndProc(ref m);
}

我真的不明白,想解释一下位掩码是如何工作的。我对如何应用按位运算符有一个合理的理解,但我不明白为什么要在这里应用这个特定的位掩码。

此外,我很难理解IntPtr 的目的。为什么LParamIntPtr 在这种情况下?谢谢。

【问题讨论】:

    标签: c# winapi bit-manipulation intptr


    【解决方案1】:

    WM_HOTKEY 的文档说LPARAM 包含两个 16 位字段。高位字(高 16 位)有按键的 VK,低位字(低 16 位)有指定的修饰符。

    LPARAM & 0xffff 将获得低 16 位,LPARAM >> 16 将获得高 16 位。

    LPARAM & 0xffff 有效,因为 32 位 LPARAM 看起来像:

       V bit 31                              V bit 0
       HIGH WORD           LOW WORD
    0y vvvv vvvv vvvv vvvv mmmm mmmm mmmm mmmm where v is the vk, and m is the modifier 
    0y 0000 0000 0000 0000 1111 1111 1111 1111 == 0x0000ffff
    ========================================== Bitwise and
    0y 0000 0000 0000 0000 mmmm mmmm mmmm mmmm Just left with the modifier bits
    

    LPARAM >> 16 通过将位向右移动 16 个位置来工作

       V bit 31                              V bit 0
       HIGH WORD           LOW WORD
    0y vvvv vvvv vvvv vvvv mmmm mmmm mmmm mmmm where v is the vk, and m is the modifier 
    0y 0vvv vvvv vvvv vvvv vmmm mmmm mmmm mmmm right shifted once (>> 1)
    0y 00vv vvvv vvvv vvvv vvmm mmmm mmmm mmmm right shifted twice (>> 2)
    ...
    0y 0000 0000 0000 0000 vvvv vvvv vvvv vvvv right shifted sixteen times (>> 16)
    

    LPARAM 被定义为指针的大小,因此它将映射到托管代码中的IntPtr。由于我们只使用 LPARAM 的低 32 位,我们需要切掉高 32。我们可以强制转换为 int 这样做,但如果您使用 checked 算法运行,它将导致 @987654333 @。相反,我们将IntPtr 转换为long(在32 位机器上将填零),然后转换为int(将截断)。

    如果我们不将IntPtr 的大小调整为Int32,如果应用程序发送一条设置为lparam >> 16 的结果的高位消息,您可能会遇到异常。

    IntPtr lparam = /* comes from WndProc */;
    Int32 lparam32 = unchecked((int)(long)lparam);
    
    Int16 lowWord = lparam32 & 0xffff;
    Int16 highWord = lparam32 >> 16;
    

    话虽如此,这里是 C# 中热键侦听器的完整实现,我不记得在哪里找到了。如果有人对此有归属,请告诉我,或编辑此帖子以列出原作者。

    using System;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    
    public sealed class KeyboardHook : IDisposable
    {
        private int _currentId;
        private Window _window;
    
        public event EventHandler<KeyPressedEventArgs> KeyPressed;
    
        public KeyboardHook()
        {
            EventHandler<KeyPressedEventArgs> handler = null;
            this._window = new Window();
            if (handler == null)
            {
                handler = delegate (object sender, KeyPressedEventArgs args) {
                    if (this.KeyPressed != null)
                    {
                        this.KeyPressed(this, args);
                    }
                };
            }
            this._window.KeyPressed += handler;
        }
    
        public void Dispose()
        {
            for (int i = this._currentId; i > 0; i--)
            {
                UnregisterHotKey(this._window.Handle, i);
            }
            this._window.Dispose();
        }
    
        public void RegisterHotKey(ModifierKeys modifier, Keys key)
        {
            this._currentId++;
            if (!RegisterHotKey(this._window.Handle, this._currentId, (uint) modifier, (uint) key))
            {
                throw new InvalidOperationException("Couldn’t register the hot key.");
            }
        }
    
        [DllImport("user32.dll")]
        private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
        [DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
    
        private class Window : NativeWindow, IDisposable
        {
            private static int WM_HOTKEY = 0x312;
    
            public event EventHandler<KeyPressedEventArgs> KeyPressed;
    
            public Window()
            {
                this.CreateHandle(new CreateParams());
            }
    
            public void Dispose()
            {
                this.DestroyHandle();
            }
    
            protected override void WndProc(ref Message m)
            {
                base.WndProc(ref m);
                if (m.Msg == WM_HOTKEY)
                {
                    Keys key = ((Keys) (((int) m.LParam) >> 0x10)) & Keys.KeyCode;
                    ModifierKeys modifier = ((ModifierKeys) ((int) m.LParam)) & ((ModifierKeys) 0xffff);
                    if (this.KeyPressed != null)
                    {
                        this.KeyPressed(this, new KeyPressedEventArgs(modifier, key));
                    }
                }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2022-06-29
      • 2014-07-12
      • 1970-01-01
      • 2014-07-25
      • 1970-01-01
      • 2018-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多