[转]C# 键盘钩子,真正解决大小写/shift后字符获取问题

C# 读取和设置大小写切换键状态的代码 将内容过程中比较重要的一些内容记录起来,下边内容是关于C# 读取和设置大小写切换键状态的内容,希望能对各朋友有所用处。 using System; using System.Runtime.InteropServices; using System.Windows.Forms; namespace RobvanderWoude { public class CapsLock { [DllImport( “user32.dll” )] static extern void keybd_event( byte 阅读详情

留着学习用,转自https://blog.youkuaiyun.com/wwh1004/article/details/79287647


作者:wwh1004 
来源:优快云 
原文:https://blog.youkuaiyun.com/wwh1004/article/details/79287647 
版权声明:本文为博主原创文章,转载请附上博文链接!

原文复制,如下:

 


本代码支持在无消息循环的线程上调用键盘钩子,比如控制台程序,并且可以屏蔽按键(在Key*事件中返回false)
代码:

using System;
using System.Threading;
using System.Windows.Forms;
using static FastWin32.NativeMethods;

namespace FastWin32.Hook.WindowMessage
{
    /// <summary>
    /// 参数,触发条件与 <see cref="KeyEventArgs"/> 相同,但此事件有返回值。返回 <see langword="true"/> 表示将此次消息继续发送给下一个钩子,返回 <see langword="false"/> 表示屏蔽此次消息,目标窗口将无法收到此次消息
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    public delegate bool HookKeyEventHandler(KeyboardHook sender, KeyEventArgs e);

    /// <summary>
    /// 参数,触发条件与 <see cref="KeyPressEventArgs"/> 相同,但此事件有返回值。返回 <see langword="true"/> 表示将此次消息继续发送给下一个钩子,返回 <see langword="false"/> 表示屏蔽此次消息,目标窗口将无法收到此次消息
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    public delegate bool HookKeyPressEventHandler(KeyboardHook sender, KeyPressEventArgs e);

    /// <summary>
    /// 键盘消息钩子
    /// </summary>
    public class KeyboardHook
    {
        private bool _isLowLevel;

        private IntPtr _hookHandle;

        private byte[] _keyboardState = new byte[256];

        private Thread _hookThread;

        /// <summary>
        /// 按键按下事件
        /// </summary>
        public event HookKeyEventHandler KeyDown;

        /// <summary>
        /// 按键弹起事件
        /// </summary>
        public event HookKeyEventHandler KeyUp;

        /// <summary>
        /// 按键按压事件
        /// </summary>
        public event HookKeyPressEventHandler KeyPress;

        /// <summary>
        /// 是否安装
        /// </summary>
        public bool IsInstalled { get; private set; }

        /// <summary>
        /// 是否将输入处理机制附加到顶端窗口的线程,默认为否。如果大小写获取失败或无法正常挂钩键盘消息,可以将此属性设置为 <see langword="true"/>。
        /// </summary>
        public bool IsAttachInput { get; set; }

        /// <summary>
        /// 创建普通全局键盘钩子实例,非LowLevel
        /// </summary>
        public KeyboardHook() : this(false)
        {
        }

        /// <summary>
        /// 创建全局键盘钩子实例
        /// </summary>
        /// <param name="isLowLevel">是否使用低级键盘钩子</param>
        public KeyboardHook(bool isLowLevel)
        {
            _isLowLevel = true;
        }

        /// <summary>
        /// 安装钩子
        /// </summary>
        public bool Install()
        {
            if (IsInstalled)
                throw new NotSupportedException("无法重复安装钩子");

            bool finished;

            finished = false;
            _hookThread = null;
            if (Application.MessageLoop)
            {
                //调用此方法的线程如果有消息循环,就不需要开新线程启动消息循环
                _hookHandle = SetWindowsHookEx(_isLowLevel ? WH_KEYBOARD_LL : WH_KEYBOARD, KeyboardHookCallback, GetModuleHandle(null), 0);
                finished = true;
            }
            else
            {
                _hookThread = new Thread(() =>
                {
                    _hookHandle = SetWindowsHookEx(_isLowLevel ? WH_KEYBOARD_LL : WH_KEYBOARD, KeyboardHookCallback, GetModuleHandle(null), 0);
                    finished = true;
                    Application.Run();
                })
                {
                    IsBackground = true
                };
                _hookThread.Start();
            }
            while (!finished)
                Thread.Sleep(0);
            if (_hookHandle == IntPtr.Zero)
            {
                _hookThread?.Abort();
                return false;
            }
            IsInstalled = true;
            return true;
        }

        /// <summary>
        /// 键盘消息回调函数
        /// </summary>
        /// <param name="nCode">挂钩过程用于确定如何处理消息的代码。如果代码小于0,挂钩过程必须将消息传递给CallNextHookEx函数,无需进一步处理,并应返回CallNextHookEx返回的值。</param>
        /// <param name="wParam">产生击键消息的密钥的虚拟密钥代码。</param>
        /// <param name="lParam">重复计数,扫描码,扩展密钥标志,上下文代码,先前的密钥状态标志和转换状态标志。有关lParam参数的更多信息,请参阅按键消息标志。下表描述了该值的位。</param>
        /// <returns></returns>
        private unsafe IntPtr KeyboardHookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode < 0 || (KeyDown == null && KeyUp == null && KeyPress == null))
                //如果nCode小于零,则钩子过程必须返回CallNextHookEx返回的值并且不对钩子消息做处理。如果3个事件均未被订阅,直接返回
                return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
            else
            {
                if (OnEvent((uint)wParam, ((KBDLLHOOKSTRUCT*)lParam)->vkCode, ((KBDLLHOOKSTRUCT*)lParam)->scanCode))
                    return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
                else
                    return (IntPtr)(-1);
            }
        }

        /// <summary>
        /// 引发事件
        /// </summary>
        /// <param name="messageType">消息类型</param>
        /// <param name="vkCode">虚拟键码</param>
        /// <param name="scanCode">扫描码</param>
        /// <returns></returns>
        private unsafe bool OnEvent(uint messageType, uint vkCode, uint scanCode)
        {
            bool isCallNext;
            uint currentThreadId;
            uint foregroundThreadId;
            char keyChar;

            isCallNext = true;
            if (KeyDown != null && (messageType == WM_KEYDOWN || messageType == WM_SYSKEYDOWN))
                isCallNext = KeyDown(this, new KeyEventArgs((Keys)vkCode));
            if (KeyUp != null && (messageType == WM_KEYUP || messageType == WM_SYSKEYUP))
                isCallNext = KeyUp(this, new KeyEventArgs((Keys)vkCode));
            if (KeyPress != null && messageType == WM_KEYDOWN)
            {
                if (IsAttachInput && ((currentThreadId = GetCurrentThreadId()) != (foregroundThreadId = GetWindowThreadProcessId(GetForegroundWindow(), null))))
                {
                    //将输入处理机制附加到顶端窗口的线程
                    AttachThreadInput(currentThreadId, foregroundThreadId, true);
                    GetKeyState(0);
                    GetKeyboardState(_keyboardState);
                    AttachThreadInput(currentThreadId, foregroundThreadId, false);
                }
                else
                {
                    GetKeyState(0);
                    GetKeyboardState(_keyboardState);
                }
                if (ToAscii(vkCode, scanCode, _keyboardState, out keyChar, 0) == 1)
                    isCallNext = KeyPress(this, new KeyPressEventArgs(keyChar));
            }
            return isCallNext;
        }

        /// <summary>
        /// 卸载钩子
        /// </summary>
        public bool Uninstall()
        {
            if (!IsInstalled)
                throw new NotSupportedException("未安装钩子");

            _hookThread?.Abort();
            if (!UnhookWindowsHookEx(_hookHandle))
                //钩子卸载失败
                return false;
            IsInstalled = false;
            return true;
        }
    }
}

 

简易的识别大小写的键盘钩子 <br />初学钩子方面的知识,回想到一些游戏盗号的程序也是这个原理,觉得有必要好好了解一下。<br />代码段是我找了一个基本的局部键盘钩子之后修改了一下,由于我发现得到的键盘码都是大写的,那么怎么判断用户输入的究竟是大写还是小写呢?<br /> <br />我们通过判断shift键和大写锁定键这两个键的状态来确定输入的是大写还是小写,用到的函数是GetKeyState和GetAsyncKeyState,判断CapsLock只能用前者,判断Shift只能用后者,GetAsyncKeyState在按下某键的 阅读详情

相关推荐

C# WinForms软键盘控件开发:工业上位机输入解决方案

在工业自动化、医疗设备和公共查询终端等场景中,屏幕软键盘(On-Screen Keyboard)是实现人机交互的关键组件,尤其适用于操作员佩戴防护手套或触摸屏输入不便的环境。其核心原理是通过Windows API(如SendInput)模拟硬件键盘事件,将虚拟按键动作转化为系统可识别的输入信号,确保输入准确导向目标控件。这项技术的工程价值在于解决了物理键盘依赖性强、易误触等问题,提升了系统的易用性和稳定性。在C# WinForms开发中,通过封装KeySimulator引擎和动态UI管理,可以构建出高内聚、

快马扬鞭须努力! 422

C#字符串常用的方法

C#字符串常用的方法

weixin_57677300的博客 814

C#模拟键盘操作:从SendKeys到SendInput的完整实现与实战

在Windows自动化开发中,模拟键盘输入是一项基础且关键的技术,其核心原理基于Windows消息循环机制。当物理按键被触发时,系统会生成包含扫描码的WM_KEYDOWN/WM_KEYUP消息,程序通过发送这些虚拟事件即可实现自动化输入。这项技术的价值在于能显著提升测试效率与操作精度,广泛应用于自动化测试、办公辅助及游戏脚本等场景。针对C#开发者,实现方案需从简单的SendKeys过渡到底层的Windows API,其中SendInput因其官方推荐与精确的时序控制成为生产环境首选。本文深入解析了如何构建健

clijovtbq401783153的博客 416

C#中键盘钩子的使用

public class Win32Hook { [DllImport("kernel32")] public static extern int GetCurrentThreadId(); [DllImport( "user32", CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)] public static e

Ninth(天下第九)的专栏 1873

VC++ MFC软键盘开发:从原理到实践,实现自定义输入解决方案

在Windows桌面应用开发中,输入处理是核心基础技术之一,涉及消息机制、窗口管理与用户交互。其原理在于应用程序通过接收系统派发的键盘消息来响应用户输入,这构成了人机交互的底层通道。对于需要高度定制化输入界面的场景,如工业控制、触摸屏一体机或安全受限环境,系统自带输入法往往无法满足特定需求,这时开发自定义软键盘的技术价值便凸显出来。通过模拟键盘输入、管理焦点窗口和自定义绘制界面,开发者可以构建完全可控的输入解决方案。本文将深入解析使用Visual C++和MFC框架从零构建软键盘的关键技术,涵盖SendIn

weixin_33860553的博客 457

.NET+Vue企业级RBAC权限平台:开箱即用的生产就绪方案

RBAC(基于角色的访问控制)是企业系统安全治理的基础模型,其核心在于将用户、角色与权限解耦,通过动态能力组合实现细粒度管控。在真实工程中,RBAC需突破静态角色限制,支持时间维度授权、前后端双重鉴权、行级数据范围控制等关键能力。本文聚焦于一套已落地金融、政务、制造等多行业的生产级实现——基于.NET Minimal API与Vue 3的前后端分离架构,提供菜单/按钮/接口/数据四层权限控制,内置滑动过期JWT、Redis权限缓存、动态路由加载与权限指令等开箱即用能力,显著降低权限配置与审计成本。

weixin_33326218的博客 275

使用c#捕获usb扫描枪扫描二维码、条形码结果

关于扫描枪对包含中文的二维码扫描的处理,请参考使用c#捕获usb扫描枪扫描二维码、条形码结果(支持中文版),本文之后的评论不再回复关于中文扫码的问题 另外,请仔细阅读本文,因为中文支持博文仅修改了本文中的一个类,其他代码沿用本文 ----------------------------------------------------------------- 最近公司买了一些扫描枪,要做个展...

文盲的专栏 5万+

未隔离电源设备使用usb转串口调试导致串口模块爆炸烧坏事故记录

这个事就发生在前两天,我们公司的wifi模块被客户用到了咖啡机上,客户寄了一台整机给我们协助调试,还送了几包咖啡豆,本想着还能打个咖啡喝一喝的,但就在咖啡机刚寄过来第一天,就出事了。而这个事故的发生,竟然仅仅是因为同事接了个串口模块到电脑调试打印导致的。谁也想不到,这个3.3V的供电的wifi模块居然还有这么大的威力。直接将usb转TTL串口模块的转换芯片给爆开了,咖啡机也给弄坏了,据同事描述当时情况就只见到一片火光和一声巨响,状况比较惨烈,所幸的是笔记本电脑没有烧坏,但是直接给崩蓝屏了。 ...

fangye945a的博客 6192

转: C#控件中的KeyDown、KeyPress 与 KeyUp事件

<br />研究了一下KeyDown,KeyPress 和 KeyUp 的学问。让我们带着如下问题来说明: <br />1.这三个事件的顺序是怎么样的?<br />2.KeyDown 触发后,KeyUp是不是一定触发?<br />3.三个事件的定义<br />4.KeyDown、KeyUp 和KeyPress 之间的区别<br />5.如何区分是否按的是小键盘?<br />6.PrScrn按键三个事件能够捕获吗?<br />7.{菜单键}和{开始键}KeyPress能够捕获吗?<br />8.如何捕获系统的

aoxiang1998的专栏 800

ICC2 实战秘籍:create_workspace 命令全解析

必选项:工作区名称,这可是创建工作区的 “身份证”,必不可少。技术数据选项匹配:优先考虑用 -technology 直接加载技术文件,这是获取最新、最准确技术数据的首选路径;要是已经有合适的技术库了,那 -use_technology_lib 引用现有技术库也能快速上手。精度设置优先规则:技术文件自动配置排在第一位,能自动适配就别手动操心;要是自动配置不理想,那就显式指定 scale_factor;实在没要求,就用默认配置,但得清楚它的精度限制。

weixin_50820814的博客 1124

Qt Coordinate System

Qt 坐标系统Qt 坐标系统 数学基础 Qt坐标系统 视口 平移变换 缩放变换 setWindow 旋转 总结数学基础 矩阵与线性变换坐标系变换Qt坐标系统 视口和OpenGL一样,视口确定了画面在窗口(QWidget)中显示的区域,Qt的绘图坐标会完全映射到视口(View port)上,就像图示一样。默认情况下,窗口和视口是重合的,视口的大小覆盖了整个窗口。和OpenGL一样,Qt的QPa

unclerunning的博客 1151

C# 中 KeyPress 、KeyDown 和KeyPress的详细区别[转]

事件按下列顺序发生:1、KeyDown 2、KeyPress 3、KeyUpKeyDown触发后,一定触发KerUp吗KeyDown触发后,不一定触发KeyUp,当KeyDown 按下后,拖动鼠标,那么将不会触发KeyUp事件。定义KeyDown:在控件有焦点的情况下按下键时发生。 KeyPress:在控件有焦点的情况下按下键时发生。(下面会说和KeyDown 的区别) KeyUp:在控件有

柚咖小窝 4250

MuJoCo 相机图片怎么拿?视角调整获取物体图片及实时显示(附代码)

在Mujoco的仿真中,对于识别抓取场景来说,如何获得添加的body等物体的实时图像很重要,今天就分享下如何添加相机视角及可视化小方块(举例)的实时图片。复制一个scene.xml为scene_withcamera.xml,在xml中添加camera和小方块如下。设置xml文件中添加的相机body id。需要创建一个离屏渲染器。

darcsdn 2128

转载: c# keydown keypress keyup

转载: c# keydown keypress keyup   Windows窗体通过引发键盘事件来处理键盘输入以响应Windows消息,大多数Windows窗体应用程序都通过处理键盘事件来以独占方式处理键盘输入。 1.按键的类型   Windows窗体将键盘输入标识为由按位Keys枚举表示的虚拟键代码。使用Keys枚举,可以综合一系列按键以生成单个值,这些值与WM_KEYDOWN和W

hechenghai 618

SAP CBC 集成质量系统初始化接入实战指南

摘要 本文探讨了SAP S/4HANA Cloud Public Edition项目中质量系统的初始接入过程。质量系统并非开箱即用,而是需要经过SAP Central Business Configuration(CBC)的Scope and Organizational Structure阶段部署后才能具备完整功能。文章重点分析了几个关键环节:CBC里程碑确认的时机选择、Identity Authentication的初始管理员设置、Business Role Template的创建规范等。实施过程中需特

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1407

图像分割 - 使用Mask R-CNN模型在COCO数据集上进行图像分割任务

图像分割是计算机视觉领域的一个重要任务,它旨在将图像中的每个像素分类为对象或背景。Mask R-CNN是一种基于区域的卷积神经网络,可用于图像分割任务。它是Faster R-CNN的扩展,将目标检测与图像分割结合起来,能够同时检测和分割对象。在本博客中,我们将使用Mask R-CNN模型在COCO数据集上进行图像分割任务。我们将介绍如何下载和准备COCO数据集,以及如何使用Mask R-CNN模型进行训练和推理。

斌擎科技 1188

c# KeyDown,KeyPress 和KeyUp

KeyDown,KeyPress 和KeyUp 之我谈(更新版本) 最近在做一个程序,需要实现窗口下的F5 刷新功能。 研究了一下KeyDown,KeyPress 和KeyUp ,发现之间还是有点学问的。 让我们带着如下问题来说明,如果你看到这些问题你都知道,那么这篇文章你就当复习吧:) 1.这三个事件的顺序是怎么样的? 2.KeyDown 触发后,KeyUp是不是一定触发? 3.

qq_25235869的博客 576

Kaggle赛题总结:Enefit - Predict Energy Behavior of Prosumers

竞赛旨在解决能源不平衡的问题,即预计使用的能源与实际使用或产生的能源不符。自发自用者是既消耗又产生能源的个体,他们在造成能源不平衡方面起到了重要作用。尽管他们只占所有能源消费者的一小部分,但他们不可预测的能源使用行为给能源公司带来了物流和财务问题。如果不加以解决,可能会导致运营成本增加、电网不稳定以及能源资源的低效利用。如果这个问题得到有效解决,将显著降低不平衡成本,提高电网的可靠性,并使自发自用者更高效和可持续地融入能源系统中。

猫敷雪 741

C#控件中的KeyDown、KeyPress 与 KeyUp事件浅谈

研究了一下KeyDown,KeyPress 和 KeyUp 的学问。让我们带着如下问题来说明:1.这三个事件的顺序是怎么样的?2.KeyDown 触发后,KeyUp是不是一定触发?3.三个事件的定义4.KeyDown、KeyUp 和KeyPress 之间的区别5.如何区分是否按的是小键盘?6.PrScrn按键三个事件能够捕获吗?7.{菜单键}和{开始键}KeyPress能够捕获吗?8.如何捕获

我的收藏 1万+

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

C#控件KeyDown、KeyPress与KeyUp的事件

(一)这三个事件的顺序是怎么样的?   按下列顺序发生:KeyDown、KeyPress、KeyUp 。 (二)KeyDown 触发后,KeyUp是不是一定触发?   KeyDown触发后,不一定触发KeyUp,当KeyDown 按下后,拖动鼠标,那么将不会触发KeyUp事件。 (三)三个事件的定义   KeyDown:在控件有焦点的情况下按下键时发生。   KeyPress:在控件

Conan的专栏 1315

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Unity PC端软键盘自动唤醒:基于OSK.exe与Windows消息通信的完整实现方案

在桌面应用开发中,跨平台UI交互与系统原生功能的集成是常见的工程挑战。其核心原理在于进程间通信与窗口消息机制,通过系统API实现不同应用程序间的协同工作。这项技术的价值在于能够复用操作系统提供的成熟组件,避免重复开发,同时保证功能的稳定性和原生体验。在触摸屏一体机、自助终端、教育平板等Unity PC端应用场景中,用户期待点击输入框即能自动弹出软键盘,这直接关系到产品的易用性。本文聚焦于解决Unity在Windows平台下缺乏开箱即用软键盘支持的问题,详细阐述了如何通过进程管理启动系统自带的osk.exe,

congjukun0600的博客 464

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

KeyDown,KeyPress 和KeyUp 之区别

Windows窗体通过引发键盘事件来处理键盘输入以响应Windows消息,大多数Windows窗体应用程序都通过处理键盘事件来以独占方式处理键盘输入。 1.按键的类型   Windows窗体将键盘输入标识为由按位Keys枚举表示的虚拟键代码。使用Keys枚举,可以综合一系列按键以生成单个值,这些值与WM_KEYDOWN和WM_SYSKEYDOWN,Windows消息所伴随的值相对应。另外,

ltolll的博客(技术版) 1189
上一篇: 出现RPC服务器不可用的解决方法
下一篇: 【转】C#键盘钩子之局部钩子
sunstar8921
博客等级 码龄9年 12粉丝 7原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值