让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 自带的 ...
随机推荐
- poj 3237 Tree(树链剖分,线段树)
Tree Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 7268 Accepted: 1969 Description ...
- Bzoj 3505: [Cqoi2014]数三角形 数论
3505: [Cqoi2014]数三角形 Time Limits: 1000 ms Memory Limits: 524288 KB Detailed Limits Description
- (DT系列一)DTS结构及其编译方法
DTS结构及其编译方法 一:主要问题 1,需要了解dtsi与dts的关系 2,dts的结构模型 3,dts是如何被编译的,以及编译后会生成一个什么文件. 二:参考文字 1,DTS(device tre ...
- window7电脑设置好了,却无法远程?
设置远程连接: 步骤:右键[我的电脑]-->[属性] 点击[远程设置],然后设置如下: 在 cmd 中 通过 [ipconfig]命令查看IP: 以上设置好了,发现仍无法远程?解决办法如下: 电 ...
- android开发环境与工具使用相关备忘录
一.名称简介 1.ADT(Android Development Tools) 可以简单理解为在eclipse下开发安卓的插件或工具包. 查看当前ADT版本方法:help-> about ecl ...
- Linux达人养成计划1(第2章 Linux系统安装)
2.3 系统分区之分区与格式化 1. 分区类型 主分区:最多只能有四个. 扩展分区: 最多只能有1个. 主分区加扩展分区最多有4个. 不能写入数据,只能包含逻辑分区. 逻辑分区: 2. 格式化(高级格 ...
- Shell简介:什么是Shell,Shell命令的两种执行方式
Shell本身是一个用C语言编写的程序,它是用户使用Unix/Linux的桥梁,用户的大部分工作都是通过Shell完成的.Shell既是一种命令语言,又是一种程序设计语言.作为命令语言,它交互式地解释 ...
- Android 镜像地址[持续更新中]
这里收集android国内镜像资源地址 大连东软信息学院镜像服务器地址:– http://mirrors.neusoft.edu.cn 端口:80北京化工大学镜像服务器地址:– IPv4: http: ...
- js两个时间比较
var applyStart = $("#ApplyStart").val().replace(/-/g,'/'); var applyEnd = $("#ApplyEn ...
- Java或web中解决所有路径问题
Java开发中使用的路径,分为两种:绝对路径和相对路径.归根结底,Java本质上只能使用绝对路径来寻找资源.所有的相对路径寻找资源的方法,都不过是一些便利方法.不过是API在底层帮助我们构建了绝对路径 ...