首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

如何在C# .netcore中读取按下的键盘和鼠标

在C# .NET Core中读取按下的键盘和鼠标的方法可以使用System.Windows.Forms命名空间中的类来实现。

首先,需要引用System.Windows.Forms命名空间,在项目中添加对System.Windows.Forms.dll的引用。然后,可以使用以下代码来实现读取键盘和鼠标的按下事件:

代码语言:txt
复制
using System;
using System.Windows.Forms;

public class KeyboardMouseReader
{
    public static void Main()
    {
        // 创建一个全局的键盘和鼠标钩子
        using (var hook = new KeyboardMouseHook())
        {
            // 注册键盘和鼠标按下事件的处理方法
            hook.KeyDown += Hook_KeyDown;
            hook.MouseDown += Hook_MouseDown;

            // 启动钩子
            hook.Start();

            // 运行程序直到用户按下ESC键
            while (true)
            {
                if (Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape)
                {
                    break;
                }
            }

            // 停止钩子
            hook.Stop();
        }
    }

    private static void Hook_KeyDown(object sender, KeyEventArgs e)
    {
        // 处理按下的键盘事件
        Console.WriteLine("键盘按下:" + e.KeyCode);
    }

    private static void Hook_MouseDown(object sender, MouseEventArgs e)
    {
        // 处理鼠标按下事件
        Console.WriteLine("鼠标按下:" + e.Button);
    }
}

public class KeyboardMouseHook : IDisposable
{
    private readonly IntPtr hookHandle;
    private readonly NativeMethods.HookProc hookCallback;

    public event KeyEventHandler KeyDown;
    public event MouseEventHandler MouseDown;

    public KeyboardMouseHook()
    {
        hookCallback = HookCallback;
        hookHandle = SetHook(hookCallback);
    }

    public void Start()
    {
        // 启动钩子
        NativeMethods.StartHook(hookHandle);
    }

    public void Stop()
    {
        // 停止钩子
        NativeMethods.StopHook(hookHandle);
    }

    private IntPtr SetHook(NativeMethods.HookProc proc)
    {
        using (var curProcess = System.Diagnostics.Process.GetCurrentProcess())
        using (var curModule = curProcess.MainModule)
        {
            // 安装钩子
            return NativeMethods.SetWindowsHookEx(
                NativeMethods.WH_KEYBOARD_LL,
                proc,
                NativeMethods.GetModuleHandle(curModule.ModuleName),
                0);
        }
    }

    private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode >= 0)
        {
            var eventType = (NativeMethods.WindowMessage)wParam;
            if (eventType == NativeMethods.WindowMessage.WM_KEYDOWN)
            {
                var vkCode = Marshal.ReadInt32(lParam);
                var key = (Keys)vkCode;

                // 触发键盘按下事件
                KeyDown?.Invoke(this, new KeyEventArgs(key));
            }
            else if (eventType == NativeMethods.WindowMessage.WM_LBUTTONDOWN ||
                     eventType == NativeMethods.WindowMessage.WM_RBUTTONDOWN ||
                     eventType == NativeMethods.WindowMessage.WM_MBUTTONDOWN)
            {
                var button = GetMouseButtonFromEventType(eventType);

                // 触发鼠标按下事件
                MouseDown?.Invoke(this, new MouseEventArgs(button, 0, 0, 0, 0));
            }
        }

        // 继续执行下一个钩子
        return NativeMethods.CallNextHookEx(hookHandle, nCode, wParam, lParam);
    }

    private MouseButtons GetMouseButtonFromEventType(NativeMethods.WindowMessage eventType)
    {
        switch (eventType)
        {
            case NativeMethods.WindowMessage.WM_LBUTTONDOWN:
                return MouseButtons.Left;
            case NativeMethods.WindowMessage.WM_RBUTTONDOWN:
                return MouseButtons.Right;
            case NativeMethods.WindowMessage.WM_MBUTTONDOWN:
                return MouseButtons.Middle;
            default:
                throw new ArgumentOutOfRangeException(nameof(eventType), eventType, null);
        }
    }

    public void Dispose()
    {
        // 卸载钩子
        NativeMethods.UnhookWindowsHookEx(hookHandle);
    }
}

public static class NativeMethods
{
    public const int WH_KEYBOARD_LL = 13;

    public enum WindowMessage : uint
    {
        WM_KEYDOWN = 0x0100,
        WM_LBUTTONDOWN = 0x0201,
        WM_RBUTTONDOWN = 0x0204,
        WM_MBUTTONDOWN = 0x0207
    }

    public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool UnhookWindowsHookEx(IntPtr hhk);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

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

    [DllImport("user32.dll")]
    public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    [DllImport("user32.dll")]
    public static extern IntPtr GetForegroundWindow();

    [DllImport("user32.dll")]
    public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

    [DllImport("kernel32.dll")]
    public static extern uint GetCurrentThreadId();

    [DllImport("user32.dll")]
    public static extern IntPtr SetForegroundWindow(IntPtr hWnd);

    [DllImport("user32.dll")]
    public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);

    [DllImport("user32.dll")]
    public static extern IntPtr GetFocus();

    [DllImport("user32.dll")]
    public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

    public static void StartHook(IntPtr hookHandle)
    {
        ShowWindow(GetForegroundWindow(), 2);

        uint currentThreadId = GetCurrentThreadId();
        uint foregroundThreadId = GetWindowThreadProcessId(GetForegroundWindow(), out var _);

        if (currentThreadId != foregroundThreadId)
        {
            AttachThreadInput(currentThreadId, foregroundThreadId, true);
        }

        SetForegroundWindow(hookHandle);

        if (currentThreadId != foregroundThreadId)
        {
            AttachThreadInput(currentThreadId, foregroundThreadId, false);
        }

        SetForegroundWindow(GetFocus());
    }

    public static void StopHook(IntPtr hookHandle)
    {
        ShowWindow(GetForegroundWindow(), 1);
        SetForegroundWindow(hookHandle);
    }
}

这段代码会监听键盘和鼠标的按下事件,并在控制台中打印出按下的按键或鼠标按钮。可以根据需求对事件进行进一步处理。

此外,C# .NET Core还有其他方式可以读取键盘和鼠标的输入,例如使用WindowsAPI函数来监听原始输入,或者使用第三方库如InputSimulator等。具体选择何种方法取决于项目需求和开发偏好。

注意:在使用键盘和鼠标钩子的时候,请确保以管理员身份运行程序,否则可能会无法捕捉系统级别的按键事件。

腾讯云相关产品:

  • 云服务器CVM:https://cloud.tencent.com/product/cvm
  • 弹性伸缩CVM:https://cloud.tencent.com/product/as
  • 云数据库MySQL:https://cloud.tencent.com/product/cdb
  • 弹性公网IP:https://cloud.tencent.com/product/eip
  • 轻量应用服务器Lighthouse:https://cloud.tencent.com/product/lighthouse

请注意,以上链接仅为参考,具体使用腾讯云产品时,请根据实际需求进行选择和配置。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

  • 互联网+ 何人能挡?带着你的Code飞奔吧!

    SQLServer性能优化专题 01.SQLServer性能优化之----强大的文件组----分盘存储(水平分库) http://www.cnblogs.com/dunitian/p/5276431.html 02.SQLServer性能优化之---水平分库扩展 http://www.cnblogs.com/dunitian/p/6078512.html 03.SQLServer性能优化之---分表分库技术--(同义词+链接服务器) http://www.cnblogs.com/dunitian/p/6041745.html 04.SQLServer性能优化之---读写分离&数据同步(发布订阅) http://www.cnblogs.com/dunitian/p/6041758.html 05.换环境了,以后继续更 06.备份,07.xxxx,08.故障转移 09.SQLServer性能优化之---数据库级日记监控(XEVENT) http://www.cnblogs.com/dunitian/p/6022967.html 很久以前: 我为NET狂官方面试题-数据库篇 http://www.cnblogs.com/dunitian/p/6028838.html 我为NET狂官方面试题-数据库篇答案 http://www.cnblogs.com/dunitian/p/6041323.html 01.有朋友问了数据库ID不连续,怎么获取上下篇文章?(不是所有情况都适用) http://www.cnblogs.com/dunitian/p/5239049.html 01.在sql server中建存储过程,如果需要参数是一个可变集合怎么处理? http://www.cnblogs.com/dunitian/p/4501268.html 02.把插入的数据自动备份到另一个表中 ~ 语境:本地和服务器自动同步(非数据同步解决方案) http://www.cnblogs.com/dunitian/p/5367445.html 03.SQL:指定名称查不到数据的衍伸~空格 换行符 回车符的批量处理 http://www.cnblogs.com/dunitian/p/5416429.html 04.利用SQLServer数据库发送邮件 http://www.cnblogs.com/dunitian/p/6022826.html 05.SQL Server 无法连接到服务器。SQL Server 复制需要有实际的服务器名称才能连接到服务器。请指定实际的服务器名称。 http://www.cnblogs.com/dunitian/p/6041824.html 06."无法删除数据库,因为该数据库当前正在使用"问题解决 http://www.cnblogs.com/dunitian/p/6047760.html 07.SQLServer文件收缩-图形化+命令 http://www.cnblogs.com/dunitian/p/6047709.html 08.关于全局ID,雪花(snowflake)算法的说明 http://www.cnblogs.com/dunitian/p/6130543.html 09.数据库分离附加(附日记丢失的处理) http://www.cnblogs.com/dunitian/p/6165945.html 10.数据库改名系列(数据库名,逻辑名,物理文件名) http://www.cnblogs.com/dunitian/p/6165998.html 11.牛逼的OSQL----大数据导入(cmd) http://www.cnblogs.com/dunitian/p/5276449.html 12.【SQLServer】记一次数据迁移-标识重复的简单处理 http://www.cnblogs.com/dunitian/p/6195827.html 13.【恢复挂起的解决方案】附加文件时候的提示“无法重新生成日志,原因是数据库关闭时存在打开的事务/用户,该数据库没有检查点或者该数据库是只读的。 ”【数据库恢复】 http://www.cnblogs.com/dunitian/p/6197051.html 14.数据库备份相关 http://www.cnblogs.com/dunitian/p/6260481.html

    07

    AgileConfig-如何使用AgileConfig.Client读取配置

    首先祝大家新年快乐,身体健康! 前面的文章(AgileConfig基于.NetCore的一个轻量级配置中心,AgileConfig轻量级配置中心 1.1.0 发布,支持应用间配置继承)都是介绍AgileConfig服务端已经控制台是如何工作、如何使用的,其实AgileConfig还有一个重要的组成部分:AgileConfig.Client。 AgileConfig.Client是使用C#编写的一个类库,只有使用它才能跟AgileConfig的服务端更好的配合工作实现实时推送配置信息等功能。 最近有几个同学问我如何集成Client,如何使用Client,看来光是Readme上的示例还是不够的,有必要比较详细的介绍下如何使用AgileConfig.Client。 下面通过几个示例来演示下如何AgileConfig.Client如何在mvc,控制台,wpf等程序上来读取配置:

    01

    在 C#和ASP.NET Core中创建 gRPC 客户端和服务器

    gRPC 是一种可以跨语言运行的现代高性能远程过程调用 (RPC) 框架。gRPC 实际上已经成为 RPC 框架的行业标准,Google 内外的组织都在使用它来从微服务到计算的“最后一英里”(移动、网络和物联网)的强大用例。 gRPC是一个高性能的开源的通用RPC框架,由Google公司开发,支持常用的C++、Java、Python、C#/.Net、Go、Node、Dart、Kotlin、Object-C、PHP、Ruby等语言,采用protobuf作为数据交换格式,并且采用C++开发,支持Windows 、Linux、macOS跨平台开发。对于跨语言服务调用非常方便,只要使用protobuf定义接口协议,然后按照gRPC语言SDK调用即可。比如我们使用C++对环保数采仪器设备通过串口或者网口传送的数据协议如Modbus协议、HJ212协议、或者厂商自定义的协议进行解析之后,将数据存放到本地数据库,这个时候我们如何将C++的数据传给前端网页呢? 这个时候可以使用多种方式。比如通过数据库、HTTP协议、WebSocket协议、RPC远程过程调用等方式。 我之前做环保的时候,采用C++和环保硬件设备打交道,通过C++后台程序将数采仪数据解析之后存入到本地Sqlite数据库中(分表分页存储),然后由于展示的网页比较简单,只是用网页展示当前站点的数据,前端采用ElementUI和Vue.js,后端采用Node.js。另外,C++后台写了一套RPC服务端接口,Node.js通过RPC客户端调用C++的后台RPC服务,双方之间通过Google Protobuf数据协议交互。

    00

    dotnet 使用 Crossgen2 对 DLL 进行 ReadyToRun 提升启动性能

    我对几个应用进行严格的启动性能评估,对比了在 .NET Framework 和 dotnet 6 下的应用启动性能,非常符合预期的可以看到,在用户的设备上,经过了 NGen 之后的 .NET Framework 可以提供非常优越的启动性能,再加上 .NET Framework 本身就是属于系统组件的部分,很少存在冷启动的时候,大部分的 DLL 都在系统里预热。启动性能方面,依然是 .NET Framework 比 dotnet 6 快非常多。而在破坏了 .NET Framework 的运行时框架层的 NGen 之后,可以发现 .NET Framework 的启动性能就比不过 dotnet 6 的启动性能。为了在 dotnet 6 下追平和 .NET Framework 的启动性能差异,引入与 NGen 的同等级的 ReadyToRun 用来提升整体的性能。本文将告诉大家如何在 dotnet 6 的应用里面,使用 Crossgen2 工具,给 DLL 生成 AOT 数据,提升应用启动性能

    02
    领券