拖/放时可以使用鼠标滚轮吗?

2023-11-27

在 WinForms 中,调用DoDragDrop要开始拖动项目,控件不再使用鼠标滚轮滚动,并且控件的MouseWheel事件不再被调用,直到用户放下他正在拖动的任何东西。

有没有办法让鼠标滚轮在拖动时工作?


你可以获得全球MouseWheel带有键盘挂钩。

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Microsoft.Win32.SafeHandles;

using BOOL = System.Boolean;
using DWORD = System.UInt32;
using HHOOK = SafeHookHandle;
using HINSTANCE = System.IntPtr;
using HOOKPROC = HookProc;
using LPARAM = System.IntPtr;
using LRESULT = System.IntPtr;
using POINT = System.Drawing.Point;
using ULONG_PTR = System.IntPtr;
using WPARAM = System.IntPtr;

public delegate LRESULT HookProc(int nCode, WPARAM wParam, LPARAM lParam);

internal static class NativeMethods
{
    [DllImport("User32.dll", SetLastError = true)]
    internal static extern HHOOK SetWindowsHookEx(
        HookType idHook,
        HOOKPROC lpfn,
        HINSTANCE hMod,
        DWORD dwThreadId);

    [DllImport("User32.dll")]
    internal static extern LRESULT CallNextHookEx(
        HHOOK hhk,
        int nCode,
        WPARAM wParam,
        LPARAM lParam);

    [DllImport("User32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern BOOL UnhookWindowsHookEx(
        IntPtr hhk);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr GetModuleHandle(string lpModuleName);
}

internal static class NativeTypes
{
    internal enum MSLLHOOKSTRUCTFlags : uint
    {
        LLMHF_INJECTED = 0x00000001U,
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct MSLLHOOKSTRUCT
    {
        internal POINT pt;
        internal DWORD mouseData;
        internal MSLLHOOKSTRUCTFlags flags;
        internal DWORD time;
        internal ULONG_PTR dwExtraInfo;
    }
}

internal static class NativeConstants
{
    internal const int WH_MOUSE_LL = 14;

    internal const int HC_ACTION = 0;

    internal const int WM_MOUSEWHEEL = 0x020A;
    internal const int WM_MOUSEHWHEEL = 0x020E;

    internal const int WHEEL_DELTA = 120;
}

public enum HookType
{
    LowLevelMouseHook = NativeConstants.WH_MOUSE_LL
}

public enum HookScope
{
    LowLevelGlobal,
}

public class SafeHookHandle : SafeHandleZeroOrMinusOneIsInvalid
{
    private SafeHookHandle() : base(true) { }

    public static SafeHookHandle SetWindowsHook(HookType idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId)
    {
        var hhk = NativeMethods.SetWindowsHookEx(idHook, lpfn, hMod, dwThreadId);

        if(hhk.IsInvalid)
        {
            throw new Win32Exception();
        }
        else
        {
            return hhk;
        }
    }

    public IntPtr CallNextHook(int nCode, IntPtr wParam, IntPtr lParam)
    {
        return NativeMethods.CallNextHookEx(this, nCode, wParam, lParam);
    }

    protected override bool ReleaseHandle()
    {
        return NativeMethods.UnhookWindowsHookEx(this.handle);
    }
}

public abstract class WindowsHook : IDisposable
{
    private SafeHookHandle hhk;
    private HookProc lpfn;

    protected WindowsHook(HookType idHook, HookScope scope)
    {
        this.lpfn = this.OnWindowsHook;

        switch(scope)
        {
            case HookScope.LowLevelGlobal:
                IntPtr moduleHandle = NativeMethods.GetModuleHandle(null);
                this.hhk = SafeHookHandle.SetWindowsHook(idHook, this.lpfn, moduleHandle, 0U);
                return;
            default:
                throw new InvalidEnumArgumentException("scope", (int)scope, typeof(HookScope));
        }
    }

    protected virtual IntPtr OnWindowsHook(int nCode, IntPtr wParam, IntPtr lParam)
    {
        return this.hhk.CallNextHook(nCode, wParam, lParam);
    }

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if(disposing)
        {
            if(this.hhk != null) { this.hhk.Dispose(); }
        }
    }
}

public class LowLevelMouseHook : WindowsHook
{
    public event MouseEventHandler MouseWheel;

    public LowLevelMouseHook() : base(HookType.LowLevelMouseHook, HookScope.LowLevelGlobal) { }

    protected sealed override IntPtr OnWindowsHook(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if(nCode == NativeConstants.HC_ACTION)
        {
            var msLLHookStruct = (NativeTypes.MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(NativeTypes.MSLLHOOKSTRUCT));

            switch(wParam.ToInt32())
            {
                case NativeConstants.WM_MOUSEWHEEL:
                case NativeConstants.WM_MOUSEHWHEEL:
                    this.OnMouseWheel(new MouseEventArgs(Control.MouseButtons, 0, msLLHookStruct.pt.X, msLLHookStruct.pt.Y, (int)msLLHookStruct.mouseData >> 16));
                    break;
            }
        }

        return base.OnWindowsHook(nCode, wParam, lParam);
    }

    protected virtual void OnMouseWheel(MouseEventArgs e)
    {
        if(this.MouseWheel != null)
        {
            this.MouseWheel(this, e);
        }
    }
} 

用法示例:

using (LowLevelMouseHook hook = new LowLevelMouseHook())
{
    hook.MouseWheel += (sender, e) =>
    {
        Console.WriteLine(e.Delta);
    };
    Application.Run();
}

代码提供了一个类LowLevelMouseHook有一个事件MouseWheel其行为类似于内置 Windows 窗体控件类中的事件。

(此外,代码被分成一个抽象类WindowsHooks与其他钩子一起使用,SafeHookHandle确保句柄被释放的类以及本机方法的帮助器类)

你应该看看SetWindowsHookEx and CALLBACK LowLevelMouseProc了解其背后的技术。


此事件不仅限于您的应用程序,还会捕获表单外部的鼠标,因此它也应该适用于您无法使用本地事件的操作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

拖/放时可以使用鼠标滚轮吗? 的相关文章

  • 带有 ASP.NET 按钮回发的 jQuery UI 对话框

    我的 ASP NET 页面上有一个运行良好的 jQuery UI 对话框 jQuery function jQuery dialog dialog draggable true resizable true show Transfer hi
  • 使用管道在父级和子级之间传递整数值

    我对如何正确使用 pipeline 在两个进程之间传递整数值有点困惑 在我的程序中 我首先创建一个管道 然后分叉它 我假设我有 两个 管道 据我了解 这是我的任务 我的父母通过 for 循环检查某个操作的整数值 i 增加计数变量 并将值保存
  • 如何从经过身份验证的 SecurityToken 中获取声明

    我将令牌作为字符串传递到 SOAP 服务中 并验证了该令牌是否有效 我现在有一个 SecurityToken 在调试模式下我可以看到所有声明 特别是我想传递到另一个方法的 userId 声明 我似乎不知道如何获得这些索赔 现在 我解码了令牌
  • 如何在 C++ 中为指针“this”赋值

    在函数中 如何分配this一个新的价值 您可以分配对象this点于 this XY 但你不能分配直接值this this XY Error Expression is not assignable
  • Visual Studio 2013 调试器显示 std::string 的奇怪值

    我有一个大型的 cmake 生成的解决方案 其中包含许多项目 由于某种原因 我无法查看字符串的内容 因为根据调试器 Bx Buf含有一些垃圾 text c str 正确返回 Hello 该问题不仅仅发生在本地字符串上 返回的函数std st
  • 获取列表框中视图中的项目

    我有一个 ListBox 其属性 VirtualizingStackPanel VirtualizationMode 设置为 回收 我正在绑定一个自定义集合 实现IList and IList
  • 我担心我添加了太多接口

    我正在构建我的领域模型并继续重构它 正如我所做的那样 我发现我喜欢接口 因为它允许我根据接口为具体类型创建可重用的方法 控制器 视图 但是 我发现每次向域实体之一添加新属性时 我都会创建一个接口 例如 我有一个会员状态从抽象继承的对象Ent
  • 在 C# 中解析 JS Date.toIsoString

    我需要将 JS 日期存储为 ISO 8601 日期 我目前正在从格式为 2019 06 22T00 00 00 000Z 的表单中获取日期 正如 JS 的 toIsoString 方法所期望的那样 当这个日期传递到我的 API 控制器时 我
  • 维护 VS Test Project 中单元测试方法之间的上下文

    我想按顺序运行以下单元测试 使用随机数字的名称 密码等创建新客户 检索刚刚创建的客户并断言其属性包含相同的随机数 对同一用户调用 ForgotPassword 函数 并使用相同的随机数作为用户名 清楚地看到 我需要生成一次随机数 并在 3
  • 如何在 C++ 中正确使用 cin.fail()

    我正在编写一个程序 从用户那里获取整数输入cin gt gt iUserSel 如果用户输入一个字母 程序就会进入无限循环 我试图用下面的代码来阻止这种情况 但程序进入无限循环并打印出 错误 输入 我该如何修复我的程序 cin gt gt
  • main.cpp 是必需的吗?

    我试图编译一个程序cmake 我最终删除了我的main cpp文件 我刚刚将其复合到另一个包含我的项目名称的文件中 即 我刚刚将主函数剪切并粘贴到该文件中 问题是我有一个main cpp未发现错误 不确定是否在C 一个名为main cpp是
  • MPI - 发送和接收列

    我需要从一个进程发送矩阵列并从另一个进程接收它 我尝试运行以下程序 但得到了一个奇怪的结果 至少我这么认为 仅复制矩阵的第一个元素 某些矩阵元素会发生意外变化 include
  • 在 clang 中向量化函数

    我正在尝试根据此用 clang 对以下函数进行矢量化铿锵参考 http llvm org docs Vectorizers html 它采用字节数组向量并根据以下条件应用掩码this RFC https www rfc editor org
  • C++网络序列化[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一种将 C 数据包序列化为网络流的解决方案 我在这里看到很多帖子提到人们 ACE 谷歌协议缓
  • 从单应性估计 R/T

    我一直在尝试计算 2 个图像中的特征 然后将这些特征传递回CameraParams R没有运气 特征已成功计算并匹配 但是问题是将它们传递回R t 我明白你必须分解Homography为了使这一点成为可能 我已经使用如下方法完成了 http
  • 在一个解决方案中调用不同项目的方法

    1 个解决方案中有 3 个项目 我对第一个项目中的主文件进行的主要操作 但是我需要调用第三个项目中的方法并使用类 例如 第三个项目有 public DataClasses1DataContext base global WindowsFor
  • 在 Visual Studio 2012 Express 中设置 C++ 调试环境

    我需要调试的应用程序需要设置环境变量 这在 Visual Studio 2012 中似乎非常复杂 我想做类似的事情 set path c foo c bar c windows c program files application set
  • 为什么我可以在另一个函数中定义一个函数?

    请参阅下面的代码 我在另一个函数中定义了一个函数 void test1 void void test2 void printf test2 n printf test1 n int main void test1 return 0 这个用法
  • 将同步 zip 操作转换为异步

    我们有一个现有的库 其中一些方法需要转换为异步方法 但是我不确定如何使用以下方法执行此操作 错误处理已被删除 该方法的目的是压缩文件并将其保存到磁盘 请注意 zip 类不公开任何异步方法 public static bool ZipAndS
  • Adobe Illustrator 中的折线简化如何工作?

    我正在开发一个记录笔划的应用程序 您可以使用定点设备来绘制笔划 在上图中 我绘制了一个笔划 其中包含 453 个数据点 我的目标是大幅减少数据点的数量 同时仍然保持原始笔画的形状 对于那些感兴趣的人 上图笔画的坐标可以作为GitHub 上的

随机推荐