阅读:3998回复:10
键盘过滤驱动(精简)
发一份ctrl2cap代码(去除了许多功能部分).
对于初学者来说,我相信最简单的可用代码是学习入门的最好方法。 同样作为初学者的我,总希望能找到最简单的可用代码,以便于快速理解学习。 代码如下: #include "ntddk.h" #include "ntddkbd.h" #include "stdio.h" //包含三个要用到的头文件 #define KEY_UP 1 #define KEY_DOWN 0 //定义按键按下、弹起标志 #define LCONTROL ((USHORT)0x1D) #define CAPS_LOCK ((USHORT)0x3A) //定义按键扫描码 PDEVICE_OBJECT HookDeviceObject; PDEVICE_OBJECT kbdDevice; //声明两个全局变量---设备对象 NTSTATUS Ctrl2capInit( IN PDRIVER_OBJECT DriverObject ); NTSTATUS Ctrl2capDispatchRead( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS Ctrl2capReadComplete( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ); NTSTATUS Ctrl2capDispatchGeneral(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp ); //函数使用前的声明 NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath) //驱动入口 { DbgPrint("DriverEntry starting...\n"); //输出调试信息,可用Dbgview查看。 DriverObject->MajorFunction[IRP_MJ_READ] = Ctrl2capDispatchRead; //读按键分派例程,有按键按下时才开始执行。 DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = DriverObject->MajorFunction[IRP_MJ_CLEANUP] = DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Ctrl2capDispatchGeneral; //有建立事件,关闭事件,应用程序调用时才执行。 return Ctrl2capInit(DriverObject); //直接执行的初始化例程 } NTSTATUS Ctrl2capInit( IN PDRIVER_OBJECT DriverObject ) { CCHAR ntNameBuffer[64]; STRING ntNameString; UNICODE_STRING ntUnicodeString; NTSTATUS status; //定义一些要用到的变量 DbgPrint("Ctrl2capInit starting...\n"); //调试用信息 sprintf( ntNameBuffer, "\\Device\\KeyboardClass0" ); RtlInitAnsiString( &ntNameString, ntNameBuffer ); RtlAnsiStringToUnicodeString( &ntUnicodeString, &ntNameString, TRUE ); status = IoCreateDevice( DriverObject, 0, NULL, FILE_DEVICE_KEYBOARD, 0, FALSE, &HookDeviceObject ); //建立一键盘类设备 if( !NT_SUCCESS(status) ) { DbgPrint("Ctrl2cap: Keyboard hook failed to create device!\n"); RtlFreeUnicodeString( &ntUnicodeString ); return STATUS_SUCCESS; } HookDeviceObject->Flags |= DO_BUFFERED_IO; status = IoAttachDevice( HookDeviceObject, &ntUnicodeString, &kbdDevice ); //连接我们的过滤设备到\\Device\\KeyboardClass0设备上 if( !NT_SUCCESS(status) ) { DbgPrint("Ctrl2cap: Connect with keyboard failed!\n"); IoDeleteDevice( HookDeviceObject ); RtlFreeUnicodeString( &ntUnicodeString ); return STATUS_SUCCESS; } RtlFreeUnicodeString( &ntUnicodeString ); DbgPrint("Ctrl2cap: Successfully connected to keyboard device\n"); return STATUS_SUCCESS; } NTSTATUS Ctrl2capDispatchRead( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) //有按键按下时执行 { PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); //获取当前的IRP包 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); *nextIrpStack = *currentIrpStack; IoSetCompletionRoutine( Irp, Ctrl2capReadComplete, DeviceObject, TRUE, TRUE, TRUE ); //调用完成例程 return IoCallDriver( kbdDevice, Irp ); } NTSTATUS Ctrl2capReadComplete( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { PIO_STACK_LOCATION IrpSp; PKEYBOARD_INPUT_DATA KeyData; IrpSp = IoGetCurrentIrpStackLocation( Irp ); if( NT_SUCCESS( Irp->IoStatus.Status ) ) { KeyData = Irp->AssociatedIrp.SystemBuffer; DbgPrint("ScanCode: %x ", KeyData->MakeCode ); DbgPrint("%s\n", KeyData->Flags ? "Up" : "Down" ); //输出按键的扫描码 if( KeyData->MakeCode == CAPS_LOCK) { KeyData->MakeCode = LCONTROL; //修改按键 } } if( Irp->PendingReturned ) { IoMarkIrpPending( Irp ); } return Irp->IoStatus.Status; } NTSTATUS Ctrl2capDispatchGeneral( //通用事件处理例程 IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; if( DeviceObject == HookDeviceObject ) { *nextIrpStack = *currentIrpStack; return IoCallDriver( kbdDevice, Irp ); } else { return STATUS_SUCCESS; } } 以上代码可直接编译成驱动文件,运行后可用Dbgview查看按键的扫描码。 |
|
沙发#
发布于:2007-07-15 02:24
在此顺便向大牛们请教个问题:应用程序 如何控制 键盘过滤驱动实现获取按键信息(可查看,修改)???
也就是说上面的代码虽然能获取键盘按键(整个系统的按健)。 但是我想做的是:当应用程序需要获取按键的扫描码时,驱动才开始获取,当应用程序不需要时,就停止。 想到头疼都不知如何实现,希望大牛们能出手帮忙,给个代码,或是思路!!! 想到的几个方法: 1:由应用程序加载驱动,开始获取按键信息(可查看,修改),不需要时卸载驱动。 不过过滤驱动要动态卸载实现起来很有难度,也不是个好方法。 2:由应用程序ReadFile实现?不知可行不? 3:由应用程序DeviceIoControl实现?可能这方法可以,不过我不知道如何实现!!! 4:由应用程序事件方面实现,没往这方面想。 想到希望能快点解决!!! |
|
板凳#
发布于:2007-07-18 15:48
看来你和我一样是个牛犊,你的问题说白了就是,
应用程序 与 驱动程序 通讯的问题, 通过这个函数 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] 来发送指令,就可以了 至于指令,使自己定义的,类似于 MFC自己定义的消息, 就是 CTL_CODE 宏, 例如:#define IOCTL_SET_KEYBOARD_DOWN CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0405, METHOD_BUFFERED, FILE_ANY_ACCESS) 能通讯了,那么 事情就好办了,你可以设置一个事件 或者开关变量, 如果开关打开了,你就截获,否则不解货 不久完了,我也是个菜鸟... 希望没有误导你... |
|
地板#
发布于:2007-07-19 02:26
楼上兄台,具体要怎么做?
已实现用户程序通过DeviceIoControl(控制码为自己定义)和驱动程序通讯。 问题是有按键时,按键的IRP是发给键盘过滤驱动(也就是整个系统),而不是单单在我的用户程序中实现。 期待有人浪费一点时间帮我搞定这个让我郁闷了好久的问题,谢谢先!!! |
|
地下室#
发布于:2007-07-19 09:41
用户被禁言,该主题自动屏蔽! |
|
5楼#
发布于:2007-07-20 04:19
楼上兄弟给的网址已去看过,看过之后发现那样好象很复杂,不过倒又学到了一些。
现在发现其实用动态加载和卸载键盘过滤驱动的方法,应该更简单些,不知是否? 另:楼上兄弟可会韩语,韩国MM真漂亮呀(虽说大多数整过容),但要是会韩语,那可就太好了。 |
|
6楼#
发布于:2007-07-20 09:25
用户被禁言,该主题自动屏蔽! |
|
7楼#
发布于:2007-07-20 15:33
在家呀,白天没时间,活动时间一般是晚上1点过后。
其实我要实现的跟Ctrl2cap例子一样,就是获取键盘按键的IRP包,然后修改(Caps Lock键转为Control键),并不需要自己发IRP模拟按键。 只不Ctrl2cap是针对整个系统,而我要实现的是局限于个人程序。 |
|
8楼#
发布于:2008-12-22 17:24
我是菜鸟来的,请问一下“ntddkbd.h”引入为什么用引号方式?不是用<ntddkbd.h>的吗?两者有什么区别?哪位高手能否指点一下?多谢了
|
|
9楼#
发布于:2009-01-08 10:19
<>是先在源文件所在目录中查找ntddkbd.h文件
""是先在环境变量指定目录查找ntddkbd.h文件 查找ntddkbd.h文件的顺序不同而已,功能基本一样的 |
|
|
10楼#
发布于:2009-02-19 18:44
*nextIrpStack = *currentIrpStack; 鸡肋
|
|