阅读:7356回复:6
[学习]通过驱动实现模拟键盘鼠标操作的思路
最近想试着做个模拟键盘鼠标操作的小程序,几经努力终于完成了PostMessage, keybd_event的方法。但发现对于游戏Direct Input来说这一点用也没有。
查阅资料后,正式决定开始学习驱动编写,希望大家多多给予指点。 首先想到的是创建一个虚拟的键盘,让系统也认为它是一个真正的键盘,然后利用程序控制它发出指定的按键信息。在我的系统中也发现有类似设备,比如微软的"SMS Virtual Keyboard", "SMS Virtual Mouse",是在kbdclass和mouclass之下的设备。 我的思路是: 1。编写一个键盘的上层过滤驱动,创建一个虚拟设备,挂接到kbdclass设备下 2。在应用程序中打开这个设备,通知驱动程序按指定数据创建Irp实现模拟 但问题是: 1、这样虚拟设备的方法正确吗?为什么微软的"SMS Virtual Keyboard"在设备管理器中却看不到? 2、我能不能用应用程序实现上面的操作?若可以,又能否直接访问打开系统真正的键盘来操作? 3、应该创建什么样的Irp?是直接对60/64端口的I/O?但这样必定不通用,能否利用系统HAL接口实现?又如何访问HAL? 希望大家将你知道的为我解惑,谢谢了 继续关注中。。。 |
|
沙发#
发布于:2007-02-05 20:29
NTSTATUS DispatchWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{ PDEVICE_EXTENSION devExt; PIO_STACK_LOCATION currentIrpStack; PIO_STACK_LOCATION nextIrpStack; // // Gather our variables. // devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; currentIrpStack = IoGetCurrentIrpStackLocation(Irp); nextIrpStack = IoGetNextIrpStackLocation(Irp); // Push params down for keyboard class driver. *nextIrpStack = *currentIrpStack; // Set the completion callback IoSetCompletionRoutine(Irp, WriteComplete, DeviceObject, TRUE, TRUE, TRUE); // Return the results of the call to the keyboard class driver. return IoCallDriver(devExt->NextStackDevice,Irp); } //---------------------------------------------------------------------- // WriteComplete //---------------------------------------------------------------------- NTSTATUS WriteComplete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { PIO_STACK_LOCATION IrpSp; PKEYBOARD_INPUT_DATA KeyData; int numKeys, i; // Request completed - look at the result. IrpSp = IoGetCurrentIrpStackLocation(Irp); if(NT_SUCCESS(Irp->IoStatus.Status)) { KeyData = (PKEYBOARD_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer; numKeys = Irp->IoStatus.Information / sizeof(PKEYBOARD_INPUT_DATA); for( i = 0; i < numKeys; i++ ) { if(KeyData.MakeCode==LCONTROL) { KeyData.MakeCode = SPACE; } if(KeyData.MakeCode==RCONTROL) { KeyData.MakeCode = SPACE; } } } // Mark the Irp pending if required if( Irp->PendingReturned ) { IoMarkIrpPending(Irp); } return Irp->IoStatus.Status; } |
|
板凳#
发布于:2007-02-28 20:29
终于发现写驱动不是那么简单。。
但同时又发现 原来用RING0下直接端口I/O也能实现 虽然有N大局限性 如果写驱动不知道如何创建IRP来模拟按键,还是不能达到目的。。 继续研究。。 |
|
地板#
发布于:2007-03-28 23:40
顶一个~~~~偶也对这个感兴趣~~~~~
|
|
|
地下室#
发布于:2007-04-10 14:05
![]() |
|
5楼#
发布于:2007-04-12 12:30
发现用ZwDebugControl()进行60/64的I/O,可以模拟PS/2的Keyboard和PS/2的鼠标。
但前提是你必须有物理的PS/2键盘和PS/2鼠标 我试过只接了USB鼠标,结果一模拟鼠标就用不了PS/2键盘了,所有输入都无效 只能重启。 估计是端口数据缓冲区出错 还有在pudn网上找到个Fakeyboard的驱动,虚拟了一个在devmgr里能看到的键盘 其关键代码: typedef struct { int Count; struct { int Press; int Code; }Keys[6]; }VK_SENDKEY,*PVK_SENDKEY; .... NTSTATUS DeviceControl(IN PDEVICE_OBJECT fdo,IN PIRP Irp) { if(FunctionDevice != fdo) { PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp); ULONG CtlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode; DbgPrint("device io ctrl code = %x\n",CtlCode); PDEVICE_EXTENSION dx = (PDEVICE_EXTENSION)fdo->DeviceExtension; IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver( dx->NextStackDevice, Irp); } PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; ULONG BytesTxd = 0; ULONG ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode; PVK_SENDKEY ioBuffer = (PVK_SENDKEY)Irp->AssociatedIrp.SystemBuffer; ULONG InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength; //ULONG OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength; switch( ControlCode) { case IOCTL_SENDKEY: if( (ioBuffer==0) || (InputLength < sizeof(VK_SENDKEY)) || (ioBuffer->Count > 5) ) { status = STATUS_INVALID_PARAMETER; break; } // Send data to KeyboardClass { ULONG NumSend = 0; MYKEYBOARD_INPUT_DATA Data[6]; for(int i =0 ; i< ioBuffer->Count ; i++) { if( ioBuffer->Keys[i].Press == 0 ) { Data[i].Flags = KEY_BREAK; } Data[i].UnitId = UnitId ; Data[i].MakeCode = ioBuffer->Keys[i].Code; } SeviceCallback(KeyboardClassDO,Data,&Data[ioBuffer->Count],&NumSend); } status = STATUS_SUCCESS; break; default: status = STATUS_INVALID_DEVICE_REQUEST; } // Complete IRP return CompleteIrp(Irp,status,BytesTxd); } dll: extern "C" SENDKEY_API int VKSendKey(PVK_SENDKEY key) { HANDLE file = CreateFile(DEVICE_NAME,GENERIC_WRITE|GENERIC_READ,0,0,OPEN_EXISTING,0,0); if(file == INVALID_HANDLE_VALUE) { return false; } DWORD BytesRet = 0; int ret = DeviceIoControl(file,IOCTL_SENDKEY,key,sizeof(VK_SENDKEY),0,0,&BytesRet,0); if(ret == 0) { return false; } CloseHandle(file); return true; } extern "C" SENDKEY_API HANDLE VKOpenVirtualKey() { return CreateFile(DEVICE_NAME,GENERIC_WRITE|GENERIC_READ,0,0,OPEN_EXISTING,0,0); } extern "C" SENDKEY_API int VKCloseVirtualKey(HANDLE VKHandle) { return CloseHandle(VKHandle); } extern "C" SENDKEY_API int VKSendKeyEx(HANDLE VKHandle,PVK_SENDKEY key) { DWORD BytesRet = 0; return DeviceIoControl(VKHandle,IOCTL_SENDKEY,key,sizeof(VK_SENDKEY),0,0,&BytesRet,0); } 但没找到PS/2鼠标的模拟程序,希望有人能搞出来 能支持USB的就更好了 ![]() |
|
6楼#
发布于:2012-06-06 18:02
我也好像写一个虚拟鼠标,但是不知道思路是什么?
|
|