tmp002
驱动牛犊
驱动牛犊
  • 注册日期2007-01-25
  • 最后登录2008-02-14
  • 粉丝0
  • 关注0
  • 积分20分
  • 威望3点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
阅读:6959回复:6

[学习]通过驱动实现模拟键盘鼠标操作的思路

楼主#
更多 发布于:2007-02-02 12:00
  最近想试着做个模拟键盘鼠标操作的小程序,几经努力终于完成了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?

希望大家将你知道的为我解惑,谢谢了

继续关注中。。。
xiaopengyp
驱动牛犊
驱动牛犊
  • 注册日期2005-08-30
  • 最后登录2008-03-10
  • 粉丝0
  • 关注0
  • 积分520分
  • 威望53点
  • 贡献值0点
  • 好评度52点
  • 原创分0分
  • 专家分0分
沙发#
发布于: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;
}
tmp002
驱动牛犊
驱动牛犊
  • 注册日期2007-01-25
  • 最后登录2008-02-14
  • 粉丝0
  • 关注0
  • 积分20分
  • 威望3点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2007-02-28 20:29
终于发现写驱动不是那么简单。。

但同时又发现 原来用RING0下直接端口I/O也能实现 虽然有N大局限性

如果写驱动不知道如何创建IRP来模拟按键,还是不能达到目的。。

继续研究。。
computer00
驱动小牛
驱动小牛
  • 注册日期2004-09-27
  • 最后登录2009-08-22
  • 粉丝0
  • 关注0
  • 积分1002分
  • 威望120点
  • 贡献值0点
  • 好评度110点
  • 原创分0分
  • 专家分0分
地板#
发布于:2007-03-28 23:40
顶一个~~~~偶也对这个感兴趣~~~~~
博客Http://computer00.21ic.org
rom007
驱动牛犊
驱动牛犊
  • 注册日期2007-03-24
  • 最后登录2008-01-05
  • 粉丝0
  • 关注0
  • 积分160分
  • 威望17点
  • 贡献值0点
  • 好评度16点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2007-04-10 14:05
tmp001
驱动牛犊
驱动牛犊
  • 注册日期2005-09-20
  • 最后登录2010-04-04
  • 粉丝0
  • 关注0
  • 积分20分
  • 威望3点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
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的就更好了
wangjd123
驱动牛犊
驱动牛犊
  • 注册日期2009-06-08
  • 最后登录2012-06-25
  • 粉丝0
  • 关注0
  • 积分6分
  • 威望41点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2012-06-06 18:02
我也好像写一个虚拟鼠标,但是不知道思路是什么?
游客

返回顶部