让USB键盘的LED灯听你的!(不干扰使用)
最近在研究一个课题,如何能利用键盘的led灯通道进行有效通信,那么首先要做的就是尝试能否在不影响键盘的情况下控制LED灯(num lock ,caps lock ,scroll lock)的使用。
首先,如果并不是HID USB键盘,下面的C代码就可以解决:
http://www.rohitab.com/discuss/topic/32092-toggle-led-lights/?p=10051697#entry10051697
同样的C#版的在此:
http://www.aboutmycode.com/miscellaneous/faking-num-lock-caps-lock-and-scroll-lock-leds/
如果是USB键盘上面的代码是不奏效的,其中一个重要原因就是使用Windows API的Createfile是打不开USB键盘设备,无法得到他的句柄(通过GetLastError()得到2查看错误编码解释就知道了),这是因为Mouse和Keyboard这类HID类设备是被系统独占的。但是现在很多人都要使用USB设备的键盘,那怎么办呢?
这里介绍一款Autohotkey的软件,使用简单的脚本编写就能实现替代手工键盘操作的方式,他可以向游戏出大招一样制定一系列的操作,包括开机后你想干什么干什么用这个软件编写些脚本很容易实现,用这款脚本实现的LED灯控制在下面这篇文章中也得到了实现:
http://www.autohotkey.com/board/topic/9587-keyboard-led-control-capslocknumlockscrolllock-lights/
OK,到此结束……
/*----------------------------------------------------------------------------------------------------------------------------*/
显然,你不想为一个功能装上一个软件吧!所以我们就对C代码进行一个修改,让他能够完成这项工作。
这里就不得不用到一个内核级的WindowsAPI调用NtCreatefile()神器。
首先此函数在 Winternl.h 下有申明,里面记载着内核调用的各种原型,但它并没有导入到标准的库中,要使用他只能采用载入运行时动态链接库的方式,简称动态载入库。
在代码中写入:
HINSTANCE hinstLib;
hinstLib=LoadLibrary(_T("NtDll.dll"));
在函数外定义好NtCreatefile的原型:(参数中的WINAPI漏了会出现外部命令解析错误)
typedef NTSTATUS (WINAPI *ntcf)( _Out_ PHANDLE FileHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_In_opt_ PLARGE_INTEGER AllocationSize,
_In_ ULONG FileAttributes,
_In_ ULONG ShareAccess,
_In_ ULONG CreateDisposition,
_In_ ULONG CreateOptions,
_In_ PVOID EaBuffer,
_In_ ULONG EaLength
);
重点是设置好设备注册时的路径:(这个在注册表里可以查到的)
wfilename->Buffer = _T("\\Device\\KeyboardClass2");
这里我的是KeyboardClass2,因电脑而已,0、1、2、3都尝试一下吧。(注:_T是获取Unicode的编码格式)
完事后要检查loadlibrary的成功性,获取函数入口地址并且执行:
if (hinstLib != NULL)
{
ProcAdd = (ntcf) GetProcAddress(hinstLib, "NtCreateFile"); // If the function address is valid, call the function.
if (NULL != ProcAdd)
{
fRunTimeLinkSuccess = TRUE;
(ProcAdd) ((PHANDLE)&hKeybd,(ACCESS_MASK)(+0x00000100+0x00000080+0x00100000),objattrib,io,,,,,(ULONG)(0x00000040+0x00000020),,);
}
// Free the DLL module.
fFreeResult = FreeLibrary(hinstLib);
}
这里的参数很复杂,也让我头疼了半天,主要是仔细看MSDN官方文档,尤其是其中的objattrib设置是关键:
InitializeObjectAttributes(objattrib,wfilename,OBJ_CASE_INSENSITIVE,NULL,NULL);
这是一个专门初始化这个数据结构的函数,一般情况下第三个参数就是使用OBJ_CASE_INSENSITIVE,别的一加进去就不行,即便你用的或,由于或实际上是“+”,也就是功能相加,如果其中的参数是带限制性的,出来的问题就是受限制更多。如果函数执行时出现IO方面的错误,通过上面的io参数查看对应码就能知道了。
若一切顺利下面的检查就能通过了:
// If unable to call the DLL function, use an alternative.
if (! fRunTimeLinkSuccess)
{
printf("Message printed from executable\n");
return ;
}
当然,hKeybd句柄的返回值一定不能是NULL,必须保证有所返回才说明函数执行成功。
成功后就可以发参数操控了,这里先解释一下操控原理:
每当用户在键盘上按下一个按键的时候就会在系统中写入一个键盘输出报告,这个报告会通知所有键盘设备作出相应的改变,例如你在笔记本电脑把scroll lock灯点亮的,别的键盘的灯也会亮,实际上他只是在键盘输入报告中写入了一个字节:

后三位就是灯状态的记录,1表示亮,0表示不亮,所有键盘都会根据这个状态改变,所有我们要做的就是更改这个键盘报告这个字节中的后三位即可。
根据这个我们可以写三个宏定义,表示灯的情况:
#define KBD_CAPS 4
#define KBD_NUM 2
#define KBD_SCROLL 1
更改输出报告的状态,使用DeviceIoControl()神器,原型如下:
BOOL WINAPI DeviceIoControl(
_In_ HANDLE hDevice,
_In_ DWORD dwIoControlCode,
_In_opt_ LPVOID lpInBuffer,
_In_ DWORD nInBufferSize,
_Out_opt_ LPVOID lpOutBuffer,
_In_ DWORD nOutBufferSize,
_Out_opt_ LPDWORD lpBytesReturned,
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
哪些参数是输入哪些是输出一目了然。
首先通过buffer获取灯状态:
DeviceIoControl(hKeybd, IOCTL_KEYBOARD_QUERY_INDICATORS, , , &buffer, sizeof(buffer), &retlen, );//buffer拿不到灯状态信息.
接着给buffer赋值:
buffer.wFlags ^= wFlags ;
这个异或操作实际上是为了关与开,如果原来是开的那就关了他,如果关着的就打开它:
DeviceIoControl(hKeybd, IOCTL_KEYBOARD_SET_INDICATORS, &buffer, sizeof(buffer), , , &retlen, );
其中的宏需要有自定义:
// most of these are taken from ntkbdddk.h or w/e it's called
#define IOCTL_KEYBOARD_SET_INDICATORS CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0002, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_KEYBOARD_QUERY_TYPEMATIC CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0008, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_KEYBOARD_QUERY_INDICATORS CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS)
好了,做个测试,给buffer传对应参数,这个时候对应灯就成功点亮了。
这个技能可以做的事情很多,尤其是接近被废弃的scroll lock的灯,可以将他变成邮件通知,或者是各种需求的通知,这就根据需要而定了,如果要改成C#版本也非常容易,毕竟都是调用dll的api实现的,或许还能做成让他随音乐跳到,变成disco模式,随便玩吧。
让USB键盘的LED灯听你的!(不干扰使用)的更多相关文章
- 基于arduino UNO R3+ESP8266控制LED灯的开关(无USB转TTL工具实现)
最近由于项目要求,需要开发物联网云平台,而本人对硬件和通信技术一窍不通,故而选择arduino这一简单单片机来实现学习掌握基础的硬件和通信技术. 下面就是本人通过查阅大佬资料做的一个整合版本的通过手机 ...
- 用LED灯和按键来模拟工业自动化设备的运动控制
开场白: 前面三节讲了独立按键控制跑马灯的各种状态,这一节我们要做一个机械手控制程序,这个机械手可以左右移动,最左边有一个开关感应器,最右边也有一个开关感应器.它也可以上下移动,最下面有一个开关感应器 ...
- 我的 FPGA 学习历程(02)—— 实验:点亮 LED 灯
关于 Quartus 的操作可以使用 Quartus 自带的帮助,帮助中带有全套的操作教程. 中文网络教程链接(链接至 altera中文官网,点击观看) Quartus II 软件设计系列:基础 Qu ...
- 51单片机学习笔记(郭天祥版)(1)——单片机基础和点亮LED灯
关于单片机型号的介绍: STC89C52RC40C-PDIP 0721CV4336..... STC:STC公司 89:89系列 C:COMS 52(还有51,54,55,58,516,):2表示存储 ...
- USB键盘驱动分析
简介 本文介绍USB驱动程序编写的流程,分析一个键盘的USB程序,基于linux-2.6.39 USB驱动概要 分层 主机层面的USB驱动的整体架构可以分成4层,自顶到下依次是 1.USB设备驱动:本 ...
- Arduino 翻译系列 - LED 灯闪烁
原文地址 - https://www.arduino.cc/en/Tutorial/Blink 闪烁 这个例子展示了你能拿 Arduino / Genuino 板子来干的最简单的事:使开发板上的 LE ...
- 警惕USB键盘记录器
最近媒体报道了一种新型的能记录账号.密码输入的“USB键盘记录器”,引发网友关注,该设备看上去和普通U盘没什么区别,将其插入电脑USB接口,然后把键盘线和它连接,该设备就能够自动记录用户在电脑上输入的 ...
- arduino 红外遥控器控制LED灯
/* 日期:2016.9.1 功能:红外遥控器控制LED灯 开,关,闪烁,呼吸 元件: 跳线公公头 * 5 led 220欧电阻 红外接收管,红外遥控 接线: 红外灯面向自己从左到右分别接 IO3 , ...
- Beaglebone Black–GPIO 高低电平控制 LED 灯
上一篇,运用 Linux 的 sysfs,控制本机上的 LED 灯,usr0 至 usr3,这次用 GPIO 控制外部的电路,点亮 LED 灯. 这次的全部材料: BBB 一台 购买 BBB 自带的 ...
随机推荐
- C#开发移动平台iOS、Android 与Windows
1.Xamarin http://www.csdn.net/article/2014-02-28/2818585-Xamarin-CSDN-mobile-develop
- 解决DATASNAP远程方法参数超过32个的问题
群里有位同仁提出他有一个DATASNAP远程方法超过了32个参数,然后DELPHI编译通不过,提示方法参数不能超过32个,问怎么办?于是群内同仁纷纷出主意,我说用OLEVARINAT数组,有人说用RE ...
- solr4.0.0学习(二) 数据库导入clob与blob为索引
导入clob很简单.但是blob好像没有提供方法,所以改了一下源码,重新编译替换class文件,竟然成功了. 先把配置文件贴上 SCHEMA.XML <?xml version="1. ...
- MINA学习之IoService
从上一篇文章中知道,IoService出于MINA体系中的底层.IoService将会帮你维护网络交互,接受消息,发送消息,管理Sessions,管理连接Connections等等. IoServic ...
- 软件项目量化管理(CMMI高成熟度)实践经验谈——之项目管理过程策划篇
续:软件项目量化管理(CMMI高成熟度)实践经验谈--之概述篇 二.项目管理过程 软件开发项目管理过程,从项目全视角来看,分为售前.售中.售后等三个大的阶段.本文所谈的是售中阶段项目管理过程,在售中阶 ...
- Yet Another 10 Common Mistakes Java Developers Make When Writing SQL (You Won’t BELIEVE the Last One)--reference
(Sorry for that click-bait heading. Couldn’t resist ;-) ) We’re on a mission. To teach you SQL. But ...
- hdu2015java
偶数求和 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submissio ...
- android之frame动画详解
上一篇我们说了android中的tween动画,这一篇我们说说frame动画,frame动画主要是实现了一种类似于gif动画的效果,就是多张图按预先设定好的时间依次连续显示. 新建一个android项 ...
- VC++ 响应回车键的2种方法
众所周知,VC++响应回车键经常用的方法是利用 BOOL PreTranslateMessage(MSG* pMsg) 截取回车键消息,如: if (pMsg->message == WM_KE ...
- Android(java)学习笔记188:关于构造代码块,构造函数的一道面试题(华为面试题)
1.源码是: package text; public class TestStaticCon { public static int a = 0; static { a = 10; System.o ...